Skip to content

Multi-word AND search + path-segment matching + substring highlight#84

Merged
RasputinKaiser merged 1 commit into
mainfrom
search/multi-word-and-highlight
Jun 22, 2026
Merged

Multi-word AND search + path-segment matching + substring highlight#84
RasputinKaiser merged 1 commit into
mainfrom
search/multi-word-and-highlight

Conversation

@RasputinKaiser

Copy link
Copy Markdown
Owner

Summary

First Search slice of v0.5.0.

  • Extends StorageItem.matchesNormalizedSearchQuery(_:) to split queries by whitespace and require ALL terms to match (AND semantics). Single-term queries degenerate to v0.4.5 behavior; multi-term queries combine name / path / path-segments.
  • Adds path-segment awareness: a term matches if it equals (case-insensitively) any /-split segment — NOT as a contiguous substring across segments. "xDoc" correctly does NOT match /tmp/Doc/file.txt even though it's a substring of the joined path string.
  • Renders substring highlights in StorageItemRow (StorageItemTable.swift) and TreeNodeRow (TreeExplorerView.swift) via a new HighlightedText SwiftUI view struct (Sources/StorageScope/Support/HighlightedText.swift). Extracted because inline ? AnyShapeStyle(.tint) : Color ternaries trip Swift type-checker timeouts inside long HStack bodies — same pattern as the established FileTypeRowLabel in TypeBreakdownView.swift.

Critical invariants preserved

  • FilterStore queryfileTypeFocus mutual exclusivity (untouched)
  • searchText.didSet instant-clears query on empty (untouched)
  • selectedView auto-clears fileTypeFocus on non-applicable views (untouched)
  • matchesNormalizedSearchQuery signature stays (_ query: String) -> Bool so existing call sites in FilterStore.swift:218, ScanStore.swift:777, ScanStore.swift:1136 keep working

New API

StorageItem.searchHighlightRanges(for query: String) -> [Range<String.Index>] — matched ranges in name per term. Used for highlighting now; reserved for S2 (search result count badge) and S4 (Cmd+G find-next navigation) later in v0.5.0.

Test plan

  • swift test — 66 tests in 6 suites pass (54 prior + 12 new S1 cases)
  • swift build succeeds
  • ./script/public_upload_audit.sh passes
  • No surname "Zvirbulis"; GitHub handle "RasputinKaiser"
  • FilterStore invariants structurally verified

Manual E2E (visual highlight)

Run bash ./script/build_and_run.sh --fixture-scan, type a multi-word query like "foo bar" into the search field — matched substrings in the file list should render in accent color. Switch to Folder Tree view — same behavior.

🤖 Generated with NCode

Extends `matchesNormalizedSearchQuery(_:)` to split search queries by whitespace
and require ALL terms to match (AND semantics). Single-term queries degenerate
to the v0.4.5 single-contains behavior on each of name / path / path-segments;
multi-term queries combine them so "Documents foo" matches `/tmp/work/Documents/foo.txt`
via "Documents" segment + "foo" substring of name.

Path-segment awareness: term matches if it equals (case-insensitively) any
`/`-split segment, NOT as a contiguous substring across segments — so "xDoc"
correctly does NOT match `/tmp/Doc/file.txt` even though it's a substring of
the joined path string.

Substring highlight in result rows rendered via a new `HighlightedText` SwiftUI
View struct (Sources/StorageScope/Support/HighlightedText.swift). Extracted as
its own struct because the inline ternary `? AnyShapeStyle(.tint) : ...` on
matched vs unmatched runs was tripping Swift type-checker timeouts inside the
long HStack bodies; matches the established FileTypeRowLabel pattern in
TypeBreakdownView.swift, which the v0.5.0 TypeBreakdownView focus work proved out.

Wired into StorageItemRow (StorageItemTable.swift) and TreeNodeRow
(TreeExplorerView.swift) via store.filters.searchText. Reads zero from
FilterStore state other than `.searchText`. FilterStore chip invariants
(query / fileTypeFocus mutual exclusivity, searchText didSets instant-clearing
query on empty, selectedView auto-clears fileTypeFocus) untouched.

New `searchHighlightRanges(for:)` API on StorageItem returns matched String.Index
ranges in `name` per term — used for highlighting now, reserved for S2/S4
result-count-badge / Cmd+G find-next navigation work later in v0.5.0.

12 new tests in StorageItemSearchQueryTests.swift cover backward compat,
single-term name / path / segment matching, multi-word AND positive + negative,
path-segment negative (no substring-across-segments), case-insensitive matching,
highlight-range empty / single / multi-term cases.

Co-Authored-By: NCode <noreply@noumena.com>
@RasputinKaiser RasputinKaiser merged commit f91114e into main Jun 22, 2026
6 checks passed
@RasputinKaiser RasputinKaiser deleted the search/multi-word-and-highlight branch June 22, 2026 01:33
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.

1 participant