Skip to content

@-picker rebuild + mouse-wheel chat scroll#479

Merged
esengine merged 2 commits into
mainfrom
feat/at-picker-rebuild
May 9, 2026
Merged

@-picker rebuild + mouse-wheel chat scroll#479
esengine merged 2 commits into
mainfrom
feat/at-picker-rebuild

Conversation

@esengine

@esengine esengine commented May 9, 2026

Copy link
Copy Markdown
Owner

Summary

Two related fixes addressing user reports in #478 and discussion #22.

1. feat(at-picker): rebuild as file browser with streaming search

Replaces the upfront 500-file walk that was unusable on real-sized repos — on a 5k-file tree the cap evicted ~90% of paths before ranking ever ran, so the picker often showed nothing useful.

New behavior:

  • @ alone or @some/dir/ → browse mode: lists ONE directory's immediate children (no recursion). Folders selectable; Tab drills, Enter commits.
  • Anything else (@foo, @auth/log) → search mode: cancelable streaming walk across the full tree, results stream in as the walker finds them, footer shows searching… N scanned while in flight.
  • Drops the 500-file cap; cancellation bounds work instead.

Internals:

  • walkFilesStream — cancelable streaming walker (per-entry onEntry callback + AbortSignal)
  • listDirectory — single-level browse, gitignore-aware
  • parseAtQuery — splits dir/filter with trailing-slash awareness
  • listFilesWithStatsAsync now delegates to walkFilesStream (no behavior change for existing callers)
  • expandAtUrls + helpers split out to at-mentions-url.ts to keep at-mentions.ts under the 800-line ceiling

Closes #478

2. fix(scroll): route mouse wheel via SGR mouse tracking

The picker rebuild surfaces a pre-existing UX problem more often: terminals like Windows Terminal map the scroll wheel to ↑/↓ key sequences, which PromptInput consumes for history recall and cursor motion. So scrolling the wheel while typing did history recall instead of scrolling chat.

Fix: enable SGR mouse tracking (DECSET 1006 + 1000) at startup. The terminal now reports wheel events as \x1b[<btn;col;row;M mouse sequences instead of arrow keys; the chat-scroll handler routes those mouseScrollUp/Down events to scrollback, bypassing the arrow-key path entirely.

The SGR mouse parser already lived in stdin-reader.ts — this just turns on the terminal-side feature.

Trade-off: terminal-native drag-to-select needs a modifier (Shift on Windows Terminal / Alacritty / WezTerm, Option on iTerm2). Same convention as tmux, Claude Code, Cursor's terminal.

Test plan

  • npm run verify — build + lint + typecheck + 2291 tests pass
  • 18 new tests covering walkFilesStream (cancel, halt, ignore-dirs, progress), listDirectory (folders-first, gitignore, escape, missing dir), parseAtQuery (trailing slash, backslash normalization)
  • Manual: @ on a 5000-file repo shows root listing instantly
  • Manual: @src/au streams matches with searching… N scanned footer
  • Manual: Tab on a folder appends / and re-opens picker for that subdir; Enter commits
  • Manual: mouse wheel scrolls chat history while typing in PromptInput
  • Manual: ↑/↓ keys retain history recall (empty buffer) and cursor motion (non-empty)
  • Manual: Shift+drag still selects text in Windows Terminal

esengine added 2 commits May 8, 2026 19:25
Empty / trailing-slash queries (`@`, `@src/`) browse one directory level
with a single readdir — folders selectable, drill via Tab. Any non-slash
filter (`@foo`, `@auth/log`) kicks off a cancelable streaming walk across
the full tree, batching matches into the popup as they're found, with a
`searching… N scanned` footer while in flight.

Replaces the upfront 500-file walk that was unusable on large repos —
on a 5k-file tree the cap evicted ~90% of paths before ranking, leaving
the picker effectively empty.

- walkFilesStream: cancelable streaming walker; powers search mode
- listDirectory: single-level browse, no recursion; powers browse mode
- parseAtQuery: splits `dir/filter` with trailing-slash awareness
- listFilesWithStatsAsync now delegates to walkFilesStream (no behavior
  change for existing callers)
- expandAtUrls + helpers split into at-mentions-url.ts to keep
  at-mentions.ts under the 800-line ceiling

Closes #478
Enable DECSET 1006 + 1000 at startup so the terminal reports wheel
events as `\x1b[<btn;col;row;M` mouse sequences instead of translating
them to ↑/↓ key presses. The chat-scroll handler routes the resulting
mouseScrollUp/Down events to scrollback, bypassing the arrow-key path
entirely — the wheel now scrolls chat regardless of buffer state, while
↑/↓ keys retain their existing PromptInput bindings (history recall on
empty buffer, cursor motion otherwise).

The SGR mouse parser already lived in stdin-reader.ts; this just
turns on the terminal-side feature so events actually flow.

Cost: terminal-native drag-to-select needs a modifier (Shift on Windows
Terminal / Alacritty / WezTerm, Option on iTerm2) — same trade-off as
tmux, Claude Code, Cursor's terminal.
@esengine esengine merged commit bb5b124 into main May 9, 2026
2 checks passed
@esengine esengine deleted the feat/at-picker-rebuild branch May 9, 2026 02:28
ChasLui pushed a commit to ChasLui/DeepSeek-Reasonix that referenced this pull request May 23, 2026
* feat(at-picker): rebuild as file browser with streaming search

Empty / trailing-slash queries (`@`, `@src/`) browse one directory level
with a single readdir — folders selectable, drill via Tab. Any non-slash
filter (`@foo`, `@auth/log`) kicks off a cancelable streaming walk across
the full tree, batching matches into the popup as they're found, with a
`searching… N scanned` footer while in flight.

Replaces the upfront 500-file walk that was unusable on large repos —
on a 5k-file tree the cap evicted ~90% of paths before ranking, leaving
the picker effectively empty.

- walkFilesStream: cancelable streaming walker; powers search mode
- listDirectory: single-level browse, no recursion; powers browse mode
- parseAtQuery: splits `dir/filter` with trailing-slash awareness
- listFilesWithStatsAsync now delegates to walkFilesStream (no behavior
  change for existing callers)
- expandAtUrls + helpers split into at-mentions-url.ts to keep
  at-mentions.ts under the 800-line ceiling

Closes esengine#478

* fix(scroll): route mouse wheel via SGR mouse tracking

Enable DECSET 1006 + 1000 at startup so the terminal reports wheel
events as `\x1b[<btn;col;row;M` mouse sequences instead of translating
them to ↑/↓ key presses. The chat-scroll handler routes the resulting
mouseScrollUp/Down events to scrollback, bypassing the arrow-key path
entirely — the wheel now scrolls chat regardless of buffer state, while
↑/↓ keys retain their existing PromptInput bindings (history recall on
empty buffer, cursor motion otherwise).

The SGR mouse parser already lived in stdin-reader.ts; this just
turns on the terminal-side feature so events actually flow.

Cost: terminal-native drag-to-select needs a modifier (Shift on Windows
Terminal / Alacritty / WezTerm, Option on iTerm2) — same trade-off as
tmux, Claude Code, Cursor's terminal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@-mention picker: rebuild as a file browser with on-demand directory walk + streaming search

1 participant