Simplify text editing state changes

This commit is contained in:
iris committed 2026-09-13 02:42:28 -04:00
1 parent 5fe7c3b6df
commit dc008441e4
2 files changed
+51 -61

No files matched your search

+47 -57
View File
@@ -111,7 +111,7 @@ impl<'a> TextEditCtx<'a> {
self.text.view.buf.layout() self.text.view.buf.layout()
} }
fn refresh(&mut self) { fn clamp_selection_to_layout(&mut self) {
if let Some(sel) = self.text.selection { if let Some(sel) = self.text.selection {
let layout = self.layout(); let layout = self.layout();
self.text.selection = Some(sel.refresh(layout)); self.text.selection = Some(sel.refresh(layout));
@@ -119,8 +119,8 @@ impl<'a> TextEditCtx<'a> {
} }
pub fn take(&mut self) -> String { pub fn take(&mut self) -> String {
let text = self.text.view.buf.text().to_string(); let text = std::mem::take(self.text.view.buf.edit());
self.set(""); self.text.selection = None;
text text
} }
@@ -219,23 +219,21 @@ impl<'a> TextEditCtx<'a> {
if end == 0 { if end == 0 {
return; return;
} }
let start = { let layout = self.layout();
let layout = self.layout(); let start = if word {
if word { sel.focus().previous_logical_word(layout).index()
sel.focus().previous_logical_word(layout).index() } else {
let Some(cluster) = sel.focus().logical_clusters(layout)[0] else {
return;
};
let range = cluster.text_range();
if cluster.is_hard_line_break() || cluster.is_emoji() {
range.start
} else { } else {
let Some(cluster) = sel.focus().logical_clusters(layout)[0] else { self.text.view.buf.text()[..range.end]
return; .char_indices()
}; .next_back()
let range = cluster.text_range(); .map_or(range.start, |(start, _)| start)
if cluster.is_hard_line_break() || cluster.is_emoji() {
range.start
} else {
self.text.view.buf.text()[..range.end]
.char_indices()
.next_back()
.map_or(range.start, |(start, _)| start)
}
} }
}; };
self.delete_range(start, end); self.delete_range(start, end);
@@ -252,27 +250,20 @@ impl<'a> TextEditCtx<'a> {
if start >= self.text.view.buf.text().len() { if start >= self.text.view.buf.text().len() {
return; return;
} }
let end = { let layout = self.layout();
let layout = self.layout(); let end = if word {
if word { sel.focus().next_logical_word(layout).index()
sel.focus().next_logical_word(layout).index() } else {
} else { let clusters = sel.focus().logical_clusters(layout);
let clusters = sel.focus().logical_clusters(layout); let Some(cluster) = clusters[1].as_ref() else {
let Some(cluster) = clusters[1].as_ref() else { return;
return; };
}; cluster.text_range().end
cluster.text_range().end
}
}; };
self.delete_range(start, end); self.delete_range(start, end);
} }
fn delete_range(&mut self, start: usize, end: usize) { fn delete_range(&mut self, start: usize, end: usize) {
let len = self.text.view.buf.text().len();
let (start, end) = (start.min(end).min(len), start.max(end).min(len));
if start == end {
return;
}
self.text.view.buf.edit().replace_range(start..end, ""); self.text.view.buf.edit().replace_range(start..end, "");
self.text.view.buf.changed = true; self.text.view.buf.changed = true;
self.set_caret(start); self.set_caret(start);
@@ -294,31 +285,30 @@ impl<'a> TextEditCtx<'a> {
let prev_sel = self.text.selection; let prev_sel = self.text.selection;
let prev_hit = self.text.double_hit; let prev_hit = self.text.double_hit;
let outcome = { let layout = self.layout();
let layout = self.layout(); let (selection, double_hit) = if drag {
if drag { let Some(selection) = prev_sel else {
prev_sel.map(|sel| (Some(sel.extend_to_point(layout, pos.x, pos.y)), prev_hit)) return;
};
(selection.extend_to_point(layout, pos.x, pos.y), prev_hit)
} else {
let hit = Selection::from_point(layout, pos.x, pos.y);
let index = hit.focus().index();
// Successive clicks at one index select the word, then the line.
if recent && prev_hit == Some(index) {
(Selection::line_from_point(layout, pos.x, pos.y), None)
} else if recent && prev_sel.map(|s| s.focus().index()) == Some(index) {
(
Selection::word_from_point(layout, pos.x, pos.y),
Some(index),
)
} else { } else {
let hit = Selection::from_point(layout, pos.x, pos.y); (hit, None)
let index = hit.focus().index();
// Successive clicks at one index select the word, then the line.
Some(if recent && prev_hit == Some(index) {
(Some(Selection::line_from_point(layout, pos.x, pos.y)), None)
} else if recent && prev_sel.map(|s| s.focus().index()) == Some(index) {
(
Some(Selection::word_from_point(layout, pos.x, pos.y)),
Some(index),
)
} else {
(Some(hit), None)
})
} }
}; };
if let Some((selection, double_hit)) = outcome { self.text.selection = Some(selection);
self.text.selection = selection; self.text.double_hit = double_hit;
self.text.double_hit = double_hit;
}
} }
pub fn deselect(&mut self) { pub fn deselect(&mut self) {
@@ -334,7 +324,7 @@ impl<'a> TextEditCtx<'a> {
if let Some((old, selection)) = self.text.history.pop() { if let Some((old, selection)) = self.text.history.pop() {
self.set(&old); self.set(&old);
self.text.selection = selection; self.text.selection = selection;
self.refresh(); self.clamp_selection_to_layout();
} }
} else if self.text.view.buf.text() != old.0 { } else if self.text.view.buf.text() != old.0 {
self.text.history.push(old); self.text.history.push(old);
+4 -4
View File
@@ -23,7 +23,7 @@ pub struct TextView {
} }
impl TextView { impl TextView {
fn is_blank(&self) -> bool { fn is_empty(&self) -> bool {
self.buf.is_empty() self.buf.is_empty()
} }
@@ -76,7 +76,7 @@ impl TextView {
self.tex.as_ref() self.tex.as_ref()
} }
pub fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { pub fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len {
if self.is_blank() if self.is_empty()
&& let Some(hint) = &self.hint && let Some(hint) = &self.hint
{ {
ctx.width(hint) ctx.width(hint)
@@ -85,7 +85,7 @@ impl TextView {
} }
} }
pub fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { pub fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len {
if self.is_blank() if self.is_empty()
&& let Some(hint) = &self.hint && let Some(hint) = &self.hint
{ {
ctx.height(hint) ctx.height(hint)
@@ -96,7 +96,7 @@ impl TextView {
pub fn draw(&mut self, painter: &mut Painter) -> UiRegion { pub fn draw(&mut self, painter: &mut Painter) -> UiRegion {
let tex = self.render(&mut painter.size_ctx()); let tex = self.render(&mut painter.size_ctx());
let region = tex.size.align(self.align); let region = tex.size.align(self.align);
if self.is_blank() if self.is_empty()
&& let Some(hint) = &self.hint && let Some(hint) = &self.hint
{ {
painter.widget(hint); painter.widget(hint);