Windows与WSL的终端美化(三)——Zellij工作区管理
上一篇把 WezTerm 这层入口收拾顺了,这一篇就该轮到终端里面真正干活的那一层了。窗口再漂亮,如果里面还是一个孤零零的 shell,写代码、看日志、跑脚本、盯监控这些事情一叠起来,现场还是会乱。对我来说,Zellij 真正解决的不是“能不能分屏”,而是“这套工作现场能不能长期保持下来”。
我现在最常见的日常场景很固定,左边写代码,右下角开 lazygit,另一个 tab 留给临时命令,再单独开一个监控页盯着 btop。如果只靠终端模拟器自带分屏,每次开工都得重新摆桌子。可一旦把这件事交给 Zellij,pane、tab、session、layout 就都变成了可以保存、复用、切换的工作区元素,终端才真的像个工作台。
为什么需要 terminal multiplexer
很多人第一次接触 terminal multiplexer,第一反应都是“这不就是分屏工具吗”。其实它更像是终端里的工作区管理器,重点不在分屏本身,而在于把一整套工作状态组织起来。
只靠终端模拟器分屏,通常会遇到这几个问题:
- 终端窗口一关,现场就没了
- SSH 断开、WSL 重启或者误关窗口以后,很难回到原来的工作状态
- 同一个项目里,代码、日志、Git、监控、临时命令混在一起,切来切去很乱
- 每次开工都要重复“开 tab, 分 pane, 跑命令”这套动作
terminal multiplexer 解决的正是这些日常摩擦:
- 它能保住会话。你可以把当前工作拆成多个 session,需要时 detach,回来再 attach。
- 它能把项目结构固定下来。一个 layout 文件就能定义默认 tab、pane 和启动命令。
- 它更适合远程和长任务。即使外层终端断了,里面跑着的任务和现场通常还在。
- 它能把一个项目的操作面板标准化。不是每次打开终端都重新摆桌子,而是直接进入预设工作台。
说得直白一点,terminal multiplexer 让终端从“命令输入窗口”变成“可恢复、可复用、可切换的工作空间”。这也是我后来认真把 Zellij 放进整套 Windows + WSL 终端方案里的原因。
为什么我最后选了 Zellij
我不是没试过 tmux。tmux 当然强,生态深,历史也长,很多老用户手上都有一套很成熟的配置。但如果你不是为了研究一整套 tmux 哲学,而是想尽快把工作区整理顺,Zellij 的上手体验确实更轻。
项目文档里总结过几个很关键的点,我完全同意:
- 它是 Rust 写的,启动快,交互也很顺
- 默认 UI 很“可发现”,底栏会直接提示当前模式能做什么
- 支持 WASM 插件,像
zjstatus这种状态栏插件很好接 - 配置语言用的是 KDL,比传统
tmux.conf更清楚 - 内置 floating panes 和 stacked panes,多任务开发时更自然
- 从 v0.44.0 开始已经支持原生 Windows,不过我自己的实际体验还是 WSL 里更稳
Zellij vs tmux,对我最有感的一张表
| 维度 | Zellij | tmux |
|---|---|---|
| 默认体验 | UI 直接提示可用操作,新手更容易上手 | 默认体验偏硬,很多操作要先记快捷键 |
| 配置方式 | config.kdl、layout.kdl,结构清楚 |
tmux.conf 功能强,但读写门槛更高 |
| 插件体系 | WASM 插件,接入方式现代 | 生态很大,但更多依赖脚本和社区插件 |
| 浮动窗口 | 原生支持 floating panes,临时任务很好用 | 也能做类似效果,但不是核心工作流 |
| 状态反馈 | 底栏模式提示明显,discoverable UI 很友好 | 更依赖记忆和经验 |
| 学习成本 | 相对更低 | 相对更高 |
| 老牌生态深度 | 还在持续扩展 | 更成熟,历史包袱也更多 |
如果你已经是 tmux 老手,当然没必要硬切。可如果你现在是在 Windows + WSL 里重新搭一套终端环境,想要的是现代一点、清楚一点、默认就顺手一点的工作区工具,我会更推荐从 Zellij 开始。
安装方式对比,cargo、二进制、包管理器该怎么选
Zellij 官方文档给了几种主流安装路径。真要落到 WSL 日常使用里,我会把它们分成三类来看。
| 方式 | 示例命令 | 优点 | 缺点 | 我会怎么选 |
|---|---|---|---|---|
| Cargo | cargo install --locked zellij --version 0.44.1 |
版本可控,适合已经装好 Rust toolchain 的人 | 需要编译,慢,占空间,纯为了装 Zellij 有点重 | 已经长期用 Rust 的机器可以选 |
| 二进制 | 下载 release 里的 tar.gz,解压后放到 ~/.local/bin |
不需要编译,安装快,版本可控,最适合 WSL | 需要自己管升级 | 我最推荐 |
| 包管理器 | sudo apt install zellij、brew install zellij、sudo pacman -S zellij |
最省心,跟系统包一起管理 | 版本常常落后于上游,发行版差异也大 | 只想快速试用时很方便 |
如果你本来就有 Rust 环境,Cargo 没问题。要是你只想稳稳装一个 Zellij,不想为它顺带装一整套编译链,那二进制安装通常最舒服。包管理器则适合“先用起来再说”,只是版本不一定跟得上。
推荐安装方式,直接把二进制放进 ~/.local/bin
这一套是我更愿意长期保留的方法。原因很简单,路径干净、依赖少、版本可控,而且很适合 WSL 这种偏“自己管自己”的环境。
下面示例按 WSL x86_64 Linux 来写,版本和项目文档保持一致,用 0.44.1。如果你是 ARM 设备,把下载文件名里的 x86_64 换成 aarch64 就行。
第一步,准备目录
mkdir -p ~/.local/bin
mkdir -p ~/.config/zellij/layouts
mkdir -p ~/.config/zellij/plugins
如果你的 ~/.local/bin 还没进 PATH,把下面这行加到 ~/.zshrc 或 ~/.bashrc:
export PATH="$HOME/.local/bin:$PATH"
加完以后重新加载 shell:
source ~/.zshrc
第二步,下载并校验 Zellij 二进制
export ZELLIJ_VERSION="0.44.1"
cd /tmp
curl -LO "https://github.com/zellij-org/zellij/releases/download/v${ZELLIJ_VERSION}/zellij-x86_64-unknown-linux-musl.tar.gz"
curl -LO "https://github.com/zellij-org/zellij/releases/download/v${ZELLIJ_VERSION}/zellij-x86_64-unknown-linux-musl.sha256sum"
sha256sum -c "zellij-x86_64-unknown-linux-musl.sha256sum"
这里多做一次 sha256sum 校验不算麻烦,但能避免你把损坏文件装进去。
第三步,解压并安装到 ~/.local/bin
tar -xvf "zellij-x86_64-unknown-linux-musl.tar.gz"
install -Dm755 zellij "$HOME/.local/bin/zellij"
第四步,验证安装
zellij --version
正常的话,你会看到类似下面的输出:
zellij 0.44.1
如果你只是想快速试一下,也可以用 Cargo 或系统包管理器:
# Cargo
cargo install --locked zellij --version 0.44.1
# Ubuntu / Debian,是否有新版本取决于仓库
sudo apt update && sudo apt install zellij
# Homebrew
brew install zellij
# Arch Linux
sudo pacman -S zellij
不过就我自己的习惯来说,WSL 里还是二进制最清爽。
基础配置,先把 config.kdl 定下来
Zellij 的主配置文件在 ~/.config/zellij/config.kdl。官方文档说,第一次运行后它通常会自动生成这个文件,也可以用 zellij setup --dump-config > ~/.config/zellij/config.kdl 导出默认配置。但如果你已经知道自己想要什么,直接写一份更省事。
这是我建议保留的完整配置。它以项目文档里的基础配置为核心,再把 zjframes 的后台加载一起放进去:
theme "catppuccin-mocha"
default_layout "dev"
default_shell "zsh"
pane_frames false
simplified_ui true
copy_on_select true
scrollback_editor "/usr/bin/nvim"
mouse_mode true
load_plugins {
"file:~/.config/zellij/plugins/zjframes.wasm" {
hide_frame_for_single_pane "true"
hide_frame_except_for_search "true"
hide_frame_except_for_scroll "true"
hide_frame_except_for_fullscreen "true"
}
}
这份 config.kdl 每个参数都在干什么
| 参数 | 作用 | 为什么值得保留 |
|---|---|---|
theme "catppuccin-mocha" |
把 Zellij 主题切到 Catppuccin Mocha | 和整套终端主题保持一致 |
default_layout "dev" |
启动时默认加载 dev.kdl |
一进来就是熟悉的工作台,不用重摆布局 |
default_shell "zsh" |
新 pane 默认用 zsh |
如果你后面用 Oh My Zsh、Starship,这项最好明确写上 |
pane_frames false |
关闭默认 pane 边框 | 视觉更干净,外层如果已经有 WezTerm 美化,边框可以收掉 |
simplified_ui true |
简化 Zellij 内置 UI | 配合自定义状态栏时更统一,不会显得太杂 |
copy_on_select true |
鼠标选中就复制 | 这是那种用了就回不去的小设置 |
scrollback_editor "/usr/bin/nvim" |
查看长输出时,用 nvim 打开滚动历史 |
查编译日志、报错堆栈时很好用 |
mouse_mode true |
启用鼠标支持 | 选中文本、切 pane、滚动输出都更顺手 |
load_plugins { ... } |
在 session 启动时后台加载插件 | 这里专门留给 zjframes 这种后台型插件 |
file:~/.config/zellij/plugins/zjframes.wasm |
zjframes 的本地 wasm 路径 |
本地文件比远程 URL 更稳,也更适合长期配置 |
hide_frame_for_single_pane "true" |
单 pane 时隐藏边框 | 只有一个 pane 时不需要明显边框 |
hide_frame_except_for_search "true" |
搜索模式之外隐藏边框 | 只有在搜索这类需要定位的场景下才强调边框 |
hide_frame_except_for_scroll "true" |
滚动模式之外隐藏边框 | 浏览长输出时边框提示更有帮助 |
hide_frame_except_for_fullscreen "true" |
全屏模式之外隐藏边框 | 全屏聚焦时保留更明确的视觉反馈 |
这里有个很关键的区别。zjstatus 是前台状态栏插件,应该放在 layout 里。zjframes 是后台插件,官方 README 也明确建议只放在 load_plugins 里。两者职责不同,别混着写。
zjstatus 和 zjframes,分别负责什么
这两个插件我通常一起装,但它们不是同一种角色。
zjstatus
zjstatus 是一个可配置状态栏插件,可以把 mode、session、tabs、Git branch、time 这些信息集中显示在底部。项目文档里用的就是这套方案,因为它很适合和 Catppuccin Mocha 一起统一视觉风格。
它的优势主要有三点:
- 信息密度高,但不乱
- 格式和颜色都能细调
- 非常适合把 session、tab、Git 分支这些上下文压缩成一条清楚的状态栏
zjframes
zjframes 不是状态栏,它做的是“智能边框”。同一个仓库 README 里对它的说明很直接,它可以在不同条件下自动切换 pane frame 是否显示,哪怕你没加载 zjstatus 也能单独工作。
这件事看起来小,实际很有用。因为很多时候你想要的是大部分时间界面干净,但进入搜索、滚动、全屏这些状态时,边框又能回来给你一点定位感。zjframes 解决的就是这个平衡问题。
安装 zjstatus 和 zjframes 插件
先把插件目录准备好,然后把两个 wasm 文件都下载到本地:
mkdir -p ~/.config/zellij/plugins
curl -L https://github.com/dj95/zjstatus/releases/latest/download/zjstatus.wasm \
-o ~/.config/zellij/plugins/zjstatus.wasm
curl -L https://github.com/dj95/zjstatus/releases/latest/download/zjframes.wasm \
-o ~/.config/zellij/plugins/zjframes.wasm
第一次启动带插件的 Zellij 时,它通常会弹权限确认。直接按 y 授权就行。插件更新后如果遇到奇怪的缓存问题,可以清理 ~/.cache/zellij/ 再重启。
dev.kdl,把常用工作台直接固化下来
真正让我觉得 Zellij 值得长期保留的,不只是 session,而是 layout。因为 layout 解决的是一个非常具体的问题,你打开终端的第一屏,究竟应该长什么样。
我现在更喜欢把这件事写死在 ~/.config/zellij/layouts/dev.kdl 里。这样每次进来,都会直接得到三个 tab:
code,主开发区,右下角顺手开lazygitshell,留给临时命令和脚本monitor,直接跑btop盯资源
完整的 dev.kdl 内容如下,和项目文档保持一致:
layout {
default_tab_template {
children
pane size=1 borderless=true {
plugin location="file:~/.config/zellij/plugins/zjstatus.wasm" {
// Catppuccin Mocha color aliases
color_bg "#1e1e2e"
color_fg "#cdd6f4"
color_blue "#89b4fa"
color_green "#a6e3a1"
color_red "#f38ba8"
color_peach "#fab387"
color_mauve "#cba6f7"
color_surface "#313244"
color_overlay "#6c7086"
format_left "{mode} #[fg={blue},bold]{session}"
format_center "{tabs}"
format_right "{command_git_branch} {datetime}"
format_space ""
border_enabled "false"
hide_frame_for_single_pane "true"
mode_normal "#[bg={green},fg={bg},bold] NORMAL "
mode_locked "#[bg={red},fg={bg},bold] LOCKED "
mode_pane "#[bg={blue},fg={bg},bold] PANE "
mode_tab "#[bg={peach},fg={bg},bold] TAB "
mode_resize "#[bg={mauve},fg={bg},bold] RESIZE "
mode_tmux "#[bg={peach},fg={bg},bold] TMUX "
tab_normal "#[fg={overlay}] {name} "
tab_active "#[fg={blue},bold,italic] {name} "
command_git_branch_command "git rev-parse --abbrev-ref HEAD"
command_git_branch_format "#[fg={green}] {stdout}"
command_git_branch_interval "5"
command_git_branch_rendermode "static"
datetime "#[fg={overlay},bold] {format} "
datetime_format "%H:%M"
datetime_timezone "Asia/Shanghai"
}
}
}
tab name="code" focus=true {
pane split_direction="vertical" {
pane size="65%"
pane split_direction="horizontal" {
pane
pane command="lazygit"
}
}
}
tab name="shell" {
pane
}
tab name="monitor" {
pane command="btop"
}
}
这份 dev.kdl 里,真正关键的是哪些地方
可以把它拆成三层来看:
-
default_tab_template这是给每个 tab 套上的公共模板。这里我把zjstatus挂到了一个size=1 borderless=true的 pane 里,所以每个 tab 底部都会统一出现状态栏。 -
plugin location="file:.../zjstatus.wasm" { ... }这一大段就是状态栏配置本体。里面定义了颜色别名、左右中三段格式、不同 mode 的样式、tab 显示样式、Git 分支命令和时间格式。 -
三个 tab 的具体布局
codetab 是主工作区,左边大 pane 负责编辑,右下角直接开lazygitshelltab 只保留一个干净 pane,适合跑临时命令monitortab 启动就跑btop,把资源监控单独隔离出去
我很喜欢这种写法,因为它把“我通常怎么工作”固化成一个稳定入口。你不是每次开终端都重新组织桌面,而是直接进入已经摆好的工作台。
zjstatus 配置里每个关键参数都是什么意思
很多人第一次看到 zjstatus 配置会觉得有点长,其实拆开以后很清楚。
配色别名
color_bg、color_fg定义状态栏主背景和主文字色color_blue、color_green、color_red、color_peach、color_mauve用来给 mode、Git、强调信息上色color_surface、color_overlay用来做层级和次要信息
这些颜色都来自 Catppuccin Mocha。项目里的主题统一文档也把这套色板当成整条终端栈的语义基准。
布局格式
format_left,左侧区域显示 mode 和 sessionformat_center,中间显示 tabsformat_right,右侧显示 Git branch 和时间format_space,定义区域之间的空白字符,这里留空,让状态栏更紧凑
边框与 frame 行为
border_enabled "false",关闭插件自身边框hide_frame_for_single_pane "true",单 pane 场景下隐藏 frame
注意这里的 hide_frame_for_single_pane 会和 zjframes 的逻辑一起影响 pane frame。如果你想强制保留边框,就不要把这里设成 true。
mode 样式
mode_normalmode_lockedmode_panemode_tabmode_resizemode_tmux
这些参数控制不同输入模式下左侧状态块的样式。Zellij 的 discoverable UI 很大程度就靠它们,因为你抬眼就知道自己现在处在哪个模式。
tab 样式
tab_normal定义非激活 tab 的显示方式tab_active定义当前激活 tab 的显示方式
这里我让激活 tab 用蓝色、加粗和斜体,这样中间区域一眼就能看清焦点。
Git 分支模块
command_git_branch_command,运行git rev-parse --abbrev-ref HEADcommand_git_branch_format,把命令输出渲染成状态栏文字command_git_branch_interval,每 5 秒刷新一次command_git_branch_rendermode,用static渲染模式
这组配置的作用很直接,你在项目目录里工作时,不用敲 git branch,底栏已经告诉你现在在哪个分支。
时间模块
datetime,定义时间展示格式的外层样式datetime_format,这里用%H:%M,只显示小时和分钟datetime_timezone,固定成Asia/Shanghai
如果你有跨时区协作需求,这里最好明确写出来,别完全依赖系统默认值。
Zellij 的核心概念,先把词义理顺再用会轻松很多
Zellij 这套模型其实不复杂,四个词记住就行。
panes
pane 就是一块终端工作区域。它可以是普通平铺 pane,也可以在 layout 里指定启动命令,比如 pane command="lazygit" 或 pane command="btop"。
你可以把它理解成“桌面上的一块工作面板”。
tabs
tab 是更高一层的任务页。一个 tab 里可以有多个 pane。比如我会把主开发放在 code,临时命令放在 shell,系统监控放在 monitor。这样分工比把所有 pane 都硬塞在一页里清楚得多。
sessions
session 是整套工作现场。它包含当前开的 tabs、panes、焦点位置和很多运行状态。真正让 multiplexer 有价值的,就是 session 可以 detach、attach,可以在你关掉外层终端之后继续活着。
floating windows
Zellij 文档和 CLI 里通常叫 floating panes,很多人也会把它叫成 floating windows。它们不参与主布局平铺,而是像临时拉出来的小窗,适合放一次性命令、文档、排障输出,或者某个需要短时间关注的任务。
这类窗口的好处是灵活,不会打乱主 layout。你平时工作还是围绕固定的 tiled panes 展开,临时任务再交给 floating windows。
一句话概括它们的关系就是:session 包含多个 tab,tab 里包含多个 pane,而 floating windows 是可以临时浮在 tab 上的一类 pane。
常用快捷键,先记住这些就够用了
Zellij 最大的优点之一,就是你不用一开始就背完整套快捷键。进入不同 mode 之后,底栏会直接提示下一步能做什么。不过下面这些常用键我还是建议先熟悉。
| 快捷键 | 模式 | 功能 |
|---|---|---|
Ctrl+g |
Locked / Normal | 锁定或解锁输入模式 |
Ctrl+p |
Pane | 进入窗格管理模式 |
Ctrl+t |
Tab | 进入标签页模式 |
Ctrl+n |
Resize | 进入调整窗格大小模式 |
Ctrl+s |
Scroll | 进入滚动和搜索相关模式 |
Ctrl+o |
Session | 进入会话管理模式 |
Ctrl+o 然后 d |
Session | Detach 当前会话 |
Ctrl+o 然后 w |
Session | 打开 Session Manager |
Ctrl+o 然后 p |
Session | 打开 Plugin Manager |
Ctrl+o 然后 l |
Session | 打开 Layout Manager,v0.44+ 很方便 |
除此之外,再记两个高频动作就差不多了:
Alt+n,快速新建 pane- 在 pane 模式里,多看底栏提示,用
h、j、k、l移动焦点会很顺
刚开始别给自己压力,真的不用背成考试题。Zellij 的强项本来就是“边用边发现”。
会话管理,日常最常用的就是这四个命令
项目文档里把 session workflow 总结得很实用,我这里也直接保留下来。
# 创建命名会话
zellij -s dev
# 列出会话
zellij ls
# 重新连接
zellij attach dev
# 删除会话
zellij delete-session dev
如果你平时同时开多个项目,我建议 session 直接按项目名起,比如 api、frontend、infra。这样切起来非常直观。
如何创建和使用自定义布局
这部分其实很简单,思路就是三步。
第一步,把 layout 文件放到默认目录
把 dev.kdl 放到:
~/.config/zellij/layouts/dev.kdl
Zellij 会把这个目录当成 layout 默认目录,所以你后面既可以写完整路径,也可以直接用布局名。
第二步,告诉 Zellij 默认加载哪个布局
在 config.kdl 里写上:
default_layout "dev"
这样以后你直接运行 zellij,它就会自动加载 dev.kdl。
第三步,按场景选择启动方式
常见用法有三种:
# 直接启动默认布局
zellij
# 显式指定布局名
zellij --layout dev
# 用完整路径启动
zellij --layout ~/.config/zellij/layouts/dev.kdl
如果你已经在一个 session 里,也可以把新 layout 应用到当前会话:
zellij action override-layout ~/.config/zellij/layouts/dev.kdl
另外,从 v0.44 开始,Ctrl+o 然后 l 打开的 Layout Manager 也很好用。你有多个 layout 文件时,用它切换会更直观。
一个很实用的习惯
建议把 layout 按工作类型来命名,而不是按“分了几个 pane”来命名。比如:
dev.kdl,开发主工作台monitor.kdl,监控和日志专用ops.kdl,运维和排障场景
这样你的布局文件会更像“工作模式切换器”,而不是一堆难记的窗口拼图。
这一套组合为什么会让我留下来
到了这一步,Zellij 在这套 Windows + WSL 终端环境里的角色其实已经很清楚了。
WezTerm 负责把外层入口做稳、做顺眼,Zellij 负责把里面的工作现场组织起来。config.kdl 解决的是默认行为,zjstatus 解决的是状态反馈,zjframes 解决的是边框的轻重平衡,dev.kdl 则把我最常见的工作流固定成一个一进来就能开工的桌面。
我现在再回头看,Zellij 真正好用的地方从来不是“它也能分屏”,而是它把 terminal multiplexer 这件事做得更现代、更清楚,也更愿意让人真的每天用下去。
下一篇我会继续把 shell 这一层接上,也就是 Zsh 和 prompt 怎么配,才能让整套体验从窗口、工作区一路顺到命令行本身。
Comments (0)
No comments yet. Be the first!