Skip to content

Add TreeSitter syntax highlighting and markdown preview to file preview panel - #4259

Open
shishirsharma wants to merge 16 commits into
manaflow-ai:mainfrom
shishirsharma:feature/syntax-highlighting-file-preview
Open

shishirsharma wants to merge 16 commits into
manaflow-ai:mainfrom
shishirsharma:feature/syntax-highlighting-file-preview

Conversation

@shishirsharma

@shishirsharma shishirsharma commented May 16, 2026 •

Copy link
Copy Markdown

Summary

  • Syntax highlighting: integrates CodeEditSourceEditor (v0.15.2, TreeSitter-based) for 40+ file extensions (Swift, JS/TS, Python, Go, Rust, JSON, YAML, and more). Files above 500 KB and unsupported extensions fall back to the existing plain NSTextView path unchanged.

Scope change (2026-05-18)

The markdown preview button that originally shipped in this PR has been removed in light of #4285, which now routes all .md file opens through Workspace.openFileSurfaces → MarkdownPanel (the rendered viewer). After that change, .md files no longer land in FilePreviewPanel from any current entry point, so the in-header preview button became unreachable in normal flows. This PR is now syntax highlighting only.

Related issues

Relates to:

Architecture

HighlightedFilePreviewRouter (new router, replaces the direct FilePreviewTextEditor call in the .text preview mode):

  • Detects language once via SyntaxLanguageDetector (cached in @State, not re-run on every keystroke)
  • Routes to HighlightedFilePreviewEditor (CodeEditSourceEditor) or falls back to the existing generic FilePreviewTextEditor for unsupported types

HighlightedEditorBridge (@MainActor, implements TextViewCoordinator):

  • Owns NSTextStorage shared with CodeEditSourceEditor so async file loads are reflected immediately
  • Detects user edits via textViewDidChangeText(controller:) — NSTextStorageDelegate cannot be used because CodeEditTextView.setTextStorage() replaces the delegate
  • Registers the inner TextView with FilePreviewFocusCoordinator for keyboard-driven panel switching
  • Manages a local NSEvent monitor for zoom gestures (pinch/scroll/smart-magnify), anchored to the inner NSScrollView and tied to isVisibleInUI so hidden panels cannot steal events. Token access is serialized through NSLock so destroy() (called nonisolated) and @MainActor install/remove paths can never double-call NSEvent.removeMonitor.

HighlightedEditorContainerView (NSView):

  • Sits in the AppKit responder chain to intercept performKeyEquivalent (save shortcut, including chord shortcuts from KeyboardShortcutSettings)
  • Overrides layout() to keep the hosted SwiftUI content filling bounds

SyntaxLanguageDetector (extracted to its own file per single-responsibility):

  • Maps 40+ extensions to CodeLanguage via detectLanguageFrom(url:)
  • Falls back to plain editor for files > 500 KB to avoid TreeSitter latency on large logs/generated code

Build notes

CodeEditSourceEditor transitively brings in SwiftLintPlugin as a build-tool plugin. Two paths:

  1. Developer machines: open the project in Xcode.app once and click "Trust & Enable All" — persisted in IDEPackagePluginTrustTable.plist, no flag needed afterwards
  2. CI / headless: set CMUX_SKIP_PLUGIN_VALIDATION=1 before running reload.sh

Addressed review feedback

  • Replaced nonisolated(unsafe) + DispatchQueue.main.async with Task { @MainActor [weak self] in } for correct Swift concurrency isolation in TextViewCoordinator callbacks.
  • Serialized zoomEventMonitor access through NSLock so the synchronous nonisolated destroy() and the @MainActor install/remove paths can never double-call NSEvent.removeMonitor with the same token.
  • Converted FileLanguageCache from ObservableObject/@StateObject to a plain struct with @State (never publishes changes).
  • Extracted SyntaxLanguageDetector to its own file (Sources/Panels/SyntaxLanguageDetector.swift); Dockerfile basename check is case-insensitive.
  • Fixed save not working: CodeEditTextView.setTextStorage() replaces textStorage.delegate so NSTextStorageDelegate callbacks never fired; switched to TextViewCoordinator.textViewDidChangeText.
  • drawsContentBackground is threaded through the highlighted path; isDark for the syntax palette is always derived from themeBackground so transparent dark panels keep the dark token colors.

Test plan

  • Open a .swift, .ts, .py, and .json file — syntax colours visible, matching dark/light terminal theme
  • Open a file > 500 KB — plain editor, no lag
  • Edit a highlighted file and verify Cmd+S (save shortcut) works and the save button enables/disables correctly
  • Pinch to zoom / Cmd+scroll changes font size in the highlighted editor
  • Keyboard panel focus switching works after opening a highlighted file

@vercel

vercel Bot commented May 16, 2026

Copy link
Copy Markdown

@shishirsharma 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 May 16, 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

Integrates CodeEdit packages, adds a SyntaxLanguageDetector gating highlightability, enables a Markdown-specific "Open Preview" control, replaces text preview routing with a highlighted-editor router and bridge-based CodeEdit integration, and adds an opt-in CI flag to skip package plugin validation.

Changes

CodeEdit Integration & Markdown Preview with Syntax-Highlighted Editor

Layer / File(s) Summary
CodeEdit package wiring, dependency lockfile, CI opt-in, and setup docs
CLAUDE.md, scripts/reload.sh, cmux.xcodeproj/project.pbxproj, cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
Adds CodeEdit package references and product dependencies to the Xcode project, registers SyntaxLanguageDetector.swift in project sources/build phases, updates Package.resolved with new/updated pins, adds an opt-in -skipPackagePluginValidation flag when CMUX_SKIP_PLUGIN_VALIDATION is set, and documents first-time Xcode setup and CI/headless guidance.
Language detection with extension and size gating
Sources/Panels/SyntaxLanguageDetector.swift
Adds SyntaxLanguageDetector with a fixed allowlist of extensions (and "dockerfile" by filename) and a maxHighlightBytes (500_000) threshold; returns CodeLanguage.detectLanguageFrom(url:) only when both checks pass.
Markdown preview UI in FilePreviewPanel
Sources/Panels/FilePreviewPanel.swift
Adds isMarkdownFile computed property and owningWorkspace() helper; adds a conditional Markdown-only "Open Preview" header button that opens/focuses a Markdown split in the owning workspace or falls back to external open, with disabled/help labeling when dirty/saving; routes text preview content through HighlightedFilePreviewRouter.
FilePreviewTextEditor refactor: highlighted and plain editor routing
Sources/Panels/FilePreviewTextEditor.swift
Converts FilePreviewTextEditor to a router that caches detected CodeLanguage? and chooses between HighlightedFilePreviewEditor (highlighted path) and the existing plain editor fallback. Adds HighlightedEditorBridge (shared NSTextStorage, theme, font-size, edit propagation, focus, zoom monitor), HighlightedEditorContainerView (NSView host intercepting save key equivalents including chords), HighlightedSourceEditorCore (SourceEditor wiring and dynamic EditorTheme), and HighlightedFilePreviewEditor (NSViewRepresentable) that synchronizes content/theme and manages zoom monitor visibility.

Sequence Diagram

sequenceDiagram
  participant Router as HighlightedFilePreviewRouter
  participant Cache as FileLanguageCache
  participant Detector as SyntaxLanguageDetector
  participant Highlighted as HighlightedFilePreviewEditor
  participant Bridge as HighlightedEditorBridge
  participant Plain as PlainFilePreviewEditor

  Router->>Cache: check cached language for panel.fileURL
  alt language detected
    Cache->>Detector: request language(for: url)
    Detector->>Detector: check extension allowlist
    Detector->>Detector: check file size < maxHighlightBytes
    Detector-->>Cache: return CodeLanguage?
    Cache-->>Router: cached language available
    Router->>Highlighted: render highlighted path
    Highlighted->>Bridge: initialize and sync content/theme
    Bridge->>Bridge: publish font size and foreground/background
  else no language or unsupported
    Cache-->>Router: no language
    Router->>Plain: render plain fallback
  end
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 I hopped through lines of code and light,
Brought Markdown buttons into sight,
A bridge for highlights, zoom to play,
Trust the build, or skip in CI’s way,
Small rabbit clap — the preview’s bright.


Caution

Pre-merge checks failed

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

  • Ignore

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux No Hacky Sleeps ❌ Error PR introduces scripts/reload.sh with 7 hacky sleep statements used to paper over process, startup, and socket readiness races, violating runtime-no-hacky-sleeps.md. Replace sleeps with event-driven synchronization: use inotifywait/fs_monitor for socket readiness, waitpid for process termination, and fcntl for lock coordination instead of fixed delays.
Cmux Swift File And Package Boundaries ❌ Error FilePreviewTextEditor.swift (429 lines) exceeds 400-line threshold and mixes state, platform bridge, and event handling. Markdown aliases missing from textExtensions list. Extract bridge logic to package or split responsibilities. Add mkd, mkdn, mdwn, mdown to textExtensions to sync with isMarkdownFile property.
Cmux Architecture Rethink ❌ Error Duplicate markdown detection splits logic: isMarkdownFile checks mkd/mkdn/mdwn/mdown but textExtensions doesn't, causing .mkd files to start as .quickLook and making preview button appear late. Add mkd/mkdn/mdwn/mdown to FilePreviewKindResolver.textExtensions to align with isMarkdownFile and prevent preview button flicker.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (12 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the two main features added: TreeSitter syntax highlighting and Markdown preview functionality for the file preview panel.
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.
Cmux Swift Actor Isolation ✅ Passed Swift changes correctly implement actor isolation. Core classes marked @MainActor appropriately. UI views properly isolated. Utility enum has no isolation issues. No regressions found.
Cmux Swift Blocking Runtime ✅ Passed No blocking synchronization patterns found. Zero semaphores, blocking waits, sleeps, .main.sync, or locks in new production code.
Cmux Swift Concurrency ✅ Passed Combine and Tasks only at required AppKit/SwiftUI/third-party boundaries. No background Dispatch queues, completion handlers, or unmanaged fire-and-forget Tasks.
Cmux Swift @Concurrent ✅ Passed No violations detected. No nonisolated async functions added, no invalid @concurrent usage. All nonisolated methods correctly use Task { @MainActor } for actor hops.
Cmux Swift Logging ✅ Passed All Swift code changes comply with swift-logging.md rules. No print, debugPrint, dump, NSLog, ad-hoc file logging, or personal data exposure detected in the three modified/new files.
Cmux User-Facing Error Privacy ✅ Passed No privacy violations found. User strings are generic and localized. CMUX_SKIP_PLUGIN_VALIDATION is dev-only. Vendor names only in code comments.
Cmux Swiftui State Layout ✅ Passed HighlightedEditorBridge is AppKit bridge in NSHostingView (allowed exemption). HighlightedSourceEditorCore's @ObservedObject confined within. No violations found.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed No new NSWindow/NSPanel/Window types created. All changes enhance existing FilePreviewPanel with View components only. performKeyEquivalent handles save shortcut, not close shortcuts.
Description check ✅ Passed The PR description comprehensively addresses all template sections: summary explains what changed and why (TreeSitter syntax highlighting integration), testing section outlines manual verification steps, build notes document setup requirements, and a detailed checklist covers local testing, documentation updates, and review resolution.
✨ 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 May 16, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds TreeSitter-based syntax highlighting to the file preview panel via CodeEditSourceEditor (v0.15.2). The markdown preview button originally included in scope has been removed; the PR is now syntax highlighting only. All previously raised review concerns have been addressed: zoom monitor leak fixed via dismantleNSView, actor isolation corrected with Task { @MainActor }, nil-caching of oversized files fixed with updateValue, SyntaxLanguageDetector extracted to its own file, and StateObject/@autoclosure restored to prevent per-render language detection.

  • HighlightedFilePreviewRouter detects language once via a @StateObject-cached FileLanguageCache and routes to either HighlightedFilePreviewEditor (CodeEditSourceEditor) or the existing plain FilePreviewTextEditor fallback for unsupported extensions or files above 500 KB.
  • HighlightedEditorBridge owns the shared NSTextStorage, serializes zoom monitor install/remove through NSLock so the nonisolated destroy() path can never race with @MainActor callers, and uses TextViewCoordinator.textViewDidChangeText (inside a Task { @MainActor }) for edit detection since CodeEditTextView.setTextStorage() replaces the NSTextStorageDelegate.
  • CI / reload.sh both gain -skipPackagePluginValidation support (opt-in env var in reload.sh, unconditional in CI where headless builds can never interactively trust SwiftLintPlugin).

Confidence Score: 5/5

Safe to merge; the highlighted editor path is well-isolated and falls back to the unchanged plain editor for unsupported files.

All previously flagged issues have been addressed: the zoom monitor is removed synchronously in dismantleNSView, actor isolation uses Task @mainactor throughout, the nil cache sentinel is stored correctly with updateValue, and SyntaxLanguageDetector is extracted to its own file. The only remaining finding is that the static language cache has no eviction policy, which is a long-session memory concern rather than a functional defect.

SyntaxLanguageDetector.swift — static cache grows without bound; no other files require special attention.

Important Files Changed

Filename Overview
Sources/Panels/FilePreviewTextEditor.swift Adds HighlightedEditorBridge (NSTextStorage sharing, zoom monitor via NSLock, TextViewCoordinator), HighlightedEditorContainerView (performKeyEquivalent for save chord), HighlightedSourceEditorCore (theme palette), and HighlightedFilePreviewEditor (NSViewRepresentable with dismantleNSView cleanup). Actor isolation is correct: monitor closure uses MainActor.assumeIsolated, edit detection uses Task { @mainactor }, destroy() serializes through NSLock.
Sources/Panels/SyntaxLanguageDetector.swift Extracted language detector mapping 40+ extensions to CodeLanguage. Uses NSLock-protected static cache with updateValue to store nil sentinel correctly. Cache has no eviction policy and grows for the process lifetime.
Sources/Panels/FilePreviewPanel.swift Introduces FilePreviewTextInsertionTarget protocol with NSTextView conformance; generalises the panel's textView reference to any insertion target. Routes .text preview to HighlightedFilePreviewRouter. handleDroppedFileURLsAsText and saveTextContent both updated cleanly.
cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved Adds CodeEditSourceEditor 0.15.2, CodeEditLanguages 0.1.20, CodeEditTextView 0.12.1, SwiftLintPlugin 0.63.1, SwiftTreeSitter 0.25.0, and ChimeHQ support packages. All pins are exact or match project-level requirements.
.github/workflows/ci.yml Adds -skipPackagePluginValidation to all xcodebuild invocations (resolve, build, test) to handle SwiftLintPlugin in headless CI; bumps release-smoke-test timeout from 20 to 30 minutes.
scripts/reload.sh Opt-in -skipPackagePluginValidation gated on CMUX_SKIP_PLUGIN_VALIDATION=1; well-commented with the interactive trust path for developer machines.
cmuxTests/WindowAndDragTests.swift Adds FilePreviewTextInsertionTargetTests covering drop-to-insert via a FakeFilePreviewTextInsertionTarget; covers focus, insertion, and panel.textContent sync in a single test.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["FilePreviewPanelView (.text mode)"] --> B["HighlightedFilePreviewRouter"]
    B --> C{"FileLanguageCache (StateObject, runs once)"}
    C -->|"language detected"| D["HighlightedFilePreviewEditor (NSViewRepresentable)"]
    C -->|"nil: unsupported ext or file > 500 KB"| E["FilePreviewTextEditor (plain NSTextView fallback)"]
    D --> F["makeNSView: HighlightedEditorContainerView"]
    F --> G["NSHostingView → HighlightedSourceEditorCore → SourceEditor"]
    D --> I["HighlightedEditorBridge (TextViewCoordinator)"]
    I -->|"prepareCoordinator Task @MainActor"| J["installZoomMonitor via NSLock"]
    I -->|"textViewDidChangeText Task @MainActor"| K["panel.updateTextContent"]
    I -->|"dismantleNSView"| L["removeZoomMonitor synchronous"]
    K --> M["FilePreviewPanel @Published textContent"]
    M -->|"SwiftUI updateNSView"| N["bridge.setContent (no-op if unchanged)"]
    I --> O["registerFocusIfReady"]
    O --> P["panel.attachTextInsertionTarget (TextView)"]
    P --> Q["saveTextContent via filePreviewCurrentText"]
Loading

Reviews (14): Last reviewed commit: "fix: cache unsupported preview language ..." | Re-trigger Greptile

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/Panels/FilePreviewTextEditor.swift
Comment thread Sources/Panels/FilePreviewTextEditor.swift
Comment thread Sources/Panels/FilePreviewTextEditor.swift

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 6 files

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Re-trigger cubic

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 18, 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 `@GhosttyTabs.xcodeproj/project.pbxproj`:
- Around line 2392-2407: The package version constraints for the
XCRemoteSwiftPackageReference entries "CodeEditSourceEditor" and
"CodeEditLanguages" are asymmetric and may break when CodeEditSourceEditor is
bumped; update the two XCRemoteSwiftPackageReference objects so they use
matching requirement kinds—either pin both to known-compatible exact versions
(e.g., set both to the exact versions that are known to work together) or make
both use upToNextMajorVersion with the same minimumVersion to allow coordinated
minor/patch updates; modify the entries for "CodeEditSourceEditor" and
"CodeEditLanguages" accordingly so their requirement.kind and
version/minimumVersion are consistent.
🪄 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: 8ff59953-0824-4fa6-985c-b343b146eb15

