diff --git a/Cargo.lock b/Cargo.lock index d103705..fcaf8ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1018,6 +1018,7 @@ dependencies = [ "tracing-appender", "tracing-panic", "tracing-subscriber", + "unicode-width", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2d8c3da..4572ecd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,3 +20,4 @@ tracing = "0.1" tracing-appender = "0.2" tracing-panic = "0.1" tracing-subscriber = "0.3" +unicode-width = "0.2.2" diff --git a/src/tui/render.rs b/src/tui/render.rs index dad72bb..420b183 100644 --- a/src/tui/render.rs +++ b/src/tui/render.rs @@ -116,7 +116,12 @@ impl TerminalState { .map(|g| g.width(total_lines) as u16) .sum(); let y = cursor.y() as usize; - let screen_x = (cursor.x() as usize).min(display_buffer.line_len(y)) as u16; + let line = display_buffer + .visible_lines(y, y + 1) + .into_iter() + .next() + .unwrap_or_default(); + let screen_x = char_idx_to_display_col(&line, cursor.x() as usize) as u16; frame.set_cursor_position(( rect.x + left_gutter_width + screen_x, rect.y + cursor.y() as u16, @@ -283,6 +288,17 @@ impl TerminalState { } } +/// Convert a char index into a terminal display column by summing the display +/// width of each preceding character. Wide characters (e.g. CJK, hiragana) +/// count as 2 columns; narrow chars count as 1. +fn char_idx_to_display_col(line: &str, char_idx: usize) -> usize { + use unicode_width::UnicodeWidthChar; + line.chars() + .take(char_idx) + .map(|c| c.width().unwrap_or(0)) + .sum() +} + fn process_line(input: &str, expand_tab: usize) -> String { input .chars()