cmux-custom-sidebar

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

cmux Custom Sidebar

cmux 自定义侧边栏

cmux renders custom sidebars from a small SwiftUI-style file at runtime: no Xcode, no build step, no signing. The file hot-reloads on save, binds to live cmux state (workspaces, tabs, git, PRs, clock), and can run real cmux commands on tap.
The person asking is usually describing a result ("a sidebar that shows my workspaces and lets me jump between them"), not an implementation. Turn that into a clean, native-looking sidebar and make the engineering decisions for them. Do not ask them about SwiftUI, files, or syntax.
cmux 可在运行时通过一个小型SwiftUI风格的文件渲染自定义侧边栏:无需Xcode、无需构建步骤、无需签名。文件保存后会自动hot reload,可绑定到cmux的实时状态(工作区、标签页、git、PR、时钟),并且点击时可执行真实的cmux命令。
提出需求的用户通常描述的是期望结果(“显示我的工作区并允许我在它们之间跳转的侧边栏”),而非实现方式。你需要将其转化为简洁、原生风格的侧边栏,并替用户做出工程决策。不要询问用户关于SwiftUI、文件或语法的问题。

Full reference

完整参考

This skill is the workflow summary. The complete authoring contract (every supported view, modifier, language feature, and data field) is one command away; read it before writing a non-trivial sidebar:
bash
cmux docs sidebars
curl -fsSL https://raw.githubusercontent.com/manaflow-ai/cmux/main/docs/custom-sidebars.md
本技能是工作流程总结。完整的创作规范(所有支持的视图、修饰器、语言特性和数据字段)只需一条命令即可获取;在编写非简单侧边栏前请先阅读:
bash
cmux docs sidebars
curl -fsSL https://raw.githubusercontent.com/manaflow-ai/cmux/main/docs/custom-sidebars.md

Workflow

工作流程

  1. Enable the beta (once). Custom sidebars are behind Settings → Beta features → Custom sidebars (
    customSidebars.beta.enabled
    ). If a written sidebar does not appear in the picker, this flag is the first thing to check.
  2. Write a named file. The name becomes the menu label; use short kebab-case:
    ~/.config/cmux/sidebars/<name>.swift
    The file is a single SwiftUI-style view expression (no
    struct
    , no
    var body
    , no imports). A
    .json
    variant exists for static layouts; prefer
    .swift
    for anything dynamic.
  3. Validate and select it:
    bash
    cmux sidebar validate <name>   # parse/interpret check with real data shapes
    cmux sidebar select <name>     # switch the sidebar to it
    The user can also pick it manually: right-click the sidebar toggle button.
  4. Iterate. Saving the file hot-reloads the sidebar in place (
    cmux sidebar reload
    forces it). Look at the result, fix what looks off, and verify rows show real data and taps do the right thing before declaring it done.
  1. 启用测试版功能(仅需一次)。自定义侧边栏位于「设置 → Beta功能 → Custom sidebars」(配置项
    customSidebars.beta.enabled
    )。如果编写的侧边栏未出现在选择器中,首先检查此标记是否开启。
  2. 编写命名文件。文件名会成为菜单标签;建议使用简短的短横线命名法:
    ~/.config/cmux/sidebars/<name>.swift
    文件内容为单个SwiftUI风格的视图表达式(无需
    struct
    var body
    或导入语句)。还有
    .json
    变体用于静态布局;对于任何动态场景,优先选择
    .swift
    格式。
  3. 验证并选择侧边栏
    bash
    cmux sidebar validate <name>   # 使用真实数据结构进行解析/解释检查
    cmux sidebar select <name>     # 切换到该侧边栏
    用户也可以手动选择:右键点击侧边栏切换按钮。
  4. 迭代优化。保存文件后侧边栏会原地hot reload(
    cmux sidebar reload
    可强制重载)。查看结果,修复不合理的地方,在完成前验证行是否显示真实数据,以及点击是否执行正确操作。

Authoring rules

