Add expand/collapse all, per-pane key legends
SectionTree: - 'e': expand all nodes - 'c': collapse all nodes - Home/End already wired from previous commit Key legend shown at bottom border of each focused pane: - Tree panes: nav, expand/collapse, expand/collapse all, paging - Agent list: select, tab - History: scroll, paging Legend only appears on the focused pane to avoid clutter. Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
parent
19bb6d02e3
commit
578be807e7
3 changed files with 54 additions and 14 deletions
|
|
@ -11,7 +11,7 @@ use ratatui::{
|
|||
};
|
||||
|
||||
use super::{App, ScreenView, screen_legend};
|
||||
use super::widgets::{SectionTree, pane_block, render_scrollable};
|
||||
use super::widgets::{SectionTree, pane_block, render_scrollable, tree_legend};
|
||||
|
||||
pub(crate) struct ConsciousScreen {
|
||||
agent: std::sync::Arc<tokio::sync::Mutex<crate::agent::Agent>>,
|
||||
|
|
@ -94,7 +94,8 @@ impl ScreenView for ConsciousScreen {
|
|||
lines.push(Line::raw(format!(" Active tools: {}", app.active_tools.lock().unwrap().len())));
|
||||
|
||||
let block = pane_block("context")
|
||||
.title_top(Line::from(screen_legend()).left_aligned());
|
||||
.title_top(Line::from(screen_legend()).left_aligned())
|
||||
.title_bottom(tree_legend());
|
||||
|
||||
render_scrollable(frame, area, lines, block, self.tree.scroll);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use ratatui::{
|
|||
};
|
||||
|
||||
use super::{App, ScreenView, screen_legend};
|
||||
use super::widgets::{SectionTree, pane_block_focused, render_scrollable, format_age, format_ts_age};
|
||||
use super::widgets::{SectionTree, pane_block_focused, render_scrollable, tree_legend, format_age, format_ts_age};
|
||||
use crate::agent::context::ContextSection;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
|
|
@ -185,9 +185,16 @@ impl SubconsciousScreen {
|
|||
}
|
||||
}).collect();
|
||||
|
||||
let mut block = pane_block_focused("agents", self.focus == Pane::Agents)
|
||||
.title_top(Line::from(screen_legend()).left_aligned());
|
||||
if self.focus == Pane::Agents {
|
||||
block = block.title_bottom(Line::styled(
|
||||
" ↑↓:select Tab:next pane ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
));
|
||||
}
|
||||
let list = List::new(items)
|
||||
.block(pane_block_focused("agents", self.focus == Pane::Agents)
|
||||
.title_top(Line::from(screen_legend()).left_aligned()))
|
||||
.block(block)
|
||||
.highlight_symbol("▸ ")
|
||||
.highlight_style(Style::default().bg(Color::DarkGray));
|
||||
|
||||
|
|
@ -207,9 +214,9 @@ impl SubconsciousScreen {
|
|||
self.output_tree.render_sections(§ions, &mut lines);
|
||||
}
|
||||
|
||||
render_scrollable(frame, area, lines,
|
||||
pane_block_focused("state", self.focus == Pane::Outputs),
|
||||
self.output_tree.scroll);
|
||||
let mut block = pane_block_focused("state", self.focus == Pane::Outputs);
|
||||
if self.focus == Pane::Outputs { block = block.title_bottom(tree_legend()); }
|
||||
render_scrollable(frame, area, lines, block, self.output_tree.scroll);
|
||||
}
|
||||
|
||||
fn draw_history(&self, frame: &mut Frame, area: Rect, app: &App) {
|
||||
|
|
@ -246,9 +253,14 @@ impl SubconsciousScreen {
|
|||
}
|
||||
}
|
||||
|
||||
render_scrollable(frame, area, lines,
|
||||
pane_block_focused(&title, self.focus == Pane::History),
|
||||
self.history_scroll);
|
||||
let mut block = pane_block_focused(&title, self.focus == Pane::History);
|
||||
if self.focus == Pane::History {
|
||||
block = block.title_bottom(Line::styled(
|
||||
" ↑↓:scroll PgUp/Dn ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
));
|
||||
}
|
||||
render_scrollable(frame, area, lines, block, self.history_scroll);
|
||||
}
|
||||
|
||||
fn draw_context(
|
||||
|
|
@ -273,8 +285,8 @@ impl SubconsciousScreen {
|
|||
.map(|s| s.name.as_str())
|
||||
.unwrap_or("—");
|
||||
|
||||
render_scrollable(frame, area, lines,
|
||||
pane_block_focused(title, self.focus == Pane::Context),
|
||||
self.context_tree.scroll);
|
||||
let mut block = pane_block_focused(title, self.focus == Pane::Context);
|
||||
if self.focus == Pane::Context { block = block.title_bottom(tree_legend()); }
|
||||
render_scrollable(frame, area, lines, block, self.context_tree.scroll);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,14 @@ pub fn format_ts_age(ts: i64) -> String {
|
|||
format_age((now - ts).max(0) as f64)
|
||||
}
|
||||
|
||||
/// Key legend for SectionTree panes.
|
||||
pub fn tree_legend() -> Line<'static> {
|
||||
Line::styled(
|
||||
" ↑↓:nav →/Enter:expand ←:collapse e:expand all c:collapse all PgUp/Dn Home/End ",
|
||||
Style::default().fg(Color::DarkGray),
|
||||
)
|
||||
}
|
||||
|
||||
/// Render a paragraph with a vertical scrollbar.
|
||||
pub fn render_scrollable(
|
||||
frame: &mut Frame,
|
||||
|
|
@ -90,6 +98,14 @@ impl SectionTree {
|
|||
Self { selected: None, expanded: std::collections::HashSet::new(), scroll: 0 }
|
||||
}
|
||||
|
||||
/// Total nodes in the tree (regardless of expand state).
|
||||
fn total_nodes(&self, sections: &[ContextSection]) -> usize {
|
||||
fn count_all(section: &ContextSection) -> usize {
|
||||
1 + section.children.iter().map(|c| count_all(c)).sum::<usize>()
|
||||
}
|
||||
sections.iter().map(|s| count_all(s)).sum()
|
||||
}
|
||||
|
||||
pub fn item_count(&self, sections: &[ContextSection]) -> usize {
|
||||
fn count(section: &ContextSection, expanded: &std::collections::HashSet<usize>, idx: &mut usize) -> usize {
|
||||
let my_idx = *idx;
|
||||
|
|
@ -146,6 +162,17 @@ impl SectionTree {
|
|||
self.expanded.remove(&sel);
|
||||
}
|
||||
}
|
||||
KeyCode::Char('e') => {
|
||||
// Expand all
|
||||
let total = self.total_nodes(sections);
|
||||
for i in 0..total {
|
||||
self.expanded.insert(i);
|
||||
}
|
||||
}
|
||||
KeyCode::Char('c') => {
|
||||
// Collapse all
|
||||
self.expanded.clear();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_to_selected(height);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue