tui: support Ghostty Ctrl-b/Ctrl-f fallback (#2427)
Ensure Emacs-style Ctrl-b/Ctrl-f work when terminals send bare control chars. - Map ^B (U+0002) to move left when no CONTROL modifier is reported. - Map ^F (U+0006) to move right when no CONTROL modifier is reported. - Preserve existing Ctrl-b/Ctrl-f and Alt-b/Alt-f behavior. - Add unit test covering the fallback path. Background: Ghostty (and some tmux/terminal configs) can emit bare control characters for Ctrl-b/Ctrl-f. Previously these could be treated as literal input; with this change both styles behave identically.
This commit is contained in:
@@ -204,6 +204,16 @@ impl TextArea {
|
||||
|
||||
pub fn input(&mut self, event: KeyEvent) {
|
||||
match event {
|
||||
// Some terminals (or configurations) send Control key chords as
|
||||
// C0 control characters without reporting the CONTROL modifier.
|
||||
// Handle common fallbacks for Ctrl-B/Ctrl-F here so they don't get
|
||||
// inserted as literal control bytes.
|
||||
KeyEvent { code: KeyCode::Char('\u{0002}'), modifiers: KeyModifiers::NONE, .. } /* ^B */ => {
|
||||
self.move_cursor_left();
|
||||
}
|
||||
KeyEvent { code: KeyCode::Char('\u{0006}'), modifiers: KeyModifiers::NONE, .. } /* ^F */ => {
|
||||
self.move_cursor_right();
|
||||
}
|
||||
KeyEvent {
|
||||
code: KeyCode::Char(c),
|
||||
// Insert plain characters (and Shift-modified). Do NOT insert when ALT is held,
|
||||
@@ -1142,6 +1152,25 @@ mod tests {
|
||||
assert_eq!(t.cursor(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn control_b_f_fallback_control_chars_move_cursor() {
|
||||
use crossterm::event::KeyCode;
|
||||
use crossterm::event::KeyEvent;
|
||||
use crossterm::event::KeyModifiers;
|
||||
|
||||
let mut t = ta_with("abcd");
|
||||
t.set_cursor(2);
|
||||
|
||||
// Simulate terminals that send C0 control chars without CONTROL modifier.
|
||||
// ^B (U+0002) should move left
|
||||
t.input(KeyEvent::new(KeyCode::Char('\u{0002}'), KeyModifiers::NONE));
|
||||
assert_eq!(t.cursor(), 1);
|
||||
|
||||
// ^F (U+0006) should move right
|
||||
t.input(KeyEvent::new(KeyCode::Char('\u{0006}'), KeyModifiers::NONE));
|
||||
assert_eq!(t.cursor(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cursor_vertical_movement_across_lines_and_bounds() {
|
||||
let mut t = ta_with("short\nloooooooooong\nmid");
|
||||
|
||||
Reference in New Issue
Block a user