创作规则

  • Default to live data. Bind to the
    workspaces
    context instead of hard-coding text so the sidebar stays correct on its own.
  • Make it interactive by default. Rows that represent something openable should run the matching
    cmux(...)
    action on tap. A list that just displays text is rarely what they wanted.
  • Prefer
    Reorderable
    for workspace-like lists.
    It gives persisted drag-and-drop reordering for free.
  • Keep it native and uncluttered: a title, a divider, then the content.
  • Cap long lists (
    .prefix(20)
    , filter/sort before rendering). The sidebar re-evaluates about once a second; do not render hundreds of rows.
  • Stay inside the supported subset. Unsupported syntax is skipped gracefully (never crashes), but choose the closest supported approach rather than shipping a half-blank sidebar.
  • 默认使用实时数据。绑定到
    workspaces
    上下文而非硬编码文本,这样侧边栏可自动保持内容准确。
  • 默认设置为交互式。代表可打开内容的行,点击时应执行对应的
    cmux(...)
    操作。仅显示文本的列表几乎不是用户想要的。
  • 对于类工作区列表,优先使用
    Reorderable
    。它可免费提供持久化的拖放重排序功能。
  • 保持原生风格且简洁:一个标题、一条分隔线,然后是内容。
  • 限制长列表(使用
    .prefix(20)
    ,渲染前先过滤/排序)。侧边栏大约每秒重新评估一次;不要渲染数百行内容。
  • 使用支持的子集。不支持的语法会被优雅跳过(绝不会崩溃),但请选择最接近的支持方案,而非交付半空白的侧边栏。

Quick start

快速开始

bash
cat > ~/.config/cmux/sidebars/mine.swift <<'SWIFT'
VStack(alignment: .leading, spacing: 8) {
    Text("My sidebar").font(.title3).bold()
    Text(clock.time).font(.caption).foregroundColor(.secondary)
    Divider()
    Reorderable(workspaces, move: "workspace.reorder") { w in
        Button(action: { cmux("workspace.select", workspace_id: w.id) }) {
            HStack {
                Text(w.selected ? "●" : "○").foregroundColor(w.selected ? "#FF8800" : .secondary)
                Text(w.title)
                Spacer()
            }.padding(4)
        }
    }
}
SWIFT
cmux sidebar validate mine && cmux sidebar select mine
bash
cat > ~/.config/cmux/sidebars/mine.swift <<'SWIFT'
VStack(alignment: .leading, spacing: 8) {
    Text("My sidebar").font(.title3).bold()
    Text(clock.time).font(.caption).foregroundColor(.secondary)
    Divider()
    Reorderable(workspaces, move: "workspace.reorder") { w in
        Button(action: { cmux("workspace.select", workspace_id: w.id) }) {
            HStack {
                Text(w.selected ? "●" : "○").foregroundColor(w.selected ? "#FF8800" : .secondary)
                Text(w.title)
                Spacer()
            }.padding(4)
        }
    }
}
SWIFT
cmux sidebar validate mine && cmux sidebar select mine

Live data context (read-only, refreshes ~1s)

实时数据上下文(只读,约每秒刷新一次)

  • workspaces
    : array with
    id
    ,
    title
    ,
    selected
    ,
    pinned
    ,
    index
    ,
    directory
    ,
    ports
    +
    portCount
    ,
    unread
    ,
    tabs
    +
    tabCount
    ; plus, when present:
    description
    ,
    color
    ,
    branch
    +
    dirty
    ,
    pr
    /
    prs
    (
    {number, label, url, status, stale, branch}
    ),
    progress
    (
    {value, label}
    ),
    latestMessage
    ,
    latestPrompt
    ,
    latestAt
    ,
    remote
    (
    {target, state, connected}
    ).
  • workspaces[i].tabs
    :
    id
    ,
    title
    ,
    focused
    ,
    pinned
    ; plus
    directory
    ,
    branch
    +
    dirty
    ,
    ports
    when available.
  • clock
    :
    {time, hour, minute, second, weekday, epoch}
    .
  • Scalars:
    workspaceCount
    ,
    selectedTitle
    ,
    selectedId
    ,
    unreadTotal
    .
Optional fields are omitted when absent; guard with
if let b = w.branch { ... }
or
w.pr != nil ? ... : ...
.
  • workspaces
    :数组,包含
    id
    title
    selected
    pinned
    index
    directory
    ports
    +
    portCount
    unread
    tabs
    +
    tabCount
    ;若存在则还包含:
    description
    color
    branch
    +
    dirty
    pr
    /
    prs
    {number, label, url, status, stale, branch}
    )、
    progress
    {value, label}
    )、
    latestMessage
    latestPrompt
    latestAt
    remote
    {target, state, connected}
    )。
  • workspaces[i].tabs
    :包含
    id
    title
    focused
    pinned
    ;若可用则还包含
    directory
    branch
    +
    dirty
    ports
  • clock
    {time, hour, minute, second, weekday, epoch}
  • 标量值:
    workspaceCount
    selectedTitle
    selectedId
    unreadTotal
可选字段不存在时会被省略;可使用
if let b = w.branch { ... }
w.pr != nil ? ... : ...
进行判断。

