summaryrefslogtreecommitdiff
path: root/makima/src/daemon/tui/mod.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-01-19 13:47:32 +0000
committerGitHub <noreply@github.com>2026-01-19 13:47:32 +0000
commit0833fb1f30c0c3b920157deb882e0e902c3af02a (patch)
tree45110fb8cb9277dfbaccfeb53ed9c1f76975022b /makima/src/daemon/tui/mod.rs
parent786510379bed060db2b3742b7dfca671552d2c34 (diff)
downloadsoryu-0833fb1f30c0c3b920157deb882e0e902c3af02a.tar.gz
soryu-0833fb1f30c0c3b920157deb882e0e902c3af02a.zip
Add interactive TUI browser for tasks, contracts, and files (makima view) (#7)
* feat(tui): Implement fuzzy search with real-time filtering and highlighting Adds comprehensive fuzzy search functionality to the TUI browser: ## Fuzzy Matching (fuzzy.rs) - FuzzyMatcher wrapper using SkimMatcherV2 from fuzzy-matcher crate - fuzzy_match() returns score and matched character indices - fuzzy_match_all() supports multi-term search (space-separated) - Recency-aware scoring to boost recent items in results - Unit tests for all matching scenarios ## App State (app.rs) - FilteredItem struct with index, score, and matched_indices - apply_filter() uses fuzzy matching with score-based sorting - match_count() and has_no_matches() helper methods - Results sorted by match score (highest first) ## List View (list_view.rs) - Highlighted matched characters in search results - Yellow bold styling for matched chars - Status icons with color coding ## Search Input (search_input.rs) - Real-time match count display (X/Y matches) - Visual feedback for no matches (red border) - Placeholder text when search is empty - Active search mode indication (yellow border) ## Event Handling (event.rs) - Arrow key navigation while in search mode - Ctrl+K/J for vim-style navigation during search - Delete key support alongside backspace - Ctrl+U to clear search query - Tab toggles preview while searching - Escape clears search and exits search mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * Task completion checkpoint * [WIP] Heartbeat checkpoint - 2026-01-19 11:20:34 UTC * Task completion checkpoint * [WIP] Heartbeat checkpoint - 2026-01-19 11:31:19 UTC * Task completion checkpoint * [WIP] Heartbeat checkpoint - 2026-01-19 11:39:07 UTC * fix(tui): Fix module exports and main binary integration - Update mod.rs to properly export app, event, fuzzy, and ui modules - Add run() function for TUI entry point - Fix run_view() to use ViewCommand enum instead of ViewArgs - Fix event handling to use poll_event and handle_key_event Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/src/daemon/tui/mod.rs')
-rw-r--r--makima/src/daemon/tui/mod.rs96
1 files changed, 96 insertions, 0 deletions
diff --git a/makima/src/daemon/tui/mod.rs b/makima/src/daemon/tui/mod.rs
new file mode 100644
index 0000000..fd1d44d
--- /dev/null
+++ b/makima/src/daemon/tui/mod.rs
@@ -0,0 +1,96 @@
+//! TUI module for interactive browsing.
+//!
+//! This module provides an interactive Terminal User Interface (TUI) for
+//! browsing and managing tasks, contracts, and files in the makima system.
+//!
+//! # Features
+//!
+//! - **Fuzzy Search**: Real-time filtering with the SkimMatcherV2 algorithm
+//! - **Keyboard Navigation**: Vim-style keybindings (j/k) and arrow keys
+//! - **Preview Pane**: Side-by-side view of item details
+//! - **Multiple Views**: Browse tasks, contracts, or files
+
+pub mod app;
+pub mod event;
+pub mod fuzzy;
+pub mod ui;
+
+pub use app::{App, ListItem, ViewType, InputMode, Action};
+pub use fuzzy::FuzzyMatcher;
+
+use std::io;
+use crossterm::{
+ event::{DisableMouseCapture, EnableMouseCapture},
+ execute,
+ terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
+};
+use ratatui::prelude::*;
+use ratatui::backend::CrosstermBackend;
+
+pub type Terminal = ratatui::Terminal<CrosstermBackend<io::Stdout>>;
+
+/// Run the TUI application
+pub fn run(mut app: App) -> Result<Option<String>, Box<dyn std::error::Error>> {
+ // Setup terminal
+ enable_raw_mode()?;
+ let mut stdout = io::stdout();
+ execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
+ let backend = CrosstermBackend::new(stdout);
+ let mut terminal = ratatui::Terminal::new(backend)?;
+
+ // Run the main loop
+ let result = run_app(&mut terminal, &mut app);
+
+ // Cleanup terminal
+ disable_raw_mode()?;
+ execute!(
+ terminal.backend_mut(),
+ LeaveAlternateScreen,
+ DisableMouseCapture
+ )?;
+ terminal.show_cursor()?;
+
+ result
+}
+
+fn run_app(
+ terminal: &mut Terminal,
+ app: &mut App,
+) -> Result<Option<String>, Box<dyn std::error::Error>> {
+ use crossterm::event::Event;
+ use std::time::Duration;
+
+ loop {
+ terminal.draw(|f| ui::render(f, app))?;
+
+ // Poll for events with 100ms timeout
+ if let Some(evt) = event::poll_event(Duration::from_millis(100))? {
+ if let Event::Key(key) = evt {
+ let action = event::handle_key_event(app, key);
+ match action {
+ Action::Quit => break,
+ Action::OutputPath(path) => return Ok(Some(path)),
+ Action::None => {}
+ _ => {
+ let result = app.handle_action(action);
+ // Check if handle_action returned a special action
+ if let Action::OutputPath(path) = result {
+ return Ok(Some(path));
+ }
+ }
+ }
+ }
+ }
+
+ if app.should_quit {
+ break;
+ }
+ }
+
+ Ok(None)
+}
+
+/// Print a path to stdout (for cd integration)
+pub fn print_path(path: &str) {
+ println!("{}", path);
+}