Compare commits

3 Commits

Author SHA1 Message Date
14a9da0553 hold shift to select text 2025-11-22 21:38:16 -05:00
8e08f67627 ctrl x 2025-11-22 21:15:50 -05:00
84b3bf9078 fix zalgotext highlight 2025-11-22 21:14:41 -05:00
2 changed files with 55 additions and 27 deletions

View File

@@ -46,8 +46,9 @@ impl Widget for TextEdit {
fn draw(&mut self, painter: &mut Painter) { fn draw(&mut self, painter: &mut Painter) {
let base = painter.layer; let base = painter.layer;
painter.child_layer(); painter.child_layer();
let region = self.view.draw(painter); self.view.draw(painter);
painter.layer = base; painter.layer = base;
let region = self.region();
let size = vec2(1, self.attrs.line_height); let size = vec2(1, self.attrs.line_height);
match self.selection { match self.selection {
@@ -62,7 +63,8 @@ impl Widget for TextEdit {
} }
TextSelection::Span { start, end } => { TextSelection::Span { start, end } => {
let (start, end) = sort_cursors(start, end); let (start, end) = sort_cursors(start, end);
for (top_left, width) in iter_layout_lines(start, end, &self.buf) { for (l, x, width) in iter_layout_lines(start, end, &self.buf) {
let top_left = vec2(x, self.attrs.line_height * l as f32);
painter.primitive_within( painter.primitive_within(
RectPrimitive::color(Color::SKY), RectPrimitive::color(Color::SKY),
size.with_x(width) size.with_x(width)
@@ -97,34 +99,34 @@ fn iter_layout_lines(
start: Cursor, start: Cursor,
end: Cursor, end: Cursor,
buf: &TextBuffer, buf: &TextBuffer,
) -> impl Iterator<Item = (Vec2, f32)> { ) -> impl Iterator<Item = (usize, f32, f32)> {
gen move { gen move {
let mut iter = buf.layout_runs(); let mut iter = buf.layout_runs().enumerate();
for line in iter.by_ref() { for (i, line) in iter.by_ref() {
if line.line_i == start.line if line.line_i == start.line
&& let Some(start_x) = index_x(&line, start.index) && let Some(start_x) = index_x(&line, start.index)
{ {
if start.line == end.line if start.line == end.line
&& let Some(end_x) = index_x(&line, end.index) && let Some(end_x) = index_x(&line, end.index)
{ {
yield (vec2(start_x, line.line_top), end_x - start_x); yield (i, start_x, end_x - start_x);
return; return;
} }
yield (vec2(start_x, line.line_top), line.line_w - start_x); yield (i, start_x, line.line_w - start_x);
break; break;
} }
} }
for line in iter { for (i, line) in iter {
if line.line_i > end.line { if line.line_i > end.line {
return; return;
} }
if line.line_i == end.line if line.line_i == end.line
&& let Some(end_x) = index_x(&line, end.index) && let Some(end_x) = index_x(&line, end.index)
{ {
yield (vec2(0.0, line.line_top), end_x); yield (i, 0.0, end_x);
return; return;
} }
yield (vec2(0.0, line.line_top), line.line_w); yield (i, 0.0, line.line_w);
} }
} }
} }
@@ -200,18 +202,35 @@ impl<'a> TextEditCtx<'a> {
self.text.selection.clear(); self.text.selection.clear();
} }
pub fn motion(&mut self, motion: Motion) { pub fn motion(&mut self, motion: Motion, select: bool) {
if let TextSelection::Pos(cursor) = self.text.selection if let TextSelection::Pos(cursor) = self.text.selection
&& let Some(cursor) = self.buf_motion(cursor, motion) && let Some(new) = self.buf_motion(cursor, motion)
{ {
self.text.selection = TextSelection::Pos(cursor); if select {
self.text.selection = TextSelection::Span {
start: cursor,
end: new,
};
} else {
self.text.selection = TextSelection::Pos(new);
}
} else if let TextSelection::Span { start, end } = self.text.selection { } else if let TextSelection::Span { start, end } = self.text.selection {
let (start, end) = sort_cursors(start, end); if select {
let sel = &mut self.text.selection; if let Some(cursor) = self.buf_motion(end, motion) {
match motion { self.text.selection = TextSelection::Span { start, end: cursor };
Motion::Left | Motion::LeftWord => *sel = TextSelection::Pos(start), }
Motion::Right | Motion::RightWord => *sel = TextSelection::Pos(end), } else {
_ => (), let (start, end) = sort_cursors(start, end);
let sel = &mut self.text.selection;
match motion {
Motion::Left | Motion::LeftWord => *sel = TextSelection::Pos(start),
Motion::Right | Motion::RightWord => *sel = TextSelection::Pos(end),
_ => {
if let Some(cursor) = self.buf_motion(end, motion) {
self.text.selection = TextSelection::Pos(cursor);
}
}
}
} }
} }
} }
@@ -277,7 +296,7 @@ impl<'a> TextEditCtx<'a> {
edit_line(line, line_text); edit_line(line, line_text);
if mov { if mov {
for _ in 0..text.chars().count() { for _ in 0..text.chars().count() {
self.motion(Motion::Right); self.motion(Motion::Right, false);
} }
} }
} }
@@ -300,7 +319,7 @@ impl<'a> TextEditCtx<'a> {
&& let TextSelection::Pos(cursor) = &mut self.text.selection && let TextSelection::Pos(cursor) = &mut self.text.selection
&& (cursor.index != 0 || cursor.line != 0) && (cursor.index != 0 || cursor.line != 0)
{ {
self.motion(if word { Motion::LeftWord } else { Motion::Left }); self.motion(if word { Motion::LeftWord } else { Motion::Left }, false);
self.delete(word); self.delete(word);
} }
} }
@@ -442,20 +461,20 @@ impl<'a> TextEditCtx<'a> {
} }
NamedKey::ArrowRight => { NamedKey::ArrowRight => {
if modifiers.control { if modifiers.control {
self.motion(Motion::RightWord) self.motion(Motion::RightWord, modifiers.shift)
} else { } else {
self.motion(Motion::Right) self.motion(Motion::Right, modifiers.shift)
} }
} }
NamedKey::ArrowLeft => { NamedKey::ArrowLeft => {
if modifiers.control { if modifiers.control {
self.motion(Motion::LeftWord) self.motion(Motion::LeftWord, modifiers.shift)
} else { } else {
self.motion(Motion::Left) self.motion(Motion::Left, modifiers.shift)
} }
} }
NamedKey::ArrowUp => self.motion(Motion::Up), NamedKey::ArrowUp => self.motion(Motion::Up, modifiers.shift),
NamedKey::ArrowDown => self.motion(Motion::Down), NamedKey::ArrowDown => self.motion(Motion::Down, modifiers.shift),
NamedKey::Escape => { NamedKey::Escape => {
self.deselect(); self.deselect();
return TextInputResult::Unfocus; return TextInputResult::Unfocus;
@@ -472,6 +491,13 @@ impl<'a> TextEditCtx<'a> {
return TextInputResult::Copy(content); return TextInputResult::Copy(content);
} }
} }
"x" => {
if let TextSelection::Span { start, end } = self.text.selection {
let content = self.text.select_content(start, end);
self.clear_span();
return TextInputResult::Copy(content);
}
}
"a" => { "a" => {
if !self.text.buf.lines[0].text().is_empty() if !self.text.buf.lines[0].text().is_empty()
|| self.text.buf.lines.len() > 1 || self.text.buf.lines.len() > 1

View File

@@ -35,6 +35,8 @@ impl TextView {
} }
} }
/// region where the text should be draw
/// does not include extra height or width from weird unicode
pub fn region(&self) -> UiRegion { pub fn region(&self) -> UiRegion {
self.tex() self.tex()
.map(|t| t.size) .map(|t| t.size)