Unify screen dispatch — put InteractScreen in the screens array

active_screen is now the F-key number (1-based), dispatch is just
screens[active_screen - 1].tick() everywhere. Eliminates the
special-cased interact variable and duplicated if/else branching.

Also adds diff_mind_state() for dirty-flag tracking and gates the
bottom-of-loop render on dirty, avoiding redundant redraws.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
This commit is contained in:
Kent Overstreet 2026-04-06 19:00:53 -04:00
parent 6e9ad04bfc
commit 0d20d66196

View file

@ -58,11 +58,10 @@ pub struct ContextInfo {
}
/// Build the screen legend from screen labels.
pub(crate) fn screen_legend_from(interact: &dyn ScreenView, screens: &[Box<dyn ScreenView>]) -> String {
let mut parts = vec![format!("F1={}", interact.label())];
for (i, s) in screens.iter().enumerate() {
parts.push(format!("F{}={}", i + 2, s.label()));
}
pub(crate) fn screen_legend_from(screens: &[Box<dyn ScreenView>]) -> String {
let parts: Vec<String> = screens.iter().enumerate()
.map(|(i, s)| format!("F{}={}", i + 1, s.label()))
.collect();
format!(" {} ", parts.join(" "))
}
@ -357,18 +356,18 @@ pub async fn run(
}
let notify_rx = crate::thalamus::channels::subscribe_all();
let mut interact = crate::user::chat::InteractScreen::new(
mind.agent.clone(), mind.shared.clone(), mind_tx.clone(),
);
// Overlay screens: F2=conscious, F3=subconscious, F4=unconscious, F5=thalamus
// F1=chat, F2=conscious, F3=subconscious, F4=unconscious, F5=thalamus
let mut screens: Vec<Box<dyn tui::ScreenView>> = vec![
Box::new(crate::user::chat::InteractScreen::new(
mind.agent.clone(), mind.shared.clone(), mind_tx.clone(),
)),
Box::new(crate::user::context::ConsciousScreen::new()),
Box::new(crate::user::subconscious::SubconsciousScreen::new()),
Box::new(crate::user::unconscious::UnconsciousScreen::new()),
Box::new(crate::user::thalamus::ThalamusScreen::new()),
];
let mut active_screen: usize = 0; // 0 = interact, 1-4 = overlay
tui::set_screen_legend(tui::screen_legend_from(&interact, &screens));
let mut active_screen: usize = 1; // F-key number
tui::set_screen_legend(tui::screen_legend_from(&*screens));
let mut terminal = tui::init_terminal()?;
@ -397,7 +396,7 @@ pub async fn run(
{
let mut frame = terminal.get_frame();
let area = frame.area();
interact.tick(&mut frame, area, &[], &mut app);
screens[active_screen - 1].tick(&mut frame, area, &[], &mut app);
drop(frame);
terminal.flush()?;
terminal.swap_buffers();
@ -465,11 +464,7 @@ pub async fn run(
if global_pos > 0 {
let mut frame = terminal.get_frame();
let area = frame.area();
if active_screen == 0 {
interact.tick(&mut frame, area, &pending[..global_pos], &mut app);
} else {
screens[active_screen - 1].tick(&mut frame, area, &pending[..global_pos], &mut app);
}
drop(frame);
terminal.flush()?;
terminal.swap_buffers();
@ -486,11 +481,10 @@ pub async fn run(
match event {
Event::Key(key) => {
if let KeyCode::F(n) = key.code {
active_screen = match n {
1 => 0,
n @ 2..=5 if (n as usize - 2) < screens.len() => n as usize - 1,
_ => active_screen,
};
let idx = n as usize;
if idx >= 1 && idx <= screens.len() {
active_screen = idx;
}
} else if key.modifiers.contains(KeyModifiers::CONTROL) {
match key.code {
KeyCode::Char('c') => { app.should_quit = true; }
@ -510,11 +504,7 @@ pub async fn run(
if dirty {
let mut frame = terminal.get_frame();
let area = frame.area();
if active_screen == 0 {
interact.tick(&mut frame, area, &[], &mut app);
} else {
screens[active_screen - 1].tick(&mut frame, area, &[], &mut app);
}
drop(frame);
terminal.flush()?;
terminal.swap_buffers();