Search: global-as-you-type with ranked name matching #292
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#292
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Dogfood finding (2026-08-20, Nikola): "the search bar can so far only search within the current folder." Scouted reality: a global search already exists —
GET /api/v1/search?q=(internal/api/search.go) does a bounded BFS from/over the scoped store (exactly the caller's visible tree: Personal + member spaces), case-insensitive substring, caps 200 results / 500 dirs / depth 12. But the UI fires it only on Enter; typing runsfilterRowswhich just hides rows of the current listing. The global capability is invisible.Target UX: typing in the search box (≥2 chars) IS the global search — debounced live results across everything the user can access, ranked intelligently. Enter no longer required (still works). Escape restores the previous view (existing behavior).
Frontend
/api/v1/search, render into the existingsearchview (renderRows(items, {showPath:true})).Backend ranking ("intelligent")
Replace the plain path sort with match-quality ranking, all case-insensitive on the NAME:
-,_,., space, digit/letter transitions)Tiebreaks: shallower path first, then name alphabetically. Multi-token queries (split on whitespace): every token must match the name; rank by the best token's class.
Bounds unchanged (no index; the backend stays the source of truth).
truncatedalready reported and surfaced.Mockup-first per house process.
Shipped as v0.6.56 (PR #294), live on both dogfoods.
What changed:
q3-fall-…) → plain contains by position in the name; ties broken by shallower path, then name. Multi-word queries need every word to match.Dogfood checklist:
fall.pdf>fall-report…>q3-fall…>waterfall…)Dogfood verified by Nikola on both instances (v0.6.56) — search-as-you-type with ranked global results works as designed. Closing.
Solution summary: the global search engine already existed (bounded BFS over the caller's scoped store) but only fired on Enter. The fix wired typing directly to it (300ms debounce, sequence guard against stale responses, Escape restore) and added ranked matching in
internal/api/search.go:matchClass(exact incl. sans-extension → prefix → word-boundary → substring-by-position) andrankName(multi-token: all must match, worst class scores), sorted rank → path depth → name. Covered byTestMatchClassOrdering/TestRankNameMultiToken.