Skip to content

Commit 2ca0216

Browse files
WendellXYclaude
andcommitted
fix(cli): eliminate TUI flash on key navigation for Latin-script content
The full terminal.clear() fix for complex-script glyph artifacts caused a visible screen flash on every j/k navigation. Now only clear when the old or new key actually contains complex-script characters (Arabic, Devanagari, Bengali, Tamil, Thai, and related Indic/SE Asian scripts). Latin-only keys navigate without any flash; complex-script keys still get the full repaint needed to eliminate ratatui diff-renderer ghost cells. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3ad9f7c commit 2ca0216

1 file changed

Lines changed: 50 additions & 3 deletions

File tree

  • langcodec-cli/src/editor

langcodec-cli/src/editor/mod.rs

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,62 @@ pub fn run_browse_command(opts: BrowseOptions) -> Result<(), String> {
101101
if let HandlerResult::Quit = handle_event(&mut app, event) {
102102
break;
103103
}
104-
// Force full repaint when key selection changes to clear complex-script
105-
// glyph artifacts that ratatui's diff renderer leaves behind.
104+
// Complex-script glyphs (Arabic, Bengali, Hindi, …) can render wider
105+
// than unicode-width reports, leaving ghost cells that ratatui's diff
106+
// renderer won't overwrite. A full terminal clear fixes this, but it
107+
// causes a visible flash on every navigation. Only clear when the
108+
// old or new key actually contains complex-script text.
106109
let cur_key_idx = app.key_list_state.selected();
107110
if cur_key_idx != prev_key_idx {
111+
let old_key = prev_key_idx.and_then(|i| app.filtered_keys.get(i).cloned());
112+
let new_key = cur_key_idx.and_then(|i| app.filtered_keys.get(i).cloned());
108113
prev_key_idx = cur_key_idx;
109-
term.terminal.clear().ok();
114+
115+
let needs_clear = [old_key, new_key].iter().any(|k| {
116+
k.as_ref().map(|key| {
117+
app.languages.iter().any(|lang| {
118+
app.get_translation(key, lang)
119+
.map(|v| has_complex_scripts(&v))
120+
.unwrap_or(false)
121+
})
122+
}).unwrap_or(false)
123+
});
124+
125+
if needs_clear {
126+
term.terminal.clear().ok();
127+
}
110128
}
111129
}
112130
}
113131

114132
Ok(())
115133
}
134+
135+
/// Returns true if the string contains characters from scripts whose glyphs
136+
/// commonly render wider than unicode-width predicts (Arabic, Devanagari,
137+
/// Bengali, Tamil, Thai, Gujarati, Gurmukhi, Kannada, Malayalam, Telugu, …).
138+
/// Used to decide whether a full terminal clear is needed to avoid artifacts.
139+
fn has_complex_scripts(s: &str) -> bool {
140+
s.chars().any(|c| {
141+
let cp = c as u32;
142+
matches!(cp,
143+
0x0600..=0x06FF // Arabic
144+
| 0x0750..=0x077F // Arabic Supplement
145+
| 0xFB50..=0xFDFF // Arabic Pres. Forms-A
146+
| 0xFE70..=0xFEFF // Arabic Pres. Forms-B
147+
| 0x0900..=0x097F // Devanagari (Hindi, Marathi, …)
148+
| 0x0980..=0x09FF // Bengali / Assamese
149+
| 0x0A00..=0x0A7F // Gurmukhi (Punjabi)
150+
| 0x0A80..=0x0AFF // Gujarati
151+
| 0x0B00..=0x0B7F // Odia
152+
| 0x0B80..=0x0BFF // Tamil
153+
| 0x0C00..=0x0C7F // Telugu
154+
| 0x0C80..=0x0CFF // Kannada
155+
| 0x0D00..=0x0D7F // Malayalam
156+
| 0x0E00..=0x0E7F // Thai
157+
| 0x0E80..=0x0EFF // Lao
158+
| 0x0F00..=0x0FFF // Tibetan
159+
| 0x1000..=0x109F // Myanmar
160+
)
161+
})
162+
}

0 commit comments

Comments
 (0)