← Windows与WSL的终端美化

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 解决的正是这些日常摩擦:

  1. 它能保住会话。你可以把当前工作拆成多个 session,需要时 detach,回来再 attach。
  2. 它能把项目结构固定下来。一个 layout 文件就能定义默认 tab、pane 和启动命令。
  3. 它更适合远程和长任务。即使外层终端断了,里面跑着的任务和现场通常还在。
  4. 它能把一个项目的操作面板标准化。不是每次打开终端都重新摆桌子,而是直接进入预设工作台。

说得直白一点,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.kdllayout.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 zellijbrew install zellijsudo 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,主开发区,右下角顺手开 lazygit
  • shell,留给临时命令和脚本
  • 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 里,真正关键的是哪些地方

可以把它拆成三层来看:

  1. default_tab_template 这是给每个 tab 套上的公共模板。这里我把 zjstatus 挂到了一个 size=1 borderless=true 的 pane 里,所以每个 tab 底部都会统一出现状态栏。

  2. plugin location="file:.../zjstatus.wasm" { ... } 这一大段就是状态栏配置本体。里面定义了颜色别名、左右中三段格式、不同 mode 的样式、tab 显示样式、Git 分支命令和时间格式。

  3. 三个 tab 的具体布局

    • code tab 是主工作区,左边大 pane 负责编辑,右下角直接开 lazygit
    • shell tab 只保留一个干净 pane,适合跑临时命令
    • monitor tab 启动就跑 btop,把资源监控单独隔离出去

我很喜欢这种写法,因为它把“我通常怎么工作”固化成一个稳定入口。你不是每次开终端都重新组织桌面,而是直接进入已经摆好的工作台。

zjstatus 配置里每个关键参数都是什么意思

很多人第一次看到 zjstatus 配置会觉得有点长,其实拆开以后很清楚。

配色别名

  • color_bgcolor_fg 定义状态栏主背景和主文字色
  • color_bluecolor_greencolor_redcolor_peachcolor_mauve 用来给 mode、Git、强调信息上色
  • color_surfacecolor_overlay 用来做层级和次要信息

这些颜色都来自 Catppuccin Mocha。项目里的主题统一文档也把这套色板当成整条终端栈的语义基准。

布局格式

  • format_left,左侧区域显示 mode 和 session
  • format_center,中间显示 tabs
  • format_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_normal
  • mode_locked
  • mode_pane
  • mode_tab
  • mode_resize
  • mode_tmux

这些参数控制不同输入模式下左侧状态块的样式。Zellij 的 discoverable UI 很大程度就靠它们,因为你抬眼就知道自己现在处在哪个模式。

tab 样式

  • tab_normal 定义非激活 tab 的显示方式
  • tab_active 定义当前激活 tab 的显示方式

这里我让激活 tab 用蓝色、加粗和斜体,这样中间区域一眼就能看清焦点。

Git 分支模块

  • command_git_branch_command,运行 git rev-parse --abbrev-ref HEAD
  • command_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 模式里,多看底栏提示,用 hjkl 移动焦点会很顺

刚开始别给自己压力,真的不用背成考试题。Zellij 的强项本来就是“边用边发现”。

会话管理,日常最常用的就是这四个命令

项目文档里把 session workflow 总结得很实用,我这里也直接保留下来。

# 创建命名会话
zellij -s dev

# 列出会话
zellij ls

# 重新连接
zellij attach dev

# 删除会话
zellij delete-session dev

如果你平时同时开多个项目,我建议 session 直接按项目名起,比如 apifrontendinfra。这样切起来非常直观。

如何创建和使用自定义布局

这部分其实很简单,思路就是三步。

第一步,把 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 怎么配,才能让整套体验从窗口、工作区一路顺到命令行本身。

系列文章导航

  1. Windows与WSL的终端美化(零)——系列概览
  2. Windows与WSL的终端美化(一)——WSL安装与配置
  3. Windows与WSL的终端美化(二)——WezTerm配置
  4. Windows与WSL的终端美化(三)——Zellij工作区管理(本篇)
  5. Windows与WSL的终端美化(四)——Shell与Prompt配置
  6. Windows与WSL的终端美化(五)——CLI工具链美化
  7. Windows与WSL的终端美化(六)——Catppuccin主题统一
目录

Comments (0)

No comments yet. Be the first!