mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
tui: rename pending input preview
This commit is contained in:
@@ -18,7 +18,7 @@ use std::path::PathBuf;
|
||||
use crate::app_event::ConnectorsSnapshot;
|
||||
use crate::app_event_sender::AppEventSender;
|
||||
use crate::bottom_pane::pending_thread_approvals::PendingThreadApprovals;
|
||||
use crate::bottom_pane::queued_user_messages::QueuedUserMessages;
|
||||
use crate::bottom_pane::pending_input_preview::PendingInputPreview;
|
||||
use crate::bottom_pane::unified_exec_footer::UnifiedExecFooter;
|
||||
use crate::key_hint;
|
||||
use crate::key_hint::KeyBinding;
|
||||
@@ -94,8 +94,8 @@ pub(crate) use status_line_setup::StatusLineItem;
|
||||
pub(crate) use status_line_setup::StatusLineSetupView;
|
||||
mod paste_burst;
|
||||
mod pending_thread_approvals;
|
||||
mod pending_input_preview;
|
||||
pub mod popup_consts;
|
||||
mod queued_user_messages;
|
||||
mod scroll_state;
|
||||
mod selection_popup_common;
|
||||
mod textarea;
|
||||
@@ -172,8 +172,8 @@ pub(crate) struct BottomPane {
|
||||
/// When a status row exists, this summary is mirrored inline in that row;
|
||||
/// when no status row exists, it renders as its own footer row.
|
||||
unified_exec_footer: UnifiedExecFooter,
|
||||
/// Queued user messages to show above the composer while a turn is running.
|
||||
queued_user_messages: QueuedUserMessages,
|
||||
/// Preview of pending nudges and queued drafts shown above the composer.
|
||||
pending_input_preview: PendingInputPreview,
|
||||
/// Inactive threads with pending approval requests.
|
||||
pending_thread_approvals: PendingThreadApprovals,
|
||||
context_window_percent: Option<i64>,
|
||||
@@ -223,7 +223,7 @@ impl BottomPane {
|
||||
is_task_running: false,
|
||||
status: None,
|
||||
unified_exec_footer: UnifiedExecFooter::new(),
|
||||
queued_user_messages: QueuedUserMessages::new(),
|
||||
pending_input_preview: PendingInputPreview::new(),
|
||||
pending_thread_approvals: PendingThreadApprovals::new(),
|
||||
esc_backtrack_hint: false,
|
||||
animations_enabled,
|
||||
@@ -312,7 +312,7 @@ impl BottomPane {
|
||||
/// Update the key hint shown next to queued messages so it matches the
|
||||
/// binding that `ChatWidget` actually listens for.
|
||||
pub(crate) fn set_queued_message_edit_binding(&mut self, binding: KeyBinding) {
|
||||
self.queued_user_messages.set_edit_binding(binding);
|
||||
self.pending_input_preview.set_edit_binding(binding);
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
@@ -769,14 +769,14 @@ impl BottomPane {
|
||||
true
|
||||
}
|
||||
|
||||
/// Update the queued messages preview shown above the composer.
|
||||
pub(crate) fn set_queued_user_messages(
|
||||
/// Update the pending-input preview shown above the composer.
|
||||
pub(crate) fn set_pending_input_preview(
|
||||
&mut self,
|
||||
queued: Vec<String>,
|
||||
pending_nudges: Vec<String>,
|
||||
) {
|
||||
self.queued_user_messages.pending_nudges = pending_nudges;
|
||||
self.queued_user_messages.messages = queued;
|
||||
self.pending_input_preview.pending_nudges = pending_nudges;
|
||||
self.pending_input_preview.messages = queued;
|
||||
self.request_redraw();
|
||||
}
|
||||
|
||||
@@ -1019,19 +1019,19 @@ impl BottomPane {
|
||||
flex.push(0, RenderableItem::Borrowed(&self.unified_exec_footer));
|
||||
}
|
||||
let has_pending_thread_approvals = !self.pending_thread_approvals.is_empty();
|
||||
let has_queued_messages = !self.queued_user_messages.messages.is_empty()
|
||||
|| !self.queued_user_messages.pending_nudges.is_empty();
|
||||
let has_pending_input = !self.pending_input_preview.messages.is_empty()
|
||||
|| !self.pending_input_preview.pending_nudges.is_empty();
|
||||
let has_status_or_footer =
|
||||
self.status.is_some() || !self.unified_exec_footer.is_empty();
|
||||
let has_inline_previews = has_pending_thread_approvals || has_queued_messages;
|
||||
let has_inline_previews = has_pending_thread_approvals || has_pending_input;
|
||||
if has_inline_previews && has_status_or_footer {
|
||||
flex.push(0, RenderableItem::Owned("".into()));
|
||||
}
|
||||
flex.push(1, RenderableItem::Borrowed(&self.pending_thread_approvals));
|
||||
if has_pending_thread_approvals && has_queued_messages {
|
||||
if has_pending_thread_approvals && has_pending_input {
|
||||
flex.push(0, RenderableItem::Owned("".into()));
|
||||
}
|
||||
flex.push(1, RenderableItem::Borrowed(&self.queued_user_messages));
|
||||
flex.push(1, RenderableItem::Borrowed(&self.pending_input_preview));
|
||||
if !has_inline_previews && has_status_or_footer {
|
||||
flex.push(0, RenderableItem::Owned("".into()));
|
||||
}
|
||||
@@ -1407,7 +1407,7 @@ mod tests {
|
||||
StatusDetailsCapitalization::CapitalizeFirst,
|
||||
STATUS_DETAILS_DEFAULT_MAX_LINES,
|
||||
);
|
||||
pane.set_queued_user_messages(vec!["Queued follow-up question".to_string()], Vec::new());
|
||||
pane.set_pending_input_preview(vec!["Queued follow-up question".to_string()], Vec::new());
|
||||
|
||||
let width = 48;
|
||||
let height = pane.desired_height(width);
|
||||
@@ -1434,7 +1434,7 @@ mod tests {
|
||||
});
|
||||
|
||||
pane.set_task_running(true);
|
||||
pane.set_queued_user_messages(vec!["Queued follow-up question".to_string()], Vec::new());
|
||||
pane.set_pending_input_preview(vec!["Queued follow-up question".to_string()], Vec::new());
|
||||
pane.hide_status_indicator();
|
||||
|
||||
let width = 48;
|
||||
@@ -1462,7 +1462,7 @@ mod tests {
|
||||
});
|
||||
|
||||
pane.set_task_running(true);
|
||||
pane.set_queued_user_messages(vec!["Queued follow-up question".to_string()], Vec::new());
|
||||
pane.set_pending_input_preview(vec!["Queued follow-up question".to_string()], Vec::new());
|
||||
|
||||
let width = 48;
|
||||
let height = pane.desired_height(width);
|
||||
|
||||
+13
-13
@@ -17,7 +17,7 @@ use crate::wrapping::adaptive_wrap_lines;
|
||||
/// queued user messages to pop back into the composer. Because some terminals
|
||||
/// intercept certain modifier-key combinations, the displayed binding is
|
||||
/// configurable via [`set_edit_binding`](Self::set_edit_binding).
|
||||
pub(crate) struct QueuedUserMessages {
|
||||
pub(crate) struct PendingInputPreview {
|
||||
pub pending_nudges: Vec<String>,
|
||||
pub messages: Vec<String>,
|
||||
/// Key combination rendered in the hint line. Defaults to Alt+Up but may
|
||||
@@ -25,7 +25,7 @@ pub(crate) struct QueuedUserMessages {
|
||||
edit_binding: key_hint::KeyBinding,
|
||||
}
|
||||
|
||||
impl QueuedUserMessages {
|
||||
impl PendingInputPreview {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
pending_nudges: Vec::new(),
|
||||
@@ -97,7 +97,7 @@ impl QueuedUserMessages {
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderable for QueuedUserMessages {
|
||||
impl Renderable for PendingInputPreview {
|
||||
fn render(&self, area: Rect, buf: &mut Buffer) {
|
||||
if area.is_empty() {
|
||||
return;
|
||||
@@ -119,20 +119,20 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn desired_height_empty() {
|
||||
let queue = QueuedUserMessages::new();
|
||||
let queue = PendingInputPreview::new();
|
||||
assert_eq!(queue.desired_height(40), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desired_height_one_message() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.messages.push("Hello, world!".to_string());
|
||||
assert_eq!(queue.desired_height(40), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_one_message() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.messages.push("Hello, world!".to_string());
|
||||
let width = 40;
|
||||
let height = queue.desired_height(width);
|
||||
@@ -143,7 +143,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_two_messages() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.messages.push("Hello, world!".to_string());
|
||||
queue.messages.push("This is another message".to_string());
|
||||
let width = 40;
|
||||
@@ -155,7 +155,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_more_than_three_messages() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.messages.push("Hello, world!".to_string());
|
||||
queue.messages.push("This is another message".to_string());
|
||||
queue.messages.push("This is a third message".to_string());
|
||||
@@ -169,7 +169,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_wrapped_message() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue
|
||||
.messages
|
||||
.push("This is a longer message that should be wrapped".to_string());
|
||||
@@ -183,7 +183,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_many_line_message() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue
|
||||
.messages
|
||||
.push("This is\na message\nwith many\nlines".to_string());
|
||||
@@ -196,7 +196,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn long_url_like_message_does_not_expand_into_wrapped_ellipsis_rows() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.messages.push(
|
||||
"example.test/api/v1/projects/alpha-team/releases/2026-02-17/builds/1234567890/artifacts/reports/performance/summary/detail/session_id=abc123def456ghi789"
|
||||
.to_string(),
|
||||
@@ -228,7 +228,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_one_pending_nudge() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.pending_nudges.push("Implement the plan.".to_string());
|
||||
let width = 48;
|
||||
let height = queue.desired_height(width);
|
||||
@@ -239,7 +239,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn render_pending_nudges_above_queued_messages() {
|
||||
let mut queue = QueuedUserMessages::new();
|
||||
let mut queue = PendingInputPreview::new();
|
||||
queue.pending_nudges.push("Implement the plan.".to_string());
|
||||
queue
|
||||
.pending_nudges
|
||||
@@ -1901,7 +1901,7 @@ impl ChatWidget {
|
||||
self.maybe_send_pending_nudges();
|
||||
} else if let Some(combined) = self.drain_queued_messages_for_restore() {
|
||||
self.restore_user_message_to_composer(combined);
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
}
|
||||
|
||||
self.request_redraw();
|
||||
@@ -3435,7 +3435,7 @@ impl ChatWidget {
|
||||
{
|
||||
if let Some(user_message) = self.queued_user_messages.pop_back() {
|
||||
self.restore_user_message_to_composer(user_message);
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
self.request_redraw();
|
||||
}
|
||||
return;
|
||||
@@ -3479,7 +3479,7 @@ impl ChatWidget {
|
||||
&& (self.is_plan_streaming_in_tui() || self.stream_controller.is_some());
|
||||
if should_defer_as_pending_nudge {
|
||||
self.pending_nudges.push_back(user_message);
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
} else if self.is_session_configured() {
|
||||
// Submitted is only emitted when steer is enabled.
|
||||
// Reset any reasoning header only when we are actually submitting a turn.
|
||||
@@ -4096,7 +4096,7 @@ impl ChatWidget {
|
||||
|| self.is_review_mode
|
||||
{
|
||||
self.queued_user_messages.push_back(user_message);
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
} else {
|
||||
self.submit_user_message(user_message);
|
||||
}
|
||||
@@ -4106,7 +4106,7 @@ impl ChatWidget {
|
||||
if !self.is_session_configured() {
|
||||
tracing::warn!("cannot submit user message before session is configured; queueing");
|
||||
self.queued_user_messages.push_front(user_message);
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4760,7 +4760,7 @@ impl ChatWidget {
|
||||
self.submit_user_message(user_message);
|
||||
}
|
||||
// Update the list to reflect the remaining queued messages (if any).
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
}
|
||||
|
||||
fn maybe_send_pending_nudges(&mut self) -> bool {
|
||||
@@ -4781,12 +4781,12 @@ impl ChatWidget {
|
||||
while let Some(pending_nudge) = self.pending_nudges.pop_front() {
|
||||
self.submit_user_message(pending_nudge);
|
||||
}
|
||||
self.refresh_queued_user_messages();
|
||||
self.refresh_pending_input_preview();
|
||||
true
|
||||
}
|
||||
|
||||
/// Rebuild and update the queued user messages from the current queue.
|
||||
fn refresh_queued_user_messages(&mut self) {
|
||||
/// Rebuild and update the bottom-pane pending-input preview.
|
||||
fn refresh_pending_input_preview(&mut self) {
|
||||
let messages: Vec<String> = self
|
||||
.queued_user_messages
|
||||
.iter()
|
||||
@@ -4798,7 +4798,7 @@ impl ChatWidget {
|
||||
.map(|nudge| nudge.text.clone())
|
||||
.collect();
|
||||
self.bottom_pane
|
||||
.set_queued_user_messages(messages, pending_nudges);
|
||||
.set_pending_input_preview(messages, pending_nudges);
|
||||
}
|
||||
|
||||
pub(crate) fn set_pending_thread_approvals(&mut self, threads: Vec<String>) {
|
||||
|
||||
@@ -1169,7 +1169,7 @@ async fn interrupted_turn_restores_queued_messages_with_images_and_elements() {
|
||||
text_elements: second_elements,
|
||||
mention_bindings: Vec::new(),
|
||||
});
|
||||
chat.refresh_queued_user_messages();
|
||||
chat.refresh_pending_input_preview();
|
||||
|
||||
chat.bottom_pane
|
||||
.set_composer_text(existing_text, existing_elements, existing_images.clone());
|
||||
@@ -1239,7 +1239,7 @@ async fn interrupted_turn_restore_keeps_active_mode_for_resubmission() {
|
||||
text_elements: Vec::new(),
|
||||
mention_bindings: Vec::new(),
|
||||
});
|
||||
chat.refresh_queued_user_messages();
|
||||
chat.refresh_pending_input_preview();
|
||||
|
||||
chat.handle_codex_event(Event {
|
||||
id: "interrupt".into(),
|
||||
@@ -3168,7 +3168,7 @@ async fn alt_up_edits_most_recent_queued_message() {
|
||||
.push_back(UserMessage::from("first queued".to_string()));
|
||||
chat.queued_user_messages
|
||||
.push_back(UserMessage::from("second queued".to_string()));
|
||||
chat.refresh_queued_user_messages();
|
||||
chat.refresh_pending_input_preview();
|
||||
|
||||
// Press Alt+Up to edit the most recent (last) queued message.
|
||||
chat.handle_key_event(KeyEvent::new(KeyCode::Up, KeyModifiers::ALT));
|
||||
@@ -3202,7 +3202,7 @@ async fn assert_shift_left_edits_most_recent_queued_message_for_terminal(
|
||||
.push_back(UserMessage::from("first queued".to_string()));
|
||||
chat.queued_user_messages
|
||||
.push_back(UserMessage::from("second queued".to_string()));
|
||||
chat.refresh_queued_user_messages();
|
||||
chat.refresh_pending_input_preview();
|
||||
|
||||
// Press Shift+Left to edit the most recent (last) queued message.
|
||||
chat.handle_key_event(KeyEvent::new(KeyCode::Left, KeyModifiers::SHIFT));
|
||||
@@ -7088,7 +7088,7 @@ async fn interrupt_restores_queued_messages_into_composer() {
|
||||
.push_back(UserMessage::from("first queued".to_string()));
|
||||
chat.queued_user_messages
|
||||
.push_back(UserMessage::from("second queued".to_string()));
|
||||
chat.refresh_queued_user_messages();
|
||||
chat.refresh_pending_input_preview();
|
||||
|
||||
// Deliver a TurnAborted event with Interrupted reason (as if Esc was pressed).
|
||||
chat.handle_codex_event(Event {
|
||||
@@ -7128,7 +7128,7 @@ async fn interrupt_prepends_queued_messages_before_existing_composer_text() {
|
||||
.push_back(UserMessage::from("first queued".to_string()));
|
||||
chat.queued_user_messages
|
||||
.push_back(UserMessage::from("second queued".to_string()));
|
||||
chat.refresh_queued_user_messages();
|
||||
chat.refresh_pending_input_preview();
|
||||
|
||||
chat.handle_codex_event(Event {
|
||||
id: "turn-1".into(),
|
||||
|
||||
Reference in New Issue
Block a user