📥 Commits

Reviewing files that changed from the base of the PR and between aba20b6 and d47e8b3.

📒 Files selected for processing (4)
  • GhosttyTabs.xcodeproj/project.pbxproj
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/FilePreviewTextEditor.swift
  • Sources/Panels/SyntaxLanguageDetector.swift

Comment thread cmux.xcodeproj/project.pbxproj
@shishirsharma
shishirsharma force-pushed the feature/syntax-highlighting-file-preview branch from d47e8b3 to 050b33e Compare May 18, 2026 16:31
coderabbitai[bot]
coderabbitai Bot previously requested changes May 18, 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: 4

🤖 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 1269-1274: The markdown fallback currently calls
NSWorkspace.shared.open(fileURL) in FilePreviewPanel's action, which bypasses
the self-filtering in FileExternalOpenAction; replace that direct open with
invoking the shared external-open helper (use FileExternalOpenAction or its
public API) so the same self-filtering and external-launch logic runs for the
markdown fallback — e.g. call the shared action with the panel (panel.id,
panel.filePath, fileURL and/or owningWorkspace()) instead of
NSWorkspace.shared.open(fileURL).

In `@Sources/Panels/FilePreviewTextEditor.swift`:
- Around line 58-66: The highlighted branch in FilePreviewTextEditor ignores the
panel's drawsContentBackground setting causing opaque themes when syntax
highlighting is enabled; update the HighlightedFilePreviewEditor initializer
call to pass the panel.drawsContentBackground (or a derived drawsBackground
Bool) and then consume that value inside HighlightedFilePreviewEditor to set the
editor theme's background alpha/transparent color (or set the
NSTextView/NSTextField drawsBackground accordingly), so the highlighted path
respects drawsContentBackground just like the plain TextEditor path; reference
FilePreviewTextEditor, HighlightedFilePreviewEditor,
drawsContentBackground/drawsBackground and languageCache.language to locate the
change.
- Around line 201-205: registerFocusIfReady currently attaches focus to the
panel but never registers the highlighted text view with the panel, leaving
FilePreviewPanel.textView nil and causing handleDroppedFileURLsAsText(_:) to
bail; update registerFocusIfReady to call panel.attachTextView(textView) (or the
appropriate attachTextView(_) API) before calling panel.attachPreviewFocus(...)
so the panel's textView is populated and subsequent drops/hotpaths that rely on
FilePreviewPanel.textView work correctly.

In `@Sources/Panels/SyntaxLanguageDetector.swift`:
- Around line 51-53: The allowlist check currently compares filename ==
"Dockerfile" and misses lowercase variants; change the normalization so the
Dockerfile basename is lowercased before checking — e.g., compute a lowercased
basename (or use filename.lowercased()) and update the guard to check
supportedExtensions.contains(ext) || lowercasedBasename == "dockerfile" so both
"Dockerfile" and "dockerfile" are accepted; ensure you update references to
ext/filename as needed in SyntaxLanguageDetector so the comparison is
case-insensitive.
🪄 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: fc33692e-9537-4a75-bf2d-f93363bf0758

📥 Commits

Reviewing files that changed from the base of the PR and between d47e8b3 and 050b33e.

📒 Files selected for processing (6)
  • CLAUDE.md
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/FilePreviewTextEditor.swift
  • Sources/Panels/SyntaxLanguageDetector.swift
  • cmux.xcodeproj/project.pbxproj
  • cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/Panels/FilePreviewTextEditor.swift
Comment thread Sources/Panels/FilePreviewTextEditor.swift
Comment thread Sources/Panels/SyntaxLanguageDetector.swift Outdated
Comment thread Sources/Panels/FilePreviewTextEditor.swift
coderabbitai[bot]
coderabbitai Bot previously requested changes May 18, 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

♻️ Duplicate comments (1)
Sources/Panels/FilePreviewTextEditor.swift (1)

204-210: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Highlighted previews still lose file-drop insertion.

Line 209 only registers focus. FilePreviewPanel.handleDroppedFileURLsAsText(_:) still requires panel.textView, so every syntax-highlighted file drops the existing file-URL insertion path that the plain editor supports. Please keep a shared insertion path here, or fall back to the plain editor until the highlighted path can service drops too.

Based on learnings: "When a behavior is exposed through multiple entrypoints (keyboard shortcut, command palette, context menu, CLI, settings, debug menu), implement one shared action/model path and verify every entrypoint that should invoke it."

🤖 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 1263-1268: The Markdown preview button currently uses
PanelHeaderIconButton with its isDisabled computed from panel.isDirty ||
panel.isSaving but misses panel.isFileUnavailable; update the disabled guard to
also include panel.isFileUnavailable so the button is disabled when the file is
unavailable (matching the logic used in FileExternalOpenMenu), i.e., add
panel.isFileUnavailable to the boolean expression guarding the
PanelHeaderIconButton.

In `@Sources/Panels/FilePreviewTextEditor.swift`:
- Around line 333-336: In makeSyntaxTheme(), compute isDark from
bridge.themeBackground regardless of bridge.drawsBackground so transparent
panels use the correct dark/light token palette; replace the current conditional
isDark assignment with one that calls backgroundIsDark(bridge.themeBackground)
unconditionally (keeping bg = bridge.drawsBackground ? bridge.themeBackground :
.clear and still using fg = bridge.themeForeground) so the syntax theme
selection uses bridge.themeBackground to pick the dark palette even when
drawsBackground is false.
🪄 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: 9875b11c-158f-4d97-bfd5-01b2f615ea5d

📥 Commits

Reviewing files that changed from the base of the PR and between 050b33e and 5ddd80d.

📒 Files selected for processing (4)
  • Sources/Panels/FilePreviewPanel.swift
  • Sources/Panels/FilePreviewTextEditor.swift
  • Sources/Panels/SyntaxLanguageDetector.swift
  • cmux.xcodeproj/project.pbxproj

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
Comment thread Sources/Panels/FilePreviewTextEditor.swift Outdated
Comment thread Sources/Panels/FilePreviewTextEditor.swift

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread Sources/Panels/FilePreviewTextEditor.swift Outdated
coderabbitai[bot]
coderabbitai Bot previously requested changes May 18, 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 `@Sources/Panels/FilePreviewPanel.swift`:
- Around line 927-930: The markdown extension alias list is duplicated:
isMarkdownFile recognizes .mkd, .mkdn, .mdwn, and .mdown but
FilePreviewKindResolver.textExtensions does not, causing inconsistent
quick-preview behavior; update the code so both surfaces share a single source
of truth—either extract the markdown extensions into a shared constant/allowlist
used by isMarkdownFile and FilePreviewKindResolver.textExtensions, or add the
missing aliases (.mkd, .mkdn, .mdwn, .mdown) to
FilePreviewKindResolver.textExtensions; ensure you reference and update the
symbols isMarkdownFile and FilePreviewKindResolver.textExtensions (or the new
shared constant) so all preview entrypoints use the same list.
🪄 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: 9d26122c-94b9-484e-b5cd-a13fda9ebf60

📥 Commits

Reviewing files that changed from the base of the PR and between 5ddd80d and d845172.

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

Comment thread Sources/Panels/FilePreviewPanel.swift Outdated

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread Sources/Panels/FilePreviewTextEditor.swift Outdated
…ew panel

Integrates CodeEditSourceEditor (v0.15.2) for TreeSitter-based syntax
highlighting in the file preview panel, and adds a one-click markdown
preview button that opens the existing MarkdownPanelView in a split.

- Routes 40+ file extensions (Swift, JS/TS, Python, Go, Rust, JSON,
  YAML, Markdown, and more) through HighlightedFilePreviewEditor backed
  by CodeEditSourceEditor/TreeSitter; unsupported extensions fall back
  to the existing PlainFilePreviewEditor unchanged
- Files over 500 KB fall back to plain editor to avoid TreeSitter latency
- Language detection cached in @StateObject — runs once per panel, not
  on every keystroke
- Dark/light syntax theme picked automatically by background luminance
  (VS Code-inspired palette)
- Save shortcut (including chord shortcuts from KeyboardShortcutSettings)
  forwarded through HighlightedEditorContainerView in the AppKit
  responder chain
- Pinch/scroll zoom handled via a local NSEvent monitor anchored to the
  inner scroll view; monitor tied to isVisibleInUI so inactive panels
  cannot steal gesture events
- Focus registration via TextViewCoordinator.prepareCoordinator gives
  the file preview panel a real first responder for keyboard-driven
  panel switching
- NSTextStorage bridge (HighlightedEditorBridge) keeps text in sync
  both directions: panel → editor on async file load, editor → panel
  on each edit; saves work correctly with panel.saveTextContent()

- doc.richtext icon in the file preview header for .md files, next to
  the existing revert/save buttons
- Disabled while the buffer is dirty (preview is disk-backed)
- Calls workspace.openOrFocusMarkdownSplit to open/focus MarkdownPanelView
  in a horizontal split; falls back to NSWorkspace.shared.open on failure

- CodeEditSourceEditor and CodeEditLanguages added as Swift Package deps
- reload.sh documents Xcode trust path and CMUX_SKIP_PLUGIN_VALIDATION=1
  opt-in for CI/headless builds (SwiftLintPlugin transitive dep)
- Add missing `mkdn` extension to `isMarkdownFile` so .mkdn files get
  the markdown preview button consistently with syntax highlighting
- Replace `nonisolated(unsafe)` + `DispatchQueue.main.async` with
  `Task { @mainactor [weak self] in }` for Swift-concurrency-correct
  actor isolation in HighlightedEditorBridge
- Convert `FileLanguageCache` from `ObservableObject`/`@StateObject` to
  a plain struct with `@State` — it never publishes changes so the class
  added no value
- Extract `SyntaxLanguageDetector` to its own file to keep
  FilePreviewTextEditor.swift within the single-responsibility threshold
- textViewDidChangeText: read controller.textView.string inside Task { @mainactor }
  to avoid reading AppKit main-thread property before the actor hop (greptile P1)
- drawsBackground propagated into HighlightedFilePreviewEditor and theme:
  transparent-background appearances now work in highlighted path (coderabbit)
- FileExternalOpenAction.openDefault used in markdown preview fallback instead
  of NSWorkspace.shared.open, consistent with existing cmd-click route (coderabbit)
- Dockerfile filename check lowercased to match case-insensitively (coderabbit)
- CodeEditLanguages version constraint changed from exact to upToNextMajorVersion
  to match CodeEditSourceEditor, avoiding future incompatibility when CESE updates
  (coderabbit)
- @preconcurrency NSTextStorageDelegate on HighlightedEditorBridge to satisfy
  Swift actor isolation while the conformance methods are all @mainactor (greptile)
- Note: CodeEditTextView.TextView is not NSTextView so panel.attachTextView cannot
  be called in the highlighted path; focus registration uses attachPreviewFocus
  and file-drop via NSTextView APIs remains unavailable in that path
- Zoom monitor leak: NSEvent.removeMonitor was deferred via Task { @mainactor }
  with [weak self], but SwiftUI releases the coordinator synchronously when
  destroy() is called, so self was already nil and the monitor leaked
  permanently. Now removed synchronously in destroy(); zoomEventMonitor is
  nonisolated(unsafe) because NSEvent.removeMonitor is thread-safe and the
  field is written only on the main actor. (greptile P1)
- isDark now always derived from bridge.themeBackground, not the resolved
  background (which is .clear when drawsBackground=false). Otherwise transparent
  dark editors would pick the light syntax palette. (coderabbit + cubic)
- Markdown preview button also disabled when panel.isFileUnavailable, mirroring
  the existing dirty/saving guards. (coderabbit)
- Serialize zoomEventMonitor access through NSLock so destroy() (called
  nonisolated) and @mainactor install/remove paths can never double-call
  NSEvent.removeMonitor with the same token (cubic P1).
- Add markdown aliases (mkd, mkdn, mdwn, mdown) to
  FilePreviewKindResolver.textExtensions so they take the text path on
  first resolution instead of needing a sniff hop (coderabbit).
Extract FilePreviewKindResolver.markdownExtensions as the single source of
truth and consume it from both FilePreviewKindResolver.textExtensions (via
.union) and FilePreviewPanel.isMarkdownFile. Keeps the text-mode allowlist
and the markdown-preview button in lockstep so neither can drift.
Comment thread Sources/Panels/FilePreviewTextEditor.swift
@shishirsharma
shishirsharma force-pushed the feature/syntax-highlighting-file-preview branch from 72f0290 to c0669f8 Compare May 19, 2026 18:26
Comment thread Sources/Panels/FilePreviewPanel.swift Outdated
@shishirsharma

Copy link
Copy Markdown
Author

