Skip to content

feat(tui): @-triggered fuzzy file picker in input #600

@bug-ops

Description

@bug-ops

Summary

Add @-triggered fuzzy file search popup to the TUI input area. Typing @ in Insert mode opens an interactive file picker that fuzzy-matches project files by name, path, and extension.

Motivation

When composing messages in TUI, users often need to reference files. Currently they must type full paths manually. An @-triggered picker (similar to VS Code, GitHub, etc.) provides fast file discovery without leaving the input.

Design

UX Flow

  1. Type @ in Insert mode → popup opens above input
  2. Continue typing to fuzzy-filter (e.g., @main.rs, @src/app)
  3. Up/Down navigate results (top 10 shown)
  4. Enter/Tab accept → replaces @query with relative file path
  5. Esc dismisses without inserting
  6. Backspace past @ auto-dismisses

Implementation

  • Fuzzy engine: nucleo-matcher (same as Helix editor — fast, zero-alloc)
  • File walking: ignore crate (already in workspace, respects .gitignore)
  • File index: cached with 30s TTL, rebuilt on next @ trigger
  • Rendering: overlay popup above input (reuses Clear + centered_rect pattern from confirm modal)
  • State: FilePickerState { query, matches, selected, anchor } in App

New files

  • crates/zeph-tui/src/file_search.rs — file index + fuzzy matching
  • crates/zeph-tui/src/widgets/file_picker.rs — popup widget

Modified files

  • crates/zeph-tui/src/app.rs — state + key interception
  • crates/zeph-tui/src/widgets/mod.rs — module export
  • crates/zeph-tui/Cargo.toml — add nucleo-matcher, ignore

Detailed plan

.local/plan/tui-file-picker.md

Acceptance Criteria

  • @ in Insert mode opens file picker popup
  • Fuzzy search matches file name, directory, and extension
  • Results update on each keystroke
  • Enter/Tab inserts relative path at cursor position
  • Esc dismisses without side effects
  • .gitignored files excluded
  • Snapshot tests for widget rendering
  • Unit tests for fuzzy matching logic

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions