Skip to content

Add project file picker (⌘P) and project content search (⇧⌘F) - #4855

Open
jakeleventhal wants to merge 9 commits into
pingdotgg:mainfrom
jakeleventhal:t3code/rebuild-combined-pull-requests
Open

Add project file picker (⌘P) and project content search (⇧⌘F)#4855
jakeleventhal wants to merge 9 commits into
pingdotgg:mainfrom
jakeleventhal:t3code/rebuild-combined-pull-requests

Conversation

@jakeleventhal

@jakeleventhal jakeleventhal commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Screenshot 2026-07-29 at 12 35 08 PM Screenshot 2026-07-29 at 12 35 34 PM

Combines and supersedes #3985 and #4007, rebuilt from scratch against current main.

  • ⌘P file picker: fuzzy file search over the server-backed workspace index with matched-character highlighting; opens files through the same right-panel action as the Files sidebar
  • ⇧⌘F content search: VS Code-style project-wide text search with case-sensitive, whole-word, and regex options; syntax-highlighted result lines grouped by file; opens results at the matching line and reveals the file in the explorer
  • Both are modes of a single global search overlay alongside the ⌘K command palette

Why one PR

The two originals overlapped heavily (WorkspaceSearchIndex, WorkspaceEntries, keybindings, contracts, queries.ts) but made opposite hosting choices: #3985 put the file picker inside the command palette host while #4007 put content search inside ChatView with its own keydown handling and duplicated project resolution. This PR unifies them:

  • One reducer (reduceCommandPaletteUiState) owns open/mode state for all three overlays — they can never stack, re-pressing a mode's shortcut closes it, pressing a different one switches in place
  • One keydown dispatcher in the palette host handles commandPalette.toggle / filePicker.toggle / projectSearch.toggle
  • One shared useActiveProjectTarget() hook resolves the active thread/draft → project workspace for both surfaces; both open results via rightPanelStore.openFile(threadRef, path, line?)
  • ChatView needed zero changes (line reveal already existed on main)

Implementation

Server

  • WorkspaceSearchIndex.search accepts an optional kind filter and routes to fff fileSearch/directorySearch so file-only queries are filtered before truncation; all fff calls share one runSearch error wrapper
  • New searchContents backed by FileFinder.grep with a 250ms time budget; whole-word wrapping falls back to explicit non-word boundaries for punctuation-edged queries (e.g. foo-) in both literal and regex modes, and byte offsets are mapped to string indices for highlighting
  • Content indexing enabled for workspace indexes (disableContentIndexing: false)
  • New projects.searchContents RPC with orchestration read scope and structured errors that carry query length, never query text

Web

  • ProjectFilePicker preserves server ranking and computes subsequence highlight indices client-side with the same query normalization the server applies
  • ProjectContentSearchDialog state resets by unmount/keying instead of effects; regex-error and truncation states surfaced in the status line
  • Shared getSyntaxHighlighterPromise + RenderErrorBoundary extracted from ChatMarkdown; HighlightedSearchLine splits Shiki tokens around match ranges
  • FileBrowserPanel reveals/expands/selects the file open in the preview pane without echoing a synthetic open
  • useComposerPathSearch generalized to useProjectPathSearch (configurable limit + kind, debounce-aware pending state)

Command naming follows the existing toggle family: filePicker.toggle (mod+p) and projectSearch.toggle (mod+shift+f), both documented in docs/user/keybindings.md.

Validation

  • vp run typecheck — passes workspace-wide
  • vp check — 0 errors; one fewer lint warning than main
  • Full apps/web suite: 188 files / 1,676 tests; contracts + shared + client-runtime: 1,006 tests
  • Server workspace tests run against the real fff grep engine, including cases the originals lacked: directory-kind filtering and multi-byte (héllo wörld) range mapping, plus the ported gitignore, case-sensitivity, truncation, and punctuation whole-word regressions
  • Manually verified in a local dev environment

Closes #3985. Closes #4007.

🤖 Generated with Claude Code


Note

Medium Risk
Adds substantial workspace search and grep logic on the server plus new RPC surface; UI changes are localized to overlays and file panel sync with moderate integration scope.

Overview
Adds ⌘P file picker and ⇧⌘F project content search as modes of the same global overlay stack as ⌘K, with new shortcuts filePicker.toggle and projectSearch.toggle.