@lawrencecchen — when you have a moment, would appreciate a maintainer pass on this. It's been through several rounds of bot review (CodeRabbit, cubic, greptile, Socket) all green on the current head, rebased onto latest main, and now MERGEABLE. Happy to make any changes you'd like before merge.

manaflow-ai#4285 routes all .md file opens through Workspace.openFileSurfaces and
sends them directly to MarkdownPanel (the rendered viewer), so a .md file
no longer lands in FilePreviewPanel from any current entry point. The
in-header markdown preview button is therefore unreachable in normal
flows and would only fire on legacy session restores.

Remove the button, isMarkdownFile, and owningWorkspace() helper. Keep
the .mkd/.mkdn/.mdwn/.mdown additions in textExtensions inline, since
upstream MarkdownPanelFileLinkResolver.isMarkdownPathLike only covers
md/markdown/mkd/mdx — the long-tail aliases still benefit text-mode
detection if they ever reach FilePreviewPanel.

PR scope is now syntax highlighting only.
@shishirsharma

Copy link
Copy Markdown
Author

Scope reduction: dropped the in-header markdown preview button (commit ba58f7ce0).

Now that #4285 routes all .md file opens through Workspace.openFileSurfaces → MarkdownPanel (the rendered viewer), .md files no longer land in FilePreviewPanel from any current entry point. The button was redundant.

This PR is now syntax highlighting only, which keeps the change tighter and easier to review. isMarkdownFile and the owningWorkspace() helper were removed; the new long-tail markdown aliases (mkdn/mdwn/mdown) stay in FilePreviewKindResolver.textExtensions since upstream MarkdownPanelFileLinkResolver.isMarkdownPathLike only covers md/markdown/mkd/mdx.

Comment thread Sources/Panels/FilePreviewTextEditor.swift Outdated
- Memoize SyntaxLanguageDetector.language(for:) with a static URL-keyed
  cache so the resourceValues file stat runs once per file instead of
  once per parent re-render. State(wrappedValue:) is not @autoclosure,
  so the FileLanguageCache constructor was firing on every keystroke
  even though SwiftUI discards the value after the first init
  (greptile P1, line 55).
- Fix misleading "runs exactly once per panel lifetime" comment on
  FileLanguageCache.
- Wrap NSEvent.addLocalMonitorForEvents handler body in
  MainActor.assumeIsolated. The closure accesses @MainActor-isolated
  properties; NSEvent local monitors fire on the main thread by
  contract, so this is safe at runtime and clears Swift 6 strict-
  concurrency complaints (greptile P1, line 193).

Greptile's third P1 (missing .xcstrings entries for
filePreview.openMarkdownPreview*) was stale — those strings were
removed in ba58f7c with the markdown button.
@hoishing

Copy link
Copy Markdown

@lawrencecchen pls take a look, don't let the bots hinder this good PR, syntax highligh is definitely a gap need to be filled.

@greptile-apps

greptile-apps Bot commented May 23, 2026

Copy link
Copy Markdown
Contributor

Want your agent to iterate on Greptile's feedback? Try greploops.

Comment thread Sources/Panels/SyntaxLanguageDetector.swift
@austinywang
austinywang dismissed stale reviews from coderabbitai[bot], coderabbitai[bot], coderabbitai[bot], and coderabbitai[bot] May 23, 2026 02:05

All inline findings from this automated CodeRabbit review have been addressed or resolved, and the current CodeRabbit status check is passing on the PR head.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

cmux-reconcile: useful

Usefulness verdict: Keep the syntax-highlighting/editor delta; remove stale Markdown claims from the title/linked scope.

The current PR body says the Markdown preview button was removed after #4285. Its remaining contribution is TreeSitter/CodeEditSourceEditor syntax highlighting beyond the existing editable NSTextView preview. That can still be useful for #137. Do not merge or close based on the outdated title suggesting it provides Markdown viewing, which main already has. Dependency/build impact still needs normal review.

Reviewed patch head: 1d60a4150a4fa0f94e7313e2b83efad339e422e4. Source/diff triage on September 18, 2026; no new build or runtime validation. No issue state, label, or merge decision changed.

Older issue/PR tracking index — remaining scope and competing implementations are recorded there.

@teamleaderleo teamleaderleo added S3: minor Wrong behavior with a workaround area: terminal Ghostty surface, rendering, scrollback, escape sequences, fonts labels Sep 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: terminal Ghostty surface, rendering, scrollback, escape sequences, fonts S3: minor Wrong behavior with a workaround

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants