mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
feat(tui/history): polish explore block labeling
This commit is contained in:
@@ -487,7 +487,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
|
||||
EventMsg::WebSearchBegin(WebSearchBeginEvent { .. }) => {}
|
||||
EventMsg::WebSearchComplete(WebSearchCompleteEvent { call_id: _, query }) => {
|
||||
if let Some(query) = query {
|
||||
ts_println!(self, "🌐 Searched: {query}");
|
||||
ts_println!(self, "🌐 Search: {query}");
|
||||
}
|
||||
}
|
||||
EventMsg::PatchApplyBegin(PatchApplyBeginEvent {
|
||||
|
||||
@@ -1394,7 +1394,7 @@ impl ChatWidget<'_> {
|
||||
}
|
||||
|
||||
/// If a completed exec cell sits at `idx`, attempt to merge it into the
|
||||
/// previous cell when they represent the same action header (e.g., Searched, Read).
|
||||
/// previous cell when they represent the same action header (e.g., Search, Read).
|
||||
|
||||
// MCP tool call handlers now live in chatwidget::tools
|
||||
|
||||
@@ -2646,6 +2646,7 @@ impl ChatWidget<'_> {
|
||||
// Maintain input focus when new history arrives
|
||||
self.bottom_pane.ensure_input_focus();
|
||||
self.app_event_tx.send(AppEvent::RequestRedraw);
|
||||
self.refresh_explore_trailing_flags();
|
||||
self.refresh_reasoning_collapsed_visibility();
|
||||
pos
|
||||
}
|
||||
@@ -2695,6 +2696,7 @@ impl ChatWidget<'_> {
|
||||
self.history_cells[idx] = cell;
|
||||
self.invalidate_height_cache();
|
||||
self.request_redraw();
|
||||
self.refresh_explore_trailing_flags();
|
||||
// Keep debug info for this cell index as-is.
|
||||
}
|
||||
}
|
||||
@@ -2710,6 +2712,7 @@ impl ChatWidget<'_> {
|
||||
}
|
||||
self.invalidate_height_cache();
|
||||
self.request_redraw();
|
||||
self.refresh_explore_trailing_flags();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2818,6 +2821,30 @@ impl ChatWidget<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_explore_trailing_flags(&mut self) {
|
||||
let mut trailing_non_reasoning: Option<usize> = None;
|
||||
for i in (0..self.history_cells.len()).rev() {
|
||||
if self.history_cells[i]
|
||||
.as_any()
|
||||
.downcast_ref::<history_cell::CollapsibleReasoningCell>()
|
||||
.is_some()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
trailing_non_reasoning = Some(i);
|
||||
break;
|
||||
}
|
||||
|
||||
for (idx, cell) in self.history_cells.iter_mut().enumerate() {
|
||||
if let Some(explore) = cell
|
||||
.as_any_mut()
|
||||
.downcast_mut::<history_cell::ExploreAggregationCell>()
|
||||
{
|
||||
explore.set_trailing(Some(idx) == trailing_non_reasoning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn submit_user_message(&mut self, user_message: UserMessage) {
|
||||
// Surface a local diagnostic note and anchor it to the NEXT turn,
|
||||
// placing it directly after the user prompt so ordering is stable.
|
||||
|
||||
@@ -477,7 +477,7 @@ pub(super) fn handle_exec_begin_now(
|
||||
},
|
||||
);
|
||||
if !chat.tools_state.running_web_search.is_empty() {
|
||||
chat.bottom_pane.update_status_text("Searched".to_string());
|
||||
chat.bottom_pane.update_status_text("Search".to_string());
|
||||
} else {
|
||||
let preview = chat
|
||||
.exec
|
||||
|
||||
+2
-2
@@ -2,5 +2,5 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: blob1
|
||||
---
|
||||
⠋ Exploring
|
||||
└ List ls -la
|
||||
⠋ Exploring...
|
||||
└ List ls -la
|
||||
|
||||
+3
-3
@@ -2,6 +2,6 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: blob3
|
||||
---
|
||||
⠋ Exploring
|
||||
└ List ls -la
|
||||
Read foo.txt
|
||||
⠋ Exploring...
|
||||
└ List ls -la
|
||||
Read foo.txt
|
||||
|
||||
@@ -15,7 +15,7 @@ pub(super) fn web_search_begin(chat: &mut ChatWidget<'_>, call_id: String, query
|
||||
chat.tools_state
|
||||
.running_web_search
|
||||
.insert(super::ToolCallId(call_id), (idx, query));
|
||||
chat.bottom_pane.update_status_text("Searched".to_string());
|
||||
chat.bottom_pane.update_status_text("Search".to_string());
|
||||
chat.mark_needs_redraw();
|
||||
}
|
||||
|
||||
|
||||
@@ -391,7 +391,7 @@ impl ExploreEntry {
|
||||
}
|
||||
match self.action {
|
||||
ExecAction::Read => "Read",
|
||||
ExecAction::Search => "Searched",
|
||||
ExecAction::Search => "Search",
|
||||
ExecAction::List => "List",
|
||||
ExecAction::Run => "Run",
|
||||
}
|
||||
@@ -660,15 +660,21 @@ fn annotation_for_range(start: u32, end: u32) -> Option<String> {
|
||||
|
||||
pub(crate) struct ExploreAggregationCell {
|
||||
entries: Vec<ExploreEntry>,
|
||||
is_trailing: bool,
|
||||
}
|
||||
|
||||
impl ExploreAggregationCell {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
entries: Vec::new(),
|
||||
is_trailing: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_trailing(&mut self, trailing: bool) {
|
||||
self.is_trailing = trailing;
|
||||
}
|
||||
|
||||
pub(crate) fn push_from_parsed(
|
||||
&mut self,
|
||||
parsed: &[ParsedCommand],
|
||||
@@ -859,27 +865,46 @@ impl HistoryCell for ExploreAggregationCell {
|
||||
}
|
||||
|
||||
fn display_lines(&self) -> Vec<Line<'static>> {
|
||||
let header = if self.is_trailing {
|
||||
"Exploring..."
|
||||
} else {
|
||||
"Explored"
|
||||
};
|
||||
|
||||
if self.entries.is_empty() {
|
||||
return vec![Line::styled(
|
||||
"Exploring",
|
||||
header,
|
||||
Style::default().fg(crate::colors::text()),
|
||||
)];
|
||||
}
|
||||
|
||||
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||
lines.push(Line::styled(
|
||||
"Exploring",
|
||||
header,
|
||||
Style::default().fg(crate::colors::text()),
|
||||
));
|
||||
|
||||
let max_label_len = self
|
||||
.entries
|
||||
.iter()
|
||||
.map(|e| e.label().chars().count())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
for (idx, entry) in self.entries.iter().enumerate() {
|
||||
let prefix = if idx == 0 { "└ " } else { " " };
|
||||
let mut spans: Vec<Span<'static>> = vec![Span::styled(
|
||||
prefix,
|
||||
Style::default().add_modifier(Modifier::DIM),
|
||||
)];
|
||||
let label = entry.label();
|
||||
let label_len = label.chars().count();
|
||||
let padding = max_label_len.saturating_sub(label_len) + 1;
|
||||
let mut padded_label = String::with_capacity(label.len() + padding);
|
||||
padded_label.push_str(label);
|
||||
padded_label.extend(std::iter::repeat(' ').take(padding));
|
||||
spans.push(Span::styled(
|
||||
format!("{:<8} ", entry.label()),
|
||||
padded_label,
|
||||
Style::default().fg(crate::colors::text_dim()),
|
||||
));
|
||||
spans.extend(entry.summary_spans());
|
||||
@@ -2425,7 +2450,7 @@ impl HistoryCell for MergedExecCell {
|
||||
Style::default().fg(crate::colors::text()),
|
||||
)),
|
||||
ExecKind::Search => Some(Line::styled(
|
||||
"Searched",
|
||||
"Search",
|
||||
Style::default().fg(crate::colors::text_dim()),
|
||||
)),
|
||||
ExecKind::List => Some(Line::styled(
|
||||
@@ -2808,7 +2833,7 @@ fn exec_render_parts_parsed(
|
||||
Style::default().fg(crate::colors::text()),
|
||||
)),
|
||||
ExecAction::Search => pre.push(Line::styled(
|
||||
"Searched",
|
||||
"Search",
|
||||
Style::default().fg(crate::colors::text_dim()),
|
||||
)),
|
||||
ExecAction::List => pre.push(Line::styled(
|
||||
@@ -2830,7 +2855,7 @@ fn exec_render_parts_parsed(
|
||||
Some(o) if o.exit_code == 0 => {
|
||||
let done = match action {
|
||||
ExecAction::Read => "Read".to_string(),
|
||||
ExecAction::Search => "Searched".to_string(),
|
||||
ExecAction::Search => "Search".to_string(),
|
||||
ExecAction::List => "List".to_string(),
|
||||
ExecAction::Run => match &ctx_path {
|
||||
Some(p) => format!("Ran in {}", p),
|
||||
@@ -2857,7 +2882,7 @@ fn exec_render_parts_parsed(
|
||||
Some(_) => {
|
||||
let done = match action {
|
||||
ExecAction::Read => "Read".to_string(),
|
||||
ExecAction::Search => "Searched".to_string(),
|
||||
ExecAction::Search => "Search".to_string(),
|
||||
ExecAction::List => "List".to_string(),
|
||||
ExecAction::Run => match &ctx_path {
|
||||
Some(p) => format!("Ran in {}", p),
|
||||
@@ -5924,7 +5949,7 @@ fn new_parsed_command(
|
||||
};
|
||||
let header = match action {
|
||||
ExecAction::Read => "Read",
|
||||
ExecAction::Search => "Searched",
|
||||
ExecAction::Search => "Search",
|
||||
ExecAction::List => "List",
|
||||
ExecAction::Run => unreachable!(),
|
||||
};
|
||||
@@ -5942,7 +5967,7 @@ fn new_parsed_command(
|
||||
lines.push(Line::styled(
|
||||
match action {
|
||||
ExecAction::Read => "Read",
|
||||
ExecAction::Search => "Searched",
|
||||
ExecAction::Search => "Search",
|
||||
ExecAction::List => "List",
|
||||
ExecAction::Run => unreachable!(),
|
||||
},
|
||||
@@ -5969,7 +5994,7 @@ fn new_parsed_command(
|
||||
lines.push(Line::styled(
|
||||
match action {
|
||||
ExecAction::Read => "Read",
|
||||
ExecAction::Search => "Searched",
|
||||
ExecAction::Search => "Search",
|
||||
ExecAction::List => "List",
|
||||
ExecAction::Run => unreachable!(),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user