Skip to content

Live reload text file previews - #3608

Closed
lawrencecchen wants to merge 26 commits into
mainfrom
feat-file-preview-live-reload-typescript
Closed

lawrencecchen wants to merge 26 commits into
mainfrom
feat-file-preview-live-reload-typescript

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented May 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Resolve known source/text extensions before UTType media so TypeScript opens in the text preview instead of media preview.
  • Add a text-preview file watcher so clean editors update when the file changes on disk.
  • Preserve unsaved text edits while rebasing the clean baseline when external content changes.

Test Plan

  • python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv
  • git diff --check
  • xcodebuild test -quiet -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -derivedDataPath /tmp/cmux-fpreload-unit -only-testing:cmuxTests/FilePreviewReviewFeedbackTests

Summary by cubic

Adds live reload across text, image, PDF, media, and Quick Look previews. Reloads are cancellable, coalesced, and preserve state; same‑file image/PDF reloads keep viewport/zoom/page rotations, PDFs stay visible while new content loads, and a primary click focuses the PDF canvas so arrow keys scroll.

  • New Features

    • File watcher detects writes, moves/deletes, and reappearance; switches between file/dir watchers and coalesces events.
    • Previews observe fileContentRevision; Quick Look refreshes on revision changes.
    • Text preview auto‑reloads and rebases the clean baseline when external content matches local edits.
    • PDF canvas supports up/down arrow scrolling and focuses on click.
  • Bug Fixes

    • Resolve known text extensions before UTType so .ts opens in the text preview.
    • Robust reloads: cancellable tasks with close guards; availability stays in sync on moves/deletes/reappearance.
    • Same‑file reloads preserve PDF page rotations and image viewport/zoom; keep existing PDFs visible until replacements load.
    • Gate thumbnail arrow‑key navigation on thumbnail focus; standalone drop‑zone overlays animate in/out and hide when a hosted view is present; centralize preview load task cancellation with FilePreviewTaskSlot and keep decode work off the main thread to avoid concurrency warnings.
    • Add an explicit CircleCI unit watchdog with a 45‑minute timeout and periodic heartbeat to avoid stalled runs.

Written for commit fb64739. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Previews track file revisions so external edits refresh reliably across text, image, PDF, media, and QuickLook previews; per-revision viewport/position is restored.
    • New robust file-watching support to detect external changes and reappearances.
    • Standalone drop-zone overlay when no hosted view is present, with smoother animations.
  • Bug Fixes

    • Closing a preview reliably stops watchers and prevents stale/in-flight operations.
  • Tests

    • Added tests for file change detection, auto-reload, dirty-rebase behavior, thumbnail keyboard navigation, and PDF visibility during reloads.

@vercel

vercel Bot commented May 6, 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 May 6, 2026 3:55pm
cmux-staging Building Building Preview, Comment May 6, 2026 3:55pm

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented May 6, 2026 •

Copy link
Copy Markdown

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

Added a file-watching utility and threaded revision tracking through file-preview pipelines so external edits increment a per-panel revision and trigger revision-aware reloads across PDF, image, media, and QuickLook previews. Tests and project wiring for the new watcher were added.

Changes

File Watching and Revision-Aware Preview Refreshing

Layer / File(s) Summary
Revision Surface
Sources/Panels/FilePreviewPanel.swift
Added @Published private(set) var fileContentRevision: Int, isClosed; added guards so async loads/saves bail when panel closed or generation mismatches; call startFileWatcher() during content preparation; stop watcher on close.
File Watching Implementation
Sources/Panels/FilePreviewFileWatcher.swift
New FilePreviewFileWatcher (@MainActor) with nested Event enum (changed, movedOrDeleted, reappeared); watches file/directory via DispatchSource, coalesces events, and invokes onEvent callback on main actor; start/cancel lifecycle.
Panel Integration / Lifecycle
Sources/Panels/FilePreviewPanel.swift
Added fileWatcher property and methods startFileWatcher(), stopFileWatcher(), handleWatchedFileChange() to integrate watcher events into panel lifecycle and revision bumping; invalidate per-revision state and guard in-flight ops.
Preview Container APIs (core implementation)
Sources/Panels/FilePreviewPDFContainerView.swift, .../FilePreviewImageContainerView.swift, .../FilePreviewMediaView.swift, .../FilePreviewQLCoordinator.swift
Containers/coordinators gain currentRevision tracking, revision-aware setURL(_:revision:)/item caching, cancellation of previous loads on revision change, and viewport/state capture & restore per revision.
Wrapper Views (wiring/propagation)
Sources/Panels/FilePreviewPanel.swift (wrappers)
Public wrappers FilePreviewPDFView, FilePreviewImageView, FilePreviewMediaView, QuickLookPreviewView accept fileContentRevision: Int and call into revision-aware container/coordinator APIs.
Project Wiring
GhosttyTabs.xcodeproj/project.pbxproj
Added file reference and PBX build-file entries to include Sources/Panels/FilePreviewFileWatcher.swift in target Sources phases.
Tests & Helpers
cmuxTests/FilePreviewReviewFeedbackTests.swift, cmuxTests/FilePreviewPDFThumbnailSidebarTests.swift
Added tests for external-update, rebase, and focus navigation scenarios; added waitUntil(...) polling helper, writeTestPNG(color:to:), and temporaryTextFile(...pathExtension:) extension; added Carbon.HIToolbox import and key-event helper for thumbnail tests.
UI Focus/Drop Target & Small Fixes
Sources/TerminalPaneDropTargetView.swift, Sources/Panels/FilePreviewPDFThumbnailCollectionView.swift
Refined standalone drop-zone overlay animation handling and added ownsKeyboardFocus guard to prevent thumbnail navigation unless the view (or descendant) has keyboard focus.

Sequence Diagram

sequenceDiagram
    participant User as User (edits file)
    participant FS as Filesystem
    participant Watcher as FilePreviewFileWatcher
    participant Panel as FilePreviewPanel
    participant Preview as Preview Container/Coordinator

    User->>FS: write file on disk
    FS->>Watcher: DispatchSource event
    Watcher->>Panel: emit Event.changed / reappeared (MainActor)
    Panel->>Panel: handleWatchedFileChange() (check closed/generation, bump revision)
    Panel->>Preview: call setURL(url, revision)
    Preview->>Preview: invalidate/cache/restore per-revision viewport/state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • manaflow-ai/cmux#3139: Foundational file-preview panel work that this PR extends with file watching and revision propagation.
  • manaflow-ai/cmux#3539: Prior changes to FilePreviewPanel.swift and preview coordination that overlap with lifecycle and loading paths modified here.

Poem

🐰 A nibble, a ping, a tiny thump—
The watcher hops and sends a bump.
Revision tallied, stale views flee,
Fresh previews bloom for you and me.
Hooray for files that hop back free!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main feature added: live reload functionality for text file previews, matching the primary objective of the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive, covering the main changes (file watcher, text reload, state preservation), testing approach, and linking to the cubic-generated summary.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-file-preview-live-reload-typescript

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 May 6, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds live reload across all file preview types (text, image, PDF, media, Quick Look) by introducing a FilePreviewFileWatcher that detects writes, moves, and reappearances, and a fileContentRevision counter that previews observe to trigger reloads. Text previews auto-reload and rebase the clean baseline when external content matches unsaved edits; PDF and image reloads preserve viewport, zoom, and page rotations.

  • FilePreviewFileWatcher — new @MainActor watcher using DispatchSource with lock-guarded hop tasks, coalescing event flush, and nonisolated(unsafe) fields documented with SAFETY contracts.
  • FilePreviewDocumentLoader / FilePreviewTaskSlot — extracted nonisolated helpers for off-main PDF/image I/O; FilePreviewTaskSlot uses a narrow NSLock (documented) to allow deinit to cancel in-flight loads safely.
  • Kind resolver fix — moves the known-text-extension check before the UTType media lookup so .ts and similar source files open in the text preview instead of a media preview.

Confidence Score: 4/5

Safe to merge; all previously flagged actor-isolation and task-lifecycle issues have been resolved in this iteration.

The core watcher and task-cancellation machinery is well-structured. The outstanding carry-forward concern is that NSImage.init(data:) decoding still executes inside await MainActor.run in the image reload path, keeping potentially slow RAW/TIFF decodes on the main thread. FilePreviewPanel.swift also grew by 321 lines to nearly 4,000 lines, which the team's file-budget rule flags.

Sources/Panels/FilePreviewPanel.swift — continued growth of a very large file; the image decode path inside MainActor.run is the item most worth revisiting before the next reload-heavy change.

Important Files Changed

Filename Overview
Sources/Panels/FilePreviewDocumentLoader.swift New file: nonisolated helpers for PDF/image loading and a lock-guarded FilePreviewTaskSlot for safe deinit cancellation; SAFETY comment documents lock necessity
Sources/Panels/FilePreviewFileWatcher.swift New @mainactor watcher using DispatchSource; event-hop tasks are lock-guarded and cancelled on replacement; mergedEvent now correctly gives next priority for movedOrDeleted/reappeared transitions
Sources/Panels/FilePreviewPanel.swift 321 lines added to an already 3,930-line file; PDF/image loads moved to Task.detached correctly; isClosed guards added to all in-flight tasks; file growth exceeds file-budget threshold
Sources/Panels/FilePreviewMagnifyingPDFView.swift New file: PDFView subclass with keyboard scroll, gesture delegation, and focus callbacks; single clear responsibility
Sources/Panels/FilePreviewPDFThumbnailCollectionView.swift New file: thumbnail collection view with focus-gated keyboard page navigation
Sources/TerminalPaneDropTargetView.swift Adds generation-gated animated fade in/out for standalone drop zone overlay; generation counter and alphaValue reset look correct
cmuxTests/FilePreviewReviewFeedbackTests.swift New tests for TS extension resolution, external reload, dirty-rebase, PDF same-file blank prevention, and event-merge behaviour
.circleci/config.yml Adds explicit 45-minute watchdog with 5-minute heartbeat to unit test job

Sequence Diagram

sequenceDiagram
    participant FS as File System
    participant FW as FilePreviewFileWatcher
    participant MA as @MainActor (Panel)
    participant TV as Text/PDF/Image View

    FS->>FW: DispatchSource event (write/delete/rename)
    FW->>FW: scheduleFileEventHop (lock-guarded Task)
    FW->>MA: handleFileEvent via Task @MainActor
    MA->>MA: enqueueEvent coalesce flush after Task.yield
    MA->>MA: handleWatchedFileChange(event)
    MA->>MA: fileContentRevision increment
    MA->>MA: isFileUnavailable update
    alt previewMode == .text
        MA->>MA: loadTextContent replacingDirtyContent false
        MA->>MA: applyTextLoadResult rebase dirty content if matches
    else PDF or image
        TV->>TV: setURL called by SwiftUI updateNSView
        TV->>TV: Task.detached load doc or image data off-main
        TV->>MA: MainActor.run applyLoadedDocument or applyLoadedImage
    end
Loading

Reviews (16): Last reviewed commit: "Document file preview task slot isolatio..." | Re-trigger Greptile

Comment thread Sources/Panels/FilePreviewFileWatcher.swift
Comment thread Sources/Panels/FilePreviewFileWatcher.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 6, 2026

@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: 2

🤖 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/FilePreviewTextFileWatcher.swift`:
- Around line 1-123: Extract FilePreviewTextFileWatcher into a new SwiftPM
library package (e.g., CMUXFileWatch) and make the class and any APIs used by
other targets public; move the file into the package target and keep its imports
(Darwin, Foundation) while removing app-target-only dependencies. In the app
Package.swift add CMUXFileWatch as a dependency and change site references to
import CMUXFileWatch instead of using the in-app Sources/Panels copy; ensure
startFileWatcher, startDirectoryWatcher, handleFileEvent, handleDirectoryEvent
and the FilePreviewTextFileWatcher type are public/internal-as-needed and update
any other duplicated DispatchSource watchers (e.g., in MarkdownPanel.swift,
KeyboardShortcutSettingsFileStore.swift, TerminalController.swift,
FileExplorerStore.swift, CmuxConfig.swift) to reuse the new package APIs.
Finally, run swift build/tests to verify visibility and fix any access-level or
API surface mismatches.
- Around line 78-87: handleFileEvent's delete/rename branch currently calls
stopFileWatcher(), onEvent(.movedOrDeleted) and start() but if start()
immediately rebinds the file it does so silently; update handleFileEvent to
mirror handleDirectoryEvent's behavior by ensuring that after calling start()
(or after detecting the file was recreated) you emit onEvent(.reappeared) when
you successfully rebind the file (i.e., when startFileWatcher() would be
invoked). Use the same identifying symbols: modify handleFileEvent to invoke
onEvent(.reappeared) upon successful rebind/startFileWatcher() so the API
contract matches handleDirectoryEvent.
🪄 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: f20a1cc7-7ffa-4f6d-aa27-87fb984e3911

📥 Commits

Reviewing files that changed from the base of the PR and between aea6cfc and 2aaa0fb.

📒 Files selected for processing (4)
  • GhosttyTabs.xcodeproj/project.pbxproj
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/FilePreviewTextFileWatcher.swift
  • cmuxTests/FilePreviewReviewFeedbackTests.swift

Comment thread Sources/Panels/FilePreviewFileWatcher.swift
Comment thread Sources/Panels/FilePreviewFileWatcher.swift
coderabbitai[bot]
coderabbitai Bot previously requested changes May 6, 2026

@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: 2

🤖 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/FilePreviewFileWatcher.swift`:
- Around line 94-114: startDirectoryWatcher can miss a reappearance race because
the file may be recreated between opening the directory fd and the watcher
becoming active; after creating/resuming the DispatchSource (symbols:
startDirectoryWatcher, directorySource, source, fd) perform an immediate
existence check on the watched file (using directoryURL or url) and invoke the
same handling path (handleDirectoryEvent) on the main actor if the file is
present so you don't rely solely on later directory events; also ensure fd is
closed on any early return and that the check runs after directorySource =
source to avoid a race with cancellation.

In `@Sources/Panels/FilePreviewPanel.swift`:
- Around line 2009-2014: Both branches of the conditional call
refreshPDFSmartFitWithoutViewportRestore(); simplify by calling
refreshPDFSmartFitWithoutViewportRestore() once before conditionally restoring
the viewportSnapshot. Specifically, move the call to
refreshPDFSmartFitWithoutViewportRestore() out of the if/else, then if let
viewportSnapshot { viewportSnapshot.restore(in: pdfView, scrollView:
pdfScrollView()) } to remove the redundant else branch and keep restore only
when viewportSnapshot is non-nil.
🪄 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: d79fcf81-1804-432f-b7ec-6b9f9d0bd2fe

📥 Commits

Reviewing files that changed from the base of the PR and between 2aaa0fb and 80f5089.

📒 Files selected for processing (4)
  • GhosttyTabs.xcodeproj/project.pbxproj
  • Sources/Panels/FilePreviewFileWatcher.swift
  • Sources/Panels/FilePreviewPanel.swift
  • cmuxTests/FilePreviewReviewFeedbackTests.swift

Comment thread Sources/Panels/FilePreviewFileWatcher.swift
Comment thread Sources/Panels/FilePreviewPanel.swift
coderabbitai[bot]
coderabbitai Bot previously requested changes May 6, 2026

@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: 2

Caution

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

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

1967-1969: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the user’s sidebar width across revision-only PDF reloads.

On same-file refreshes this resets didUserResizeSidebar and overwrites lastSidebarWidth, so any manual sidebar sizing snaps back to the preferred width every time the file changes. Limit this reset to actual URL changes.

♻️ Minimal fix
-        let viewportSnapshot = currentURL == url ? capturePDFViewportSnapshot(anchor: .top) : nil
+        let isSameURL = currentURL == url
+        let viewportSnapshot = isSameURL ? capturePDFViewportSnapshot(anchor: .top) : nil
         currentURL = url
         currentRevision = revision
         pdfView.document = nil
         thumbnailView.setDocument(nil)
         outlineRoot = nil
         titleLabel.stringValue = url.lastPathComponent
         rotationAccumulator = 0
-        didUserResizeSidebar = false
-        lastSidebarWidth = preferredSidebarWidthForCurrentMode()
+        if !isSameURL {
+            didUserResizeSidebar = false
+            lastSidebarWidth = preferredSidebarWidthForCurrentMode()
+        }
🤖 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 1967 - 1969, The reset
block currently sets rotationAccumulator = 0, didUserResizeSidebar = false, and
lastSidebarWidth = preferredSidebarWidthForCurrentMode() on every file refresh;
change it so didUserResizeSidebar and lastSidebarWidth are only reset when the
document URL actually changes: compare the new document's url to the
stored/current url and only reset didUserResizeSidebar and recalc
lastSidebarWidth via preferredSidebarWidthForCurrentMode() when they differ
(always keep rotationAccumulator reset for non-URL changes if needed). Update
the logic surrounding rotationAccumulator, didUserResizeSidebar,
lastSidebarWidth and the URL comparison to preserve manual sidebar sizing across
revision-only PDF reloads.
🤖 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 1960-1963: When reloading the same PDF URL (the branch that calls
capturePDFViewportSnapshot(anchor:) and then sets pdfView.document = nil),
capture the current per-page rotation state (e.g., build a [pageIndex: rotation]
map by reading rotations applied via rotateCurrentPDFPage(by:) or
PDFPage.rotation) before you clear pdfView.document, persist that mapping
alongside viewportSnapshot, and then reapply those rotations inside
applyLoadedPDFDocument(...) after the new document is set so the refreshed
preview preserves rotations; apply the same capture-and-reapply fix for the
other reload path referenced around the 1991-2012 region.
- Around line 1978-1987: The nested Task.detached causes the PDF decode to run
outside structured concurrency and ignore cancellation; replace the detached
task so the PDFDocument(url: loadURL) decode runs as part of the cancellable
documentLoadTask (e.g. remove Task.detached and perform let document =
PDFDocument(url: loadURL) inside the outer Task or spawn a structured child Task
rather than Task.detached), keep the existing guard checks (Task.isCancelled,
self, currentURL/currentRevision) before calling applyLoadedPDFDocument, and
ensure any heavy work checks Task.isCancelled (or calls
Task.checkCancellation()) so stale decodes don't continue after
documentLoadTask?.cancel() (referencing documentLoadTask, Task.detached,
PDFDocument(url:), currentURL/currentRevision, and applyLoadedPDFDocument).

---

Outside diff comments:
In `@Sources/Panels/FilePreviewPanel.swift`:
- Around line 1967-1969: The reset block currently sets rotationAccumulator = 0,
didUserResizeSidebar = false, and lastSidebarWidth =
preferredSidebarWidthForCurrentMode() on every file refresh; change it so
didUserResizeSidebar and lastSidebarWidth are only reset when the document URL
actually changes: compare the new document's url to the stored/current url and
only reset didUserResizeSidebar and recalc lastSidebarWidth via
preferredSidebarWidthForCurrentMode() when they differ (always keep
rotationAccumulator reset for non-URL changes if needed). Update the logic
surrounding rotationAccumulator, didUserResizeSidebar, lastSidebarWidth and the
URL comparison to preserve manual sidebar sizing across revision-only PDF
reloads.
🪄 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: 812881f0-75c1-4b44-96a0-ccb3a0c40d25

📥 Commits

Reviewing files that changed from the base of the PR and between 80f5089 and 3a01ad2.

📒 Files selected for processing (1)
  • Sources/Panels/FilePreviewPanel.swift

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/Panels/FilePreviewFileWatcher.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 6, 2026

@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: 3

