user: hook up screen_legend from ScreenView::label()
Build legend string from actual screen labels instead of hardcoded constant. Computed once at startup via OnceLock, accessible from all screen draw methods. Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
68f115b880
commit
6f000bd0f6
3 changed files with 80 additions and 67 deletions
126
src/user/chat.rs
126
src/user/chat.rs
|
|
@ -159,71 +159,7 @@ impl InteractScreen {
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScreenView for InteractScreen {
|
||||
fn label(&self) -> &'static str { "interact" }
|
||||
|
||||
fn tick(&mut self, frame: &mut Frame, area: Rect,
|
||||
key: Option<KeyEvent>, app: &mut App) -> Option<ScreenAction> {
|
||||
// Handle keys
|
||||
if let Some(key) = key {
|
||||
match key.code {
|
||||
KeyCode::Esc => return Some(ScreenAction::Hotkey(HotkeyAction::Interrupt)),
|
||||
KeyCode::Enter if !key.modifiers.contains(KeyModifiers::ALT) && !key.modifiers.contains(KeyModifiers::SHIFT) => {
|
||||
let input: String = self.textarea.lines().join("\n");
|
||||
if !input.is_empty() {
|
||||
if self.input_history.last().map_or(true, |h| h != &input) {
|
||||
self.input_history.push(input.clone());
|
||||
}
|
||||
self.history_index = None;
|
||||
// TODO: push to submitted via app or return action
|
||||
}
|
||||
}
|
||||
KeyCode::Up if key.modifiers.contains(KeyModifiers::CONTROL) => self.scroll_active_up(3),
|
||||
KeyCode::Down if key.modifiers.contains(KeyModifiers::CONTROL) => self.scroll_active_down(3),
|
||||
KeyCode::Up => {
|
||||
if !self.input_history.is_empty() {
|
||||
let idx = match self.history_index { None => self.input_history.len() - 1, Some(i) => i.saturating_sub(1) };
|
||||
self.history_index = Some(idx);
|
||||
let mut ta = new_textarea(self.input_history[idx].lines().map(String::from).collect());
|
||||
ta.move_cursor(tui_textarea::CursorMove::End);
|
||||
self.textarea = ta;
|
||||
}
|
||||
}
|
||||
KeyCode::Down => {
|
||||
if let Some(idx) = self.history_index {
|
||||
if idx + 1 < self.input_history.len() {
|
||||
self.history_index = Some(idx + 1);
|
||||
let mut ta = new_textarea(self.input_history[idx + 1].lines().map(String::from).collect());
|
||||
ta.move_cursor(tui_textarea::CursorMove::End);
|
||||
self.textarea = ta;
|
||||
} else {
|
||||
self.history_index = None;
|
||||
self.textarea = new_textarea(vec![String::new()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
KeyCode::PageUp => self.scroll_active_up(10),
|
||||
KeyCode::PageDown => self.scroll_active_down(10),
|
||||
KeyCode::Tab => {
|
||||
self.active_pane = match self.active_pane {
|
||||
ActivePane::Autonomous => ActivePane::Tools,
|
||||
ActivePane::Tools => ActivePane::Conversation,
|
||||
ActivePane::Conversation => ActivePane::Autonomous,
|
||||
};
|
||||
}
|
||||
_ => { self.textarea.input(key); }
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
self.draw_main(frame, area, app);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl InteractScreen {
|
||||
/// Draw the main (F1) screen — four-pane layout with status bar.
|
||||
pub(crate) fn draw_main(&mut self, frame: &mut Frame, size: Rect, app: &App) {
|
||||
// Main layout: content area + active tools overlay + status bar
|
||||
|
|
@ -407,6 +343,68 @@ impl InteractScreen {
|
|||
}
|
||||
}
|
||||
|
||||
impl ScreenView for InteractScreen {
|
||||
fn label(&self) -> &'static str { "interact" }
|
||||
|
||||
fn tick(&mut self, frame: &mut Frame, area: Rect,
|
||||
key: Option<KeyEvent>, app: &mut App) -> Option<ScreenAction> {
|
||||
// Handle keys
|
||||
if let Some(key) = key {
|
||||
match key.code {
|
||||
KeyCode::Esc => return Some(ScreenAction::Hotkey(HotkeyAction::Interrupt)),
|
||||
KeyCode::Enter if !key.modifiers.contains(KeyModifiers::ALT) && !key.modifiers.contains(KeyModifiers::SHIFT) => {
|
||||
let input: String = self.textarea.lines().join("\n");
|
||||
if !input.is_empty() {
|
||||
if self.input_history.last().map_or(true, |h| h != &input) {
|
||||
self.input_history.push(input.clone());
|
||||
}
|
||||
self.history_index = None;
|
||||
// TODO: push to submitted via app or return action
|
||||
}
|
||||
}
|
||||
KeyCode::Up if key.modifiers.contains(KeyModifiers::CONTROL) => self.scroll_active_up(3),
|
||||
KeyCode::Down if key.modifiers.contains(KeyModifiers::CONTROL) => self.scroll_active_down(3),
|
||||
KeyCode::Up => {
|
||||
if !self.input_history.is_empty() {
|
||||
let idx = match self.history_index { None => self.input_history.len() - 1, Some(i) => i.saturating_sub(1) };
|
||||
self.history_index = Some(idx);
|
||||
let mut ta = new_textarea(self.input_history[idx].lines().map(String::from).collect());
|
||||
ta.move_cursor(tui_textarea::CursorMove::End);
|
||||
self.textarea = ta;
|
||||
}
|
||||
}
|
||||
KeyCode::Down => {
|
||||
if let Some(idx) = self.history_index {
|
||||
if idx + 1 < self.input_history.len() {
|
||||
self.history_index = Some(idx + 1);
|
||||
let mut ta = new_textarea(self.input_history[idx + 1].lines().map(String::from).collect());
|
||||
ta.move_cursor(tui_textarea::CursorMove::End);
|
||||
self.textarea = ta;
|
||||
} else {
|
||||
self.history_index = None;
|
||||
self.textarea = new_textarea(vec![String::new()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
KeyCode::PageUp => self.scroll_active_up(10),
|
||||
KeyCode::PageDown => self.scroll_active_down(10),
|
||||
KeyCode::Tab => {
|
||||
self.active_pane = match self.active_pane {
|
||||
ActivePane::Autonomous => ActivePane::Tools,
|
||||
ActivePane::Tools => ActivePane::Conversation,
|
||||
ActivePane::Conversation => ActivePane::Autonomous,
|
||||
};
|
||||
}
|
||||
_ => { self.textarea.input(key); }
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
self.draw_main(frame, area, app);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Draw the conversation pane with a two-column layout: marker gutter + text.
|
||||
/// The gutter shows a marker at turn boundaries, aligned with the input gutter.
|
||||
fn draw_conversation_pane(
|
||||
|
|
|
|||
|
|
@ -391,6 +391,7 @@ pub async fn run(
|
|||
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 terminal = tui::init_terminal()?;
|
||||
let mut reader = EventStream::new();
|
||||
|
|
|
|||
|
|
@ -28,10 +28,24 @@ use std::io;
|
|||
|
||||
use crate::user::ui_channel::{ContextInfo, SharedContextState, StatusInfo};
|
||||
|
||||
/// Build the screen legend from the screen table.
|
||||
/// 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()));
|
||||
}
|
||||
format!(" {} ", parts.join(" "))
|
||||
}
|
||||
|
||||
// Cached legend — set once at startup by event_loop
|
||||
static SCREEN_LEGEND: std::sync::OnceLock<String> = std::sync::OnceLock::new();
|
||||
|
||||
pub(crate) fn set_screen_legend(legend: String) {
|
||||
let _ = SCREEN_LEGEND.set(legend);
|
||||
}
|
||||
|
||||
pub(crate) fn screen_legend() -> String {
|
||||
// Built from the SCREENS table in event_loop
|
||||
" F1=interact F2=conscious F3=subconscious F4=unconscious F5=thalamus ".to_string()
|
||||
SCREEN_LEGEND.get().cloned().unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn strip_ansi(text: &str) -> String {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue