WezTerm MuxDomain Lua API 完全指南:多路复用域的管理、连接与状态控制
【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm
MuxDomain是 WezTerm 通过多路复用器(mux)管理的域(domain)在 Lua 配置接口中的对象化表示,它让用户可以在gui-startup等事件中编程化地完成域连接、断开、状态查询与标签生成等操作。本文以 MuxDomain/index.markdown 为骨架,结合 lua-api-crates/mux/src/domain.rs 与 mux/src/domain.rs 中的实现,逐一讲解该对象提供的全部方法与底层原理,使读者能够编写可靠的多域启动与恢复脚本。
什么是 MuxDomain
MuxDomain代表一个由多路复用器(multiplexer)管理的域。在 WezTerm 的架构中,domain 是终端会话的容器单元:本地local域、通过 SSH 连接的远端域、串口对应的 serial 域,以及连接其他 WezTerm 实例(connect)形成的域,都属于 mux 管理的范畴。
该 Lua 对象的引入时间是 nightly 版本 20230320-124340-559cb7b0,即从此版本起,Lua 配置脚本可以使用MuxDomain的实例方法。
从源码看,MuxDomain在 Rust 层只是一个轻量句柄:它内部只保存一个DomainId(usize类型),并通过 resolve() 从全局Mux中按 id 查回真实的Arc<dyn Domain>再进行操作。也就是说,MuxDomain本身不持有域状态,真正的连接逻辑都定义在mux::domain::Domaintrait 上(见 mux/src/domain.rs)。
获取 MuxDomain 对象的途径
在调用本文介绍的实例方法之前,需要先拿到一个MuxDomain对象。主要有三种方式:
wezterm.mux.get_domain(nil | name | id):nil返回默认域;字符串按名称查找;整数按域 id 查找(见 wezterm.mux.get_domain() 与 lua-api-crates/mux/src/lib.rs);wezterm.mux.all_domains():返回全部域的对象数组(见 wezterm.mux.all_domains());wezterm.mux.default_domain():直接取得默认域对象。
其中mux.all_domains()的 Lua 绑定实现会对每个域执行iter_domains()并逐个封装为MuxDomain(dom.domain_id()),因此返回的是同一时刻所有已注册域的只读快照(见 lua-api-crates/mux/src/lib.rs)。
域的连接与断开:attach()与detach()
domain:attach()
domain:attach()尝试连接(attach)该域。连接一个域会将其远端系统中的窗口(windows)、标签页(tabs)和窗格(panes)导入到本地 GUI 中,这与 SSH 域、连接域的场景直接相关。
关键区别在于:与 AttachDomain 键位绑定不同,调用domain:attach()时,如果域中没有窗格,它不会隐式地新建一个窗格。这一点是为gui-startup事件(见 gui-startup)中的灵活使用而设计的——脚本可以在启动时先连接域,再通过has_any_panes()判断是否有既有窗格,再决定是否要额外 spawn 新的窗格。
如果域已经处于连接状态,再次调用attach()不会有任何副作用(幂等)。
从源码实现看,attach被注册为异步方法(add_async_method),它会将可选的MuxWindow(窗口 id)透传给底层的domain.attach(window.map(|w| w.0)),并在失败时产生形如failed to attach domain <name>: <err>的 Lua 错误(见 lua-api-crates/mux/src/domain.rs)。底层 trait 的签名是async fn attach(&self, window_id: Option<WindowId>) -> anyhow::Result<()>(见 mux/src/domain.rs),意味着连接动作可能涉及网络往返与远端状态同步,在 Lua 中需要以异步方式等待完成。
domain:detach()
domain:detach()尝试断开(detach)该域。断开会使域的窗口、标签页和窗格从本地 GUI 中移除,但不会关闭这些窗格——之后再次attach()时,它们仍然存在。这是多路复用器“断开不销毁”语义的核心体现。
需要注意:并非所有域都支持断开操作。对不支持的域调用detach()会向错误日志或调试浮层(debug overlay)记录错误。从 trait 定义看,Domain提供了fn detachable(&self) -> bool来声明某域是否支持 detach(见 mux/src/domain.rs),detach在 Lua 层是一个同步方法,底层实现失败时返回failed to detach domain <name>: <err>(见 lua-api-crates/mux/src/domain.rs)。
域的查询方法:状态、名称、标识与窗格
domain:state()
domain:state()返回域当前是已连接还是未连接,结果为字符串:
"Attached"—— 域已连接;"Detached"—— 域未连接。
该字符串由 Rust 侧对DomainState::Attached/DomainState::Detached的match直接映射得到(见 lua-api-crates/mux/src/domain.rs),而DomainState枚举本身就定义在 mux/src/domain.rs,包含Detached与Attached两个变体。可以用它做启动脚本的状态分支,例如仅在state() == "Detached"时才执行连接逻辑。
domain:name()
domain:name()返回域名。域名是唯一的:任何两个域都不会重名,且名字在域的生命周期内保持不变。底层对应 trait 的fn domain_name(&self) -> &str,文档注释也明确要求它“应当是一个短标识符”(见 mux/src/domain.rs),因此可以放心地把name()当作域的稳定 key 来使用。
domain:domain_id()
domain:domain_id()返回域的 id。底层就是直接返回MuxDomain内部保存的DomainId(见 lua-api-crates/mux/src/domain.rs),id 由alloc_domain_id()通过原子计数器分配(见 mux/src/domain.rs)。配合wezterm.mux.get_domain(id)可以在脚本中保存 id、稍后重新取回同一个域对象。
domain:has_any_panes()
domain:has_any_panes()当 mux 中存在属于该域的任何窗格时返回true,否则返回false。实现上会遍历mux.iter_panes()并检查任一窗格的domain_id()是否与当前域一致(见 lua-api-crates/mux/src/domain.rs)。
官方文档特别指出,这个方法是“在连接域后决定是否要额外生成窗格”时的有力工具。结合attach()不会隐式 spawn 窗格的设计,常见的恢复场景就是:
local wezterm = require 'wezterm' local function attach_and_spawn(domain_name) local dom = wezterm.mux.get_domain(domain_name) if dom == nil then return end dom:attach() if not dom:has_any_panes() then -- 域里没有既有窗格,说明可能是全新域,spawn 一个初始窗格 wezterm.mux.spawn_window { workspace = { name = domain_name } } end enddomain:is_spawnable()
domain:is_spawnable()如果该域永远无法生成新的窗格/标签页/窗口,则返回false,否则返回true。文档给出的典型例子是串口域(serial domain):串口设备只有一个会话,不能在其中再 spawn 新窗格。底层对应 trait 的fn spawnable(&self) -> bool,默认实现返回true,需要禁用的域会覆盖该方法(见 mux/src/domain.rs)。
域标签:domain:label()
domain:label()计算一个描述域名与状态的标签(label),标签会随域状态的变化而改变——例如一个已连接的 SSH 域,其标签可能反映连接地址与状态信息,而断开后标签也会随之变化。底层调用 trait 的异步方法async fn domain_label(&self) -> String,默认实现仅返回域名本身,各具体域类型可以覆盖以返回更丰富的描述(见 mux/src/domain.rs 与 lua-api-crates/mux/src/domain.rs)。
label()与name()的区别在于:name()是稳定唯一、生命周期内不变的标识符;label()是面向展示的、随状态变化的描述文本。需要稳定 key 时用name(),需要给人看的状态摘要时用label()。
实战:在 gui-startup 中编排多域启动
将上述方法组合起来,就可以在gui-startup事件中实现一个完整的“多域恢复 + 按需建窗”流程,这也是attach()特意不隐式 spawn 窗格的设计初衷:
local wezterm = require 'wezterm' return { gui_startup = function() local mux = wezterm.mux -- 枚举所有已注册域,打印状态概览 for _, dom in ipairs(mux.all_domains()) do wezterm.log_info(string.format( 'domain: name=%s id=%s state=%s label=%s spawnable=%s has_panes=%s', dom:name(), dom:domain_id(), dom:state(), dom:label(), dom:is_spawnable(), dom:has_any_panes() )) end -- 只对未连接且支持 spawn 的域执行连接 local target = mux.get_domain('myserver') if target and target:state() == 'Detached' and target:is_spawnable() then target:attach() -- 域是空的,需要补一个初始窗格 if not target:has_any_panes() then mux.spawn_window {} end end end, }这段脚本用到了本文介绍的全部方法:all_domains()枚举、name()/domain_id()做稳定标识、state()判断连接状态、label()生成展示文本、is_spawnable()排除不可 spawn 的域、attach()恢复会话、has_any_panes()决定是否补建窗格。错误处理方面,attach()失败会以 Lua 错误形式抛出,可在pcall中包裹以进行降级处理。
相关参考
- 对象索引页:MuxDomain/index.markdown
- 域注册与查询:wezterm.mux.get_domain()、wezterm.mux.all_domains()
- 键位绑定中的连接方式:AttachDomain
- 事件入口:gui-startup
- Lua 绑定实现:lua-api-crates/mux/src/domain.rs
- 底层 Domain trait 与状态定义:mux/src/domain.rs
【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考