Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
50988b4
test: cover sidebar focus yielding tab chrome
lawrencecchen Sep 15, 2026
ecec881
fix: de-emphasize Bonsplit chrome when sidebar owns focus
lawrencecchen Sep 15, 2026
7ab53aa
fix: remove retired legacy transport timeout argument
lawrencecchen Sep 16, 2026
d761940
feat: outline the active right sidebar tab while focused
lawrencecchen Sep 16, 2026
d523851
feat: add sidebar focus style prototypes for dogfood
lawrencecchen Sep 16, 2026
4c4eafa
fix: match solid focus text to selected workspace contrast
lawrencecchen Sep 16, 2026
34c652b
fix: locate Rust tools in detached Xcode build phases
lawrencecchen Sep 16, 2026
08775f7
fix: preserve explicit build tool search paths
lawrencecchen Sep 16, 2026
080d636
feat: add region-level sidebar focus prototypes
lawrencecchen Sep 16, 2026
9cf6237
feat: outline the entire focused right sidebar
lawrencecchen Sep 17, 2026
ded1db7
fix: inset sidebar focus boundary from native window corners
lawrencecchen Sep 17, 2026
b6c08aa
fix: remove extra padding from right sidebar focus boundary
lawrencecchen Sep 17, 2026
1280278
fix: keep flush focus curves inside the window mask
lawrencecchen Sep 17, 2026
64f2af2
Merge remote-tracking branch 'origin/main' into feat-sidebar-focus-ta…
lawrencecchen Sep 29, 2026
51b83ac
refactor: derive panel focus ring from the shared main-content focus …
lawrencecchen Sep 29, 2026
e1b125a
Add a placement setting for a persistent right sidebar button
lawrencecchen Sep 29, 2026
90629bb
Add CmuxFileTree package for the Files sidebar model
lawrencecchen Sep 29, 2026
3a66f64
Count rightSidebar as a settings section in the skill path test
lawrencecchen Sep 29, 2026
fe176c9
fix: draw the sidebar focus border with the cmux accent environment
lawrencecchen Sep 29, 2026
7f37fe4
Add CmuxFileSearch package for project-wide search
lawrencecchen Sep 29, 2026
c181411
Add Settings-backed Files shortcuts for Quick Look, rename, hidden fi…
lawrencecchen Sep 29, 2026
b231fd7
Rewrite the Files sidebar on the incremental CmuxFileTree engine
lawrencecchen Sep 29, 2026
1617e72
Test the Files tree store, outline diffs and a 50k-row folder
lawrencecchen Sep 29, 2026
1aabe6a
Invalidate AppKit's cached children for folders updated while hidden
lawrencecchen Sep 29, 2026
5e6b589
Fix process-group test race and add result dismissal
lawrencecchen Sep 29, 2026
b3562c1
Let file previews select a pending line and column
lawrencecchen Sep 29, 2026
1f6f487
Rebuild Find as a streaming, grouped VS Code style search
lawrencecchen Sep 29, 2026
3b26771
Seed Find with the selection on Cmd+Shift+F
lawrencecchen Sep 29, 2026
3a49e1d
List CmuxFileSearch in the workspace package group
lawrencecchen Sep 29, 2026
e84232d
Merge remote-tracking branch 'origin/main' into feat-files-finder-rew…
lawrencecchen Sep 29, 2026
c618f4c
Localize Find strings in all nine macOS locales
lawrencecchen Sep 29, 2026
ba131b1
Keep focus in Find while F4 steps through local matches
lawrencecchen Sep 29, 2026
d13f8e8
Fix store setter access and the bare Space restore test
lawrencecchen Sep 29, 2026
b7c6c92
Isolate Find session factories to the main actor
lawrencecchen Sep 29, 2026
252e3b1
Merge remote-tracking branch 'origin/feat-sidebar-focus-tab-state' in…
lawrencecchen Sep 29, 2026
7f00ce4
Merge remote-tracking branch 'origin/feat-right-sidebar-toggle-placem…
lawrencecchen Sep 29, 2026
4f0819c
Show right sidebar focus by tinting the selected mode icon
lawrencecchen Sep 29, 2026
ef9bf41
Import CmuxFoundation for the Files style metrics
lawrencecchen Sep 29, 2026
003f01e
Hide Find results while no folder is open
lawrencecchen Sep 29, 2026
a47507a
fix(tests): compile cmuxTests again after #15116 and #15550
teamleaderleo Sep 29, 2026
57af618
Isolate the Find panel test fixture to the main actor
lawrencecchen Sep 29, 2026
ff51a7f
Keep the Files cell configure call source compatible
lawrencecchen Sep 29, 2026
64fcf61
test: disable six app-host tests that fail on main (#15564)
teamleaderleo Sep 29, 2026
c6b8bdf
Merge remote-tracking branch 'origin/main' into feat-files-finder-rew…
lawrencecchen Sep 29, 2026
d330a81
Show Find results in a flat table instead of an outline
lawrencecchen Sep 29, 2026
15f9770
Merge remote-tracking branch 'origin/main' into feat-right-sidebar-ov…
lawrencecchen Sep 29, 2026
2626d77
Merge remote-tracking branch 'origin/feat-files-finder-rewrite' into …
lawrencecchen Sep 29, 2026
54d9a85
Merge #15561 (cmuxTests compile fix on main) so this branch's test ta…
lawrencecchen Sep 29, 2026
acfdc59
Draw the Files selection with the cmux accent and redraw on accent ch…
lawrencecchen Sep 29, 2026
9747fca
Merge remote-tracking branch 'origin/main' into feat-find-vscode-quality
lawrencecchen Sep 29, 2026
b4ef9d3
Draw Find accents with the cmux accent color
lawrencecchen Sep 29, 2026
3e9020d
Drop redundant internal(set) on FileExplorerStore properties
lawrencecchen Sep 29, 2026
33e3ad6
Merge remote-tracking branch 'origin/feat-find-vscode-quality' into f…
lawrencecchen Sep 29, 2026
5fb491e
Merge remote-tracking branch 'origin/main' into feat-right-sidebar-ov…
lawrencecchen Sep 29, 2026
15c931d
Merge remote-tracking branch 'origin/main' into feat-right-sidebar-ov…
lawrencecchen Sep 29, 2026
5677f7b
Replace CmuxFileSearch namespace enums with receiver extensions and v…
lawrencecchen Sep 30, 2026
50b865e
Drive and read Find from the socket and CLI
lawrencecchen Sep 30, 2026
7632fa8
Merge remote-tracking branch 'origin/main' into feat-right-sidebar-ov…
lawrencecchen Sep 30, 2026
ea1265f
Let the Find query field shrink instead of widening a narrow Files panel
lawrencecchen Oct 1, 2026
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
47 changes: 44 additions & 3 deletions CLI/cmux.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20780,6 +20780,11 @@ struct CMUXCLI {
cmux right-sidebar set find
cmux right-sidebar set custom panel-info
cmux right-sidebar mode
""") + "\n\n" + String(localized: "cli.rightSidebar.usage.find", defaultValue: """
Find:
set find --query <text> [--regex] [--case-sensitive] [--whole-word] [--no-focus]
Search Find for <text> as if typed into its field
find-status Print the Find query, phase, results and files as JSON
""")
case "sidebar":
return String(localized: "cli.sidebar.usage", defaultValue: """
Expand Down Expand Up @@ -21269,6 +21274,8 @@ struct CMUXCLI {
let workspace: String?
let window: String?
let noFocus: Bool
/// `--query`, `--regex`, `--case-sensitive`, `--whole-word` for Find.
var findOptions: [String] = []
}

private func forwardRightSidebarCommand(
Expand All @@ -21293,7 +21300,8 @@ struct CMUXCLI {
.map(shellQuote)
.joined(separator: " ")
let response = try sendV1Command(command, client: client)
if parsed.positional.first?.lowercased() == "mode" {
let action = parsed.positional.first?.lowercased()
if action == "mode" || action == "find-status" || action == "find_status" {
print(response)
}
}
Expand Down Expand Up @@ -21478,11 +21486,21 @@ struct CMUXCLI {
var workspace: String?
var window: String?
var noFocus = false
var findOptions: [String] = []
var index = 0

while index < args.count {
let arg = args[index]
switch arg {
case "--query":
guard index + 1 < args.count else {
throw CLIError(message: String(localized: "cli.rightSidebar.error.queryRequiresValue", defaultValue: "right-sidebar: --query requires text"))
}
findOptions.append("--query=\(args[index + 1])")
index += 2
case "--regex", "--case-sensitive", "--whole-word":
findOptions.append(arg)
index += 1
case "--workspace":
guard index + 1 < args.count else {
throw CLIError(message: String(localized: "cli.rightSidebar.error.workspaceRequiresValue", defaultValue: "right-sidebar: --workspace requires an id"))
Expand All @@ -21499,7 +21517,10 @@ struct CMUXCLI {
noFocus = true
index += 1
default:
if arg.hasPrefix("--workspace=") {
if arg.hasPrefix("--query=") {
findOptions.append(arg)
index += 1
} else if arg.hasPrefix("--workspace=") {
workspace = String(arg.dropFirst("--workspace=".count))
index += 1
} else if arg.hasPrefix("--window=") {
Expand All @@ -21517,14 +21538,34 @@ struct CMUXCLI {
positional: positional,
workspace: workspace,
window: window,
noFocus: noFocus
noFocus: noFocus,
findOptions: findOptions
)
}
private func rightSidebarSocketArguments(from parsed: RightSidebarCLIArguments) throws -> [String] {
guard let action = parsed.positional.first?.lowercased() else {
throw CLIError(message: String(localized: "cli.rightSidebar.error.missingCommand", defaultValue: "right-sidebar requires a subcommand"))
}

if action == "find-status" || action == "find_status" {
guard parsed.positional.count == 1, !parsed.noFocus, parsed.findOptions.isEmpty else {
throw CLIError(message: String(localized: "cli.rightSidebar.error.unexpectedArguments", defaultValue: "right-sidebar \(action) received unexpected arguments"))
}
return ["find_status"]
}
if !parsed.findOptions.isEmpty {
let modeArgument = action == "set" && parsed.positional.count == 2 ? parsed.positional[1] : action
guard normalizedRightSidebarCLIArgument(modeArgument) == "find",
parsed.positional.count == (action == "set" ? 2 : 1),
parsed.findOptions.contains(where: { $0.hasPrefix("--query=") }) else {
throw CLIError(message: String(localized: "cli.rightSidebar.error.findOptionsRequireFind", defaultValue: "right-sidebar: --query, --regex, --case-sensitive and --whole-word need 'find' or 'set find' and a --query"))
}
guard action == "set" || !parsed.noFocus else {
throw CLIError(message: String(localized: "cli.rightSidebar.error.noFocusOnlySet", defaultValue: "right-sidebar: --no-focus is only valid with set"))
}
return ["set", "find"] + parsed.findOptions + (parsed.noFocus ? ["--no-focus"] : [])
}

switch action {
case "toggle", "show", "hide", "focus", "mode":
guard parsed.positional.count == 1 else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,17 @@ extension ControlCommandCoordinator {
"visible": .bool(visible),
"mode": .string(modeRawValue),
]))
case .findStatus(let status):
return ControlResponseEncoder().encode(.object([
"query": .string(status.query),
"regex": .bool(status.isRegex),
"case_sensitive": .bool(status.isCaseSensitive),
"whole_word": .bool(status.matchesWholeWord),
"phase": .string(status.phase),
"results": .int(Int64(status.results)),
"files": .int(Int64(status.files)),
"message": status.message.map { .string($0) } ?? .null,
]))
case .failure(let message):
return message
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,44 @@ public enum ControlSidebarRightSidebarResolution: Sendable, Equatable {
case ok
/// A `get`-style command returned sidebar state to encode.
case state(visible: Bool, modeRawValue: String)
/// `find_status` returned the Find query and totals to encode.
case findStatus(ControlSidebarFindStatus)
/// A parse or apply failure; `message` is the full legacy reply line
/// (localized app-side where the original was localized).
case failure(message: String)
}

/// The Find state `right_sidebar find_status` reports, so a script can wait
/// for a search and assert its totals.
public struct ControlSidebarFindStatus: Sendable, Equatable {
public let query: String
public let isRegex: Bool
public let isCaseSensitive: Bool
public let matchesWholeWord: Bool
/// `idle`, `searching`, `completed`, `limited` or `failed`.
public let phase: String
public let results: Int
public let files: Int
/// The status line as shown, or nil when hidden.
public let message: String?

public init(
query: String,
isRegex: Bool,
isCaseSensitive: Bool,
matchesWholeWord: Bool,
phase: String,
results: Int,
files: Int,
message: String?
) {
self.query = query
self.isRegex = isRegex
self.isCaseSensitive = isCaseSensitive
self.matchesWholeWord = matchesWholeWord
self.phase = phase
self.results = results
self.files = files
self.message = message
}
}
35 changes: 35 additions & 0 deletions Packages/macOS/CmuxFileSearch/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// swift-tools-version: 6.0

import PackageDescription

let package = Package(
name: "CmuxFileSearch",
platforms: [
.macOS(.v14),
],
products: [
.library(
name: "CmuxFileSearch",
targets: ["CmuxFileSearch"]
),
],
targets: [
.target(
name: "CmuxFileSearch",
swiftSettings: [
.swiftLanguageMode(.v6),
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("InternalImportsByDefault"),
]
),
.testTarget(
name: "CmuxFileSearchTests",
dependencies: ["CmuxFileSearch"],
swiftSettings: [
.swiftLanguageMode(.v6),
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("InternalImportsByDefault"),
]
),
]
)
27 changes: 27 additions & 0 deletions Packages/macOS/CmuxFileSearch/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# CmuxFileSearch

Project-wide search for the right sidebar's Find mode, independent of AppKit.

- `FileSearchQuery` holds the VS Code style options (Match Case, Match Whole
Word, Use Regular Expression, include and exclude globs, Use Exclude Settings
and Ignore Files). `FileSearchQuery.ripgrepArguments(rootPath:)` maps it to one `rg --json` argument
vector that runs unchanged locally, over SSH and on a Cloud VM.
- `RipgrepJSONLineParser` and `RipgrepStreamDecoder` turn ripgrep output into
one `FileSearchMatch` per submatch, with UTF-16 columns and a bounded preview
around the match. Invalid UTF-8 (`"bytes"` payloads) is decoded consistently.
- `FileSearchProcess` spawns the command with `posix_spawn` in its own process
group, so arguments are not Unicode-normalized and cancellation also stops
processes the command started.
- `FileSearchEngine` debounces requests with an injected `Clock`, cancels
superseded searches, and applies streamed batches to `FileSearchResultTree`
at most once per frame. `FileSearchRowList` flattens the tree into table
rows: `NSOutlineView` expansion is linear in the rows below each expanded
item, which measured several seconds for 100,000 streamed matches, while
appending table rows costs microseconds.

```bash
swift test --package-path Packages/macOS/CmuxFileSearch
```

`FileSearchPerformanceTests` prints decode and tree timings for 100,000
matches. The ripgrep end-to-end suite runs only when `rg` is installed.
Loading