Actions

操作

A button or
.onTapGesture
body calls
cmux("<method>", param: value)
, dispatched through the same surface as the
cmux
CLI. Common methods:
workspace.select
(
workspace_id
),
surface.focus
(
surface_id
),
workspace.reorder
(
workspace_id
+
index
).
openURL("https://...")
opens links. Discover the full command surface with
cmux docs api
.
按钮或
.onTapGesture
的主体可调用
cmux("<method>", param: value)
,通过与
cmux
CLI相同的界面分发。常用方法:
workspace.select
(参数
workspace_id
)、
surface.focus
(参数
surface_id
)、
workspace.reorder
(参数
workspace_id
+
index
)。
openURL("https://...")
可打开链接。使用
cmux docs api
可发现完整的命令集。

Supported subset at a glance

支持子集概览

Containers: stacks (incl. lazy),
Group
,
List
,
Section
, grids,
ViewThatFits
,
ScrollView
,
HSplitView
(two resizable columns). Content:
Text
,
Label
,
Image(systemName:)
,
Button
(title and label form),
Menu
,
ProgressView
,
Gauge
,
Spacer
,
Divider
, shapes, gradients via
.background
. Modifiers: full typography set, colors as hex strings or tokens,
.padding
/
.frame
/layout,
.background
/
.overlay
/
.mask
/
.contextMenu
with arbitrary nested views, shadows/borders/opacity/effects,
.onTapGesture
,
.help
,
.disabled
. Language:
let
, user
func
helpers,
for
/
ForEach
,
if/else
, ternary, string interpolation, arithmetic, array methods (
filter
/
map
/
sorted
/
prefix
/...), string and number formatting.
Not yet supported (write the natural Swift anyway; it degrades gracefully):
@State
and input controls (
TextField
,
Toggle
,
Slider
,
Picker
), custom
struct
/
View
definitions, navigation (
sheet
/
popover
),
AsyncImage
. Two-way editing does not work yet; taps that run
cmux(...)
do.
容器:栈(包括懒加载栈)、
Group
List
Section
、网格、
ViewThatFits
ScrollView
HSplitView
(两个可调整大小的列)。内容:
Text
Label
Image(systemName:)
Button
(标题和标签形式)、
Menu
ProgressView
Gauge
Spacer
Divider
、形状、通过
.background
设置渐变。修饰器:完整的排版集、十六进制字符串或标记表示的颜色、
.padding
/
.frame
/布局、
.background
/
.overlay
/
.mask
/
.contextMenu
(支持任意嵌套视图)、阴影/边框/透明度/效果、
.onTapGesture
.help
.disabled
。语言特性:
let
、用户自定义
func
辅助函数、
for
/
ForEach
if/else
、三元运算符、字符串插值、算术运算、数组方法(
filter
/
map
/
sorted
/
prefix
/...)、字符串和数字格式化。
暂不支持(仍可编写标准Swift代码;会优雅降级):
@State
和输入控件(
TextField
Toggle
Slider
Picker
)、自定义
struct
/
View
定义、导航(
sheet
/
popover
)、
AsyncImage
。双向编辑目前不可用;但点击执行
cmux(...)
是可行的。

Troubleshooting

故障排除

  • Sidebar missing from the right-click picker: the beta flag is off, or the file is not directly under
    ~/.config/cmux/sidebars/
    .
  • Blank or partial render: run
    cmux sidebar validate <name>
    ; errors show inline in the sidebar with the failing location. A broken save keeps the last working render on screen, so re-save after fixing.
  • Rows not tappable: wrap the row in
    Button(action: { cmux(...) }) { ... }
    or add
    .onTapGesture { cmux(...) }
    .
  • Reorder not persisting: use
    Reorderable(data, move: "workspace.reorder")
    , not
    List
    /
    .onMove
    /
    .draggable
    .
  • 右键选择器中找不到侧边栏:测试版功能标记未开启,或文件未直接放在
    ~/.config/cmux/sidebars/
    目录下。
  • 侧边栏空白或部分渲染:运行
    cmux sidebar validate <name>
    ;错误会连同出错位置一起显示在侧边栏内。保存错误文件后,屏幕上会保留最后可正常渲染的版本,修复后重新保存即可。
  • 行无法点击:将行包裹在
    Button(action: { cmux(...) }) { ... }
    中,或添加
    .onTapGesture { cmux(...) }
  • 重排序不持久:使用
    Reorderable(data, move: "workspace.reorder")
    ,而非
    List
    /
    .onMove
    /
    .draggable