diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-07 15:48:58 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-07 15:48:58 +0300 |
| commit | ed0c051c55e40c1ab3cdc029ba4ca518ee407a1e (patch) | |
| tree | 3c515192394da2caaca2c63eb93152ed308841b8 /src | |
| parent | 0276da6f2a44da493d1c198bcc6b5a8b1d2fda44 (diff) | |
fix: preserve lf in raw terminal input
Diffstat (limited to 'src')
| -rw-r--r-- | src/input/parse.rs | 5 | ||||
| -rw-r--r-- | src/input/tests.rs | 13 | ||||
| -rw-r--r-- | src/raw_input.rs | 10 |
3 files changed, 27 insertions, 1 deletions
diff --git a/src/input/parse.rs b/src/input/parse.rs index 525119f4..b7b449ae 100644 --- a/src/input/parse.rs +++ b/src/input/parse.rs @@ -61,7 +61,10 @@ fn parse_legacy_key_sequence(data: &str) -> Option<TerminalKey> { } match data { - "\r" | "\n" => Some(TerminalKey::new(KeyCode::Enter, KeyModifiers::empty())), + // In raw mode, Enter is carriage return. A bare line feed is ambiguous in + // terminal input and is commonly used for Ctrl+J or Shift+Enter workarounds. + // Preserve LF by letting it fall through to legacy control-byte parsing. + "\r" => Some(TerminalKey::new(KeyCode::Enter, KeyModifiers::empty())), "\t" => Some(TerminalKey::new(KeyCode::Tab, KeyModifiers::empty())), "\x1b" => Some(TerminalKey::new(KeyCode::Esc, KeyModifiers::empty())), "\x7f" => Some(TerminalKey::new(KeyCode::Backspace, KeyModifiers::empty())), diff --git a/src/input/tests.rs b/src/input/tests.rs index a3c71675..6482b245 100644 --- a/src/input/tests.rs +++ b/src/input/tests.rs @@ -462,6 +462,19 @@ fn parse_legacy_ctrl_c_sequence() { } #[test] +fn parse_legacy_lf_sequence_as_ctrl_j() { + let key = parse_terminal_key_sequence("\n").unwrap(); + assert_eq!(key.code, KeyCode::Char('j')); + assert_eq!(key.modifiers, KeyModifiers::CONTROL); +} + +#[test] +fn legacy_lf_roundtrips_as_lf() { + let key = parse_terminal_key_sequence("\n").unwrap(); + assert_eq!(encode_terminal_key(key, KeyboardProtocol::Legacy), b"\n"); +} + +#[test] fn legacy_ctrl_byte_matrix_is_covered() { for (byte, expected) in [ (b'\x01', 'a'), diff --git a/src/raw_input.rs b/src/raw_input.rs index 059791ea..262721c8 100644 --- a/src/raw_input.rs +++ b/src/raw_input.rs @@ -530,6 +530,16 @@ mod tests { assert_eq!(key.modifiers, KeyModifiers::CONTROL); } + #[test] + fn parses_raw_lf_as_ctrl_j() { + let (RawInputEvent::Key(key), consumed) = extract_one_event(b"\n").unwrap() else { + panic!("expected key"); + }; + assert_eq!(consumed, 1); + assert_eq!(key.code, KeyCode::Char('j')); + assert_eq!(key.modifiers, KeyModifiers::CONTROL); + } + fn assert_fixture_extracts_whole_events(corpus: &str, macos_layout: bool) { for line in corpus.lines() { let line = line.trim(); |