Server: New projects.searchContents RPC and WorkspaceSearchIndex.searchContents (grep with time budget, per-file caps, post-filter whole-word matching). Path search supports optional file/directory kind filtering and separate paths vs content index variants (content indexing only on the content index).

Web: ProjectFilePicker and ProjectContentSearchDialog resolve the active project via useActiveProjectTarget() and open results through rightPanelStore.openFile. The file tree reveals the open preview file; line reveal in the preview is more reliable (centered scroll + short guard against snap-back). Shared Shiki highlighting via getSyntaxHighlighterPromise and RenderErrorBoundary.

Other: Keybinding default backfill no longer truncates user rules when at max entries.

Reviewed by Cursor Bugbot for commit bca349b. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add project file picker (⌘P) and project content search (⇧⌘F) to the command palette

  • Adds a file picker (toggled via mod+p / filePicker.toggle) rendered inside the command dialog when in files mode, with fuzzy match highlighting and frecency-ordered empty-query results backed by the existing searchEntries RPC.
  • Adds a full-text content search dialog (toggled via mod+shift+f / projectSearch.toggle) with case-sensitive, whole-word, and regex options, incremental rendering, and keyboard navigation; results open the selected file in the right panel.
  • Extends the server-side WorkspaceSearchIndex with a new searchContents method that pages through grep results with a time budget, per-file match cap, whole-word post-filtering (including astral-plane characters), and byte-to-string index mapping.
  • Introduces a projects.searchContents WebSocket RPC (requiring AuthOrchestrationReadScope) with a new ProjectSearchContentsError error type.
  • The CommandPalette state is refactored into a reduceCommandPaletteUiState reducer managing three mutually exclusive overlay modes: command, files, and content.
  • File tree selection in FileBrowserPanel now syncs with the externally opened file path, expanding ancestors and centering the row without re-triggering file open.
  • Risk: useNewThreadHandler now directly spreads workspaceContext instead of workspaceContext ?? {}; if workspaceContext is null at runtime the spread will throw rather than silently use an empty object.

Macroscope summarized bca349b.

Combines and supersedes pingdotgg#3985 and pingdotgg#4007 with a unified global search
overlay: the command palette host now owns three mutually exclusive
modes — command (mod+k), file picker (mod+p), and content search
(mod+shift+f) — behind a single reducer and keydown dispatcher, so the
surfaces never stack and shortcuts switch modes in place.

Server: WorkspaceSearchIndex routes kind-filtered entry search to fff
fileSearch/directorySearch and adds grep-backed searchContents with
case/whole-word/regex options, punctuation-safe whole-word boundaries,
and byte-to-string match range mapping; content indexing is enabled for
workspace indexes. New projects.searchContents RPC with read-scope auth
and structured errors that never leak query text.

Web: shared useActiveProjectTarget hook resolves the active
thread/draft workspace for both overlays; results open through the
right-panel openFile path (with line reveal for content matches), and
the file explorer reveals and selects the opened file. Shared Shiki
highlighter promise cache and RenderErrorBoundary are extracted from
ChatMarkdown and reused for syntax-highlighted search result lines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Jul 29, 2026
Comment thread apps/web/src/components/files/FileBrowserPanel.tsx
Comment thread apps/web/src/state/queries.ts
Comment thread apps/web/src/components/search/ProjectContentSearchDialog.tsx
Comment thread apps/web/src/components/files/FileBrowserPanel.tsx
Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts Outdated
Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts
@macroscopeapp

macroscopeapp Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

This PR introduces two new user-facing features (⌘P file picker and ⇧⌘F content search) with new UI components, new RPC endpoints, new keyboard shortcuts, and search index changes. New features with significant new capability warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6a16c6c293

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts Outdated
Comment thread apps/web/src/components/files/projectFilesQueryState.ts Outdated
Comment thread apps/web/src/components/search/ProjectContentSearchDialog.tsx
Comment thread apps/web/src/components/files/FileBrowserPanel.tsx
Comment thread apps/web/src/components/CommandPalette.tsx
Comment thread packages/client-runtime/src/state/projectCommands.ts Outdated
Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts Outdated
Comment thread apps/web/src/components/CommandPalette.tsx
Comment thread packages/shared/src/keybindings.ts
Comment thread apps/web/src/components/files/FileBrowserPanel.tsx
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d72dc50c-c1d1-4cfb-838b-7d7bd12b54c0

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts Outdated
Server
- Whole-word matching now greps the bare pattern and filters match ranges
  by VS Code-style word boundaries, fixing widened highlight spans and
  dropped adjacent occurrences that consuming (?:^|\W) boundaries caused
