fix: expand copy-mode word-end window past a final wide glyph (#2145)

point_is_final_atom compared an atom's terminating column against a
word-motion target's starting column. The two are equal for narrow
cells but never for wide ones, so the read window stopped expanding
and copy-mode `e` halted at the soft-wrap boundary on CJK text.

Co-authored-by: Can Celik <ogulcancelik@gmail.com>
This commit is contained in:
Akira TSURUDA 2026-08-01 22:40:57 +09:00 committed by GitHub
parent f99647b2c2
commit f459a0df31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 28 additions and 4 deletions

View File

@ -855,14 +855,14 @@ impl RetainedTextBuffer {
}
fn point_is_final_atom(&self, point: TerminalTextPoint) -> bool {
// Word motion targets are atom start points, so compare against the
// final atom's start point. Comparing against `end_col` would never
// match a wide glyph, whose end column is one past its start.
self.atoms
.iter()
.rev()
.find(|atom| atom.point.is_some())
.is_some_and(|atom| {
atom.point
.is_some_and(|start| start.row == point.row && atom.end_col == point.col)
})
.is_some_and(|atom| atom.point == Some(point))
}
}
@ -3291,6 +3291,30 @@ mod tests {
);
}
#[test]
fn live_terminal_word_end_expands_through_a_long_wide_soft_wrap() {
let (tx, _rx) = mpsc::channel(4);
let mut terminal = crate::ghostty::Terminal::new(2, 3, 200).unwrap();
let word = "".repeat(66);
terminal.write(word.as_bytes());
let pane = PaneTerminal::new(GhosttyPaneTerminal::new(terminal, tx).unwrap());
let text_match = pane.search_text_matches(&word, true)[0];
// The word end sits on the head cell of the final wide glyph, past the
// initial read window, so the window has to expand to reach it.
assert_eq!(
pane.word_motion_target(
text_match.start.row,
text_match.start.col,
TerminalWordMotion::NextEnd,
),
Some(TerminalTextPoint {
row: text_match.end.row,
col: 0,
})
);
}
fn current_palette_color(pane: &GhosttyPaneTerminal, index: u8) -> crate::ghostty::RgbColor {
let mut core = pane.core.lock().unwrap();
let GhosttyPaneCore {