Skip to content

feat: show "did you mean" suggestions live, before Enter (#84)#85

Merged
dawsbot merged 4 commits into
masterfrom
feat/live-did-you-mean-suggestions
Jul 7, 2026
Merged

feat: show "did you mean" suggestions live, before Enter (#84)#85
dawsbot merged 4 commits into
masterfrom
feat/live-did-you-mean-suggestions

Conversation

@dawsbot

@dawsbot dawsbot commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Closes #84.

Problem

The "did you mean" fallback (getClosestMatches) almost never showed up. findRelativePath() has two paths:

  • Quick-filter path (common case, under searchCountLimit, default 10k files): used window.showQuickPick; VS Code did the filtering and a typo just produced its native empty state. getClosestMatches was never called.
  • Input-box path (>10k files): the fallback ran, but only after Enter.

Change

Migrate the quick-filter path to a managed window.createQuickPick() and own the filtering rather than cooperating with VS Code's built-in filter. Every rendered row is marked alwaysShow: true (which bypasses the native filter), and matches are computed by a new filterPaths — case-insensitive substring over the workspace-relative path, the same rule the input-box path already uses. When our filter returns nothing, after a ~150ms debounce we show getClosestMatches under a did you mean separator.

So "empty" is a value we compute, not a signal we read from VS Code. Both picker paths now share one definition of "match".

Two earlier approaches that failed (why we own the filter now)

The user's live testing drove this:

  1. Predict emptiness with a home-grown subsequence matcher — diverged from VS Code's stricter fuzzy matcher (tp is a subsequence of types.ts but VS Code shows nothing), so it both blanked real typos and, over large lists, almost never triggered.
  2. Read quickPick.activeItems — goes stale the instant the filter empties; after typing t then p, it still held types.ts, so the code saw a match and never offered suggestions. Confirmed live: tp with types.ts present showed "No matching results" and no suggestions.

Trade-off

We no longer use VS Code's fuzzy matching for the happy path — filtering is now substring (consistent with the input-box path). Fuzzy-only hits (e.g. btonButton) surface under "did you mean" instead of as direct matches. matchOnDescription = true stays on only for match highlighting.

Testing

  • npm test — 46/46 pass (filterPaths has 6 new unit tests). Project tsc compiles clean.
  • The picker-wiring layer (createQuickPick events, alwaysShow, debounce) depends on the VS Code API and needs Extension Development Host verification. Pending live confirmation that tptypes.ts under "did you mean".

Design doc (with the two failed approaches recorded): docs/superpowers/specs/2026-07-07-live-did-you-mean-suggestions-design.md

🤖 Generated with Claude Code

dawsbot and others added 4 commits July 7, 2026 13:11
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The closest-match fallback (getClosestMatches) only ran in the >10k-file
input-box path, and only after Enter. In the common quick-filter path
(window.showQuickPick) a typo just showed VS Code's empty state and the
suggestions never appeared.

Migrate the picker to a managed window.createQuickPick and, on a ~150ms
debounce after each keystroke, detect when the query would match nothing
(query is not a case-insensitive subsequence of any candidate's relative
path) and swap in getClosestMatches under a 'did you mean' separator, with
alwaysShow so VS Code's own filter doesn't drop them. Native fuzzy filtering
and highlighting stay on for the happy path.

New src/picker-suggestions.ts holds the pure emptiness check with unit
coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The first cut predicted VS Code's filter emptiness with a home-grown
subsequence matcher (hasAnyFuzzyMatch). That was wrong in both directions:

- VS Code's fuzzy matcher is stricter than a raw subsequence ('tp' is a
  subsequence of 'types.ts' yet VS Code shows nothing), so the proxy reported
  'has a match' while the user saw a blank list and got no suggestions.
- Over a large file list almost any short query is a subsequence of some path,
  so the proxy nearly always said 'has a match' and suggestions never fired
  ('no matter what I type').

Read VS Code's actual result instead: after it filters the base list against
the current value, quickPick.activeItems is empty exactly when nothing matched.
Debounce ~150ms after the last keystroke, then read activeItems; if empty, show
getClosestMatches under a 'did you mean' separator (alwaysShow). Native fuzzy
filtering and highlighting stay untouched for the happy path.

Removes the flawed src/picker-suggestions.ts and its tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both prior approaches tried to cooperate with VS Code's built-in quick-pick
filter and both broke, as the user's testing showed:

- Predicting emptiness with a subsequence matcher diverged from VS Code's
  stricter fuzzy matcher ('tp' looked like a match to us, blank to the user).
- Reading quickPick.activeItems was unreliable: it stays stale the instant the
  filter empties, so after 't' -> 'tp' it still reported the old match and
  suggestions never showed. Confirmed live: 'tp' with types.ts present showed
  'No matching results' and no suggestions.

Stop cooperating with the native filter. Mark every rendered row alwaysShow so
it bypasses VS Code's filter, and compute matches ourselves via a new
filterPaths (case-insensitive substring over the workspace-relative path, the
same rule the large-workspace input-box path already uses). 'Empty' is now a
value we control, so getClosestMatches fires whenever our filter returns
nothing. Both picker paths share one definition of 'match'.

Adds src/picker-filter.ts + tests (6). matchOnDescription stays only for match
highlighting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dawsbot dawsbot merged commit 4184271 into master Jul 7, 2026
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.

Show "did you mean" suggestions live, before Enter, when the query matches nothing

1 participant