Skip to content

fix(staged): match multi-word search queries as AND of terms - #1010

Merged
matt2e merged 2 commits into
mainfrom
staged-search-two-words
Nov 2, 2026
Merged

matt2e merged 2 commits into
mainfrom
staged-search-two-words

Conversation

@matt2e

@matt2e matt2e commented Nov 2, 2026

Copy link
Copy Markdown
Contributor

Summary

Searching one three did not find a project named one two three. Every client-side search field (landing grid/sidebar searchProjects, the sidebar's searchRepos, All repos, the branch/note project pickers, the hashtag and branch dropdowns, and the GitHub repo picker) matched the whole trimmed query as a single contiguous, case-folded substring, so a multi-word query only matched that exact phrase.

  • Add src/lib/shared/textSearch.ts with queryTerms / matchesAllTerms / matchesQuery: the query is split on whitespace and a candidate matches when every term is a case-insensitive substring of at least one of its searchable fields, in any order and not necessarily adjacent or in the same field.
  • Switch projectSearch, sidebarSearch, moveBranchTarget, BranchPicker, RepoSearchInput, ReposListView and HashtagInput to the shared helpers.
  • Single-term queries behave as before, blank queries still return the input unchanged, and result order is preserved. The repo picker's matchesRepoSearch already tokenized this way and is unchanged.

Tests

  • New textSearch.test.ts covers one three / three one matching one two three, one four not matching, single terms, case-insensitivity, blank queries and terms landing in different fields.
  • Extended projectSearch, sidebarSearch and moveBranchTarget tests with multi-word cases.
  • Pre-push CI (staged-ci, crates-*, differ-ci) passed on push.

🤖 Generated with Claude Code

Searching "one three" did not find a project named "one two three":
searchProjects (and the sidebar's searchRepos, All repos, the branch/note
project pickers, the hashtag and branch dropdowns and the GitHub repo
picker) matched the whole trimmed query as one contiguous, case-folded
substring, so a multi-word query only matched that exact phrase.

Add shared/textSearch.ts (queryTerms / matchesAllTerms / matchesQuery):
the query is split on whitespace and a candidate matches when every term
is a case-insensitive substring of at least one of its searchable fields,
in any order and not necessarily adjacent. Single-term queries behave as
before, blank queries still return the input unchanged, and result order
is preserved. The repo picker's matchesRepoSearch already tokenized this
way and is unchanged.

Tests cover "one three" / "three one" matching "one two three", "one
four" not matching, single terms, case-insensitivity, blank queries and
terms landing in different fields.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T00:31:10.901561Z 1d6305a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

… span fields

Follow-up to the multi-word search change (1d6305a), addressing its
review findings:

- filterMoveTargets (MoveBranchDialog's project picker) required every
  term to land in the project name or every term to match one attached
  repo, so "alpha widgets" found nothing for a project named "Alpha" with
  acme/widgets attached, even though the sidebar and All repos searches
  let terms straddle fields. Export searchTerms from shared/repoSearch and
  pass the name plus every attached repo's search terms into a single
  matchesAllTerms call. Test added for the mixed-field case.
- matchesRepoSearch carried its own copy of the query tokenization and
  every/some loop; it is now matchesAllTerms(queryTerms(query),
  ...searchTerms(...)), so there is one definition of how a query is
  split. Behaviour is unchanged, including blank query → true.
- matchesQuery had no production callers (every call site pre-splits with
  queryTerms once per keystroke); removed along with its tests, which now
  exercise matchesAllTerms directly.
- sidebarSearch's normalizeQuery only served as a blank check after the
  previous change; its two uses are queryTerms(query).length === 0 and
  the export and its test are gone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Matt Toohey <contact@matttoohey.com>
@matt2e
matt2e merged commit 6bc3221 into main Nov 2, 2026
4 checks passed
@matt2e
matt2e deleted the staged-search-two-words branch November 2, 2026 00:50
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