Skip to content

Add FindablePanel protocol and route Cmd+F find across all panel types#6054

Open
wowlegend wants to merge 4 commits into
manaflow-ai:mainfrom
wowlegend:fix-filepreview-markdown-find
Open

Add FindablePanel protocol and route Cmd+F find across all panel types#6054
wowlegend wants to merge 4 commits into
manaflow-ai:mainfrom
wowlegend:fix-filepreview-markdown-find

Conversation

@wowlegend

@wowlegend wowlegend commented Jun 13, 2026

Copy link
Copy Markdown

Closes #6050

Problem

Cmd+F did not open the find UI for several panel types. The existing TabManager find routing only handled TerminalPanel and BrowserPanel, silently ignoring other focused panels.

Solution

Introduce a FindablePanel capability protocol and route global find commands (startFind, findNext, findPrevious, hideFind, plus selection-for-find) through it. Menu visibility (isFindVisible) is kept accurate by only reflecting terminal and browser state, which are the only panels that expose a public find-bar visibility signal.

Panels now supported

  • FilePreviewPanel text mode — AppKit NSTextView find bar.
  • MarkdownPanel text and preview modes — NSTextView find bar or WKWebView find panel.
  • AgentSessionPanelWKWebView find panel.
  • ProjectPanel Files / Build Settings tabs — focuses the tab-specific filter search field via SwiftUI FocusState.

Implementation notes

  • Shared NSTextFinder.Action.menuItemSender helper removes duplicated NSMenuItem construction.
  • MarkdownPanel preview and AgentSessionPanel hide-find are documented no-ops because WKWebView.performFindPanelAction: uses NSFindPanelAction, which only defines values 1–10 and has no hide value.
  • FilePreviewPanel and MarkdownPanel text mode support "Use Selection for Find".
  • canUseSelectionForFind now includes FindablePanel panels that report a text selection.

Verification

  • Built the cmux Debug target successfully.
  • scripts/swift_file_length_budget.py passes after refreshing .github/swift-file-length-budget.tsv.
  • Existing unit-test scheme still crashes during bootstrap (pre-existing/environment issue).

Related issues

Summary by CodeRabbit

  • New Features
    • Text search added to file preview (text mode).
    • Markdown panel supports find in both text and preview modes.
    • Agent/session preview panes support find controls.
    • Global Cmd+F now routes to the most relevant findable panel (browser-first fallback).
    • Selection-based search supported in more panels for consistent behavior.
    • Project UI can programmatically focus files or settings search fields when find is activated.

@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

@wowlegend is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 13, 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

Adds a FindablePanel protocol and implements find UI routing for FilePreviewPanel, MarkdownPanel, and AgentSessionPanel (text and preview modes), exposes renderer webViews, wires ProjectPanel search-focus, and updates TabManager to route Cmd+F and related actions to the focused findable panel.

Changes

Find support across panels

Layer / File(s) Summary
FindablePanel protocol and helper
Sources/Panels/Panel.swift
Introduce FindablePanel API and default behaviors plus NSTextFinder.Action.menuItemSender for action routing.
Web view accessor for find dispatch
Sources/Panels/MarkdownWebSupport.swift, Sources/Panels/AgentSessionWebRendererSession.swift
Expose webView from renderer sessions so panels can send performFindPanelAction: to the WKWebView.
FilePreviewPanel text find methods
Sources/Panels/FilePreviewPanel.swift
startFind(), findNext(), findPrevious(), hideFind(), and selection gating route NSTextFinder actions to the NSTextView when in .text preview mode.
MarkdownPanel dual-mode find methods
Sources/Panels/MarkdownPanel.swift
Find operations dispatch to NSTextFinder actions in text mode or send performFindPanelAction: to the renderer WKWebView in preview mode; includes helper to send web view actions and selection-based find.
AgentSessionPanel find dispatch
Sources/Panels/AgentSessionPanel.swift
Implements FindablePanel by dispatching find actions to the agent session web view; hideFind is a no-op and missing webView returns false.
ProjectPanel focus wiring and tab views
Sources/Panels/ProjectPanel.swift, Sources/Panels/ProjectFilesTabView.swift, Sources/Panels/ProjectBuildSettingsTabView.swift
Add searchFocusRequest and ProjectPanelSearchFocus; wire focus states into files and settings tab views to allow programmatic focus when starting find.
TabManager find routing and panel accessors
Sources/TabManager.swift
Aggregate non-terminal find visibility/selection and route startSearch(), findNext(), findPrevious(), and hideFind() to focused browser or focused FindablePanel when no terminal is focused.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant TabManager
  participant FocusedPanel as FindablePanel
  participant NSTextView
  participant WKWebView

  User->>TabManager: Cmd+F (startSearch)
  TabManager->>FocusedPanel: startFind()
  alt panel in .text mode
    FocusedPanel->>NSTextView: performTextFinderAction(show/next/prev/setSearchString)
  else panel in .preview mode
    FocusedPanel->>WKWebView: performFindPanelAction: (via NSApp.sendAction)
  end
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • manaflow-ai/cmux#4298: Introduced the MarkdownRendererSession and panel-owned renderer/coordinator state used by the new webView accessor for find dispatch.

Poem

🐇 I hop from pane to pane with glee,
Cmd+F now finds what eyes can't see,
In text or preview I will peep,
Through web and view my searches leap,
A tiny rabbit, find is free!


Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Cmux Swiftui State Layout ❌ Error ProjectPanel.swift adds new @Published searchFocusRequest on an ObservableObject (legacy SwiftUI state), which swiftui-state-layout.md flags for modern @Observable/value-snapshot shape. Move/lift searchFocusRequest out of @Published on ObservableObject (e.g., use @Observable for ProjectPanel or SwiftUI @State/@binding) so the new focus-request state follows the @Observable modern pattern.
Docstring Coverage ⚠️ Warning Docstring coverage is 57.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Cmux Swift Logging ❓ Inconclusive No PR diff available (gh auth blocked; git diff shows none). Current Sources show no print/debugPrint/dump/NSLog, but TabManager has a file-scoped private let tabManagerLogger under @MainActor, w... Enable access to PR diff (authenticated gh or git refs) so we can verify whether any forbidden logging/Logger constants were added or materially changed.
✅ Passed checks (18 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and accurately summarizes the main change: introducing a FindablePanel protocol and routing Cmd+F across panel types.
Description check ✅ Passed The PR description comprehensively covers the problem, solution, affected panels, implementation notes, and verification steps, aligning well with the provided template.
Linked Issues check ✅ Passed All requirements from issue #6050 are met: FindablePanel protocol routes Cmd+F globally, affected panels are supported with appropriate find implementations, and silent failure is replaced with actual find functionality.
Out of Scope Changes check ✅ Passed All changes directly support the stated objective of routing Cmd+F find across panel types; no extraneous modifications detected.
Cmux Swift Actor Isolation ✅ Passed New find routing uses @MainActor: FindablePanel is @MainActor, TabManager is @MainActor, and implementing panels/sessions are @MainActor; no new Swift 6 actor-isolation/SENDABLE issues detected.
Cmux Swift Blocking Runtime ✅ Passed PR diff for FilePreviewPanel/MarkdownPanel/MarkdownWebSupport/TabManager shows only NSTextView.performTextFinderAction and NSApp.sendAction routing; no semaphores, waits, Task.sleep, asyncAfter, ma...
Cmux Expensive Synchronous Load ✅ Passed Reviewed swift-expensive-sync-load rule and searched PR #6054 diff for RestorableAgentSessionIndex.load / SharedLiveAgentIndex.shared / sysctl; none present, so no expensive sync loader added to in...
Cmux Cache Substitution Correctness ✅ Passed History/undo snapshot uses SharedLiveAgentIndex.currentIndexSchedulingRefresh() with cold fallback (nil coalesces to RestorableAgentSessionIndex.load) and freshness handling (scheduleRefreshIfStale...
Cmux No Hacky Sleeps ✅ Passed The only build/runtime script implicated (scripts/swift_file_length_budget.py) contains no forbidden sleep/timer/poll patterns (no sleep(), time.sleep, setTimeout, setInterval, or polling waits fou...
Cmux Algorithmic Complexity ✅ Passed FindablePanel changes in TabManager/Panel routes Cmd+F via direct focused-panel dictionary lookups and simple method calls—no nested/full-collection scans, sorts, or hot-path filtering added in the...
Cmux Swift Concurrency ✅ Passed Modernization rules flag DispatchQueue/Combine/completionHandler/Task fire-and-forget. PR #6054 diff hunks for the changed files contain only NSTextFinder/WKWebView find routing; searches show no s...
Cmux Swift @Concurrent ✅ Passed Scanned the PR’s Swift files for @concurrent/nonisolated async and new async-heavy helpers; none found, and added Cmd+F/find methods are synchronous, AppKit/WKWebView actions.
Cmux Swift File And Package Boundaries ✅ Passed Rule targets new Swift >400, >250 additions to >800, or mixed responsibilities. Added FindablePanel/protocol and find-routing only inside existing panel/router files; no new SwiftPM package-bound f...
Cmux User-Facing Error Privacy ✅ Passed PR #6054 changes only add Cmd+F routing and NSTextView/WKWebView find actions; no new user-facing error/alert/recovery text with vendor/provider/billing/secret details appears in the diff.
Cmux Full Internationalization ✅ Passed PR diff (FilePreviewPanel.swift, MarkdownPanel.swift, MarkdownWebSupport.swift, TabManager.swift) adds Cmd+F routing/find actions only; no new user-facing Swift/web strings or i18n catalog/routing...
Cmux Architecture Rethink ✅ Passed Reviewed find-related additions (FindablePanel protocol + panel start/findNext/findPrevious/hideFind routing); implementations use direct NSTextView/WKWebView finder actions with no sleeps, polling...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR changes only find support in panels/TabManager; GitHub diff contains no NSWindow/NSPanel/WindowGroup close-shortcut code or cmux.* window identifier assignments, so the auxiliary close-shortcut...
Cmux Source Artifacts ✅ Passed PR #6054 changes only 4 Swift source files under Sources/..., and the repo’s artifact rules target logs/caches/tmp/DerivedData/etc, none of which are present.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Introduces a FindablePanel protocol that lets TabManager route global Cmd+F commands to any focused panel, adding NSTextView and WKWebView find support to FilePreviewPanel, MarkdownPanel, AgentSessionPanel, and SwiftUI FocusState-based focus routing for ProjectPanel. A shared NSTextFinder.Action.menuItemSender helper centralises the NSMenuItem construction that previously existed in each panel.

  • FindablePanel protocol (Panel.swift): clean @MainActor capability protocol with default no-op implementations; TabManager casts focusedPanelId to FindablePanel to dispatch startFind, findNext, findPrevious, hideFind, and useSelectionForFind.
  • Panel conformances: FilePreviewPanel and MarkdownPanel text mode use NSTextView find bar; MarkdownPanel preview and AgentSessionPanel use WKWebView find panel (hide is a documented no-op per NSFindPanelAction value range); ProjectPanel uses a fire-and-forget @Observable ProjectPanelFocusState to drive @FocusState into the filter text field.
  • TabManager routing: startFindInFocusedNonTerminalPanel correctly keeps browser-first with an if-else guard; the three parallel helpers (findNext/findPrevious/hideFind) call both focusedBrowserPanel? and focusedFindablePanel? unconditionally rather than mirroring that guard — safe today since both resolve from the same focusedPanelId and BrowserPanel doesn't conform to FindablePanel, but inconsistent with startFind's pattern.

Confidence Score: 5/5

Safe to merge; the new find routing is purely additive and no existing find paths for terminals or browser panels are altered.

The change introduces a new protocol, adds conformances to existing panels, and extends TabManager dispatch without touching any existing terminal or browser find path. The only inconsistency (sequential vs if-else in the routing helpers) is safe under the current type hierarchy because focusedBrowserPanel and focusedFindablePanel are mutually exclusive at runtime today.

Sources/TabManager.swift — the find-routing helpers for findNext, findPrevious, and hideFind use a different dispatch pattern than startFind; worth aligning before BrowserPanel gains FindablePanel conformance.

Important Files Changed

Filename Overview
Sources/Panels/Panel.swift Adds FindablePanel protocol and NSTextFinder.Action.menuItemSender helper; both are well-scoped and correctly @MainActor-annotated.
Sources/TabManager.swift Routes global find commands through the new FindablePanel protocol; startFindInFocusedNonTerminalPanel correctly uses an if-else guard, but findNext/findPrevious/hideFind helpers unconditionally call both focusedBrowserPanel and focusedFindablePanel, leaving a latent double-dispatch risk if BrowserPanel ever gains FindablePanel conformance.
Sources/Panels/AgentSessionPanel.swift Adds FindablePanel conformance via WKWebView find panel; hideFind is correctly documented as a no-op since NSFindPanelAction has no hide action.
Sources/Panels/FilePreviewPanel.swift Adds FindablePanel conformance for text-mode previews using NSTextView find bar; hasSelectionForFind correctly gates on previewMode == .text.
Sources/Panels/MarkdownPanel.swift Adds FindablePanel conformance for both text (NSTextView) and preview (WKWebView) modes; hideFind is a documented no-op for preview mode, matching the AgentSessionPanel approach.
Sources/Panels/ProjectPanel.swift Adds FindablePanel conformance using a fire-and-forget @Observable ProjectPanelFocusState to request SwiftUI focus; hideFind clears the request but doesn't actively resign the text-field focus, which is acceptable since the filter field isn't a dismissible find bar.
Sources/Panels/ProjectFilesTabView.swift Adds @FocusState and .onChange(of: panel.focusState.request) to respond to focus requests; the fire-and-forget pattern (set nil after consuming) is correct and safe.
Sources/Panels/ProjectBuildSettingsTabView.swift Mirrors the ProjectFilesTabView focus-state wiring for the settings filter; implementation is symmetric and correct.

Sequence Diagram

sequenceDiagram
    participant User as User (Cmd+F)
    participant TM as TabManager
    participant TP as TerminalPanel
    participant BP as BrowserPanel
    participant FP as FindablePanel

    User->>TM: startFind()
    alt TerminalPanel focused
        TM->>TP: ghosttySearchFocus + search_selection
    else BrowserPanel focused
        TM->>BP: startFind()
        BP-->>TM: "searchState != nil"
    else FindablePanel focused
        TM->>FP: startFind()
        FP-->>TM: true/false
    end

    User->>TM: findNext()
    alt TerminalPanel focused
        TM->>TP: performBindingAction(search:next)
    else BrowserPanel focused
        TM->>BP: findNext()
        Note right of TM: focusedFindablePanel also called (nil today)
    else FindablePanel focused
        TM->>FP: findNext()
    end
Loading

Reviews (7): Last reviewed commit: "Address CodeRabbit architecture and docs..." | Re-trigger Greptile

Comment thread Sources/Panels/MarkdownPanel.swift Outdated
Comment on lines +321 to +331
@discardableResult
private func sendFindPanelAction(_ action: NSTextFinder.Action) -> Bool {
guard let webView = rendererSession.webView else { return false }
let item = NSMenuItem()
item.tag = action.rawValue
return NSApp.sendAction(
NSSelectorFromString("performFindPanelAction:"),
to: webView,
from: item
)
}

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 sendFindPanelAction duplicates the NSMenuItem construction that textFinderSender already encapsulates. The two helpers are otherwise identical in purpose, so sendFindPanelAction should delegate to the one it already has.

Suggested change
@discardableResult
private func sendFindPanelAction(_ action: NSTextFinder.Action) -> Bool {
guard let webView = rendererSession.webView else { return false }
let item = NSMenuItem()
item.tag = action.rawValue
return NSApp.sendAction(
NSSelectorFromString("performFindPanelAction:"),
to: webView,
from: item
)
}
@discardableResult
private func sendFindPanelAction(_ action: NSTextFinder.Action) -> Bool {
guard let webView = rendererSession.webView else { return false }
return NSApp.sendAction(
NSSelectorFromString("performFindPanelAction:"),
to: webView,
from: textFinderSender(action)
)
}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread Sources/Panels/MarkdownPanel.swift Outdated
Comment on lines +322 to +331
private func sendFindPanelAction(_ action: NSTextFinder.Action) -> Bool {
guard let webView = rendererSession.webView else { return false }
let item = NSMenuItem()
item.tag = action.rawValue
return NSApp.sendAction(
NSSelectorFromString("performFindPanelAction:"),
to: webView,
from: item
)
}

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 hideFind for WebKit preview mode may silently fail

sendFindPanelAction(.hideFindInterface) sets item.tag = NSTextFinder.Action.hideFindInterface.rawValue (11), but WKWebView's performFindPanelAction: maps only the NSFindPanelAction values (1–10). Action code 11 has no corresponding entry in that enum, so WebKit is likely to ignore it without returning false. The practical effect is that programmatic hideFind() in markdown preview mode doesn't close the find bar, leaving it open even after the user triggers dismiss (e.g., via Escape key routing through TabManager.hideFind).

Comment thread Sources/Panels/MarkdownPanel.swift Outdated
Comment on lines +315 to +319
private func textFinderSender(_ action: NSTextFinder.Action) -> NSMenuItem {
let item = NSMenuItem()
item.tag = action.rawValue
return item
}

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 textFinderSender is duplicated across panels

FilePreviewPanel defines an identical private func textFinderSender(_ action: NSTextFinder.Action) -> NSMenuItem at line 1075. This helper is now copy-pasted in two production classes. A shared extension on NSMenuItem or a free function in a FindSupport file would eliminate the drift risk if the NSMenuItem setup ever needs to change (e.g., adding keyEquivalent or a title for accessibility).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/TabManager.swift (1)

2380-2382: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

isFindVisible is now stale for newly supported panel types.

Line 2380 still reports visibility only for terminal/browser find state. After adding File Preview and Markdown find routing, this can misreport active find UI state and break find-related UI toggles/commands for those panels. Extend this computed property to account for the new panel-specific find visibility signals.

🤖 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/TabManager.swift` around lines 2380 - 2382, The isFindVisible
computed property currently only checks selectedTerminalPanel?.searchState and
focusedBrowserPanel?.searchState; update it to also include the new panel types
so it reflects File Preview and Markdown find UI state (for example, include
checks like selectedFilePreviewPanel?.searchState != nil and
focusedMarkdownPanel?.searchState != nil or whatever the actual properties are
on those panel classes); modify the isFindVisible getter to OR together the
existing checks and the new panel-specific find visibility signals so
find-related toggles/commands work correctly across all supported panels (ensure
you reference the exact property names on the File Preview and Markdown panel
types when implementing).
🤖 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.

Outside diff comments:
In `@Sources/TabManager.swift`:
- Around line 2380-2382: The isFindVisible computed property currently only
checks selectedTerminalPanel?.searchState and focusedBrowserPanel?.searchState;
update it to also include the new panel types so it reflects File Preview and
Markdown find UI state (for example, include checks like
selectedFilePreviewPanel?.searchState != nil and
focusedMarkdownPanel?.searchState != nil or whatever the actual properties are
on those panel classes); modify the isFindVisible getter to OR together the
existing checks and the new panel-specific find visibility signals so
find-related toggles/commands work correctly across all supported panels (ensure
you reference the exact property names on the File Preview and Markdown panel
types when implementing).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 537aa07d-394e-4646-9884-c3dd33f6b925

📥 Commits

Reviewing files that changed from the base of the PR and between 0b82dfe and 9405315.

📒 Files selected for processing (4)
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/MarkdownPanel.swift
  • Sources/Panels/MarkdownWebSupport.swift
  • Sources/TabManager.swift

@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 13, 2026 6:20pm

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
// MARK: - Find in text mode

extension FilePreviewPanel {
var isFindVisible: Bool { false }

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.

P1 isFindVisible stub disables the "Hide Find Bar" menu item

isFindVisible is hardcoded to false, so TabManager.isFindVisible (and isNonTerminalFindVisible) remain false even after the NSTextFinder bar opens. In cmuxApp.swift:827 the "Hide Find Bar" command is gated on activeTabManager.isFindVisible:

.disabled(!(activeTabManager.isFindVisible))

This means that after the user presses Cmd+F in a file preview text-mode panel and the system find bar appears, the Hide Find Bar menu item stays grayed out. The same stub is present in MarkdownPanel.isFindVisible at line 458. Both panels need a real tracking mechanism (e.g. a stored flag set on startFind/hideFind) so the menu item is correctly enabled whenever the bar is actually showing.

@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/Panels/FilePreviewPanel.swift`:
- Around line 4466-4468: The isFindVisible getter currently always returns
false; add a private Bool property (e.g., private var findBarVisible = false) to
track local find-bar state, update startFind() to set findBarVisible = true and
hideFind() to set findBarVisible = false, and make var isFindVisible return that
flag; additionally, clear findBarVisible (set to false) when leaving .text mode
and when the text view is detached (where the preview switches modes or the text
view is replaced) so TabManager.isNonTerminalFindVisible sees the real
visibility state.
🪄 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: 3b6bfc8a-cca8-41c4-9cd1-2a4d83292713

📥 Commits

Reviewing files that changed from the base of the PR and between c0dc700 and 1a96e9b.

📒 Files selected for processing (9)
  • Sources/Panels/AgentSessionPanel.swift
  • Sources/Panels/AgentSessionWebRendererSession.swift
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/MarkdownPanel.swift
  • Sources/Panels/Panel.swift
  • Sources/Panels/ProjectBuildSettingsTabView.swift
  • Sources/Panels/ProjectFilesTabView.swift
  • Sources/Panels/ProjectPanel.swift
  • Sources/TabManager.swift

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment on lines +4466 to +4468
/// The AppKit find bar visibility is not publicly exposed on `NSTextView`,
/// so this is conservative and reports `false` until a public signal exists.
var isFindVisible: Bool { false }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

isFindVisible is permanently false, breaking global find visibility state.

Line 4468 always returns false, but TabManager.isNonTerminalFindVisible relies on this signal to detect active find UI. When the file-preview find bar is open, global find-state checks still report “not visible.”

Track a panel-local visibility flag (set in startFind()/hideFind(), and reset when leaving .text mode or detaching the text view) so this property reflects real state.

🤖 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/Panels/FilePreviewPanel.swift` around lines 4466 - 4468, The
isFindVisible getter currently always returns false; add a private Bool property
(e.g., private var findBarVisible = false) to track local find-bar state, update
startFind() to set findBarVisible = true and hideFind() to set findBarVisible =
false, and make var isFindVisible return that flag; additionally, clear
findBarVisible (set to false) when leaving .text mode and when the text view is
detached (where the preview switches modes or the text view is replaced) so
TabManager.isNonTerminalFindVisible sees the real visibility state.

@wowlegend wowlegend changed the title Fix Cmd+F find for file preview text mode and markdown preview/text modes Add FindablePanel protocol and route Cmd+F find across all panel types Jun 13, 2026
…odes

FilePreviewPanel now routes find actions to its NSTextView in text mode.

MarkdownPanel routes find actions to its text view or WKWebView depending on display mode.

TabManager now forwards find commands to file preview and markdown panels after terminal/browser.

Closes manaflow-ai#6050, related to manaflow-ai#158 and manaflow-ai#6049.
- Move panel find helpers into extensions within the same files to keep routing centralized.

- Update isFindVisible to include file preview and markdown panels (placeholder visibility until NSTextView exposes find-bar state).

- Refresh swift-file-length-budget.tsv for TabManager, FilePreviewPanel, and MarkdownPanel.

- Build now succeeds and the file-length guard passes.
- Introduce FindablePanel protocol with shared NSTextFinder.Action helper and default selection-find no-ops.

- FilePreviewPanel & MarkdownPanel: conform to FindablePanel, support text selection for find.

- MarkdownPanel preview & AgentSessionPanel: route find actions to WKWebView; hideFind is a documented no-op because NSFindPanelAction lacks a hide value.

- ProjectPanel: Cmd+F focuses the search field in Files / Build Settings tabs via SwiftUI FocusState.

- TabManager: route all find commands, selection-for-find, and visibility checks through FindablePanel.

- Refresh swift-file-length-budget.tsv for TabManager, FilePreviewPanel, and MarkdownPanel.

- Build succeeds and file-length budget passes.
@wowlegend wowlegend force-pushed the fix-filepreview-markdown-find branch from e8c551c to 0a24455 Compare June 13, 2026 19:23

@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/TabManager.swift`:
- Around line 3788-3789: When clearing workspace probe tracking in TabManager
(the places that call sidebarGitMetadataService.clearWorkspaceGitProbes(...) and
sidebarSelectedWorkspaceIds.remove(...)) also stop/reset the pull request
polling state by clearing the entry in pullRequestProbing for that workspace
(the same workspace/tabId handled by detachWorkspace and
restoreSessionSnapshot); in practice add logic to stop any running PR poller and
remove or nil out pullRequestProbing[tabId] at those same code paths so PR
polling cannot continue for workspaces no longer owned by this TabManager.
🪄 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: cdab1e57-a803-4c36-b3e1-054685fcb64f

📥 Commits

Reviewing files that changed from the base of the PR and between e8c551c and 0a24455.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (10)
  • Sources/Panels/AgentSessionPanel.swift
  • Sources/Panels/AgentSessionWebRendererSession.swift
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/MarkdownPanel.swift
  • Sources/Panels/MarkdownWebSupport.swift
  • Sources/Panels/Panel.swift
  • Sources/Panels/ProjectBuildSettingsTabView.swift
  • Sources/Panels/ProjectFilesTabView.swift
  • Sources/Panels/ProjectPanel.swift
  • Sources/TabManager.swift

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

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/TabManager.swift`:
- Around line 3788-3789: When clearing workspace probe tracking in TabManager
(the places that call sidebarGitMetadataService.clearWorkspaceGitProbes(...) and
sidebarSelectedWorkspaceIds.remove(...)) also stop/reset the pull request
polling state by clearing the entry in pullRequestProbing for that workspace
(the same workspace/tabId handled by detachWorkspace and
restoreSessionSnapshot); in practice add logic to stop any running PR poller and
remove or nil out pullRequestProbing[tabId] at those same code paths so PR
polling cannot continue for workspaces no longer owned by this TabManager.
🪄 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: cdab1e57-a803-4c36-b3e1-054685fcb64f

📥 Commits

Reviewing files that changed from the base of the PR and between e8c551c and 0a24455.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (10)
  • Sources/Panels/AgentSessionPanel.swift
  • Sources/Panels/AgentSessionWebRendererSession.swift
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/MarkdownPanel.swift
  • Sources/Panels/MarkdownWebSupport.swift
  • Sources/Panels/Panel.swift
  • Sources/Panels/ProjectBuildSettingsTabView.swift
  • Sources/Panels/ProjectFilesTabView.swift
  • Sources/Panels/ProjectPanel.swift
  • Sources/TabManager.swift
🛑 Comments failed to post (1)
Sources/TabManager.swift (1)

3788-3789: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing pull-request tracking cleanup in non-close lifecycle paths.

Line 3788 and Line 8143 clear git probe tracking, but neither path clears/reset pullRequestProbing. After detachWorkspace and restoreSessionSnapshot, PR polling can keep running for workspaces no longer owned by this TabManager.

Proposed fix
@@
     func detachWorkspace(tabId: UUID) -> Workspace? {
         guard let index = tabs.firstIndex(where: { $0.id == tabId }) else { return nil }
         sidebarGitMetadataService.clearWorkspaceGitProbes(workspaceId: tabId)
+        pullRequestProbing.clearWorkspacePullRequestTracking(workspaceId: tabId)
         sidebarSelectedWorkspaceIds.remove(tabId)
         invalidateFocusHistoryTarget(workspaceId: tabId, panelId: nil)
@@
         ClosedItemHistoryStore.shared.removePanelRecords(
             forWorkspaceIds: Set(previousTabs.map(\.id))
         )
         sidebarGitMetadataService.resetAllWorkspaceGitProbeTracking()
+        for tab in previousTabs {
+            pullRequestProbing.clearWorkspacePullRequestTracking(workspaceId: tab.id)
+        }

Also applies to: 8143-8143

🤖 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/TabManager.swift` around lines 3788 - 3789, When clearing workspace
probe tracking in TabManager (the places that call
sidebarGitMetadataService.clearWorkspaceGitProbes(...) and
sidebarSelectedWorkspaceIds.remove(...)) also stop/reset the pull request
polling state by clearing the entry in pullRequestProbing for that workspace
(the same workspace/tabId handled by detachWorkspace and
restoreSessionSnapshot); in practice add logic to stop any running PR poller and
remove or nil out pullRequestProbing[tabId] at those same code paths so PR
polling cannot continue for workspaces no longer owned by this TabManager.

@wowlegend wowlegend force-pushed the fix-filepreview-markdown-find branch from 0a24455 to a8f253c Compare June 13, 2026 19:41
- Remove isFindVisible from FindablePanel protocol and panel implementations to avoid a placeholder UI-state source of truth.

- TabManager.isFindVisible now only reflects terminal and browser find state, which are the only panels with a public visibility signal.

- Add docstrings to all new FindablePanel methods and TabManager routing helpers.

- Refresh FilePreviewPanel file-length budget.
@wowlegend wowlegend force-pushed the fix-filepreview-markdown-find branch from a8f253c to fdf7ff5 Compare June 14, 2026 06:57
@wowlegend

Copy link
Copy Markdown
Author

Hi — I just pushed a fix for the Swift warning-budget failure introduced by the .onChange closures. Could a maintainer approve the workflow run when convenient? Thanks!

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.

Cmd+F find is silently ignored for files opened in panes (terminal + markdown preview)

1 participant