mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-29 04:46:50 -06:00
fix(text): the caret after a line break sits on the next line
`caret` put the index right after a line break (a newline, or a line separator) at the end of the line above, so after Enter the caret showed on the previous line until something was typed, and Up/Down counted lines from there. The index before the break stays at the end of its line; the one after it is now on the next line, as after a wrap. Selection highlights already started such lines at their own start (#665); their comment no longer describes the old caret.
This commit is contained in:
@@ -1171,16 +1171,12 @@ impl TextLayout {
|
||||
pub fn caret(&self, index: usize) -> (f64, usize) {
|
||||
for (li, line) in self.lines.iter().enumerate() {
|
||||
let last_line = li + 1 == self.lines.len();
|
||||
// A caret at a line's end belongs to the next line, whether the line wraps or ends with a
|
||||
// line break (before the break it is still on this line: past its glyphs).
|
||||
let in_line = index >= line.char_start && (index < line.char_end || (last_line && index <= line.char_end));
|
||||
// A caret at the end of a soft-wrapped line belongs to the next line.
|
||||
if !(in_line || index == line.char_end && line.break_after && !last_line) {
|
||||
if !in_line {
|
||||
continue;
|
||||
}
|
||||
if index == line.char_end && line.break_after && !last_line {
|
||||
// Before the line break: end of this line.
|
||||
let x = self.line_end_x(line);
|
||||
return (x, li);
|
||||
}
|
||||
let gl = self.glyphs.get(line.glyph_start..line.glyph_end).unwrap_or(&[]);
|
||||
for g in gl {
|
||||
if g.char_end == g.char_start {
|
||||
@@ -1303,8 +1299,7 @@ impl TextLayout {
|
||||
out.extend(Self::mixed_selection(gl, a, b, line));
|
||||
continue;
|
||||
}
|
||||
// From the line's own start: `caret(char_start)` after a hard break is the end of the
|
||||
// line above.
|
||||
// From the line's own start.
|
||||
let x0 = if a <= line.char_start { self.line_start_x(line) } else { self.caret(a).0 };
|
||||
let x1 = if b >= line.char_end {
|
||||
// The last line has no paragraph break to show, so it ends at its glyphs.
|
||||
|
||||
@@ -481,3 +481,19 @@ fn selection_after_a_line_break_starts_at_the_line_start() {
|
||||
// A break followed by text still doesn't highlight the next line's start.
|
||||
assert!(rect_on(&l, &l.selection_rects(0, 6), 1).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_caret_after_a_line_break_sits_on_the_next_line() {
|
||||
if !have_fonts() {
|
||||
return;
|
||||
}
|
||||
// Before the break: the end of its line; after it: the start of the next (after Enter, the
|
||||
// caret shows on the new line, and Up/Down count from there).
|
||||
let l = layout(&TextData::new("ab\ncd"), None, None);
|
||||
assert_eq!(l.caret(2).1, 0);
|
||||
assert!(l.caret(2).0 > 0.0);
|
||||
assert_eq!(l.caret(3), (0.0, 1));
|
||||
// A trailing break: the caret sits on the empty last line.
|
||||
let l = layout(&TextData::new("ab\n"), None, None);
|
||||
assert_eq!(l.caret(3), (0.0, 1));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user