fix: slim down token usage
This commit is contained in:
105
src/app/mod.rs
105
src/app/mod.rs
@@ -7,13 +7,14 @@ mod workspace_input;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
event::{self, Event, KeyEvent},
|
||||
event::{self, Event},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
@@ -21,14 +22,15 @@ use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
|
||||
use crate::cli::DEFAULT_TASK_CONFIG_PATH;
|
||||
use crate::model::{
|
||||
group_session_entries, ControllerPhase, ControllerState, Plan, Screen, SessionEntry,
|
||||
SessionSelection, StatusSnapshot, TaskConfig, UsageSnapshot,
|
||||
ControllerState, Plan, Screen, SessionEntry, SessionSelection, StatusSnapshot, TaskConfig,
|
||||
UsageSnapshot,
|
||||
};
|
||||
use crate::ui;
|
||||
use crate::ui::{self, scroll::VerticalScrollState, SessionRenderRow, SessionView, SidebarView};
|
||||
|
||||
pub(crate) const USAGE_REFRESH_INTERVAL: Duration = Duration::from_secs(120);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
pub enum AppEvent {
|
||||
Session(SessionEntry),
|
||||
Snapshot {
|
||||
@@ -66,9 +68,15 @@ pub(crate) struct WorkspaceRuntime {
|
||||
pub(crate) session_output_tokens: Option<u64>,
|
||||
pub(crate) usage_snapshot: UsageSnapshot,
|
||||
pub(crate) last_usage_refresh: Instant,
|
||||
pub(crate) session_scroll: usize,
|
||||
pub(crate) session_follow_output: bool,
|
||||
pub(crate) session_viewport_lines: usize,
|
||||
pub(crate) session_scrollbar: VerticalScrollState,
|
||||
pub(crate) session_rows: Vec<SessionRenderRow>,
|
||||
pub(crate) session_view: Option<SessionView>,
|
||||
pub(crate) session_view_area: ratatui::layout::Rect,
|
||||
pub(crate) sidebar_follow_output: bool,
|
||||
pub(crate) sidebar_scrollbar: VerticalScrollState,
|
||||
pub(crate) sidebar_view: Option<SidebarView>,
|
||||
pub(crate) sidebar_view_area: ratatui::layout::Rect,
|
||||
pub(crate) session_selection: Option<SessionSelection>,
|
||||
pub(crate) session_drag_active: bool,
|
||||
}
|
||||
@@ -80,6 +88,7 @@ pub struct App {
|
||||
pub create_input: String,
|
||||
pub create_error: Option<String>,
|
||||
pub default_task_path: PathBuf,
|
||||
pub(crate) frame_tick: u64,
|
||||
pub(crate) workspace: Option<WorkspaceRuntime>,
|
||||
}
|
||||
|
||||
@@ -93,6 +102,7 @@ impl App {
|
||||
create_input: String::new(),
|
||||
create_error: None,
|
||||
default_task_path: default_task_path.clone(),
|
||||
frame_tick: 0,
|
||||
workspace: None,
|
||||
};
|
||||
|
||||
@@ -108,7 +118,11 @@ impl App {
|
||||
pub fn run(&mut self) -> Result<()> {
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = std::io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen, crossterm::event::EnableMouseCapture)?;
|
||||
execute!(
|
||||
stdout,
|
||||
EnterAlternateScreen,
|
||||
crossterm::event::EnableMouseCapture
|
||||
)?;
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
@@ -126,13 +140,6 @@ impl App {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn workspace_groups(&self) -> Vec<crate::model::SessionGroup> {
|
||||
self.workspace
|
||||
.as_ref()
|
||||
.map(|workspace| group_session_entries(&workspace.session_entries))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn workspace_status_snapshot(&self) -> Option<StatusSnapshot> {
|
||||
let workspace = self.workspace.as_ref()?;
|
||||
Some(StatusSnapshot {
|
||||
@@ -163,6 +170,28 @@ impl App {
|
||||
.and_then(|workspace| workspace.session_selection.as_ref())
|
||||
}
|
||||
|
||||
pub(crate) fn workspace_session_rows(&self) -> Option<&[SessionRenderRow]> {
|
||||
self.workspace
|
||||
.as_ref()
|
||||
.map(|workspace| workspace.session_rows.as_slice())
|
||||
}
|
||||
|
||||
pub(crate) fn workspace_session_view(&self) -> Option<&SessionView> {
|
||||
self.workspace
|
||||
.as_ref()
|
||||
.and_then(|workspace| workspace.session_view.as_ref())
|
||||
}
|
||||
|
||||
pub(crate) fn workspace_sidebar_view(&self) -> Option<&SidebarView> {
|
||||
self.workspace
|
||||
.as_ref()
|
||||
.and_then(|workspace| workspace.sidebar_view.as_ref())
|
||||
}
|
||||
|
||||
pub(crate) fn heartbeat_frame(&self) -> u64 {
|
||||
self.frame_tick
|
||||
}
|
||||
|
||||
pub(crate) fn workspace_session_scroll(&self) -> usize {
|
||||
let Some(workspace) = self.workspace.as_ref() else {
|
||||
return 0;
|
||||
@@ -170,18 +199,18 @@ impl App {
|
||||
|
||||
let max_scroll = self
|
||||
.workspace_session_line_count()
|
||||
.saturating_sub(workspace.session_viewport_lines);
|
||||
.saturating_sub(workspace.session_scrollbar.viewport_lines);
|
||||
if workspace.session_follow_output {
|
||||
max_scroll
|
||||
} else {
|
||||
workspace.session_scroll.min(max_scroll)
|
||||
workspace.session_scrollbar.position_lines.min(max_scroll)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn workspace_session_line_count(&self) -> usize {
|
||||
self.workspace
|
||||
.as_ref()
|
||||
.map(|workspace| Self::session_line_count_for_entries(&workspace.session_entries))
|
||||
.map(|workspace| workspace.session_scrollbar.content_lines)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -192,24 +221,42 @@ impl App {
|
||||
loop {
|
||||
self.drain_workspace_events()?;
|
||||
self.maybe_refresh_usage()?;
|
||||
self.update_workspace_viewport(terminal.size()?.height as usize);
|
||||
self.update_workspace_viewport(terminal.size()?.into());
|
||||
self.tick_session_scroll_repeat();
|
||||
self.frame_tick = self.frame_tick.wrapping_add(1);
|
||||
|
||||
terminal.backend_mut().write_all(b"\x1b[?2026h")?;
|
||||
terminal.draw(|frame| ui::render(frame, self))?;
|
||||
terminal.backend_mut().write_all(b"\x1b[?2026l")?;
|
||||
terminal.backend_mut().flush()?;
|
||||
|
||||
if event::poll(Duration::from_millis(100))? {
|
||||
match event::read()? {
|
||||
Event::Key(key) => {
|
||||
if self.handle_key(key)? {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Event::Mouse(mouse) => self.handle_mouse(mouse, terminal.size()?.into())?,
|
||||
Event::Resize(_, height) => self.update_workspace_viewport(height as usize),
|
||||
_ => {}
|
||||
}
|
||||
if event::poll(Duration::from_millis(50))? && self.handle_pending_events(terminal)? {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_pending_events(
|
||||
&mut self,
|
||||
terminal: &mut Terminal<CrosstermBackend<std::io::Stdout>>,
|
||||
) -> Result<bool> {
|
||||
loop {
|
||||
match event::read()? {
|
||||
Event::Key(key) => {
|
||||
if self.handle_key(key)? {
|
||||
return Ok(true);
|
||||
}
|
||||
}
|
||||
Event::Mouse(mouse) => self.handle_mouse(mouse, terminal.size()?.into())?,
|
||||
Event::Resize(_, _) => self.update_workspace_viewport(terminal.size()?.into()),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !event::poll(Duration::ZERO)? {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user