Zellij 的插件系统基于 WASM(WebAssembly)构建,这意味着插件运行在沙盒中,安全且跨平台。本文将全面介绍 Zellij 的内置插件、插件别名机制、加载方式,以及完整的插件 API,帮助你理解 Zellij 的扩展架构。
一、内置插件
Zellij 自带一组内置插件,它们提供了核心的 UI 功能。这些插件使用 WASM 格式分发,通过 zellij: 协议前缀引用。
| 插件名 | 位置标识 | 功能说明 |
|---|---|---|
| tab-bar | zellij:tab-bar | 顶部标签栏,显示标签列表和切换按钮 |
| status-bar | zellij:status-bar | 底部状态栏,显示模式提示、快捷键和会话信息 |
| compact-bar | zellij:compact-bar | 紧凑型底部栏,结合标签和状态信息,节省屏幕空间 |
| strider | zellij:strider | 文件浏览器插件,类似文件管理器的侧边栏 |
| session-manager | zellij:session-manager | 会话管理器,列出和管理所有会话 |
| welcome-screen | zellij:welcome-screen | 欢迎屏幕,在空会话中显示入门提示 |
| filepicker | zellij:filepicker | 文件选择器,用于在插件中选取文件路径 |
这些内置插件在默认布局中自动加载。如果你使用自定义布局,可以自由替换或移除它们。例如,用 compact-bar 替换默认的 tab-bar 和 status-bar 来获得更简洁的界面。
二、插件别名
插件别名允许你在配置文件中为插件定义短名称映射,使布局文件更简洁、更易维护。
在 plugins 块中定义别名
在 config.kdl 的 plugins 块中定义插件别名:
plugins {
// 为外部 WASM 插件定义别名
my-plugin {
location "https://example.com/plugins/my-plugin.wasm"
}
// 为本地文件插件定义别名
local-tool {
location "file:///path/to/plugin.wasm"
}
// 使用别名并带配置
strider-with-config {
location "zellij:strider"
configuration {
// 传递给插件的配置项
}
}
}
在布局中使用别名
定义别名后,可以在布局文件中直接使用:
layout {
pane {
plugin "my-plugin"
}
pane {
plugin "strider-with-config"
}
}
别名的优势在于:集中管理插件位置,布局文件更简洁,方便更新插件版本(只需修改配置文件中的 location)。
三、加载插件
Zellij 提供了三种加载插件的方式:在布局中加载、通过 CLI 加载,以及通过管道通信。
布局中加载
在布局文件中使用 plugin 关键字加载插件到指定面板:
// 使用内置插件
pane {
plugin location="zellij:strider"
}
// 使用配置中定义的别名
pane {
plugin location="my-plugin"
}
// 使用外部 URL 直接加载
pane {
plugin location="https://example.com/plugin.wasm"
}
// 加载插件并传递配置
pane {
plugin location="zellij:strider" {
configuration {
// 插件专属配置
}
}
}
CLI 加载
使用 launch-plugin 命令在运行时动态加载插件:
# 在新面板中加载插件
zellij action launch-plugin "zellij:strider"
# 在浮动面板中加载
zellij action launch-plugin --floating "zellij:session-manager"
# 指定面板位置和大小
zellij action launch-plugin --x 10 --y 10 --width 30% --height 50% "my-plugin"
通过管道通信
插件加载后,可以通过管道(Pipe)机制与其他组件通信。管道是 Zellij 插件系统的核心通信方式,后面会详细介绍。
# 从 CLI 向插件发送消息
zellij pipe --plugin my-plugin --message "hello"
# 从键位绑定向插件发送消息
bind "Ctrl+P" {
Or { plugins "my-plugin" { message "triggered" } }
}
四、插件 API 概览
Zellij 的插件 API 基于 zellij-tile crate,提供了事件处理、命令调用、类型定义和权限管理等完整功能。
事件(EventType)
插件通过订阅事件来响应 Zellij 的状态变化和用户操作。主要的事件类型包括:
| 事件类型 | 说明 |
|---|---|
ModeUpdate | 输入模式发生变化(Normal、Pane、Tab 等) |
TabUpdate | 标签页信息更新(新增、关闭、重命名等) |
PaneUpdate | 面板信息更新(创建、关闭、焦点变化等) |
Key | 键盘按键事件,包含修饰键信息 |
Mouse | 鼠标事件(点击、滚动、移动等) |
Timer | 定时器事件,用于周期性任务 |
CustomMessage | 自定义消息事件,用于插件间通信 |
FocusRender | 面板获得焦点时触发渲染 |
插件在 load 阶段通过 subscribe 注册感兴趣的事件类型,之后只接收已订阅的事件。
命令 API 分组
插件可以通过命令 API 操控 Zellij 的各种功能。命令按功能分组如下:
| 分组 | 典型命令 | 说明 |
|---|---|---|
| 面板操作 | close_focus、toggle_focus_fullscreen、focus_pane、move_focus | 控制面板的打开、关闭、焦点切换和布局 |
| 面板创建 | new_pane、open_file、open_terminal | 创建新面板并指定内容 |
| 状态查询 | get_panes、get_tabs、get_active_tab | 获取当前会话的状态信息 |
| 插件控制 | subscribe、unsubscribe、set_timeout | 管理插件自身的行为 |
| 输入输出 | write、write_chars | 向当前面板写入文本内容 |
| 会话与Web | switch_session、delete_session、web_request | 管理会话和发起网络请求 |
类型参考
插件 API 中使用的核心数据类型:
| 类型 | 说明 |
|---|---|
KeyWithModifier | 表示一个按键及修饰键组合(Ctrl、Alt、Shift 等) |
Mouse | 表示鼠标事件,包括坐标、按钮和滚动方向 |
InputMode | 当前输入模式枚举(Normal、Pane、Tab、Resize、Session 等) |
PaneId | 面板的唯一标识符,区分终端面板和插件面板 |
TabInfo | 标签页的完整信息,包括名称、位置、活跃面板等 |
PaneInfo | 面板的完整信息,包括 ID、标题、尺寸、内容等 |
权限系统
由于 WASM 插件运行在沙盒中,某些敏感操作需要显式请求权限。Zellij 使用 PermissionType 枚举定义可用的权限。
常见的权限类型包括:
- 文件系统访问:读写宿主机文件系统
- 网络请求:发起 HTTP/WebSocket 请求
- 消息发送:向其他插件发送管道消息
- 进程管理:启动和管理子进程
插件在需要权限时,通过 API 请求权限:
// 在插件代码中请求权限
request_permission(&[PermissionType::ReadFileSystem,
PermissionType::WriteFileSystem]);
用户在运行时会看到权限请求提示,可以选择允许或拒绝。权限请求也可以在布局配置中预先授权:
pane {
plugin location="my-plugin" {
// 预授权权限
permissions "read_filesystem" "write_filesystem"
}
}
插件配置
插件可以接收配置数据,有两种传递方式:
在布局中传递配置:
pane {
plugin location="zellij:strider" {
configuration {
// 键值对形式的配置
show_hidden_files true
sort_order "alphabetical"
}
}
}
在别名中传递默认配置:
plugins {
my-strider {
location "zellij:strider"
configuration {
show_hidden_files true
}
}
}
文件系统访问和日志
插件可以通过 API 访问宿主机文件系统(需要相应权限):
// 读取文件内容
let content = read_file("/path/to/file");
// 写入文件
write_file("/path/to/output", "content");
// 列出目录内容
let entries = list_directory("/path/to/dir");
插件可以使用日志系统输出调试信息:
// 输出日志到 Zellij 的日志系统
log("debug", "插件初始化完成");
异步任务(Workers)
为了不阻塞主线程,插件可以创建 Worker 来处理耗时操作:
// 创建后台 Worker 处理耗时任务
spawn_worker("file-reader", || {
// 在后台读取大文件
let content = read_large_file("/path/to/large/file");
// 通过消息将结果发回主线程
send_message("file-reader-done", content);
});
Worker 运行在独立的线程中,完成后通过事件系统将结果返回给插件主线程。
管道(Pipes)
管道是 Zellij 插件系统的核心通信机制,支持从多个来源向插件发送消息:
| 来源 | 方式 | 示例 |
|---|---|---|
| CLI | zellij pipe 命令 | zellij pipe --plugin my-plugin --msg "data" |
| 键位绑定 | 配置中的 pipe 动作 | bind "Ctrl+P" { pipe "my-plugin" "data"; } |
| 其他插件 | 调用 pipe 方法 | pipe_to_plugin("target", "data") |
pipe 方法:插件可以通过 pipe 方法向其他插件发送消息:
// 向指定插件发送消息
pipe("target-plugin-name", "message-payload");
// 广播消息给所有订阅者
broadcast("event-name", "payload");
pipe_message_to_plugin:接收来自管道的消息:
// 在插件的 pipe 回调中处理消息
fn pipe(&mut self, message: PipeMessage) -> bool {
match message.source {
PipeSource::Cli(args) => { /* 处理 CLI 消息 */ },
PipeSource::Keybinding(key) => { /* 处理键位绑定消息 */ },
PipeSource::Plugin(name) => { /* 处理其他插件消息 */ },
}
true // 返回 true 表示需要重新渲染
}
管道机制使得插件之间、CLI 与插件之间、键位绑定与插件之间的通信变得统一而灵活。通过合理使用管道,你可以构建出复杂的插件协作系统,将多个独立插件组合成一个强大的工作流。