selectFromList Architecture
A webview-based fuzzy-search selector that replaces VS Code's native QuickPick for richer interaction (multi-select, range select, alternate actions).
Key Files
| File | Role |
|---|---|
src/selectFromList.js | Extension-side provider — creates/reuses webview, posts items, resolves promises |
src/selectFromList/main.js | Webview-side — List class (virtual scrolling, selection), FuzzySearch class (TextMate-style ranking) |
src/selectFromList/index.html | HTML shell with inline CSS, search input, CSP nonces |
src/selectFromList.json | Manifest fragment (contributes views, commands, configuration) |
Data Flow
code
Command invokes showSelectFromList(items, options)
→ chooseItems() on provider
→ createWebviewPanel() (reuses if alive) or sidebar path
→ reveal() panel (so it's visible before init)
→ await _isReady (resolves when webview posts "ready")
→ postMessage({ type: "init", items, requestId })
→ webview receives init
→ pre-lowercases labels (_lowerLabel, _lowerDescription)
→ computeVisible() → render() (virtual scrolling)
→ focus search input
→ user types → 30ms debounce → computeVisible() → render()
→ user submits (Enter / double-click)
→ postMessage({ type: "submit", indexes, requestId })
→ provider resolves promise with selected items
FuzzySearch (TextMate port)
- •
rank(filter, candidate, candidateLower, out)— entry point, filter is already lowercase - •
calculateRank(lhs, rhs, rhsLower, out)— matrix-based scoring from TextMate'sranker.cc - •
rankFile(filter, filename, directory, filenameLower, directoryLower)— tries filename first, falls back to full path - •
isSubset(needle, haystackLower)— fast pre-check before full ranking - •Pre-allocated typed arrays (
_matrix,_first,_last,_capitals) avoid GC pressure
Performance Characteristics
- •Virtual scrolling — only ~60 DOM nodes regardless of list size (20-row overscan)
- •Incremental filtering — typing more chars narrows from previous matches, not full list
- •Pre-lowercased labels —
toLowerCase()called once at init, not per-char in hot loop - •Panel reuse —
retainContextWhenHidden: true, panel is reused across opens
Constraints
- •The
FuzzySearch.calculateRankalgorithm is a TextMate port — modify with extreme care - •
requestIdprevents stale responses from previous invocations - •
close()disposes panel (panel path) or hides sidebar — different teardown per render mode - •The
_isReadypromise pattern: created fresh when panel/sidebar is new, stays resolved when reusing