- Cap grep matches per file (100) so one dense file cannot fill the page
- Split the workspace index into path-only and content variants; content
  indexing now initializes only when content search is used
- Entries search accepts an empty query (bounded frecency-ordered
  listing); content search queries preserve whitespace on the wire
- Startup keybinding backfill appends only the defaults that fit instead
  of evicting the user's oldest custom rules

Web
- File line reveal retries until contents and line metrics exist and
  briefly guards the target scroll position against programmatic resets,
  fixing content-search results opening at the top of the file
- Explorer reveal expands slash-keyed directory ancestors, keeps the
  drag controller's selection cache fresh, and no longer closes an
  active tree search when the selection originated inside the tree
- Content search gates Enter while results are stale and renders result
  rows in growing windows instead of mounting all 500 at once
- File picker's empty state uses the bounded file-only server search
  (recent files first) instead of transferring the full listing
- Command palette exposes "Go to file" and "Search project contents"
  actions and resolves shortcuts with the complete when-clause context
- Content search atoms moved out of the shared client-runtime surface
  (web-only); dropped the unconsumed EnvironmentApi.searchContents

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jakeleventhal

Copy link
Copy Markdown
Contributor Author

Pushed 0f7ccee addressing the review feedback:

Server

  • Whole-word matching redesigned (cursor[bot] ×2, codex P2): the grep now runs on the bare pattern and match ranges are filtered by VS Code-style word boundaries afterwards. This fixes both the widened highlight spans (regex + whole-word) and adjacent occurrences being dropped by consuming (?:^|\W) boundaries, and it aligns whole-word semantics with VS Code. Covered by new adjacency, boundary, and regex-edge tests against the real grep engine.
  • maxMatchesPerFile capped at 100 (cursor[bot]) so one dense file can't fill the whole page — test included.
  • Content indexing is no longer enabled globally (codex P1): the workspace index map is now keyed by paths/content variant, so path-only consumers (file tree, composer search, file picker) keep the lightweight index and the content-capable index initializes only on first content search.
  • Startup keybinding backfill no longer evicts the user's oldest custom rules at MAX_KEYBINDINGS_COUNT (codex P2) — defaults that don't fit are skipped with a warning.

Web

  • Explorer reveal expands ancestors using slash-terminated directory IDs (cursor[bot] High, codex P2), updates the drag controller's selection cache before the sync guard (macroscope), and skips the reveal when the selection originated inside the tree so an active tree search is preserved (codex P2).
  • Content search preserves query whitespace on the wire (macroscope) — the contract query is no longer trimmed; trimming is only used to detect blank input.
  • Enter is gated while a newer query is debouncing/in flight so stale results can't be opened (macroscope).
  • Result rows render in growing 100-row windows via a scroll sentinel instead of mounting all 500 syntax-highlighted rows at once (codex P2).
  • The ⌘P empty state now uses a bounded file-only server query (empty query = frecency-ordered recent files) instead of transferring the full workspace listing (codex P2).
  • The command palette gained explicit "Go to file" and "Search project contents" actions with their shortcut hints (codex P1), and the overlay shortcut listener resolves with the complete when-clause context including previewFocus/previewOpen (codex P2).
  • Re: mobile (codex P1): rather than adding a mobile surface, the unused mobile-facing wiring was removed — the content-search atom family moved out of the shared client-runtime project atoms into a web-only module, and the unconsumed EnvironmentApi.projects.searchContents interface method was dropped. Mobile support can be added deliberately in a follow-up.

Also fixed a bug found in manual testing: opening a content-search result could land at the top of the file instead of the matched line. The line reveal now retries until file contents and line metrics are hydrated (previously an early post-render could clamp against empty contents, scroll to line 1, and mark the request handled) and briefly guards the target scroll position against late programmatic resets from the editable editor, cancelling on real user input.

Validation: workspace typecheck clean, vp check 0 errors, full web suite (1,678 tests) plus server workspace/keybindings/contracts suites passing.

🤖 Generated with Claude Code

Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts Outdated
Comment thread apps/web/src/components/files/FileBrowserPanel.tsx
Comment thread apps/web/src/components/files/FileBrowserPanel.tsx
Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts
Comment thread apps/server/src/workspace/WorkspaceSearchIndex.ts Outdated
Comment thread apps/web/src/components/search/ProjectContentSearchDialog.tsx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants