Skip to content

Unify Files and Find in the right sidebar - #8016

Closed
austinywang wants to merge 50 commits into
mainfrom
issue-8011-unified-files-find-pane
Closed

austinywang wants to merge 50 commits into
mainfrom
issue-8011-unified-files-find-pane

Conversation

@austinywang

@austinywang austinywang commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • register Files as the single right-sidebar file tool while retaining Find as a shortcut/CLI activation alias
  • keep one mounted AppKit explorer host with two independent projections instead of stacking two views or exposing a mode switch
  • restore the original Files presentation exactly: path header plus tree, with / quick filtering of already-loaded file/folder names
  • restore the original Finder presentation exactly: the native “Find in files” textbox, status line, and results canvas with no dropdown, scope chrome, or replacement empty state
  • keep VS Code-style content-search behavior underneath: ripgrep-backed grouped file results, line numbers, previews, keyboard navigation, and stable selection during streaming updates
  • preserve each projection’s query, results, tree selection, expansion, and scroll state; filename filtering never recursively loads directories
  • route customizable ⌘⇧E to the Files outline and ⌘⇧F to the Finder field; preserve cmux right-sidebar files|find and command-palette behavior through the shared focus path

Validation

  • ./scripts/reload.sh --tag issue-8011-unified-files-find-pane --launch (committed tagged Debug build succeeded and launched)
  • live visual/behavior verification of the original Files and Finder chrome
  • live verification of / filename filtering, grouped content results, ⌘⇧E, ⌘⇧F, right-sidebar files, and right-sidebar find
  • xcodebuild -quiet -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -derivedDataPath /Users/austinwang/Library/Developer/Xcode/DerivedData/cmux-issue-8011-unit build (compile-only; passed)
  • xcrun swiftc -frontend -parse for all changed Swift files
  • ./scripts/check-pbxproj.sh
  • ./scripts/lint-pbxproj-test-wiring.sh
  • python3 scripts/check-workspace-package-groups.py --check
  • python3 scripts/check-package-resolved-policy.py
  • python3 scripts/lint-feature-flags.py
  • localization catalog JSON parse, changed-key English/Japanese audit, and bare-user-facing-string scan
  • python3 scripts/swift_file_length_budget.py (all touched files are within budget; current main has one unrelated +2-line baseline overrun in Sources/App/WorkspaceRuntimeSettings.swift)
  • no local test or XCUITest run, per task instructions; CI is the test gate

Closes #8011

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@vercel

vercel Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 14, 2026 2:09pm
cmux-staging Building Building Preview, Comment Jul 14, 2026 2:09pm

@coderabbitai

coderabbitai Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Files and Find are combined into one right-sidebar pane. Find remains an activation alias of Files, with scoped queries, filename filtering, unified focus routing, grouped results, localization, and integration coverage.

Changes

Unified file explorer

Layer / File(s) Summary
Sidebar contracts and unified presentation
Sources/FileExplorerPanel*.swift, Sources/FileExplorerSearch*.swift, Sources/FileSearchRequest.swift, Sources/FileSearchSnapshot+Grouping.swift, Sources/FileExplorerTreeFilter.swift, Sources/RightSidebar*.swift, Sources/ContentView+RightSidebarCommandPalette.swift
Adds unified panel and search types, maps Find to the Files registered tool, updates activation and selection behavior, and supports filename filtering.
Unified search and grouped results
Sources/FileExplorerView.swift, Sources/FileExplorerContainerView+SearchResults.swift, Sources/FileExplorerSearchResultCellView.swift, Sources/FileSearchController.swift
Updates scoped search state, visibility, full-text request execution, grouped results, row layout, selection preservation, and result actions.
Shared Files and Find focus handling
Sources/MainWindowFocusController.swift, Sources/AppDelegate.swift, Sources/FileExplorerNSOutlineView.swift, Sources/FileExplorerHeaderView.swift, Sources/FileExplorerKeyboardShortcuts.swift
Consolidates focus ownership around the Files host and replaces outline quick search with filename filtering.
Validation, localization, and project wiring
cmuxTests/UnifiedFileExplorer*.swift, cmuxTests/RightSidebarRemoteCommandTests.swift, Resources/Localizable.xcstrings, cmux.xcodeproj/project.pbxproj
Adds scope, grouping, accessibility, focus, state, request, and remote-command coverage, updates English and Japanese labels, and registers new sources and tests.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MainWindowFocusController
  participant RightSidebarPanelView
  participant FileExplorerContainerView
  participant FileSearchController
  MainWindowFocusController->>RightSidebarPanelView: activate Files or Find
  RightSidebarPanelView->>FileExplorerContainerView: present unified explorer
  FileExplorerContainerView->>FileSearchController: submit content search request
  FileSearchController-->>FileExplorerContainerView: publish grouped search snapshot
  MainWindowFocusController->>FileExplorerContainerView: focus outline or search field
