fix(tui): route IME-committed Chinese characters directly to composer instead of paste-burst buffer

This commit is contained in:
donglovejava
2026-05-29 06:33:25 +08:00
committed by Hunter Bown
parent 5d0a1c848e
commit 09b4f7898b
2 changed files with 20 additions and 12 deletions
+19 -11
View File
@@ -49,15 +49,24 @@ pub fn handle_paste_burst_key(app: &mut App, key: &KeyEvent, now: Instant) -> bo
}
KeyCode::Char(c) if !has_ctrl_alt_or_super => {
if !c.is_ascii() {
// IME-committed characters (Chinese, Japanese, Korean)
// arrive as individual KeyCode::Char events, typically with
// tens-of-milliseconds gaps between each committed character.
// Paste-burst buffering would lose characters when the IME
// commits slower than the burst heuristic's timing window.
//
// We still call note_plain_char + extend_window so that:
// 1. The burst timing counter advances for non-IME fast
// typing on terminals without bracketed paste support.
// 2. The Enter-suppression window stays open during a rapid
// non-ASCII sequence, preventing premature submission.
// But the character is inserted directly into the composer
// rather than placed into the paste-burst buffer.
if let Some(pending) = app.paste_burst.flush_before_modified_input() {
app.insert_str(&pending);
}
if app.paste_burst.try_append_char_if_active(c, now) {
return true;
}
if let Some(decision) = app.paste_burst.on_plain_char_no_hold(now) {
return handle_paste_burst_decision(app, decision, c, now);
}
app.paste_burst.note_plain_char(now);
app.paste_burst.extend_window(now);
app.insert_char(c);
return true;
}
@@ -190,10 +199,9 @@ mod tests {
);
}
assert!(app.flush_paste_burst_if_due(
t0 + Duration::from_millis(pasted.chars().count() as u64)
+ crate::tui::paste_burst::PasteBurst::recommended_active_flush_delay()
));
// Non-ASCII characters are now inserted directly into the composer
// rather than buffered by paste burst. The Enter suppression window
// kept the newline from submitting prematurely.
assert_eq!(app.input, pasted);
}
@@ -336,4 +344,4 @@ mod tests {
// contract here).
assert!(app.input.is_empty());
}
}
}
+1 -1
View File
@@ -94,7 +94,7 @@ impl PasteBurst {
None
}
fn note_plain_char(&mut self, now: Instant) {
pub(crate) fn note_plain_char(&mut self, now: Instant) {
match self.last_plain_char_time {
Some(prev) if now.duration_since(prev) <= PASTE_BURST_CHAR_INTERVAL => {
self.consecutive_plain_char_burst =