Repository navigation
iOS: multiple configurable toolbar rows - #6920
austinywang wants to merge 29 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughThe PR replaces the iOS terminal accessory toolbar's flat single-row model with a configurable multi-row model. ChangesiOS terminal toolbar rows
Sequence Diagram(s)sequenceDiagram
participant TerminalShortcutsSettingsView
participant TerminalAccessoryConfiguration
participant NotificationCenter
participant GhosttySurfaceView
participant TerminalInputTextView
TerminalShortcutsSettingsView->>TerminalAccessoryConfiguration: setRowCount / moveItem(toRow:) / reorderItems(limitedTo:)
TerminalAccessoryConfiguration->>TerminalAccessoryConfiguration: persist displayRows under v4 key
TerminalAccessoryConfiguration->>NotificationCenter: post didChangeNotification
NotificationCenter-->>GhosttySurfaceView: handleAccessoryConfigurationChanged()
GhosttySurfaceView->>TerminalInputTextView: dockedButtonRowHeight(rowCount:)
GhosttySurfaceView->>GhosttySurfaceView: relayout bottom dock and terminal viewport
NotificationCenter-->>TerminalInputTextView: handleAccessoryConfigurationChanged()
TerminalInputTextView->>TerminalInputTextView: populateAccessoryActions() per enabledItemRows
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 24 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (24 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
@codex review |
|
To use Codex here, create a Codex account and connect to github. |
|
✅ Action performedReview finished.
|
@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 241,260 of the 240,000 allowed lines of code this month. Reviews resume on 1 July 2026 (in 5 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
|
To use Codex here, create a Codex account and connect to github. |
|
@codex review |
|
To use Codex here, create a Codex account and connect to github. |
@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 241,260 of the 240,000 allowed lines of code this month. Reviews resume on 1 July 2026 (in 5 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
|
✅ Action performedReview finished.
|
|
@codex review |
@austinywang I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 241,260 of the 240,000 allowed lines of code this month. Reviews resume on 1 July 2026 (in 5 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
|
To use Codex here, create a Codex account and connect to github. |
|
✅ Action performedReview finished.
|
|
To use Codex here, create a Codex account and connect to github. |
Greptile SummaryThis PR adds multi-row iOS terminal toolbar support: configurable 1–3 rows persisted in a new v4
Confidence Score: 5/5Safe to merge — all layout, persistence, and migration paths look correct and are backed by new tests. The migration from v3 flat order to v4 rows is correct and idempotent: v4 keys take precedence on every subsequent launch, and the reducer's load path normalises any edge cases (empty rows, overflow, forward-compat append). Height maths are centralised in TerminalAccessoryDockMetrics and shared between GhosttySurfaceView and TerminalInputTextView via the same computed path. The notification guard in GhosttySurfaceView correctly short-circuits layout work when only content (not height) changes. All new reducer behaviour is pinned by targeted unit tests. Concerns flagged in prior review rounds (dead guard branch, integer-index ForEach identity, cross-row agentChat reorder) are pre-existing design trade-offs that the author is aware of. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User changes row count / reorders / toggles] --> B[TerminalAccessoryConfiguration.persistAndNotify]
B --> C[NotificationCenter post didChangeNotification]
C --> D[GhosttySurfaceView.handleAccessoryConfigurationChanged]
C --> E[TerminalInputTextView.handleAccessoryConfigurationChanged]
D --> F{updateDockedToolbarVisibility\nheight or visibility changed?}
F -- No change --> G[return — no layout work]
F -- Changed --> H[layoutRenderedTerminalForCurrentViewport\nsetNeedsGeometrySync\nsetNeedsLayout]
H --> I[layoutBottomDock\nreposition toolbar frame]
I --> J[layoutZoomOverlay]
E --> K[populateAccessoryActions\nrebuild per-row scroll views]
K --> L[updateAccessoryRowsHeight\nupdate constraint constant]
K --> M[applyModifierPresentation]
M --> N[setNeedsLayout / layoutIfNeeded]
subgraph Persistence
P1[cmux.terminal.toolbar.rows.v4]
P2[cmux.terminal.toolbar.enabled.v4]
end
B --> Persistence
subgraph Migration
V3[v3 order key] --> MIG[reducer.load savedRows=nil]
V2[v2 key] --> MIG
V1[v1 int keys] --> MIG
MIG --> WRITE[persist under v4 keys]
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[User changes row count / reorders / toggles] --> B[TerminalAccessoryConfiguration.persistAndNotify]
B --> C[NotificationCenter post didChangeNotification]
C --> D[GhosttySurfaceView.handleAccessoryConfigurationChanged]
C --> E[TerminalInputTextView.handleAccessoryConfigurationChanged]
D --> F{updateDockedToolbarVisibility\nheight or visibility changed?}
F -- No change --> G[return — no layout work]
F -- Changed --> H[layoutRenderedTerminalForCurrentViewport\nsetNeedsGeometrySync\nsetNeedsLayout]
H --> I[layoutBottomDock\nreposition toolbar frame]
I --> J[layoutZoomOverlay]
E --> K[populateAccessoryActions\nrebuild per-row scroll views]
K --> L[updateAccessoryRowsHeight\nupdate constraint constant]
K --> M[applyModifierPresentation]
M --> N[setNeedsLayout / layoutIfNeeded]
subgraph Persistence
P1[cmux.terminal.toolbar.rows.v4]
P2[cmux.terminal.toolbar.enabled.v4]
end
B --> Persistence
subgraph Migration
V3[v3 order key] --> MIG[reducer.load savedRows=nil]
V2[v2 key] --> MIG
V1[v1 int keys] --> MIG
MIG --> WRITE[persist under v4 keys]
end
Reviews (27): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile |
Greptile SummaryThis PR extends the iOS terminal toolbar from a single configurable row to 1–3 user-configurable rows, each scrolling independently. It introduces a v4 UserDefaults schema (
Confidence Score: 4/5The change is safe to merge; the migration path is one-way and well-guarded, the notification chain is @MainActor-posted so all UIKit layout calls stay on the main thread, and the reducer is exercised by six new deterministic unit tests. The overall implementation is solid: the v4 persistence keys are disjoint from v3, the reducer is pure and tested, and the notification-driven relayout in both TerminalInputTextView and GhosttySurfaceView follows the existing pattern correctly. The two flagged items — integer-index ForEach identity for row sections and duplicated split logic — are non-blocking quality concerns rather than correctness bugs. TerminalShortcutsSettingsView.swift (ForEach index identity) and TerminalAccessoryLayoutReducer.swift (duplicated split helper). Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Settings as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant Defaults as UserDefaults
participant NC as NotificationCenter
participant TITV as TerminalInputTextView
participant GSV as GhosttySurfaceView
Settings->>Config: setRowCount(_:) / moveItem(_:toRow:) / moveItems(from:to:inRow:)
Config->>Reducer: setRowCount / move(inRow:) / move(toRow:)
Reducer-->>Config: Layout(rows:enabled:)
Config->>Defaults: persist rows.v4 + enabled.v4
Config->>NC: post didChangeNotification
NC-->>TITV: handleAccessoryConfigurationChanged()
TITV->>TITV: populateAccessoryActions() → updateAccessoryRowsHeight()
NC-->>GSV: handleAccessoryConfigurationChanged()
GSV->>GSV: updateDockedToolbarVisibility() + layoutBottomDock() + setNeedsGeometrySync()
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Settings as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant Defaults as UserDefaults
participant NC as NotificationCenter
participant TITV as TerminalInputTextView
participant GSV as GhosttySurfaceView
Settings->>Config: setRowCount(_:) / moveItem(_:toRow:) / moveItems(from:to:inRow:)
Config->>Reducer: setRowCount / move(inRow:) / move(toRow:)
Reducer-->>Config: Layout(rows:enabled:)
Config->>Defaults: persist rows.v4 + enabled.v4
Config->>NC: post didChangeNotification
NC-->>TITV: handleAccessoryConfigurationChanged()
TITV->>TITV: populateAccessoryActions() → updateAccessoryRowsHeight()
NC-->>GSV: handleAccessoryConfigurationChanged()
GSV->>GSV: updateDockedToolbarVisibility() + layoutBottomDock() + setNeedsGeometrySync()
|
Greptile SummaryThis PR extends the iOS terminal toolbar to support 1–3 configurable shortcut rows, persisting them as a new v4 schema alongside a v1/v2/v3 migration path. A
Confidence Score: 4/5The change is safe to merge. The core reducer logic is pure and testable, the migration paths cover v1–v3 correctly, and all new user-facing strings are translated in both supported locales. One helper ( TerminalInputTextView.swift — the Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User as User (Settings)
participant TV as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant ND as NotificationCenter
participant GSV as GhosttySurfaceView
participant TIV as TerminalInputTextView
User->>TV: Stepper: increment rowCount
TV->>Config: setRowCount(newCount)
Config->>Reducer: setRowCount(_:in:)
Reducer-->>Config: Layout(rows: [...], enabled: ...)
Config->>Config: persist() → UserDefaults v4 keys
Config->>ND: post(didChangeNotification)
ND-->>GSV: handleAccessoryConfigurationChanged()
GSV->>GSV: updateDockedToolbarVisibility()
GSV->>GSV: layoutBottomDock() [reads persistentToolbarHeight → rowCount]
GSV->>GSV: layoutRenderedTerminalForCurrentViewport()
GSV->>GSV: setNeedsGeometrySync() + setNeedsLayout()
ND-->>TIV: handleAccessoryConfigurationChanged()
TIV->>TIV: populateAccessoryActions() [rebuilds row stack views]
TIV->>TIV: updateAccessoryRowsHeight(rowCount)
TIV->>TIV: applyModifierPresentation()
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User as User (Settings)
participant TV as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant ND as NotificationCenter
participant GSV as GhosttySurfaceView
participant TIV as TerminalInputTextView
User->>TV: Stepper: increment rowCount
TV->>Config: setRowCount(newCount)
Config->>Reducer: setRowCount(_:in:)
Reducer-->>Config: Layout(rows: [...], enabled: ...)
Config->>Config: persist() → UserDefaults v4 keys
Config->>ND: post(didChangeNotification)
ND-->>GSV: handleAccessoryConfigurationChanged()
GSV->>GSV: updateDockedToolbarVisibility()
GSV->>GSV: layoutBottomDock() [reads persistentToolbarHeight → rowCount]
GSV->>GSV: layoutRenderedTerminalForCurrentViewport()
GSV->>GSV: setNeedsGeometrySync() + setNeedsLayout()
ND-->>TIV: handleAccessoryConfigurationChanged()
TIV->>TIV: populateAccessoryActions() [rebuilds row stack views]
TIV->>TIV: updateAccessoryRowsHeight(rowCount)
TIV->>TIV: applyModifierPresentation()
|
Greptile SummaryThis PR adds support for 1–3 configurable horizontal toolbar rows on iOS, stacking them above the keyboard so more shortcuts stay visible without horizontal scrolling. It introduces a v4 persistence schema (rows + enabled), auto-migrates all legacy flat layouts into a single row, and wires live layout updates through
Confidence Score: 4/5Safe to merge; the multi-row feature, migration path, and live-layout wiring are well-implemented and tested. The reducer logic is pure and fully tested, the v4 migration correctly handles all legacy schema versions, and the UIKit layout updates route through the same notification channel that already drives toolbar rebuilds. The two findings are both in the settings view: a now-unreachable terminal-scope branch in the flat-move helper, and positional integer IDs on the row-section ForEach that cause full section reconstruction on row-count changes. Neither affects correctness of the feature. TerminalShortcutsSettingsView.swift — the dead terminal-scope branch in moveDisplayedItems(from:to:) and the integer-index row section identity warrant a second look. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User as User (Settings)
participant View as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant Defaults as UserDefaults
participant NC as NotificationCenter
participant TV as TerminalInputTextView
participant SV as GhosttySurfaceView
User->>View: tap stepper (+1 row)
View->>Config: setRowCount(newCount)
Config->>Reducer: setRowCount(_:in:)
Reducer-->>Config: Layout(rows: [...], enabled: ...)
Config->>Config: apply(layout) — update displayRows
Config->>Defaults: persist rows.v4 + enabled.v4
Config->>NC: post(didChangeNotification)
NC->>TV: handleAccessoryConfigurationChanged()
TV->>TV: populateAccessoryActions() — rebuild row stack
TV->>TV: updateAccessoryRowsHeight(rowCount:)
NC->>SV: handleAccessoryConfigurationChanged()
SV->>SV: updateDockedToolbarVisibility()
Note over SV: persistentToolbarHeight reads shared.rowCount
SV->>SV: layoutBottomDock() + layoutRenderedTerminalForCurrentViewport()
SV->>SV: setNeedsGeometrySync() + setNeedsLayout()
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User as User (Settings)
participant View as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant Defaults as UserDefaults
participant NC as NotificationCenter
participant TV as TerminalInputTextView
participant SV as GhosttySurfaceView
User->>View: tap stepper (+1 row)
View->>Config: setRowCount(newCount)
Config->>Reducer: setRowCount(_:in:)
Reducer-->>Config: Layout(rows: [...], enabled: ...)
Config->>Config: apply(layout) — update displayRows
Config->>Defaults: persist rows.v4 + enabled.v4
Config->>NC: post(didChangeNotification)
NC->>TV: handleAccessoryConfigurationChanged()
TV->>TV: populateAccessoryActions() — rebuild row stack
TV->>TV: updateAccessoryRowsHeight(rowCount:)
NC->>SV: handleAccessoryConfigurationChanged()
SV->>SV: updateDockedToolbarVisibility()
Note over SV: persistentToolbarHeight reads shared.rowCount
SV->>SV: layoutBottomDock() + layoutRenderedTerminalForCurrentViewport()
SV->>SV: setNeedsGeometrySync() + setNeedsLayout()
Reviews (4): Last reviewed commit: "Merge origin/main" | Re-trigger Greptile |
Greptile SummaryAdds support for 1–3 configurable horizontal toolbar rows on iOS, migrating existing flat layouts (v3/v2/v1) into a single row under the new v4
Confidence Score: 4/5The change is well-scoped to the iOS toolbar path and carries correct migration, height propagation, and live-update wiring. The single finding is a latent maintenance trap rather than a current defect. The reducer, migration, and notification-driven layout refresh are all correctly implemented and tested. The only concern is a dead Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalShortcutsSettingsView.swift — dead terminal guard in Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant SettingsView as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant NC as NotificationCenter
participant TextInput as TerminalInputTextView
participant Surface as GhosttySurfaceView
User->>SettingsView: Adjust row stepper
SettingsView->>Config: setRowCount(n)
Config->>Reducer: setRowCount(n, in: layout)
Reducer-->>Config: Layout(rows: merged/expanded)
Config->>Config: apply + persist (v4 keys)
Config->>NC: post didChangeNotification
NC->>TextInput: handleAccessoryConfigurationChanged
TextInput->>TextInput: populateAccessoryActions()
TextInput->>TextInput: updateAccessoryRowsHeight(rowCount)
TextInput->>TextInput: setNeedsLayout
NC->>Surface: handleAccessoryConfigurationChanged
Surface->>Surface: updateDockedToolbarVisibility()
Note right of Surface: persistentToolbarHeight now reads new rowCount
Surface->>Surface: layoutBottomDock()
Surface->>Surface: layoutRenderedTerminalForCurrentViewport()
Surface->>Surface: setNeedsGeometrySync + setNeedsLayout
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant SettingsView as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant NC as NotificationCenter
participant TextInput as TerminalInputTextView
participant Surface as GhosttySurfaceView
User->>SettingsView: Adjust row stepper
SettingsView->>Config: setRowCount(n)
Config->>Reducer: setRowCount(n, in: layout)
Reducer-->>Config: Layout(rows: merged/expanded)
Config->>Config: apply + persist (v4 keys)
Config->>NC: post didChangeNotification
NC->>TextInput: handleAccessoryConfigurationChanged
TextInput->>TextInput: populateAccessoryActions()
TextInput->>TextInput: updateAccessoryRowsHeight(rowCount)
TextInput->>TextInput: setNeedsLayout
NC->>Surface: handleAccessoryConfigurationChanged
Surface->>Surface: updateDockedToolbarVisibility()
Note right of Surface: persistentToolbarHeight now reads new rowCount
Surface->>Surface: layoutBottomDock()
Surface->>Surface: layoutRenderedTerminalForCurrentViewport()
Surface->>Surface: setNeedsGeometrySync + setNeedsLayout
|
Greptile SummaryMigrates the iOS terminal toolbar from a single flat configurable row to 1–3 user-configurable stacked rows, persisted under a new v4 schema, with automatic migration of v1–v3 flat layouts into a single row. The terminal grid and dock geometry are updated live whenever row count changes via a
Confidence Score: 4/5Safe to merge; the change is well-contained, migration logic is correct, and UIKit layout paths are updated consistently. The core row-aware reducer, v4 migration, and UIKit layout updates are all correct and well-tested. The one behavioral concern is that the agentChat scope flat-reorder path calls reorderItems, which now uses a positional split to reassign rows — this can silently shift terminal-only items between rows when a user with a multi-row terminal config reorders items in the agentChat settings view. This only matters for users who have configured more than one toolbar row, which is a new feature not yet in production, so the real-world risk is low for the initial release. Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/TerminalAccessoryConfiguration.swift — specifically the reorderItems method and its interaction with the agentChat flat-reorder path Important Files Changed
|
Greptile SummaryThis PR migrates the iOS terminal toolbar from a single flat row to 1–3 user-configurable horizontal rows, each scrolling independently. The terminal grid height reservation is updated live when row count changes, and existing flat layouts are migrated to a single-row v4 schema on first launch.
Confidence Score: 4/5Safe to merge. Migration logic is sound, tests cover key reducer operations, localization is complete for both supported locales, and UIKit layout changes correctly update both the constraint constant and hosting frame. The v4 schema migration is carefully gated and runs at most once. The row-aware reducer is pure and well-tested. Two minor issues worth follow-up: the new GhosttySurfaceView notification handler fires full geometry syncs on every configuration change (not only row-count changes), and the onMove offset forwarding relies on an undocumented invariant that terminal scope includes all items. GhosttySurfaceView.swift (unconditional geometry sync in the new notification handler) and TerminalShortcutsSettingsView.swift (onMove offset forwarding assumption). Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant Settings as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant InputTV as TerminalInputTextView
participant Surface as GhosttySurfaceView
User->>Settings: change row count (Stepper)
Settings->>Config: setRowCount(_:)
Config->>Reducer: setRowCount(_:in:)
Reducer-->>Config: Layout(rows:enabled:)
Config->>Config: apply + persist (v4 keys)
Config->>Config: post didChangeNotification
Config-->>InputTV: handleAccessoryConfigurationChanged
InputTV->>InputTV: populateAccessoryActions()
InputTV->>InputTV: updateAccessoryRowsHeight(rowCount:)
Config-->>Surface: handleAccessoryConfigurationChanged
Surface->>Surface: updateDockedToolbarVisibility()
Surface->>Surface: layoutBottomDock()
Surface->>Surface: layoutRenderedTerminalForCurrentViewport()
Surface->>Surface: setNeedsGeometrySync()
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant Settings as TerminalShortcutsSettingsView
participant Config as TerminalAccessoryConfiguration
participant Reducer as TerminalAccessoryLayoutReducer
participant InputTV as TerminalInputTextView
participant Surface as GhosttySurfaceView
User->>Settings: change row count (Stepper)
Settings->>Config: setRowCount(_:)
Config->>Reducer: setRowCount(_:in:)
Reducer-->>Config: Layout(rows:enabled:)
Config->>Config: apply + persist (v4 keys)
Config->>Config: post didChangeNotification
Config-->>InputTV: handleAccessoryConfigurationChanged
InputTV->>InputTV: populateAccessoryActions()
InputTV->>InputTV: updateAccessoryRowsHeight(rowCount:)
Config-->>Surface: handleAccessoryConfigurationChanged
Surface->>Surface: updateDockedToolbarVisibility()
Surface->>Surface: layoutBottomDock()
Surface->>Surface: layoutRenderedTerminalForCurrentViewport()
Surface->>Surface: setNeedsGeometrySync()
|
…le-configurable-toolbar-rows # Conflicts: # .github/swift-file-length-budget.tsv
The agent-chat Shared Shortcuts flat list reorders scoped items strictly within their current terminal rows. A flat reorder cannot move one item across a fixed-length row boundary without changing row lengths or cascading another item into a different row (the silent row scramble previously fixed for this path), so cross-row moves are intentionally routed through the per-item row picker. Add a call-site comment so the deliberate snap-back behavior is clear to future readers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Conflicts resolved: - Packages/iOS/CmuxMobileTerminal/Sources/CmuxMobileTerminal/GhosttySurfaceView.swift: Adopt origin/main's TerminalViewportCoordinator refactor (bottomDockFrames now delegates to viewportSnapshot). Preserve the multiple-configurable-toolbar-rows feature by feeding the instance persistentToolbarHeight (driven by rowCount) into the snapshot's toolbarFrameHeight, replacing origin/main's deleted single-row static Self.persistentToolbarHeight. The coordinator's toolbar-frame math is a faithful generalization of the prior inline computation, so behavior is preserved. - .github/swift-file-length-budget.tsv: regenerated via scripts/swift_file_length_budget.py --write-budget (not hand-edited).
Second sync with origin/main (6 commits, incl. #7116 iOS toolbar glass/lifecycle). GhosttySurfaceView.swift auto-merged cleanly on top of the prior coordinator-based resolution; multi-row invariants verified intact (instance persistentToolbarHeight flows into the viewport snapshot's toolbarFrameHeight; no stale Self. static reference). Only conflict was .github/swift-file-length-budget.tsv, regenerated via scripts/swift_file_length_budget.py --write-budget (not hand-edited).
autoreview flagged that increasing the iOS toolbar row count appends empty
rows at the bottom, leaving existing shortcuts on the upper row. This is
intentional. Rows are numbered top-to-bottom ("Row 1"..."Row N") in both
the settings UI (Row sections + per-item "Move to Row" picker) and the
toolbar (Row 1 at top, Row N nearest the keyboard with the fixed
HIDE/customize controls). Growth appends new empty rows AFTER the existing
ones so each existing row keeps its number and position rather than being
renumbered on every count change; users populate the new rows explicitly
via the row picker and within-row drag.
Prepending / bottom-anchoring instead would push the user's existing
shortcuts to a higher-numbered row on every increase, contradicting the
stable "Row 1...N" numbering, and would break the behavior pinned by
TerminalAccessoryLayoutReducerTests (setRowCount grow -> [[...],[],[]]).
Doc-only change: expands the setRowCount doc comment and adds an inline
note at the append site. No behavior, API, or test change.
…le-configurable-toolbar-rows # Conflicts: # .github/swift-file-length-budget.tsv
…le-configurable-toolbar-rows # Conflicts: # .github/swift-file-length-budget.tsv
…le-configurable-toolbar-rows
…le-configurable-toolbar-rows
…le-configurable-toolbar-rows
…le-configurable-toolbar-rows # Conflicts: # .github/swift-file-length-budget.tsv
Fixes #6090
Summary
Validation
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Adds 1–3 configurable iOS toolbar rows with per‑row horizontal scroll and a row‑count–aware dock height; the terminal and dock reflow instantly on any row or item change. Migrates to a v4 row schema that preserves existing setups and centralizes height/spacing in
TerminalAccessoryDockMetrics.New Features
GhosttySurfaceViewobservesTerminalAccessoryConfiguration.didChangeNotificationand updates visibility/height immediately.Bug Fixes
Written for commit f900bc8. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes