Skip to content

feat: add @-triggered file path autocomplete to TUI input panel #792

Description

@avoidwork

Summary

Add @-triggered file path autocomplete to the TUI input panel, allowing users to type @ followed by a filename fragment and select from a ranked list of matching files via glob search, with the selected path rendered in cyan/green.

Motivation

When referencing files in conversations (e.g., "look at src/tui/app.js"), users must manually type full or partial paths. This is error-prone and slow, especially for deeply nested paths. A lightweight autocomplete triggered by @ would reduce typos, speed up file references, and make the TUI feel more polished.

Proposed Solution

  1. Trigger detection: In InputPanel, detect when the user types @ and enter autocomplete mode.
  2. Glob search: Use fast-glob to search the project root for files matching the typed fragment. Limit results to top 5 matches.
  3. Dropdown rendering: Render a dropdown list below the input panel with keyboard navigation (up/down arrows to navigate, Enter to select, Esc to dismiss).
  4. Selection: On selection, replace @<query> with the full file path. Render the selected filename portion in cyan/green using chalk ANSI codes.
  5. State management: Track autocomplete state (inAutocomplete, query, matches, selectedIndex) in the App component and pass it to InputPanel.

Key files:

  • src/tui/inputPanel.js — add autocomplete mode and dropdown rendering
  • src/tui/app.js — manage autocomplete state, pass to InputPanel
  • package.json — add fast-glob dependency

UI behavior:

  • Type @ → dropdown appears below input line
  • Type more characters → list filters in real-time
  • Up/Down arrows → navigate list
  • Enter → select, replace @<query> with full path, render filename in cyan
  • Esc → dismiss dropdown, keep @<query> as-is
  • No matches → show "No files match" message

Alternatives Considered

  • Tab completion: Could work but tab is already used for other purposes in some terminals. @ is more discoverable and less likely to conflict.
  • Full fuzzy search: Could use a library like fuse.js for fuzzy matching, but glob-based prefix matching is simpler and sufficient for file paths.
  • Inline completion (like VS Code): Would require more complex rendering since Ink doesn't support true overlays. A separate dropdown below the input is simpler and still effective.

OpenSpec Note

This project uses OpenSpec for feature development. If this request is approved, I will:

  1. Run /opsx:propose to generate a full proposal with specs and tasks
  2. Iterate on the design before any code is written
  3. Follow the task-driven implementation workflow

Additional Context

Ink does not support true z-index overlays, so the dropdown must be rendered as a sibling component below the input panel. The selected text color change can be achieved by splitting the input value into segments and rendering the filename portion with a chalk color wrapper.

Audit Findings (for Issue #792)

  • src/tui/inputPanel.js:16-25 — InputPanel is a thin wrapper around ink-text-input. To add autocomplete, we need to extend this component to handle autocomplete mode: detect @ trigger, render dropdown below input, manage keyboard navigation state.
  • src/tui/app.js:949-957 — InputPanel is rendered inside a Box wrapper in the App component. Autocomplete state (inAutocomplete, query, matches, selectedIndex) needs to be lifted to App and passed as props to InputPanel.
  • src/tui/statusBar.js:60-97 — StatusBar renders below the input. The autocomplete dropdown must be rendered between InputPanel and StatusBar, not below StatusBar, to avoid pushing status bar content.
  • package.json:77 — Ink 7.1.1 is used. Ink 7 supports multiple renderers and the new component model. Autocomplete dropdown must be a sibling component rendered conditionally below InputPanel.
  • ink-text-input (dep) — The TextInput component captures all keyboard input. Autocomplete mode needs to intercept arrow keys and Enter before TextInput processes them, or use TextInput's built-in onSubmit/onChange hooks to manage state.
  • chalk (dep, v6.0.0) — Already available for colored output. Can be used to render selected filename in cyan/green within the input display.
  • fast-glob — Not currently a dependency. Would need to be added for file matching. Alternatively, use Node.js fs.readdirSync with recursive walk for a lighter approach, though fast-glob is more robust for pattern matching.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions