Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation

/// Settings under the dotted-id prefix `fileEditor.*`.
///
/// Controls the built-in plain-text file editor (the text preview that the
/// file explorer and `cmux` file routing open for editable text files). This
/// is distinct from the rendered markdown viewer, whose settings live in
/// ``MarkdownCatalogSection``.
public struct FileEditorCatalogSection: SettingCatalogSection {
/// Whether long lines soft-wrap at the editor's right edge.
///
/// `false` (the default) preserves the established behavior: lines extend
/// past the viewport and a horizontal scroller appears. `true` wraps each
/// line to the visible width and hides the horizontal scroller, the way a
/// prose editor does. Changing this applies live to open editors.
public let wordWrap = DefaultsKey<Bool>(
id: "fileEditor.wordWrap",
defaultValue: false,
userDefaultsKey: "fileEditor.wordWrap"
)

/// Creates the file editor settings section with its default keys.
public init() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public struct SettingCatalog: SettingCatalogSection {
public let browser = BrowserCatalogSection()
/// Settings for the built-in markdown viewer (the `markdown.*` keys).
public let markdown = MarkdownCatalogSection()
/// Settings for the built-in plain-text file editor (the `fileEditor.*` keys).
public let fileEditor = FileEditorCatalogSection()
public let betaFeatures = BetaFeaturesCatalogSection()
public let shortcuts = KeyboardShortcutsCatalogSection()
public let integrations = IntegrationsCatalogSection()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extension Array where Element == CuratedSettingEntry {
.init(section: .app, id: "preferred-editor", title: "Open Files With", synonyms: "app.preferredEditor editor open file code vscode visual studio zed sublime subl cursor"),
.init(section: .app, id: "supported-file-previews", title: "Open Supported Files in cmux", synonyms: "app.openSupportedFilesInCmux cmd click file preview pdf image video audio quicklook quick look editor external"),
.init(section: .app, id: "markdown-viewer", title: "Open Markdown in cmux Viewer", synonyms: "app.openMarkdownInCmuxViewer md markdown mdx viewer preview readme"),
.init(section: .app, id: "file-editor-word-wrap", title: "File Editor Word Wrap", synonyms: "fileEditor.wordWrap file editor word wrap soft wrap reflow lines text horizontal scroll preview"),

@coderabbitai coderabbitai Bot Jun 2, 2026 •

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 | 🏗️ Heavy lift

Localize this curated search entry before shipping.

This adds a new user-visible curated result with an English-only title and English-only search terms, so localized builds will surface/search this setting differently from the rest of the PR. Route the title/synonyms through localized resources or derive them from an already localized search/index source instead of hardcoding another English entry here. As per coding guidelines, "Any new or changed user-facing text must be fully localized across all supported locales."

🤖 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
`@Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry`+Default.swift
at line 44, The new CuratedSettingEntry added in
CuratedSettingEntry+Default.swift (the .init with section: .app, id:
"file-editor-word-wrap") is hardcoded in English; replace the literal title and
synonyms with localized values by routing them through your localization system
(e.g., NSLocalizedString keys or the app's localized resource helper) or by
deriving them from the existing localized search/index source used for other
curated entries; ensure you add matching keys to the appropriate .strings files
for all supported locales and reference those keys when constructing the
CuratedSettingEntry so the title and synonyms are localized consistently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intentionally consistent with the existing convention: every entry in CuratedSettingEntry+Default.swift uses English-literal titles/synonyms (the curated table is the search synonym index). The user-facing Settings control itself is localized — AppSection renders String(localized: "settings.app.fileEditorWordWrap") (en + ja in Localizable.xcstrings), and the legacy search alias has en + ja entries too. Localizing this one curated entry while ~60 siblings stay English would be inconsistent; happy to localize the whole table in a separate pass if desired.

— Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@austinywang, that makes complete sense — the file-level doc comment even states "Strings are English-only until the package ships an xcstrings catalog", and every existing sibling entry follows the same pattern. The rendered settings label and legacy search alias are already localized (en + ja), so the concern doesn't apply here. Acknowledged, and happy to see the whole table localized in a dedicated pass when the package gets its own catalog.


✏️ Learnings added
Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 5247
File: Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift:44-44
Timestamp: 2026-06-02T22:04:30.993Z
Learning: In manaflow-ai/cmux, `Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/CuratedSettingEntry+Default.swift` is an internal search-synonym index table. All entries (title and synonyms fields) are intentionally hardcoded in English — the file-level doc comment explicitly states "Strings are English-only until the package ships an xcstrings catalog." Do NOT flag individual entries in this file for missing localization; the rendered user-facing Settings UI labels are localized separately via `String(localized:)` with keys in `Resources/Localizable.xcstrings`, and the legacy search aliases have their own en/ja entries.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: pgbezerra
Repo: manaflow-ai/cmux PR: 3307
File: Sources/cmuxApp.swift:6413-6417
Timestamp: 2026-04-30T11:55:31.575Z
Learning: In this repo (manaflow-ai/cmux), when adding a new Settings section in SwiftUI (e.g., in Sources/cmuxApp.swift or related Views), don’t wire navigation/search with a raw anchor string alone. Instead: (1) create a corresponding SettingsNavigationTarget enum case (e.g., .workspaces); (2) provide the localized title, symbol, search text, and aliases for that case; (3) add/update the matching entry in SettingsSearchIndex so the sidebar/search can navigate to it; and (4) apply .settingsSearchAnchor(SettingsSearchIndex.sectionID(for: <target>)) to the section header. This prevents broken jump-to behavior by ensuring the navigation anchor and the search index stay consistent.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 5174
File: Sources/SettingsSearchAliases.swift:15-15
Timestamp: 2026-06-02T06:43:09.571Z
Learning: In manaflow-ai/cmux, the `settings.search.alias.section.*` and `settings.search.alias.setting.*` keys in `Sources/SettingsSearchAliases.swift` are intentionally absent from `Resources/Localizable.xcstrings`. They are internal fuzzy-match tokens used for Settings search, not displayed UI strings, and they resolve via their English `defaultValue` synonyms at runtime. For example, `settings.search.alias.section.betaFeatures` and `settings.search.alias.setting.betaFeatures.dock` (and now `settings.search.alias.setting.betaFeatures.feed`) are all intentionally uncataloged. Do not flag missing catalog entries for these `settings.search.alias.*` keys; cataloging them is a separate, coordinated cleanup task covering all sections together.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 4534
File: Sources/AppDelegate.swift:11307-11311
Timestamp: 2026-05-22T05:05:58.658Z
Learning: Repo: manaflow-ai/cmux
File/Area: Sources/AppDelegate.swift (menu wiring)
Learning: For the “Reload Configuration” menu item, it’s acceptable to use a localized title-based fallback only during the first configuration pass (before the NSMenuItem identifier is assigned). The stable identifier is set immediately afterward and used for subsequent lookups. Do not flag this pattern as fragile when the identifier path is present.

Learnt from: Znboston
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-03-26T19:00:12.434Z
Learning: Repo: manaflow-ai/cmux — Sources/GroupHeaderView.swift and Sources/ContentView.swift — Palette color entry labels (`Text(entry.name)`) use dynamic palette data loaded at runtime and cannot be statically keyed with `String(localized:)`. This matches the existing workspace color picker pattern in ContentView.swift. Palette name localization would require restructuring the color palette system and is intentionally deferred; do not flag `entry.name` as a missing localization in this codebase.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 4831
File: Sources/cmuxApp.swift:5350-5353
Timestamp: 2026-06-01T00:51:58.772Z
Learning: In `manafow-ai/cmux` Swift settings code, `Sources/cmuxApp.swift`'s legacy in-app `SettingsView` is no longer the presented settings window for the Kiro settings UI; the live UI is `CmuxSettingsUI`'s `AutomationSection`, and `SettingsWindowRootView` is not instantiated. For `KiroIntegrationSettings.notificationLevel`, normal write paths validate against `KiroIntegrationSettings.NotificationLevel` (picker tags are valid and the `cmux.json` parser rejects invalid values), while runtime/terminal environment readers normalize via `KiroIntegrationSettings.notificationLevel(defaults:)`. Do not flag the legacy `AppStorage` string binding for `kiroNotificationLevel` solely because it could theoretically display an invalid raw value.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 3527
File: Sources/cmuxApp.swift:0-0
Timestamp: 2026-05-05T02:03:05.654Z
Learning: In manaflow-ai/cmux, the Settings terminal-theme picker (Sources/TerminalThemePickerRow.swift) must always include an “Adaptive” option even when the current selection is .custom or .named. When not already adaptive, build the adaptive choice from GhosttyConfig.cmuxDefaultLightThemeName and GhosttyConfig.cmuxDefaultDarkThemeName. Keep named options de-duplicated case/diacritic-insensitively.

Learnt from: CR
Repo: manaflow-ai/cmux PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-06-02T19:47:28.596Z
Learning: Applies to **/*.swift : Every new cmux-owned keyboard shortcut must be added to `KeyboardShortcutSettings`, visible/editable in Settings, supported in `~/.config/cmux/cmux.json`, and documented in keyboard shortcut and configuration docs

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2528
File: Sources/cmuxApp.swift:6439-6444
Timestamp: 2026-04-03T03:37:25.743Z
Learning: Repo: manaflow-ai/cmux — In Sources/KeyboardShortcutSettings.swift, KeyboardShortcutSettings.setShortcut(_:, for:) is a no‑op when the action is managed by settings.json (isManagedBySettingsFile(action) == true), preventing UserDefaults backfill for file‑managed shortcuts.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2575
File: Sources/cmuxApp.swift:0-0
Timestamp: 2026-04-06T09:01:51.979Z
Learning: Repo: manaflow-ai/cmux — File: Sources/cmuxApp.swift — SettingsView now uses SwiftUI `.searchable(text:placement:prompt:)` for the sidebar search, which provides a native (accessible) clear button. Do not flag missing accessibility on a custom clear button in this view going forward.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2528
File: Sources/ContentView.swift:8917-8921
Timestamp: 2026-04-03T03:35:56.499Z
Learning: Repo: manaflow-ai/cmux — Sources/ContentView.swift — ShortcutHintModifierPolicy.shouldShowHints(for:) reveals sidebar/titlebar shortcut hints when the current modifier flags exactly equal KeyboardShortcutSettings.shortcut(for: .selectWorkspaceByNumber).modifierFlags, and returns false for chorded-number mappings. This follows the configured workspace-number modifier (not strictly Command-only). TabItemView’s close-button suppression via showsModifierShortcutHints therefore tracks the configured modifier. The debug toggle showHintsOnCommandHold predates customizable shortcuts and conceptually means “show hints on holding the configured workspace-number modifier(s).”

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 5178
File: web/data/cmux-shortcuts.ts:223-227
Timestamp: 2026-06-02T08:18:29.897Z
Learning: In the manaflow-ai/cmux project, `LocalizedText` in `web/data/cmux-shortcuts.ts` is intentionally typed as `{ en: string; ja: string }` — every shortcut entry in that file provides only English and Japanese descriptions. The keyboard-shortcuts docs renderer has an explicit English fallback for all other locales. This is the established design for the entire shortcuts data file. Reviewers should NOT flag individual shortcut entries for missing locale coverage beyond en/ja in this file; extending to additional locales would require a separate project-wide change to the shortcuts i18n system. The native macOS Settings UI label localization (via Localizable.xcstrings) is separate and does cover all supported catalog locales.

Learnt from: HamptonMakes
Repo: manaflow-ai/cmux PR: 4443
File: Sources/cmuxApp.swift:6678-6695
Timestamp: 2026-05-22T15:04:55.554Z
Learning: In manaflow-ai/cmux, agent/automation settings strings (settings.automation.*) follow AGENTS.md, which scopes supported locales to English and Japanese; sibling toggles on main (Cursor/Gemini) also include Korean. For new entries like settings.automation.amp.*, matching en/ja/ko is acceptable and we should not require expansion to all app locales in the touched catalog unless maintainers request it.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 3971
File: Resources/Localizable.xcstrings:64948-64951
Timestamp: 2026-05-13T21:22:34.162Z
Learning: In `Resources/Localizable.xcstrings` for the `manaflow-ai/cmux` repo, `settings.betaFeatures.*` localization keys (e.g., `settings.betaFeatures.dock`, `settings.betaFeatures.feed`, and their subtitle/warning variants) intentionally include only English ("en") and Japanese ("ja") locales while the feature is in beta. Do not flag the absence of other locales for these beta feature keys as a localization gap — this is the established convention for beta-gated features in this project.

Learnt from: HamptonMakes
Repo: manaflow-ai/cmux PR: 4443
File: Resources/Localizable.xcstrings:59654-59745
Timestamp: 2026-05-21T21:34:34.427Z
Learning: For `settings.automation.*` integration-toggle keys in `Resources/Localizable.xcstrings` (e.g., `settings.automation.cursor`, `settings.automation.gemini`, `settings.automation.amp` and their `.note`, `.subtitleOff`, `.subtitleOn` sub-keys), the established repo pattern is to provide only `en`, `ja`, and `ko` locales with `extractionState: "manual"` and `state: "translated"`. Do NOT flag these as partial-localization violations — the en/ja/ko-only set is intentional for automation integration settings and matches the existing sibling-key precedent.

Learnt from: azooz2003-bit
Repo: manaflow-ai/cmux PR: 4771
File: CLI/cmux.swift:6013-6047
Timestamp: 2026-05-26T05:16:37.569Z
Learning: In the manaflow-ai/cmux project, CLI-facing strings (CLIError messages, per-subcommand help/usage text, and diagnostic summary output in CLI/cmux.swift) are intentionally kept as hard-coded English and are NOT subject to the xcstrings/`String(localized:)` localization requirement. The localization rule (full-internationalization.md) targets in-app user-facing UI strings only. Existing CLI subcommands such as reorder-workspace follow the same hard-coded English pattern. Do not flag missing localization for CLI error messages, help text, or diagnostic output in CLI/**/*.swift.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 3393
File: web/messages/zh-TW.json:0-0
Timestamp: 2026-05-01T08:41:57.216Z
Learning: Repo: manaflow-ai/cmux — In `web/messages/*.json` locale files, the `docs.dock.agentPrompt` key is intentionally kept in English across all locales (including high-confidence locales like zh-TW, ja, ko, de, fr, etc.) because it is a verbatim prompt designed to be copied into coding agents. Do not flag the English value of `agentPrompt` as a missing translation for any locale. Only `agentPromptIntro` and all other surrounding dock doc strings are expected to be translated for high-confidence locales.

Learnt from: zlatkoc
Repo: manaflow-ai/cmux PR: 1368
File: Sources/Panels/BrowserPanel.swift:69-69
Timestamp: 2026-03-13T13:46:07.021Z
Learning: In manaflow-ai/cmux (Sources/Panels/BrowserPanel.swift), search engine `displayName` values (e.g. "Google", "DuckDuckGo", "Bing", "Kagi", "Startpage") are intentionally bare string literals and must NOT be wrapped with `String(localized:...)`. They are proper brand/product names, not translatable UI text. The localization guideline applies only to generic UI strings (labels, buttons, error messages, etc.), not to engine/brand names.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 5174
File: Packages/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/BetaFeaturesSection.swift:5-6
Timestamp: 2026-06-02T06:43:13.599Z
Learning: In manaflow-ai/cmux, all `settings.betaFeatures.*` localization keys (including `settings.betaFeatures.dock`, `.extensions`, `.warning`, `.feed`, and their `.subtitleOn`/`.subtitleOff` variants) are intentionally translated only into `en` and `ja`. This matches the project's documented supported languages in CLAUDE.md ("currently English and Japanese"). Do NOT flag missing translations for other locales in the `settings.betaFeatures.*` key family — adding other locales to only one key would make it inconsistent with the rest of the family. Broadening locale coverage for the whole beta-features string family is a separate, intentional change.

Learnt from: nanami-he
Repo: manaflow-ai/cmux PR: 4633
File: Resources/Localizable.xcstrings:38310-38310
Timestamp: 2026-05-23T08:40:54.816Z
Learning: In the manaflow-ai/cmux repository, the only required locales for newly added keys in `Resources/Localizable.xcstrings` are **English (`en`) and Japanese (`ja`)**. This is explicitly documented in `CLAUDE.md` ("Keys go in `Resources/Localizable.xcstrings` with translations for all supported languages (currently English and Japanese)"). Approximately 42% of catalog keys carry only `en`+`ja`. Keys with additional locales (up to 19) are populated by a separate batch-translation pass and are NOT a requirement for newly added keys. Do NOT flag `en`+`ja`-only entries as incomplete localization.

Learnt from: nanami-he
Repo: manaflow-ai/cmux PR: 4633
File: Resources/Localizable.xcstrings:38310-38310
Timestamp: 2026-05-23T08:40:54.816Z
Learning: In the manaflow-ai/cmux repository, the only required locales for newly added keys in `Resources/Localizable.xcstrings` are **English (`en`) and Japanese (`ja`)**. This is explicitly documented in `CLAUDE.md`: "Keys go in `Resources/Localizable.xcstrings` with translations for all supported languages (currently English and Japanese)." Approximately 42% of catalog keys (886 of 2086) carry only `en`+`ja`. Keys with additional locales (up to ~19) are populated by a separate batch-translation pass and are NOT a requirement for newly added keys. Do NOT flag `en`+`ja`-only entries as incomplete or partial localization.

Learnt from: CR
Repo: manaflow-ai/cmux PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-25T04:48:00.216Z
Learning: Applies to **/*.swift : All user-facing strings must be localized using `String(localized: "key.name", defaultValue: "English text")` for every string shown in the UI (labels, buttons, menus, dialogs, tooltips, error messages). Keys must go in `Resources/Localizable.xcstrings` with translations for all supported languages (English and Japanese). Never use bare string literals in SwiftUI `Text()`, `Button()`, alert titles, etc.

Learnt from: atani
Repo: manaflow-ai/cmux PR: 819
File: Sources/Update/UpdateTitlebarAccessory.swift:924-926
Timestamp: 2026-03-04T14:04:40.577Z
Learning: In manaflow-ai/cmux (Swift/SwiftUI macOS app), the notifications empty-state localization keys are intentionally different across two views:
- `NotificationsPage.swift` uses key `"notifications.empty.description"` with text "Desktop notifications will appear here for quick review." (full-page view).
- `UpdateTitlebarAccessory.swift` uses key `"notifications.empty.subtitle"` with text "Desktop notifications will appear here." (space-constrained titlebar popover).
Both keys have correct Japanese translations in the .xcstrings catalog. The difference in key names and text is by design, not an inconsistency.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2475
File: Sources/ContentView.swift:0-0
Timestamp: 2026-04-03T07:19:36.497Z
Learning: Repo: manaflow-ai/cmux — In Sources/ContentView.swift, the command‑palette rename flow uses a single-line SwiftUI TextField via commandPaletteEditorField(style: .singleLine(...)); the multiline NSTextView editor is only used for the workspace description input. Do not flag newline persistence for rename.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2514
File: Sources/GhosttyTerminalView.swift:3759-3761
Timestamp: 2026-04-01T22:57:41.165Z
Learning: Repo: manaflow-ai/cmux — In Sources/cmuxApp.swift, ClaudeCodeIntegrationSettings.customClaudePath(defaults:) trims surrounding whitespace and returns nil for empty/whitespace-only values; callers (e.g., TerminalSurface.createSurface(for:)) can safely set CMUX_CUSTOM_CLAUDE_PATH without additional trimming.

Learnt from: tayl0r
Repo: manaflow-ai/cmux PR: 1909
File: Sources/ContentView.swift:2156-2171
Timestamp: 2026-03-23T06:08:14.740Z
Learning: Repo: manaflow-ai/cmux — In Sources/ContentView.swift, openFileInTextEditor(_:) must attempt workspace.newTextEditorSplit(from:orientation:filePath:focus:) and, if that returns nil, fall back to workspace.newTextEditorSurface(inPane:filePath:focus:) using bonsplitController.focusedPaneId. Rationale: avoid dropping file-open requests when the focused panel is not pane-backed.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 3182
File: Sources/ContentView.swift:10850-10875
Timestamp: 2026-04-27T10:11:40.167Z
Learning: Repo: manaflow-ai/cmux — When measuring NSTextView content height (e.g., in FeedbackComposerMessageEditorView.naturalDocumentHeight(for:)), include layoutManager.extraLineFragmentRect.height when extraLineFragmentTextContainer === textContainer to account for a trailing newline; otherwise the caret on the final blank line can be clipped. Apply this pattern to future NSTextView-based editors in this repo.

Learnt from: HamptonMakes
Repo: manaflow-ai/cmux PR: 2007
File: Sources/cmuxApp.swift:3798-3799
Timestamp: 2026-03-23T16:36:55.259Z
Learning: Repo: manaflow-ai/cmux — In Sources/cmuxApp.swift, SettingsView.resetAllSettings() must reset newly added AppStorage toggles to defaults. Specifically, ensure ampHooksEnabled is set to AmpIntegrationSettings.defaultHooksEnabled so the Amp integration toggle resets correctly.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 2525
File: Sources/GhosttyTerminalView.swift:481-513
Timestamp: 2026-04-02T10:13:39.235Z
Learning: Repo: manaflow-ai/cmux — In Sources/GhosttyTerminalView.swift, terminal file-link resolution trims trailing unmatched closing delimiters “) ] } >” only when they are dangling (more closers than openers), preserving wrapped tokens like “(file:///tmp/a.png)”. Implemented via terminalFileLinkTrailingClosingDelimiters and count comparison inside trimTrailingTerminalFileLinkPunctuation(_:) and exercised by a regression test (PR `#2525`, commit 3f5c5b6d).

Learnt from: qkrwpdlr
Repo: manaflow-ai/cmux PR: 0
File: :0-0
Timestamp: 2026-03-23T07:12:42.553Z
Learning: Repo: manaflow-ai/cmux — In Sources/TerminalController.swift and Sources/Panels/BrowserPanel.swift, BiDi override (U+202A–202E, U+2066–2069) and zero-width char (U+200B–200F, U+FEFF) filtering is implemented via a shared `dangerousScalars: Set<UInt32>` in each class. v2SanitizeWebText() truncates to 200 chars; v2SanitizeXPath() caps at 2000 chars for selector fidelity. Both use a shared v2SanitizeScalar() predicate. BrowserPickerMessageHandler.sanitize() uses the same dangerousScalars pattern with a 200-char cap.

Learnt from: arieltobiana
Repo: manaflow-ai/cmux PR: 1873
File: Sources/TerminalController.swift:4071-4087
Timestamp: 2026-03-20T17:18:30.333Z
Learning: Repo: manaflow-ai/cmux — In Sources/TerminalController.swift, v2WorkspaceAction(params:) -> case "set_color": palette names are resolved via WorkspaceTabColorSettings.defaultPaletteWithOverrides(), whose entries are always valid hex (validated by the UI). Therefore, additional normalization of entry.hex is unnecessary.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 3843
File: Sources/AppDelegate.swift:14237-14239
Timestamp: 2026-05-11T06:23:21.666Z
Learning: In manaflow-ai/cmux (Sources/AppDelegate.swift), within NSWindow.cmux_performKeyEquivalent, when forwarding Return/Enter or plain arrow keys for browser inputs, the keyDown target must be the resolved owning web view: prefer firstResponderWebView (CmuxWebView), else firstResponderEmbeddedWebView (WKWebView), else fall back to firstResponder. This avoids AppKit beeps on form submit and preserves arrow handling in embedded auth web views. Tests verify embedded WKWebView delivery.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 2505
File: Sources/AppDelegate.swift:5636-5642
Timestamp: 2026-04-06T07:18:41.310Z
Learning: Repo: manaflow-ai/cmux — In AppDelegate’s .keyDown focus-repair path, never dereference NSTextView.delegate (unsafe-unretained). Resolve field-editor ownership via cmuxFieldEditorOwnerView(_), and prefer superview/nextResponder traversal or hostedView.responderMatchesPreferredKeyboardFocus(...) for matching, as applied in AppDelegate.swift and GhosttySurfaceScrollView.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 3244
File: Sources/AppDelegate.swift:6601-6614
Timestamp: 2026-04-29T06:25:44.652Z
Learning: Repo: manaflow-ai/cmux — Settings window behavior (PR `#3244`): Settings now uses a singleton SwiftUI Window scene. SettingsWindowPresenter.show(navigationTarget:) first locates any existing Settings NSWindow and, if found, deminiaturizes it when isMiniaturized and brings it to the front (makeKeyAndOrderFront/activation) instead of creating a duplicate; only opens a new window when none exists. AppDelegate.presentPreferencesWindow correctly delegates to SettingsWindowPresenter.show and should not add extra re-front/dedup logic.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 3784
File: README.md:161-161
Timestamp: 2026-05-09T04:48:35.413Z
Learning: In the cmux project, the right-sidebar keyboard shortcut labels were intentionally swapped (per PR `#3784`). Reviewers should NOT flag the ⌘⇧E (Cmd+Shift+E) label as “Open file explorer.” Use these mappings consistently: ⌘⇧E → `focusRightSidebar` with the user-facing label “Toggle right sidebar focus”; ⌘⌥B (Cmd+Option+B) → `toggleFileExplorer` with the user-facing label “Open file explorer.”

Learnt from: jt-hsiao
Repo: manaflow-ai/cmux PR: 1423
File: Sources/AppDelegate.swift:11220-11226
Timestamp: 2026-03-14T07:06:01.466Z
Learning: Repo: manaflow-ai/cmux — In Sources/Panels/CmuxWebView.swift, performKeyEquivalent(with:) handles Command-key routing end-to-end: (1) if allowed, route to NSApp.mainMenu.performKeyEquivalent; (2) fall back to AppDelegate.shared?.handleBrowserSurfaceKeyEquivalent(event) for non–menu-backed app shortcuts; (3) fall back to super.performKeyEquivalent. For non-Command keys it calls super directly. Therefore, in NSWindow.cmux_performKeyEquivalent (Sources/AppDelegate.swift), it is correct to call firstResponderWebView.performKeyEquivalent and return its Bool unconditionally to avoid re-entering SwiftUI’s performKeyEquivalent path that can swallow keys after WKWebView focus.

Learnt from: lawrencecchen
Repo: manaflow-ai/cmux PR: 3244
File: Sources/WindowDecorationsController.swift:71-73
Timestamp: 2026-04-29T06:24:53.283Z
Learning: Repo: manaflow-ai/cmux — Sources/WindowDecorationsController.swift — `trafficLightOffset(for:)` returned `.zero` for all non-settings windows on `main`; the only non-zero offset was for `cmux.settings` (nudge right/down to align with the custom Settings title row). PR `#3244` intentionally removes that offset because Settings now uses a SwiftUI WindowGroup with a native macOS system titlebar, making the nudge unnecessary. Do not flag `trafficLightOffset(for:)` always returning `.zero` as a regression.

Learnt from: atani
Repo: manaflow-ai/cmux PR: 819
File: Sources/AppDelegate.swift:0-0
Timestamp: 2026-03-04T14:05:42.574Z
Learning: Guideline: In Swift files (cmux project), when handling pluralized strings, prefer using localization keys with the ICU-style plural forms .one and .other. For example, use keys like statusMenu.unreadCount.one for the singular case (1) and statusMenu.unreadCount.other for all other counts, and similarly for statusMenu.tooltip.unread.one/other. Rationale: ensures correct pluralization across locales and makes localization keys explicit. Review code to ensure any unread count strings and related tooltips follow this .one/.other key pattern and verify the correct value is chosen based on the count.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 954
File: Sources/TerminalController.swift:0-0
Timestamp: 2026-03-05T22:04:34.712Z
Learning: Adopt the convention: for health/telemetry tri-state values in Swift, prefer Optionals (Bool?) over sentinel booleans. In TerminalController.swift, socketConnectable is Bool? and only set when socketProbePerformed is true; downstream logic must treat nil as 'not probed'. Ensure downstream code checks for nil before using a value and uses explicit non-nil checks to determine state, improving clarity and avoiding misinterpretation of default false.

Learnt from: MaTriXy
Repo: manaflow-ai/cmux PR: 1460
File: Sources/TerminalController.swift:0-0
Timestamp: 2026-03-16T08:02:06.824Z
Learning: In Swift sources, for any panel_id-only route handling in v2PanelMarkBackground(params:) and v2PanelMarkForeground(params:), first attempt v2ResolveTabManager(params:). Use the manager only if it actually owns the panelId; otherwise fall back to AppDelegate.shared?.locateSurface(surfaceId:) to locate the correct TabManager across windows. Apply this pattern to all panel_id-only routes to avoid active-window bias.

Learnt from: pratikpakhale
Repo: manaflow-ai/cmux PR: 2011
File: Resources/Localizable.xcstrings:15256-15368
Timestamp: 2026-03-23T21:39:50.795Z
Learning: When reviewing this repo’s Swift localization usage, do not flag missing `String.localizedStringWithFormat` for calls that use the modern overload `String(localized: "key", defaultValue: "...\(variable)")` (where `defaultValue` is a `String.LocalizationValue` built with `\(…)`). That overload natively supports interpolation and the xcstrings/runtime substitution handles the resulting placeholders automatically. Only require `String.localizedStringWithFormat` when using the older `String(localized:)` overload that takes a plain `String` (i.e., where format arguments must be passed separately), such as for keys like `clipboard.sshError.single`.

Learnt from: thunter009
Repo: manaflow-ai/cmux PR: 1825
File: Sources/TerminalController.swift:3620-3622
Timestamp: 2026-03-25T00:32:54.735Z
Learning: When validating or reporting workspace/tab colors in this repo, only accept and use 6-digit hex colors in the form `#RRGGBB` (no alpha, i.e., do not allow `#RRGGBBAA`). Ensure validation logic matches the existing behavior (e.g., WorkspaceTabColorSettings.normalizedHex(...) and TabManager.setTabColor(tabId:color:) as well as CLI/cmux.swift). Update any error/help text for workspace color to reference only `#RRGGBB` (not `#RRGGBBAA`).

Learnt from: ryouka0731
Repo: manaflow-ai/cmux PR: 3415
File: Sources/Worktree/WorktreeManager.swift:1-10
Timestamp: 2026-05-06T19:24:46.399Z
Learning: Do not recommend extracting Foundation-only Swift files into a new SwiftPM package target in this repo. The established pattern is to keep app-internal helper modules under Sources/ unless the repository introduces a dedicated package (e.g., CMUXAuthCore, CMUXDebugLog, CMUXWorkstream) with a clear architectural rationale. Speculative SwiftPM extractions for individual Foundation-only modules expand PR scope without documented justification. Apply this guideline when reviewing changes to Swift files under Sources/; require a documented package architecture justification before considering packaging changes.

Learnt from: austinywang
Repo: manaflow-ai/cmux PR: 3626
File: Sources/TabManager.swift:1817-1818
Timestamp: 2026-05-07T08:37:03.967Z
Learning: In this Swift repo (manafow-ai/cmux), when cleaning up stale agent process entries, use `Workspace.clearAgentPID(key:panelId:)` as the single cleanup path. Do not directly mutate `Workspace.statusEntries` or `Workspace.agentPIDs` from outside the dedicated helpers; for example, `TabManager.sweepStaleAgentPIDs` should only call `clearAgentPID` rather than performing its own mutations. This ensures panel-scoped side effects and port/refresh logic run consistently.

Learnt from: psh4607
Repo: manaflow-ai/cmux PR: 3696
File: cmuxTests/ShortcutAndCommandPaletteTests.swift:1716-1771
Timestamp: 2026-05-07T10:56:50.266Z
Learning: In the manaflow-ai/cmux repo, SwiftLint does not enforce a `required_deinit` rule (no project `.swiftlint.yml` in cmux itself, no `required_deinit` in `.github/review-bot-rules/`, and no SwiftLint CI run in `.github/workflows/`). During code reviews, do not raise findings for missing `deinit` on `XCTestCase` subclasses or other Swift classes based on a `required_deinit` rule.

.init(section: .app, id: "terminal-config", title: "Terminal Config", synonyms: "ghostty config merged generated preview terminal configuration window open config"),
.init(section: .app, id: "imessage-mode", title: "iMessage Mode", synonyms: "app.iMessageMode imessage message messages chat prompt prompts submitted texting reorder move workspace top agent send"),
.init(section: .app, id: "reorder-notification", title: "Reorder on Notification", synonyms: "app.reorderOnNotification notification reorder move workspace top unread sort"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public struct AppSection: View {
@State private var markdownFontSize: DefaultsValueModel<Int>
@State private var markdownFontFamily: DefaultsValueModel<String>
@State private var markdownMaxWidth: DefaultsValueModel<Int>
@State private var fileEditorWordWrap: DefaultsValueModel<Bool>
@State private var iMessage: DefaultsValueModel<Bool>
@State private var reorder: DefaultsValueModel<Bool>
@State private var dockBadge: DefaultsValueModel<Bool>
Expand Down Expand Up @@ -81,6 +82,7 @@ public struct AppSection: View {
_markdownFontSize = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.markdown.fontSize))
_markdownFontFamily = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.markdown.fontFamily))
_markdownMaxWidth = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.markdown.maxWidth))
_fileEditorWordWrap = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.fileEditor.wordWrap))
_iMessage = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.iMessageMode))
_reorder = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.app.reorderOnNotification))
_dockBadge = State(initialValue: DefaultsValueModel(store: defaultsStore, key: catalog.notifications.dockBadge))
Expand Down Expand Up @@ -380,6 +382,19 @@ public struct AppSection: View {
}
SettingsCardDivider()

// File Editor Word Wrap
SettingsCardRow(
configurationReview: .json("fileEditor.wordWrap"),
String(localized: "settings.app.fileEditorWordWrap", defaultValue: "File Editor Word Wrap"),
subtitle: String(localized: "settings.app.fileEditorWordWrap.subtitle", defaultValue: "Wrap long lines at the editor's right edge instead of scrolling horizontally. Applies to the plain-text file editor.")
) {
Toggle("", isOn: Binding(get: { fileEditorWordWrap.current }, set: { fileEditorWordWrap.set($0) }))
.labelsHidden()
.controlSize(.small)
.accessibilityIdentifier("SettingsFileEditorWordWrapToggle")
}
SettingsCardDivider()

// iMessage Mode
SettingsCardRow(
configurationReview: .json("app.iMessageMode"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct SettingsRowAnchorResolutionTests {
"browser.showSearchSuggestions",
"browser.theme",
"browser.urlsToAlwaysOpenExternally",
"fileEditor.wordWrap",
"notifications.command",
"notifications.dockBadge",
"notifications.paneFlash",
Expand Down
51 changes: 51 additions & 0 deletions Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,40 @@
}
}
},
"settings.app.fileEditorWordWrap": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "File Editor Word Wrap"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "ファイルエディタの行折り返し"
}
}
}
},
"settings.app.fileEditorWordWrap.subtitle": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Wrap long lines at the editor's right edge instead of scrolling horizontally. Applies to the plain-text file editor."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "長い行を横スクロールせずにエディタの右端で折り返します。プレーンテキストのファイルエディタに適用されます。"
}
}
}
},
"settings.search.alias.setting.app.markdown-font-size": {
"extractionState": "manual",
"localizations": {
Expand Down Expand Up @@ -620,6 +654,23 @@
}
}
},
"settings.search.alias.setting.app.file-editor-word-wrap": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "fileEditor.wordWrap file editor word wrap soft wrap reflow lines text horizontal scroll preview"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "fileEditor.wordWrap ファイル エディタ 行折り返し ワードラップ 折り返し 改行 テキスト 横スクロール プレビュー"
}
}
}
},
"cli.hooks.kiro.postInstallNote": {
"localizations": {
"en": {
Expand Down
57 changes: 53 additions & 4 deletions Sources/App/ShortcutRoutingSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,21 @@ func shouldDispatchCommandPaletteHorizontalArrowViaFirstResponderKeyDown(
}
}

func shouldDispatchTextBoxInputArrowViaFirstResponderKeyDown(
/// Whether an arrow keyDown belongs to a focused standalone editable text
/// responder (text-box input, file-preview editor, …) so it should be
/// forwarded to `firstResponder.keyDown` rather than swallowed by the original
/// `NSWindow.performKeyEquivalent`.
///
/// Owns the four arrows (keyCodes 123–126) for the modifier combos a text
/// editor handles itself: plain (move), Shift (extend selection), Option
/// (word/paragraph), and Command (line/document boundary) plus their Shift
/// combos. Cmd+Option+Arrow is excluded so it still reaches cmux's pane-focus
/// shortcuts. Marked text (IME composition) is left to the input method.
private func standaloneTextResponderOwnsArrowKeyDown(
keyCode: UInt16,
firstResponderIsTextBoxInput: Bool,
firstResponderHasMarkedText: Bool = false,
firstResponderHasMarkedText: Bool,
flags: NSEvent.ModifierFlags
) -> Bool {
guard firstResponderIsTextBoxInput else { return false }
guard !firstResponderHasMarkedText else { return false }
guard (123...126).contains(keyCode) else { return false }

Expand All @@ -191,6 +199,47 @@ func shouldDispatchTextBoxInputArrowViaFirstResponderKeyDown(
}
}

func shouldDispatchTextBoxInputArrowViaFirstResponderKeyDown(
keyCode: UInt16,
firstResponderIsTextBoxInput: Bool,
firstResponderHasMarkedText: Bool = false,
flags: NSEvent.ModifierFlags
) -> Bool {
guard firstResponderIsTextBoxInput else { return false }
return standaloneTextResponderOwnsArrowKeyDown(
keyCode: keyCode,
firstResponderHasMarkedText: firstResponderHasMarkedText,
flags: flags
)
}

/// Whether an arrow keyDown should be forwarded straight to the focused
/// standalone editable text view instead of falling through to the original
/// `NSWindow.performKeyEquivalent`, which swallows plain arrows before the
/// view's `keyDown` runs.
///
/// This generalizes the per-surface arrow-forwarding seam (browser, omnibar,
/// command palette, text-box input) to cover the whole class of standalone
/// editable `NSTextView`s cmux hosts — the file-preview editor today, any
/// future one tomorrow. Field editors (the omnibar / command-palette / find
/// field editors) are excluded by the caller because they have their own
/// dedicated routing or work through the normal field-editor path. Shares the
/// keyCode/modifier policy with ``shouldDispatchTextBoxInputArrowViaFirstResponderKeyDown``
/// via ``standaloneTextResponderOwnsArrowKeyDown(keyCode:firstResponderHasMarkedText:flags:)``.
func shouldDispatchEditableTextViewArrowViaFirstResponderKeyDown(
keyCode: UInt16,
firstResponderIsEditableTextView: Bool,
firstResponderHasMarkedText: Bool = false,
flags: NSEvent.ModifierFlags
) -> Bool {
guard firstResponderIsEditableTextView else { return false }
return standaloneTextResponderOwnsArrowKeyDown(
keyCode: keyCode,
firstResponderHasMarkedText: firstResponderHasMarkedText,
flags: flags
)
}
Comment thread
cursor[bot] marked this conversation as resolved.

func shouldToggleMainWindowFullScreenForCommandControlFShortcut(
flags: NSEvent.ModifierFlags,
chars: String,
Expand Down
28 changes: 28 additions & 0 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16186,6 +16186,7 @@ private var cmuxBrowserArrowForwardingDepth = 0
private var cmuxBrowserOmnibarMarkedTextForwardingDepth = 0
private var cmuxCommandPaletteArrowForwardingDepth = 0
private var cmuxTextBoxInputArrowForwardingDepth = 0
private var cmuxEditableTextViewArrowForwardingDepth = 0
private var cmuxWindowFirstResponderBypassDepth = 0
private var cmuxFieldEditorOwningWebViewAssociationKey: UInt8 = 0

Expand Down Expand Up @@ -16860,6 +16861,14 @@ private extension NSWindow {
)
let firstResponderOmnibarPanelId = browserOmnibarPanelId(for: self.firstResponder)
let firstResponderIsTextBoxInput = self.firstResponder is TextBoxInputTextView
// A standalone editable document text view (e.g. the file-preview
// editor's SavingTextView) owns arrow navigation through its own
// keyDown. Field editors (omnibar / command palette / find) are
// excluded — they route through their dedicated paths above.
let firstResponderIsStandaloneEditableTextView: Bool = {
guard let textView = self.firstResponder as? NSTextView else { return false }
return textView.isEditable && !textView.isFieldEditor
}()
if ShortcutRecorderEventRouter.dispatchActiveRecordingEvent(event, preferredWindow: self) {
return true
}
Expand Down Expand Up @@ -17010,6 +17019,25 @@ private extension NSWindow {
return true
}

// The file-preview editor and any other standalone editable NSTextView
// would otherwise lose plain/selection/word/line arrows to the original
// NSWindow.performKeyEquivalent. Route them to the text view's keyDown so
// arrow navigation works as in any text editor (manaflow-ai/cmux#5227).
if shouldDispatchEditableTextViewArrowViaFirstResponderKeyDown(
keyCode: event.keyCode,
firstResponderIsEditableTextView: firstResponderIsStandaloneEditableTextView,
firstResponderHasMarkedText: firstResponderHasMarkedText,
flags: event.modifierFlags
) {
if cmuxEditableTextViewArrowForwardingDepth > 0 {
return false
}
cmuxEditableTextViewArrowForwardingDepth += 1
defer { cmuxEditableTextViewArrowForwardingDepth = max(0, cmuxEditableTextViewArrowForwardingDepth - 1) }
self.firstResponder?.keyDown(with: event)
return true
}

// Web forms rely on Return/Enter flowing through keyDown. If the original
// NSWindow.performKeyEquivalent consumes Enter first, submission never reaches
// WebKit. Route Return/Enter directly to the current first responder and
Expand Down
1 change: 1 addition & 0 deletions Sources/CmuxSettingsJSONPathSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ extension CmuxSettingsFileStore {
"markdown.fontSize",
"markdown.fontFamily",
"markdown.maxWidth",
"fileEditor.wordWrap",
"shortcuts.bindings",
]
}
11 changes: 11 additions & 0 deletions Sources/CommandPalette/CommandPaletteSettingsToggle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,17 @@ enum CommandPaletteSettingsToggleCommands {
CmdClickMarkdownRouteSettings.notifyDidChange(notificationCenter: notificationCenter)
}
),
CommandPaletteSettingToggleDescriptor(
commandId: commandIdPrefix + "fileEditorWordWrap",
settingsKey: "fileEditor.wordWrap",
title: {
String(localized: "settings.app.fileEditorWordWrap", defaultValue: "File Editor Word Wrap")
},
sectionTitle: app,
keywords: ["fileEditor.wordWrap", "file", "editor", "word", "wrap", "soft", "reflow", "lines", "preview"],
defaultValue: FilePreviewWordWrapSettings.defaultEnabled,
defaultsKey: FilePreviewWordWrapSettings.key
),
CommandPaletteSettingToggleDescriptor(
commandId: commandIdPrefix + "iMessageMode",
settingsKey: "app.iMessageMode",
Expand Down
5 changes: 5 additions & 0 deletions Sources/KeyboardShortcutSettingsFileStore+Template.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ extension CmuxSettingsFileStore {
"maxWidth": Int(MarkdownMaxWidthSettings.defaultCSSPixels),
],
],
[
"fileEditor": [
"wordWrap": FilePreviewWordWrapSettings.defaultEnabled,
],
],
[
"shortcuts": [
"bindings": shortcutsBindings,
Expand Down
15 changes: 15 additions & 0 deletions Sources/KeyboardShortcutSettingsFileStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,9 @@ final class CmuxSettingsFileStore {
if let markdownSection = root["markdown"] as? [String: Any] {
parseMarkdownSection(markdownSection, sourcePath: sourcePath, snapshot: &snapshot)
}
if let fileEditorSection = root["fileEditor"] as? [String: Any] {
parseFileEditorSection(fileEditorSection, sourcePath: sourcePath, snapshot: &snapshot)
}
if let workspaceGroupsSection = root["workspaceGroups"] as? [String: Any] {
parseWorkspaceGroupsSection(workspaceGroupsSection, sourcePath: sourcePath, snapshot: &snapshot)
}
Expand Down Expand Up @@ -629,6 +632,18 @@ final class CmuxSettingsFileStore {
}
}

private func parseFileEditorSection(
_ section: [String: Any],
sourcePath: String,
snapshot: inout ResolvedSettingsSnapshot
) {
if let value = jsonBool(section["wordWrap"]) {
snapshot.managedUserDefaults[FilePreviewWordWrapSettings.key] = .bool(value)
} else if section.keys.contains("wordWrap") {
logInvalid("fileEditor.wordWrap", sourcePath: sourcePath)
}
}

private func parseSidebarSection(
_ section: [String: Any],
sourcePath: String,
Expand Down
4 changes: 3 additions & 1 deletion Sources/Panels/FilePreviewPanel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,7 @@ struct FilePreviewPanelView: View {

@State private var focusFlashOpacity = 0.0
@State private var focusFlashAnimationGeneration = 0
@AppStorage(FilePreviewWordWrapSettings.key) private var fileEditorWordWrap = FilePreviewWordWrapSettings.defaultEnabled

private var themeForegroundColor: NSColor {
appearance.foregroundColor
Expand Down Expand Up @@ -1354,7 +1355,8 @@ struct FilePreviewPanelView: View {
isVisibleInUI: isVisibleInUI,
themeBackgroundColor: contentBackgroundColor,
themeForegroundColor: themeForegroundColor,
drawsBackground: appearance.drawsContentBackground
drawsBackground: appearance.drawsContentBackground,
wordWrap: fileEditorWordWrap
)
case .pdf:
FilePreviewPDFView(
Expand Down
Loading
Loading