feat: show "did you mean" suggestions live, before Enter (#84)#85
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #84.
Problem
The "did you mean" fallback (
getClosestMatches) almost never showed up.findRelativePath()has two paths:searchCountLimit, default 10k files): usedwindow.showQuickPick; VS Code did the filtering and a typo just produced its native empty state.getClosestMatcheswas never called.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 markedalwaysShow: true(which bypasses the native filter), and matches are computed by a newfilterPaths— 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 showgetClosestMatchesunder adid you meanseparator.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:
tpis a subsequence oftypes.tsbut VS Code shows nothing), so it both blanked real typos and, over large lists, almost never triggered.quickPick.activeItems— goes stale the instant the filter empties; after typingtthenp, it still heldtypes.ts, so the code saw a match and never offered suggestions. Confirmed live:tpwithtypes.tspresent 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.
bton→Button) surface under "did you mean" instead of as direct matches.matchOnDescription = truestays on only for match highlighting.Testing
npm test— 46/46 pass (filterPathshas 6 new unit tests). Projecttsccompiles clean.createQuickPickevents,alwaysShow, debounce) depends on the VS Code API and needs Extension Development Host verification. Pending live confirmation thattp→types.tsunder "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