Skip to content

Commit f1f1dd0

Browse files
committed
Let Ctrl+Enter insert a newline in the TUI input box
1 parent 3fa9b88 commit f1f1dd0

2 files changed

Lines changed: 31 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to Sofos are documented in this file.
66

77
### Fixed
88

9+
- **Ctrl+Enter now inserts a newline in the TUI input box, matching Shift+Enter and Alt+Enter.** Earlier the keystroke was silently swallowed by the textarea router, even though the placeholder text and the dispatch comments already documented it as a fallback newline binding for terminals that do not deliver Shift+Enter distinctly.
910
- **Setting `compaction_preserve_recent` to `0` no longer crashes the next compaction.** The split-point lookup used to index one past the end of the message list and panic. It now clamps to the last valid index, so a zero-preserve configuration just compacts everything older than the very last message.
1011
- **The summary call's token usage is now counted toward the session total.** When auto-compaction got a usable response from the model but the summary was too short to apply (fell back to plain trimming), sofos used to discard the response without billing it; the spend now lands on the session counters in every Ok path.
1112
- **The auto-compaction summary call no longer fights the prompt cache.** The one-shot summary used to share the OpenAI prompt-cache shard with the regular session, so the two distinct prefixes evicted each other on every compaction. The summary call now uses a `"<session>-summary"` shard of its own.

src/repl/tui/app.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,11 @@ impl App {
226226
/// Route a key event into the textarea (idle) or picker (overlay).
227227
pub fn handle_textarea_input(&mut self, key: KeyEvent) {
228228
let input = key_to_input(key);
229-
// Ignore Enter here — the caller handles submission.
230-
if matches!(input.key, Key::Enter) && !input.shift && !input.alt {
229+
// Ignore plain Enter here — the caller handles submission.
230+
// Modified Enter (Shift/Alt/Ctrl) falls through so the
231+
// textarea inserts a newline, matching the fallback bindings
232+
// documented at the input dispatch site.
233+
if matches!(input.key, Key::Enter) && !input.shift && !input.alt && !input.ctrl {
231234
return;
232235
}
233236
self.textarea.input(input);
@@ -353,6 +356,31 @@ mod tests {
353356
assert_eq!(a.textarea.lines(), &["hello", ""]);
354357
}
355358

359+
#[test]
360+
fn ctrl_enter_inserts_newline_through_textarea_handler() {
361+
// Ctrl+Enter is documented at the input dispatch site as a
362+
// fallback newline binding for terminals that don't deliver
363+
// Shift+Enter distinctly. The early-return used to drop the
364+
// event because only Shift and Alt were checked.
365+
let mut a = app();
366+
a.textarea.insert_str("hello");
367+
let ctrl_enter = KeyEvent::new(KeyCode::Enter, KeyModifiers::CONTROL);
368+
a.handle_textarea_input(ctrl_enter);
369+
assert_eq!(a.textarea.lines(), &["hello", ""]);
370+
}
371+
372+
#[test]
373+
fn alt_enter_inserts_newline_through_textarea_handler() {
374+
// Mirror of the Shift+Enter test; pinned so a future tweak
375+
// to the early-return guard does not silently regress the
376+
// documented Alt+Enter fallback.
377+
let mut a = app();
378+
a.textarea.insert_str("hello");
379+
let alt_enter = KeyEvent::new(KeyCode::Enter, KeyModifiers::ALT);
380+
a.handle_textarea_input(alt_enter);
381+
assert_eq!(a.textarea.lines(), &["hello", ""]);
382+
}
383+
356384
#[test]
357385
fn is_safe_mode_reads_from_status_snapshot() {
358386
use crate::repl::tui::event::{Mode, StatusSnapshot};

0 commit comments

Comments
 (0)