Loading

Possibly related PRs


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (5 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error FileExplorerTreeFilter rebuilds the whole loaded tree on each names keystroke and recurses through/sorts every node via sortedChildren, with no cache or bound. Use a cached/indexed filter plan or bound the tree walk; avoid re-sorting/re-scanning the full loaded tree on every query change.
Cmux Swift File And Package Boundaries ❌ Error FileExplorerView is already 1580 lines and the patch adds 341 lines to it; it doesn’t shrink by >200, so the oversized-file extraction exception isn’t met. Move the unified-search model/filter/request code into a small SwiftPM package and split FileExplorerView’s orchestration/search-layout code out of the 1500+ line file.
Cmux User-Facing Error Privacy ❌ Error Search failures are shown via Search failed: %@, and FileSearchController fills it from raw stderr/localizedDescription, exposing upstream text. Use a generic user-facing failure message (optionally with a safe hint) and keep raw stderr/localizedDescription only in logs or internal telemetry.
Cmux Full Internationalization ❌ Error New file-explorer/sidebar strings are localized only in en/ja, but Localizable.xcstrings supports 20 locales, so the touched keys are not fully translated. Add translations for every existing locale in Resources/Localizable.xcstrings for the new fileExplorer.* and rightSidebar.mode.* keys.
Cmux No Test Or Debug Seam In Production Source ❌ Error PR adds production #if DEBUG seams: MainWindowFocusController exposes debugPendingRightSidebarFocusMode/debugSyncAfterResponderChange, used only by tests. Move the observation into cmuxTests via @testable import and remove the DEBUG wrapper/accessor from Sources/; keep any debug-only tooling in a dedicated debug file.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (19 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes address the unified pane goals, preserve shortcuts and CLI behavior, localize strings, and avoid lazy-loading regressions for #8011.
Out of Scope Changes check ✅ Passed The touched files all support the unified Files/Find work, with no clear unrelated or extraneous code changes.
Cmux Swift Actor Isolation ✅ Passed New value types are plain nonisolated structs/enums, and the UI/search controllers remain explicitly @MainActor; no new cross-actor store access appears.
Cmux Swift Blocking Runtime ✅ Passed Touched files add no new semaphores, sync waits, sleeps, or locks; the only wait is actor-based signaling in FileSearchTerminationSignal.
Cmux Browser Automation Off-Main ✅ Passed Diff only touches file-explorer/localization code; it does not modify TerminalController or ControlCommandExecutionPolicy, so no browser.* socket-routing regression is introduced.
Cmux Expensive Synchronous Load ✅ Passed Changes stay in-memory or on detached ripgrep-stream tasks; no agent-history loads, broad scans, or main-actor JSON/JSONL parsing were added.
Cmux Cache Substitution Correctness ✅ Passed No persisted/history/undo/snapshot read was replaced by a stale cache; new filters and mode aliasing stay transient and have live/cold fallbacks.
Cmux No Hacky Sleeps ✅ Passed The PR only updates a submodule pointer; the submodule commit touches Swift files only, with no changed TypeScript/JS/shell/runtime scripts or wait/sleep patterns.
Cmux Swift Concurrency ✅ Passed PASS: New unified-file-explorer code is sync UI/model work; async use stays at AppKit/XCTest boundaries and the existing search pipeline, with no new DispatchQueue/Combine/completion-handler expans...
Cmux Swift @Concurrent ✅ Passed No new nonisolated async boundary without @concurrent or invalid @concurrent usage is introduced; UI call sites already hop to Task for heavy preview work.
Cmux Swiftpm Lockfiles ✅ Passed The pbxproj diff only adds source file refs/build files; no SwiftPM package-reference keywords or .gitignore/Package.resolved edits appear.
Cmux Swift Logging ✅ Passed No added print/debugPrint/dump/NSLog or new Logger declarations appeared in the touched runtime changes; nearby AppDelegate logs are existing/debug-only.
Cmux Swiftui State Layout ✅ Passed No new ObservableObject/GeometryReader/lazy-row store refs or render-time writes were introduced; changes stay in AppKit bridges and a top-level mode bar using value snapshots.
Cmux Architecture Rethink ✅ Passed Unified FileExplorerContainerView owns query/scope/search state; focus routing maps .find→.files via registeredToolMode, with no symptom-patch sleeps/locks/polling introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only changes right-sidebar/file-explorer views and test NSWindow fixtures; no new standalone cmux-owned windows or close-shortcut ownership changes.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source, test, localization, or Xcode project files; none are logs, screenshots, caches, build output, or other artifact dirs.
Cmux No Ambient Global State ✅ Passed No new ambient globals or singletons were added; new logic lives in structs/classes or type extensions, and file-scope helpers are private file-local utilities.
Title check ✅ Passed The title is concise and clearly describes the main change: unifying Files and Find in the right sidebar.
Description check ✅ Passed The description covers the required Summary and Validation content with concrete details; the optional demo and checklist sections are omitted but not blocking.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8011-unified-files-find-pane

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.

@greptile-apps

greptile-apps Bot commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR combines Files and Find in one right-sidebar explorer. The main changes are:

  • One shared AppKit host with separate Files and Find projections.
  • Filename filtering over the loaded tree and grouped content-search results.
  • Independent query, selection, expansion, and scroll state.
  • Shared shortcut, command-palette, and CLI activation paths.
  • Updated localization, project wiring, and tests.

Confidence Score: 5/5

This looks safe to merge.

  • Search matches are grouped before adjacency-based headers and row heights are calculated.
  • Streaming updates restore the selected result after regrouping.
  • No blocking issue remains in the reviewed fixes.

Important Files Changed

Filename Overview
Sources/FileSearchSnapshot+Grouping.swift Groups content-search matches by file while preserving file and match order.
Sources/FileExplorerView.swift Hosts the unified explorer, applies grouped search snapshots, and restores selection by result.
Sources/FileExplorerContainerView+SearchResults.swift Renders grouped search rows and handles result navigation, opening, dragging, and menus.
Sources/FileExplorerPanelView+TreeFilter.swift Adds loaded-tree filename filtering with asynchronous snapshot handling.
Sources/RightSidebarPanelView.swift Routes Files and Find through the shared explorer host.

Reviews (33): Last reviewed commit: "Reuse in-flight filename filter work" | Re-trigger Greptile

Comment thread Sources/FileExplorerView.swift Outdated
Comment on lines +1555 to +1556
guard row >= 0, row < searchSnapshot.results.count else { return nil }
let result = searchSnapshot.results[row]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Grouping Depends On Result Order

The adjacency check groups matches correctly only when every result for a file is contiguous. If the search producer interleaves paths while streaming or ranking results, the same file starts multiple groups, repeats its header, and receives inconsistent row heights; either enforce path-contiguous ordering before this point or carry explicit group boundaries in the snapshot.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/FileExplorerView.swift`:
- Around line 868-870: Update the search bar height condition in the
font-magnification layout path to require that searchBarView is not hidden,
alongside the existing visibility checks. Ensure searchBarVisibleHeight is
applied only when the search field is actually active, preventing expansion
while content is empty or loading.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7037ebcc-a65c-45da-bbbe-498936c9bd2e

📥 Commits

Reviewing files that changed from the base of the PR and between a023bef and 0ffbde4.

📒 Files selected for processing (13)
  • Resources/Localizable.xcstrings
  • Sources/ContentView+RightSidebarCommandPalette.swift
  • Sources/FileExplorerPanelPlacement.swift
  • Sources/FileExplorerPanelPresentation.swift
  • Sources/FileExplorerSearchResultCellView.swift
  • Sources/FileExplorerState.swift
  • Sources/FileExplorerView.swift
  • Sources/MainWindowFocusController.swift
  • Sources/RightSidebarMode+Availability.swift
  • Sources/RightSidebarPanelView.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/RightSidebarRemoteCommandTests.swift
  • cmuxTests/UnifiedFileExplorerTests.swift

Comment thread Sources/FileExplorerView.swift Outdated

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
Sources/FileExplorerView.swift (1)

868-870: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix layout bug during font magnification in collapsed search state.

Using presentation.keepsSearchFieldVisible to forcefully apply the non-zero searchBarVisibleHeight bypasses the content-loading checks in updateSearchLayout(). If the font size changes when the workspace is empty or loading (i.e., when showSearchField evaluated to false), this logic erroneously expands the search bar height constraint without unhiding it, leaving a blank vertical gap at the top of the sidebar.

Checking !searchBarView.isHidden ensures the non-zero height is only applied when the search field is actually active.

🐛 Proposed fix
-        if presentation.keepsSearchFieldVisible || isSearchVisible {
+        if !searchBarView.isHidden {
             searchBarHeightConstraint?.constant = searchBarVisibleHeight
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/FileExplorerView.swift` around lines 868 - 870, Update the search bar
height adjustment in the font-magnification layout path to require that
searchBarView is not hidden, rather than relying on
presentation.keepsSearchFieldVisible. Preserve the existing isSearchVisible
condition and keep the visible height applied only when the search field is
actually active.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Sources/FileExplorerView.swift`:
- Line 958: Update the visibility transition handling around isSearchVisible to
cancel the active search when visibility changes from true to false, including
unified-to-files mode transitions. Preserve refreshSearchIfNeeded() for
false-to-true transitions and use the existing search cancellation mechanism.

---

Duplicate comments:
In `@Sources/FileExplorerView.swift`:
- Around line 868-870: Update the search bar height adjustment in the
font-magnification layout path to require that searchBarView is not hidden,
rather than relying on presentation.keepsSearchFieldVisible. Preserve the
existing isSearchVisible condition and keep the visible height applied only when
the search field is actually active.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d3355bdb-9a07-4bc8-b202-fda4ac0fd208

📥 Commits

Reviewing files that changed from the base of the PR and between 0ffbde4 and 683a28e.

📒 Files selected for processing (3)
  • Sources/FileExplorerView.swift
  • Sources/MainWindowFocusController.swift
  • cmuxTests/UnifiedFileExplorerTests.swift

Comment thread Sources/FileExplorerView.swift Outdated
@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/UnifiedFileExplorerTests.swift`:
- Around line 54-56: Mark the UnifiedFileExplorerTests suite declaration with
the .serialized trait so tests accessing the shared UserDefaults.standard key
rightSidebar.mode run sequentially. Keep the existing suite name and test
behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0720798c-eece-437d-ac40-5bf3b89c6836

📥 Commits

Reviewing files that changed from the base of the PR and between 683a28e and 9a0f161.

📒 Files selected for processing (4)
  • Resources/Localizable.xcstrings
  • Sources/FileExplorerSearchResultCellView.swift
  • Sources/FileExplorerView.swift
  • cmuxTests/UnifiedFileExplorerTests.swift

Comment thread cmuxTests/UnifiedFileExplorerTests.swift Outdated
@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

This branch was successfully deployed

1 active deployment
Preview – cmux — ef124474 Deployed Jul 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Merge Files and Find into a single unified right-sidebar pane (one tool, not two vertical tabs)

3 participants