feat: collapse "waiting" of unified_exec (#8257)

Screenshots here but check the snapshot files to see it better
<img width="712" height="408" alt="Screenshot 2025-12-18 at 11 58 02"
src="https://github.com/user-attachments/assets/84a2c410-0767-4870-84d1-ae1c0d4c445e"
/>
<img width="523" height="352" alt="Screenshot 2025-12-18 at 11 17 41"
src="https://github.com/user-attachments/assets/d029c7ea-0feb-4493-9dca-af43a0c70c52"
/>
This commit is contained in:
jif-oai authored and GitHub committed 2025-12-18 17:03:43 -08:00
1 parent 3429de21b3
commit 6c76d17713
8 files changed
+310 -4

No files matched your search

+71 -4
View File
@@ -558,6 +558,7 @@ impl ChatWidget {
fn on_task_complete(&mut self, last_agent_message: Option<String>) {
// If a stream is currently active, finalize it.
self.flush_answer_stream_with_separator();
self.flush_wait_cell();
// Mark task stopped and request redraw now that all content is in history.
self.bottom_pane.set_task_running(false);
self.running_commands.clear();
@@ -880,10 +881,54 @@ impl ChatWidget {
.iter()
.find(|session| session.key == ev.process_id)
.map(|session| session.command_display.clone());
self.add_to_history(history_cell::new_unified_exec_interaction(
command_display,
ev.stdin,
));
if ev.stdin.is_empty() {
// Empty stdin means we are still waiting on background output; keep a live shimmer cell.
if let Some(wait_cell) = self.active_cell.as_mut().and_then(|cell| {
cell.as_any_mut()
.downcast_mut::<history_cell::UnifiedExecWaitCell>()
}) && wait_cell.matches(command_display.as_deref())
{
// Same session still waiting; update command display if it shows up late.
wait_cell.update_command_display(command_display);
self.request_redraw();
return;
}
let has_non_wait_active = matches!(
self.active_cell.as_ref(),
Some(active)
if active
.as_any()
.downcast_ref::<history_cell::UnifiedExecWaitCell>()
.is_none()
);
if has_non_wait_active {
// Do not preempt non-wait active cells with a wait entry.
return;
}
self.flush_wait_cell();
self.active_cell = Some(Box::new(history_cell::new_unified_exec_wait_live(
command_display,
self.config.animations,
)));
self.request_redraw();
} else {
if let Some(wait_cell) = self.active_cell.as_ref().and_then(|cell| {
cell.as_any()
.downcast_ref::<history_cell::UnifiedExecWaitCell>()
}) {
// Convert the live wait cell into a static "(waited)" entry before logging stdin.
let waited_command = wait_cell.command_display().or(command_display.clone());
self.active_cell = None;
self.add_to_history(history_cell::new_unified_exec_interaction(
waited_command,
String::new(),
));
}
self.add_to_history(history_cell::new_unified_exec_interaction(
command_display,
ev.stdin,
));
}
}
fn on_patch_apply_begin(&mut self, event: PatchApplyBeginEvent) {
@@ -1780,12 +1825,34 @@ impl ChatWidget {
}
fn flush_active_cell(&mut self) {
self.flush_wait_cell();
if let Some(active) = self.active_cell.take() {
self.needs_final_message_separator = true;
self.app_event_tx.send(AppEvent::InsertHistoryCell(active));
}
}
// Only flush a live wait cell here; other active cells must finalize via their end events.
fn flush_wait_cell(&mut self) {
// Wait cells are transient: convert them into "(waited)" history entries if present.
// Leave non-wait active cells intact so their end events can finalize them.
let Some(active) = self.active_cell.take() else {
return;
};
let Some(wait_cell) = active
.as_any()
.downcast_ref::<history_cell::UnifiedExecWaitCell>()
else {
self.active_cell = Some(active);
return;
};
self.needs_final_message_separator = true;
let cell =
history_cell::new_unified_exec_interaction(wait_cell.command_display(), String::new());
self.app_event_tx
.send(AppEvent::InsertHistoryCell(Box::new(cell)));
}
fn add_to_history(&mut self, cell: impl HistoryCell + 'static) {
self.add_boxed_history(Box::new(cell));
}