tui: rename pending input preview

This commit is contained in:
Charles Cunningham
2026-03-02 16:13:51 -08:00
parent dbb69dd163
commit 1d5cad006f
6 changed files with 47 additions and 47 deletions
+18 -18
View File
@@ -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);
@@ -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
+10 -10
View File
@@ -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>) {
+6 -6
View File
@@ -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(),