Skip to content

fix: match non-ASCII folder names in Open Project search#25662

Open
ysm-dev wants to merge 3 commits intoanomalyco:devfrom
ysm-dev:fix-open-project-non-ascii-search
Open

fix: match non-ASCII folder names in Open Project search#25662
ysm-dev wants to merge 3 commits intoanomalyco:devfrom
ysm-dev:fix-open-project-non-ascii-search

Conversation

@ysm-dev
Copy link
Copy Markdown
Contributor

@ysm-dev ysm-dev commented May 4, 2026

Issue for this PR

Closes #25661

Type of change

  • Bug fix

What does this PR do?

Open Project search in web/serve returned no results when typing a Korean folder name on macOS. Two causes:

  • macOS legacy paths can come back as NFD; the browser IME emits NFC, so fuzzysort's code-point compare never matched the same visible string.
  • The input fired filter updates for every IME composition step (per jamo), wasting SDK calls and flickering the list before the syllable was complete.

Fix:

  • Normalize the search query and fuzzysort comparison keys to NFC at every entry point (packages/opencode/src/file/index.ts server search, packages/app/src/components/dialog-select-directory.tsx client async directory search, packages/ui/src/hooks/use-filtered-list.tsx generic filter, recent-project search rows). Returned filesystem paths stay in their original form so normalization-sensitive filesystems still resolve.
  • Defer applyFilter while the <List> search input is in IME composition; apply once on compositionend. Gate Arrow keys and Ctrl+N/Ctrl+P on isComposing so co-resident IMEs don't move the list selection during composition.

How did you verify your code works?

  • bun typecheck from packages/app, packages/ui, packages/opencode.
  • bun turbo typecheck (push hook): all 13 typecheck tasks pass.
  • Manual repro on macOS: mkdir ~/한국어테스트 → Open Project → type → folder now appears (was empty before).
  • Runtime sanity check: fuzzysort.go("한", ["<NFD-한>-test/"]) returns []; same query against the NFC-normalized comparison key returns the original NFD path.

Screenshots / recordings

Before:

before

After:

after

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

- Normalize search query and fuzzysort comparison keys to NFC at the
  server search, client directory search, generic filtered list, and
  recent-project rows. Returned paths stay in original form.
- Defer filter updates while the list search input is in IME
  composition; apply once on compositionend. Gate Arrow keys and
  Ctrl+N/Ctrl+P on isComposing.
{ key: "search" },
)
.map((x) => x.obj.target) as T[]
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still misses the keyed path. needle is NFC, but fuzzysort reads raw values from filterKeys, so an NFD Korean path returned by file search can get wrapped as title and filtered out again. dumb fix: normalize the keyed values too, or make callers use a normalized search key.

Copy link
Copy Markdown
Contributor Author

@ysm-dev ysm-dev May 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — pushed f70eeb85d. The keyed branch now resolves nested paths (e.g. provider.name) and runs .normalize("NFC") on each key's string value before handing it to fuzzysort, so all callers get the fix without changes (file-mention popover, line-comment mention, Cmd+K palette, model dialogs).

Verified with bun typecheck across app / ui / opencode, plus a runtime check: NFD display value vs NFC query now matches; dotted provider.name resolves correctly; multi-key [title, description, category] works; ASCII queries unchanged.


Written by Opus 4.7

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per Hona's review: the keyed branch only normalized the needle. Items
referenced by string filterKeys were still passed raw to fuzzysort, so
NFD paths returned by file search (e.g. macOS) never matched an NFC
needle typed via an IME. Resolve nested paths ("provider.name") and
normalize string field values to NFC inside the hook so all callers
benefit (file mention popover, line-comment mention, Cmd+K palette,
model dialogs).
items.map((target) => ({ target, search: target.normalize("NFC") })),
{ key: "search", limit: searchLimit },
)
.map((item) => item.obj.target)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the backend match, but TUI still drops it after this. find.files returns the original NFD path here, then prompt autocomplete runs a second raw fuzzysort over obj.value and gets 0 results for NFC Korean input. lazy fix: normalize that TUI comparison key too, keep returning the original path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed b72aba644. The TUI fuzzysort entry points (prompt/autocomplete.tsx and the shared dialog-select.tsx) now NFC-normalize the needle and the per-key comparison values, so an NFC IME query matches an NFD path returned by find.files. The selected option still carries the original path/value (verified: matched.value and matched.path remain NFD), so file inserts and on-disk lookups are unaffected.

Skipped dialog-model.tsx and the provider.ts "did you mean" lookups since their data is ASCII identifiers — happy to fold those in if you'd rather have it uniform.

Verified with workspace-wide bun turbo typecheck (13/13) and a runtime harness mirroring the autocomplete keys shape: NFC needle vs NFD value returns the option; ASCII regression unaffected.


Written by Opus 4.7

Per Hona's review: even with the server file search normalized, the
TUI prompt autocomplete and the shared dialog-select reran fuzzysort
over raw item strings, dropping NFD paths returned by find.files for
NFC needles typed via an IME. Convert string keys to function keys
that return NFC values; the original path/value remains on the
selected option so file inserts and on-disk lookups stay correct.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Open Project search returns no results for Korean folder names on macOS

2 participants