Complete llmfit TUI Keyboard Shortcuts Reference: Modal Navigation Guide

The llmfit TUI uses a modal interface where q or Esc quits the current view, j/k navigate lists, v enters visual selection mode, and all input is handled in llmfit-tui/src/tui_events.rs dispatching to mode-specific handlers like handle_normal_mode and handle_visual_mode.

The llmfit TUI keyboard shortcuts are implemented in a modal terminal interface built with ratatui and crossterm. Every keystroke is processed in llmfit-tui/src/tui_events.rs where the handle_events function routes input to mode-specific handlers that manipulate the central App state defined in llmfit-tui/src/tui_app.rs. Understanding these vim-inspired bindings is essential for navigating the model browser, running benchmarks, and managing downloads efficiently.

Understanding llmfit's Modal Architecture

The interface isolates concerns across distinct input modes. Normal mode displays the primary model table, while Visual mode enables range selection, Select mode targets specific columns, and Search mode filters the dataset. This design keeps the rendering logic in tui_ui.rs stateless while ensuring shortcuts affect only the intended UI component. Each mode handler—handle_normal_mode, handle_visual_mode, handle_select_mode, and handle_search_mode—matches crossterm::event::KeyCode values to methods on the App struct.

Normal Mode Shortcuts

Normal mode is the default state when launching llmfit. The handle_normal_mode function (lines 49-138 in tui_events.rs) processes these bindings.

  • j or Down: Move down in lists (benchmark view, multi-compare view, or tables).
  • k or Up: Move up in lists.
  • Ctrl-u: Half-page up (app.half_page_up()).
  • Ctrl-d: Half-page down (app.half_page_down()).
  • PageUp / PageDown: Full-page navigation (app.page_up() / app.page_down()).
  • g or Home: Jump to top or bottom of the list (app.cycle_top_bottom()).
  • h / l (in multi-compare): Scroll columns left/right (app.multi_compare_scroll_left() / right()).
  • Left / Right (in multi-compare): Same horizontal scrolling as h / l.

Filtering and Sorting

  • /: Open the search box (app.enter_search()).
  • f: Cycle through fit filters (Perfect → Good → ...).
  • F: Open the filter popup for range filters, sorting, and fit criteria (app.open_filter_popup()).
  • a: Cycle availability filter (All / Installed / GGUF).
  • T: Cycle Tensor-Parallel compatibility filter.
  • s: Cycle sort column (app.cycle_sort_column()).
  • i: Toggle "installed-first" sort when providers are available (app.toggle_installed_first()).

View Management

  • Enter: Toggle detail view or expand benchmark details (app.toggle_detail()).
  • t: Switch theme between dark and light (app.cycle_theme()).
  • p: Open the plan view (app.open_plan_mode()).
  • P: Open provider selection popup.
  • U: Open use-case popup.
  • C: Open capability popup.
  • L: Open license popup.
  • R: Open runtime popup.
  • S: Open simulation popup.
  • h: Open help popup (app.open_help_popup()).
  • b: Open benchmarks view (community leaderboard) (app.open_benchmarks()).
  • D: Toggle download manager view (app.toggle_downloads()).

Model Actions

  • v: Enter visual mode for range selection (app.enter_visual_mode()).
  • V: Enter select mode for column-specific actions (app.enter_select_mode()).
  • m: Mark or unmark selected model for comparison (app.mark_selected_for_compare()).
  • c: Toggle compare view (app.toggle_compare_view()).
  • x: Clear all compare marks (app.clear_compare_mark()).
  • y: Copy selected model name to clipboard (app.copy_selected_model_name()).
  • d: Start model download via best provider (app.start_download()), requires confirmation if no download is active.
  • r: Refresh installed models (app.refresh_installed()).
  • I: Open or rerun live inference benchmark (app.open_bench() / app.rerun_bench()).
  • A: Open advanced config popup (app.open_advanced_config_popup()).
  • q or Esc: Quit or close current view, setting should_quit = true if at the top level.

Visual Mode Shortcuts

Activated by pressing v in normal mode, handle_visual_mode (lines 41-62) enables selection ranges.

  • Esc, q, or v: Exit visual mode.
  • j / Down, k / Up, Ctrl-u, Ctrl-d, PageUp, PageDown, g / Home: Navigation helpers that extend the visual selection.
  • m: Mark selected rows for comparison.
  • c: Compare the first and last rows of the current visual selection.

Select Mode Shortcuts

Activated by V in normal mode, handle_select_mode (lines 65-82) targets specific columns.

  • Esc or q: Exit select mode.
  • h / Left or l / Right: Move column cursor left or right.
  • Enter or Space: Activate filter for the current column.
  • j / Down or k / Up: Move row cursor up or down.

Search Mode Shortcuts

When the search box is open via /, handle_search_mode (lines 85-106) manages text input.

  • Esc or Enter: Close the search box.
  • Backspace or Delete: Remove characters.
  • Ctrl-u: Clear the entire search query.
  • ← / →: Move cursor inside the search string.
  • Any printable character (without Ctrl/Alt modifiers): Insert character via app.search_input(c).
  • ↑ / ↓: Navigate the list while typing a search term.

Provider, use-case, capability, license, and runtime popups share common bindings in their respective handlers (e.g., provider at lines 9-44, use-case at lines 86-98).

  • Esc, q, or the popup's capital letter (U, C, L, R): Close the popup.
  • ↑ / k: Move selection up.
  • ↓ / j: Move selection down (Shift-scrolls by 25 lines).
  • Space or Enter: Toggle the highlighted item.
  • a: Select all providers (provider popup only).
  • n: Deselect all providers (provider popup only).
  • Ctrl-u: Clear typed filter text.
  • Plain ASCII characters: Filter the list via provider_search_input, use_case_search_input, etc.

Filter Popup Controls

In handle_filter_popup_mode (lines 68-83):

  • Esc or q: Close filter popup.
  • Enter: Apply the filter.
  • Tab / Down or Shift-Tab / Up: Switch between fields.
  • ← / →: Move cursor inside numeric fields.
  • Backspace / Delete: Erase characters.
  • Ctrl-u: Clear the active input (except enum fields).
  • Space: Toggle sort direction or cycle fit/availability values.
  • Digits or . (period): Input numeric values like RAM thresholds.

Plan View Controls

The handle_plan_mode function (lines 67-84) manages the hardware planning interface.

  • Esc: Close plan view.
  • Tab / Down / j or Shift-Tab / Up / k: Move between plan fields.
  • ← / →: Move cursor inside the current field.
  • Backspace / Delete: Remove characters.
  • Ctrl-u: Clear the current field.
  • Printable characters: Insert into the field (numbers and periods allowed).

Simulation and Advanced Config

Both handle_simulation_mode (lines 16-31) and handle_advanced_config_mode (lines 51-68) use similar editing shortcuts.

  • Esc or q: Close popup.
  • Enter: Apply changes (or simulated config).
  • Tab / Down / j or Shift-Tab / Up / k: Navigate between fields.
  • ← / →: Cursor movement within fields.
  • Backspace / Delete or Ctrl-u: Edit or clear field contents.
  • Ctrl-r: Reset to real hardware (simulation) or defaults (advanced config).
  • Digits or . (period): Input numeric values.

Benchmark Hardware Picker

Within handle_benchmarks_mode (lines 145-184), the hardware picker sub-modal responds to:

  • Esc, q, or H: Close hardware picker.
  • ↑ / k or ↓ / j: Move selection.
  • Enter or Space: Confirm hardware selection.

Download Manager Controls

In handle_download_manager_mode (lines 83-133), the download interface uses:

  • Esc, D, or q: Close download manager.
  • Tab or Shift-Tab: Cycle focus between History and Config panes.
  • ↑ / k (History focus): Move up in download history.
  • ↓ / j (History focus): Move down in download history.
  • x (History focus): Mark selected download for deletion (requires confirmation).
  • e (Config focus): Edit the download directory.
  • During edit mode: Esc, Enter, ← / →, Backspace, Delete, Ctrl-u, and printable chars perform standard line-editing on the path field.

Help System

The handle_help_popup_mode (lines 1-14) provides documentation browsing.

  • Esc, h, or q: Close help.
  • ↑ / k or ↓ / j: Scroll help text up or down.

Programmatic Shortcut Access

You can invoke these shortcuts programmatically for testing or automation by constructing crossterm::event::KeyEvent objects and calling the handlers directly.

// Simulate pressing "/" to open the search box
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
let ev = KeyEvent::new(KeyCode::Char('/'), KeyModifiers::NONE);

// In tests, call the handler directly
crate::tui_events::handle_normal_mode(&mut app, ev);
assert!(app.input_mode == InputMode::Search);
// Toggle the "installed-first" sort while any provider is available
let ev = KeyEvent::new(KeyCode::Char('i'), KeyModifiers::NONE);
crate::tui_events::handle_normal_mode(&mut app, ev);
assert!(app.installed_first);
// Verify that the plan field accepts "q4_k" input without closing
let mut app = crate::tui_events::tests::plan_mode_app();
app.plan_field = PlanField::KvQuant;
for c in ['q','4','_','k'] {
    crate::tui_events::handle_plan_mode(&mut app,
        KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE));
}
assert_eq!(app.input_mode, InputMode::Plan);
assert_eq!(app.plan_kv_quant_input, "q4_k");

These examples demonstrate how the #[cfg(test)] module at the end of tui_events.rs validates that keyboard bindings manipulate the App state correctly without requiring a live terminal.

Summary

  • All keyboard handling is centralized in llmfit-tui/src/tui_events.rs, where handle_events dispatches to mode-specific functions like handle_normal_mode and handle_visual_mode.
  • Navigation relies on vim-style bindings: j/k for vertical movement, h/l for horizontal scrolling, and Ctrl-u/Ctrl-d for half-page jumps.
  • Modes include Normal (browsing), Visual (range selection), Select (column targeting), Search (text filtering), and various popups for providers, filters, and configuration.
  • Global exit keys are q and Esc, which close the current view or quit the application when at the top level.
  • Comparison workflow: Use m to mark models, v to enter visual mode for range selection, and c to open the comparison view.
  • Programmatic testing is supported by calling handlers directly with KeyEvent objects constructed via crossterm.

Frequently Asked Questions

How do I exit any mode or popup in the llmfit TUI?

Press Esc or q to exit the current mode or close the active popup. In normal mode, these keys set should_quit = true to exit the application entirely, while in sub-modes like visual, select, or search, they return you to normal mode without quitting the program. Specific popups like the provider selector (P) also close when you press their activation key again.

What are the vim-style navigation keys in llmfit?

The llmfit TUI uses standard vim motion keys: j moves down, k moves up, h scrolls columns left, and l scrolls columns right. These work in normal mode and extend selection in visual mode. Additionally, g or Home jumps to the top or bottom of lists, while Ctrl-u and Ctrl-d perform half-page scrolling.

How do I search and filter models in the interface?

Press / to enter search mode and type to filter the model list dynamically. For advanced filtering, press F to open the filter popup where you can set range filters for RAM and other metrics, cycle fit quality with f, toggle availability with a, or filter by Tensor-Parallel compatibility with T. Use s to cycle through sort columns in the main view.

How do I compare multiple models side-by-side?

First, navigate to a model and press m to mark it for comparison. Enter visual mode by pressing v, select a range using j/k, then press m again to mark multiple rows, or press c to compare the first and last rows of your selection. Press c in normal mode to toggle the compare view, and x to clear all comparison marks.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →