feat(tui): support Shift+Enter to insert newline in composer (#801)

* feat(tui): support Shift+Enter to insert newline in composer

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(tui): cover shift-enter newline handling

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Hunter Bown <hmbown@gmail.com>
This commit is contained in:
YuanSheng Wang
2026-05-06 16:10:12 +08:00
committed by GitHub
parent 950860768f
commit 3e93143079
3 changed files with 42 additions and 5 deletions
+1 -1
View File
@@ -145,7 +145,7 @@ pub const KEYBINDINGS: &[KeybindingEntry] = &[
section: KeybindingSection::Editing,
},
KeybindingEntry {
chord: "Ctrl+J / Alt+Enter",
chord: "Ctrl+J / Alt+Enter / Shift+Enter",
description_id: crate::localization::MessageId::KbInsertNewline,
section: KeybindingSection::Editing,
},
+13 -4
View File
@@ -2370,10 +2370,7 @@ async fn run_event_loop(
continue;
}
// Input handling
KeyCode::Char('j') if key.modifiers.contains(KeyModifiers::CONTROL) => {
app.insert_char('\n');
}
KeyCode::Enter if key.modifiers.contains(KeyModifiers::ALT) => {
_ if is_composer_newline_key(key) => {
app.insert_char('\n');
}
KeyCode::Enter
@@ -3108,6 +3105,18 @@ fn next_escape_action(app: &App, slash_menu_open: bool) -> EscapeAction {
}
}
fn is_composer_newline_key(key: KeyEvent) -> bool {
match key.code {
KeyCode::Char('j') => key.modifiers.contains(KeyModifiers::CONTROL),
KeyCode::Enter => {
key.modifiers.contains(KeyModifiers::ALT)
|| (key.modifiers.contains(KeyModifiers::SHIFT)
&& !key.modifiers.contains(KeyModifiers::CONTROL))
}
_ => false,
}
}
fn handle_history_search_key(app: &mut App, key: KeyEvent) {
match key.code {
KeyCode::Enter => {
+28
View File
@@ -16,6 +16,34 @@ use std::process::Command;
use std::time::{Duration, Instant};
use tempfile::TempDir;
#[test]
fn composer_newline_shortcuts_do_not_steal_ctrl_enter() {
assert!(is_composer_newline_key(KeyEvent::new(
KeyCode::Char('j'),
KeyModifiers::CONTROL,
)));
assert!(is_composer_newline_key(KeyEvent::new(
KeyCode::Enter,
KeyModifiers::ALT,
)));
assert!(is_composer_newline_key(KeyEvent::new(
KeyCode::Enter,
KeyModifiers::SHIFT,
)));
assert!(!is_composer_newline_key(KeyEvent::new(
KeyCode::Enter,
KeyModifiers::NONE,
)));
assert!(!is_composer_newline_key(KeyEvent::new(
KeyCode::Enter,
KeyModifiers::CONTROL,
)));
assert!(!is_composer_newline_key(KeyEvent::new(
KeyCode::Enter,
KeyModifiers::CONTROL | KeyModifiers::SHIFT,
)));
}
#[test]
fn selection_point_from_position_ignores_top_padding() {
let area = Rect {