mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
fix(tui): restore cancelled prompt cursor at end (#26457)
## Why Pressing `Esc` on a turn that produced no visible output restores the submitted prompt so the user can keep editing it. That restore path preserved the prompt content, images, and mention bindings, but left the composer cursor at the start of the restored text. The next edit therefore inserted at the beginning instead of continuing from the end of the prompt. ## What Changed - Move the cursor to the end after `BottomPane::set_composer_text_with_mention_bindings` rehydrates a restored draft. - Add test-only cursor accessors so restore tests can assert the composer state directly. - Extend the queued restore regression to assert the restored composer cursor is positioned at `text.len()`. ## How to Test Manual reviewer flow: 1. Start Codex in the TUI. 2. Submit a prompt that will take long enough to interrupt. 3. Press `Esc` before any visible assistant output appears. 4. Confirm the prompt is restored into the composer and the cursor is at the end, so typing appends to the prompt. 5. Repeat with a prompt that includes an attached image or resolved mention and confirm the restored content remains intact. Targeted tests: - `just test -p codex-tui chatwidget::tests::composer_submission::queued_restore_with_remote_images_keeps_local_placeholder_mapping` Lint note: - `just argument-comment-lint` is blocked locally by the existing Bazel `compiler-rt` empty glob failure before analyzing touched code. The touched Rust diff was manually inspected and adds no new opaque positional literal callsites.
This commit is contained in:
committed by
GitHub
Unverified
parent
713192381b
commit
679a944dbc
@@ -1258,6 +1258,11 @@ impl ChatComposer {
|
||||
self.draft.textarea.cursor() + if self.draft.is_bash_mode { 1 } else { 0 }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn cursor(&self) -> usize {
|
||||
self.current_cursor()
|
||||
}
|
||||
|
||||
fn history_navigation_cursor(&self) -> usize {
|
||||
if self.draft.is_bash_mode && self.draft.textarea.cursor() == 0 {
|
||||
0
|
||||
|
||||
@@ -786,6 +786,7 @@ impl BottomPane {
|
||||
local_image_paths,
|
||||
mention_bindings,
|
||||
);
|
||||
self.composer.move_cursor_to_end();
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
@@ -824,6 +825,11 @@ impl BottomPane {
|
||||
self.composer.current_text()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn composer_cursor(&self) -> usize {
|
||||
self.composer.cursor()
|
||||
}
|
||||
|
||||
pub(crate) fn composer_draft_snapshot(&self) -> chat_composer::ComposerDraftSnapshot {
|
||||
self.composer.draft_snapshot()
|
||||
}
|
||||
|
||||
@@ -730,6 +730,7 @@ async fn queued_restore_with_remote_images_keeps_local_placeholder_mapping() {
|
||||
});
|
||||
|
||||
assert_eq!(chat.bottom_pane.composer_text(), text);
|
||||
assert_eq!(chat.bottom_pane.composer_cursor(), text.len());
|
||||
assert_eq!(chat.bottom_pane.composer_text_elements(), text_elements);
|
||||
assert_eq!(chat.bottom_pane.composer_local_images(), local_images);
|
||||
assert_eq!(chat.remote_image_urls(), remote_image_urls);
|
||||
|
||||
Reference in New Issue
Block a user