Skip to content

Commit 5b820c5

Browse files
authored
feat: ctrl-d only exits when there is no user input (openai#1589)
While this does make it so that `ctrl-d` will not exit Codex when the composer is not empty, `ctrl-d` will still exit Codex if it is in the "working" state. Fixes openai#1443.
1 parent f14b5ad commit 5b820c5

5 files changed

Lines changed: 30 additions & 3 deletions

File tree

codex-rs/tui/src/app.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,21 @@ impl<'a> App<'a> {
199199
modifiers: crossterm::event::KeyModifiers::CONTROL,
200200
..
201201
} => {
202-
self.app_event_tx.send(AppEvent::ExitRequest);
202+
match &mut self.app_state {
203+
AppState::Chat { widget } => {
204+
if widget.composer_is_empty() {
205+
self.app_event_tx.send(AppEvent::ExitRequest);
206+
} else {
207+
// Treat Ctrl+D as a normal key event when the composer
208+
// is not empty so that it doesn't quit the application
209+
// prematurely.
210+
self.dispatch_key_event(key_event);
211+
}
212+
}
213+
AppState::Login { .. } | AppState::GitWarning { .. } => {
214+
self.app_event_tx.send(AppEvent::ExitRequest);
215+
}
216+
}
203217
}
204218
_ => {
205219
self.dispatch_key_event(key_event);

codex-rs/tui/src/bottom_pane/chat_composer.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ impl ChatComposer<'_> {
7676
this
7777
}
7878

79+
/// Returns true if the composer currently contains no user input.
80+
pub(crate) fn is_empty(&self) -> bool {
81+
self.textarea.is_empty()
82+
}
83+
7984
/// Update the cached *context-left* percentage and refresh the placeholder
8085
/// text. The UI relies on the placeholder to convey the remaining
8186
/// context when the composer is empty.

codex-rs/tui/src/bottom_pane/chat_composer_history.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ impl ChatComposerHistory {
7272
return false;
7373
}
7474

75-
let lines = textarea.lines();
76-
if lines.len() == 1 && lines[0].is_empty() {
75+
if textarea.is_empty() {
7776
return true;
7877
}
7978

@@ -85,6 +84,7 @@ impl ChatComposerHistory {
8584
return false;
8685
}
8786

87+
let lines = textarea.lines();
8888
matches!(&self.last_history_text, Some(prev) if prev == &lines.join("\n"))
8989
}
9090

codex-rs/tui/src/bottom_pane/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ impl BottomPane<'_> {
162162
}
163163
}
164164

165+
pub(crate) fn composer_is_empty(&self) -> bool {
166+
self.composer.is_empty()
167+
}
168+
165169
pub(crate) fn is_task_running(&self) -> bool {
166170
self.is_task_running
167171
}

codex-rs/tui/src/chatwidget.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,10 @@ impl ChatWidget<'_> {
432432
}
433433
}
434434

435+
pub(crate) fn composer_is_empty(&self) -> bool {
436+
self.bottom_pane.composer_is_empty()
437+
}
438+
435439
/// Forward an `Op` directly to codex.
436440
pub(crate) fn submit_op(&self, op: Op) {
437441
if let Err(e) = self.codex_op_tx.send(op) {

0 commit comments

Comments
 (0)