🤖 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/FilePreviewFileWatcher.swift`:
- Around line 68-76: In mergedEvent(_ current: Event?, _ next: Event) prefer the
latest availability transition by checking for reappearance on the "next" event
first (so a sequence like .movedOrDeleted then .reappeared yields .reappeared),
then fall back to reappeared on current, then handle movedOrDeleted (either next
or current), and finally return .changed; update the condition order in
mergedEvent to check next == .reappeared before any .movedOrDeleted checks and
include explicit checks for next/current where appropriate.

In `@Sources/Panels/FilePreviewPanel.swift`:
- Around line 3164-3179: The nested Task.detached means the decode isn't
cancelled by imageLoadTask?.cancel(); instead, move the NSImage(contentsOf:
loadURL) call into the parent Task (imageLoadTask) so it respects parent
cancellation (check Task.isCancelled after the decode), and perform UI-affecting
work such as calling applyLoadedImage on the MainActor (use MainActor.run) to
keep thread-safety; keep the existing guards for currentURL and currentRevision
and ensure you do not spawn a detached task for the image decode.

In `@Sources/TerminalPaneDropTargetView.swift`:
- Around line 377-379: The guard can early-return while a fade-out animation is
still running, leaving the overlay stuck at alphaValue 0; before the guard
returns, cancel any in-flight fade-out on dropZoneOverlayView so the old
completion cannot leave the view hidden. Update the block around the guard to
call dropZoneOverlayView.layer?.removeAllAnimations() (or equivalent NSAnimation
cancel) and restore a sensible visible state (e.g., set alphaValue to the
current presentation opacity or 1 and isHidden = false) when
previousZone/activeZone changes, then proceed with the existing guard check;
reference dropZoneOverlayView, rectApproximatelyEqual(_:,_:), needsFrameUpdate,
activeZone and previousZone to locate the change.
🪄 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: b92329fa-f88f-4d6c-b8e9-3a21ac87b4a5

📥 Commits

Reviewing files that changed from the base of the PR and between 3a01ad2 and d96b0b6.

📒 Files selected for processing (4)
  • Sources/Panels/FilePreviewFileWatcher.swift
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/TerminalPaneDropTargetView.swift
  • cmuxTests/FilePreviewReviewFeedbackTests.swift

Comment thread Sources/Panels/FilePreviewFileWatcher.swift Outdated
Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/TerminalPaneDropTargetView.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 6, 2026

@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/FilePreviewPDFThumbnailSidebarTests.swift`:
- Around line 160-174: The helper keyEvent(keyCode: UInt16) currently hardcodes
characters/charactersIgnoringModifiers to NSDownArrowFunctionKey instead of
using the supplied keyCode; update keyEvent to either be split into a no-arg
downArrowKeyEvent() (if you only need down-arrow events) or compute the correct
character for the given keyCode and pass that into the NSEvent.keyEvent call so
characters and charactersIgnoringModifiers match the keyCode; locate and update
the keyEvent(...) helper (and any call sites that assume its signature) to
ensure consistency between keyCode and characters.
🪄 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: 316b537e-b837-4eff-b92e-67ee91975fa4

📥 Commits

Reviewing files that changed from the base of the PR and between d96b0b6 and 17fb52e.

📒 Files selected for processing (2)
  • Sources/Panels/FilePreviewPDFThumbnailCollectionView.swift
  • cmuxTests/FilePreviewPDFThumbnailSidebarTests.swift

Comment thread cmuxTests/FilePreviewPDFThumbnailSidebarTests.swift Outdated
Comment thread Sources/Panels/FilePreviewFileWatcher.swift Outdated
Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/Panels/FilePreviewDocumentLoader.swift
@lawrencecchen
lawrencecchen dismissed stale reviews from coderabbitai[bot], coderabbitai[bot], coderabbitai[bot], coderabbitai[bot], and coderabbitai[bot] May 6, 2026 15:49

Stale CodeRabbit review from an earlier commit. The actionable inline findings have been addressed or are outdated, and the current CodeRabbit check is green.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — fb647391 Deployed May 6, 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.

2 participants