tui: ^C in prompt area resets history navigation cursor (#5078)

^C resets the history navigation, similar to zsh/bash.

Fixes #4834

------
https://chatgpt.com/codex/tasks/task_i_68e9674b6ac8832c8212bff6cba75e87
This commit is contained in:
Jeremy Rose
2025-10-15 13:57:44 -07:00
committed by GitHub
parent f38ad65254
commit 0016346dfb
3 changed files with 37 additions and 1 deletions

View File

@@ -316,6 +316,11 @@ impl ChatComposer {
self.sync_file_search_popup();
}
pub(crate) fn clear_for_ctrl_c(&mut self) {
self.set_text_content(String::new());
self.history.reset_navigation();
}
/// Get the current composer text.
pub(crate) fn current_text(&self) -> String {
self.textarea.text().to_string()

View File

@@ -70,6 +70,12 @@ impl ChatComposerHistory {
self.local_history.push(text.to_string());
}
/// Reset navigation tracking so the next Up key resumes from the latest entry.
pub fn reset_navigation(&mut self) {
self.history_cursor = None;
self.last_history_text = None;
}
/// Should Up/Down key presses be interpreted as history navigation given
/// the current content and cursor position of `textarea`?
pub fn should_handle_navigation(&self, text: &str, cursor: usize) -> bool {
@@ -271,4 +277,24 @@ mod tests {
history.on_entry_response(1, 1, Some("older".into()))
);
}
#[test]
fn reset_navigation_resets_cursor() {
let (tx, _rx) = unbounded_channel::<AppEvent>();
let tx = AppEventSender::new(tx);
let mut history = ChatComposerHistory::new();
history.set_metadata(1, 3);
history.fetched_history.insert(1, "command2".into());
history.fetched_history.insert(2, "command3".into());
assert_eq!(Some("command3".into()), history.navigate_up(&tx));
assert_eq!(Some("command2".into()), history.navigate_up(&tx));
history.reset_navigation();
assert!(history.history_cursor.is_none());
assert!(history.last_history_text.is_none());
assert_eq!(Some("command3".into()), history.navigate_up(&tx));
}
}

View File

@@ -236,7 +236,7 @@ impl BottomPane {
CancellationEvent::NotHandled
} else {
self.view_stack.pop();
self.set_composer_text(String::new());
self.clear_composer_for_ctrl_c();
self.show_ctrl_c_quit_hint();
CancellationEvent::Handled
}
@@ -270,6 +270,11 @@ impl BottomPane {
self.request_redraw();
}
pub(crate) fn clear_composer_for_ctrl_c(&mut self) {
self.composer.clear_for_ctrl_c();
self.request_redraw();
}
/// Get the current composer text (for tests and programmatic checks).
pub(crate) fn composer_text(&self) -> String {
self.composer.current_text()