Skip to content

feat(desktop): enable fuzzy @-search with directory support in Composer#3846

Merged
esengine merged 1 commit into
esengine:main-v2from
SuMuxi66:fix/fuzzy-at-search
Jun 11, 2026
Merged

feat(desktop): enable fuzzy @-search with directory support in Composer#3846
esengine merged 1 commit into
esengine:main-v2from
SuMuxi66:fix/fuzzy-at-search

Conversation

@SuMuxi66

Copy link
Copy Markdown
Contributor

Summary

Restore the v1-style fuzzy @file search behavior in the Composer so that
an intermediate directory segment in a query (e.g. @planind) surfaces
nested matches such as src/planind/index.tsx, and directory names like
assets/ are selectable from the @-menu.

Previously the backend matched only on d.Name() (basename), the frontend
filter reduced searchEntries to basename-only, and SearchFileRefs
hardcoded IsDir: false for all results — so deep paths and directories
were invisible to the @-menu.

Closes #3769.

What changed

  • internal/fileref/search.go

    • Search now returns []SearchResult (with Path and IsDir) instead of
      []string.
    • Matches are collected into three tiers: basename hits (preferred), path-
      segment hits (fallback), and directory-name hits (lowest). A dirQuota
      of 5 ensures directories are never fully crowded out by file matches.
    • pathSegmentContains(relSlash, queryLower) checks any slash-separated
      path segment for a match.
    • Noise directories (.git, node_modules, build, dist, ...) are
      still skipped. The public API signature is unchanged.
  • desktop/app.go

    • SearchFileRefs now propagates r.IsDir from SearchResult to
      DirEntry.IsDir, fixing a pre-existing bug where all results were
      hardcoded IsDir: false.
  • internal/cli/complete.go

    • Adapted to the new []SearchResult return type (CLI only uses Path).
  • desktop/frontend/src/lib/atMatches.ts (new)

    • Pure helper filterAtMatches(entries, searchEntries, atFrag) that
      matches against the full slash-normalized relative path and de-duplicates
      by e.name with the local list taking precedence.
  • desktop/frontend/src/__tests__/at-matches.test.ts (new)

    • 5 cases covering nested-path surfacing, basename match, de-duplication,
      local-before-fuzzy ordering, and the empty-fragment legacy behavior.
  • desktop/frontend/src/components/Composer.tsx

    • The atMatches useMemo now delegates to filterAtMatches. The rest
      of the @-menu logic, the atDir !== "" guard, and the directory
      navigation UX are intentionally untouched.
  • internal/fileref/search_test.go (new)

    • 6 cases covering path-segment match, basename match, directory match
      with IsDir=true, sort order between tiers, and noise-directory skip.

Test results

  • go test ./internal/fileref -count=1 — 6/6 PASS
  • pnpm exec tsx src/__tests__/at-matches.test.ts — 5/5 PASS
  • go build ./... — clean
  • Manual Wails dev test — directories and files both surface correctly

The v2 @-menu search matched only on the basename of each file, so an
input like "@planind" never surfaced a deeply-nested match such as
"src/planind/index.tsx" whose basename is "index.tsx".

* internal/fileref/search.go: split matches into a basename tier and a
  path-segment tier; basename hits still win, but the segment tier now
  fills the remaining capacity using pathSegmentContains(rel, query).
  Noise directories (node_modules, build, dist, .git, ...) are still
  skipped before the matching switch.
* internal/fileref/search_test.go: cover path-segment match, basename
  match, sort order between tiers, and noise-directory skip list.
* desktop/frontend/src/lib/atMatches.ts: extract the Composer @-menu
  filter into a pure helper so it can be unit-tested without React.
* desktop/frontend/src/__tests__/at-matches.test.ts: regression tests
  for nested path surfacing, basename match, and stable de-duplication.
* desktop/frontend/src/components/Composer.tsx: delegate the filter
  to the helper. The atDir !== "" guard for sub-path search is
  intentionally left unchanged for this fix.
@github-actions github-actions Bot added desktop Wails desktop app (desktop/**) v2 Go rewrite (1.x) — main-v2 branch, active development tui Terminal UI / CLI (internal/cli, internal/control) labels Jun 10, 2026

@esengine esengine left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Reviewed. The three-tier match (basename → path-segment → directory) with a small directory quota is the right ranking, and the switch in the walk callback means tier 2 is effectively "non-basename segments only" — no double counting. Dropping the early SkipAll is the necessary cost of tiering and the walk stays bounded by maxWalkEntries. Propagating IsDir out of SearchFileRefs fixes a genuine pre-existing bug, and the pure filterAtMatches helper with its own test file is exactly how I want Composer logic factored. Both test suites are meaningful. Merging, thanks!

@esengine esengine merged commit 406fd03 into esengine:main-v2 Jun 11, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

desktop Wails desktop app (desktop/**) tui Terminal UI / CLI (internal/cli, internal/control) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: @选择上下文无法模糊搜索的问题

2 participants