WezTermwezterm.url模块完全指南:在 Lua 配置中解析 URL 与使用 Url 对象
【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm
wezterm.url是 WezTerm 在20240127-113634-bbcac864版本中引入的 Lua 模块,用于在配置脚本中解析 URL 并操作其结构化的Url对象。通过它,你可以安全地解码含百分号编码(percent-encoding)的路径、提取主机名与查询参数,从而在open-uri事件处理、状态栏展示当前工作目录等场景中编写可靠的自定义逻辑。读完本文,你将掌握wezterm.url.parse的用法、Url对象的全部字段语义,以及如何与pane:get_current_working_dir、OSC 7 工作目录协议配合完成实战级配置。
模块概览与适用场景
wezterm.url模块(入口见 docs/config/lua/wezterm.url/index.markdown)对外暴露处理 URL 的函数与对象。其设计动机来自一个实际问题:终端里的 URL(尤其是file://形式的本地路径)往往带有百分号编码,直接对字符串做sub/gsub手工解码既繁琐又容易出错。把 URL 解析成结构化对象后,读写路径、主机名、查询串都变成字段访问。
该模块在实际使用中主要服务于两类场景:
- 自定义超链接行为:监听
open-uri事件,对file://链接判断是目录还是文本文件,进而执行cd、启动编辑器等操作; - 状态栏展示:在
update-right-status中读取当前 pane 的工作目录,展示远程主机名与路径(配合 OSC 7 shell 集成)。
核心 API:wezterm.url.parse(URL_STRING)
wezterm.url.parse是模块对外暴露的唯一函数,签名与行为定义在 docs/config/lua/wezterm.url/parse.md:
wezterm.url.parse(URL_STRING)它尝试把传入的字符串当作 URL 解析;解析成功时返回一个 Url 对象,解析失败则抛出错误。调用方式是标准的模块方法调用:
local wezterm = require 'wezterm' local url = wezterm.url.parse 'file://myhost/some/path%20with%20spaces'其底层实现位于 lua-api-crates/url-funcs/src/lib.rs。register函数通过get_or_create_sub_module(lua, "url")注册url子模块,再向其中写入parse函数。parse内部直接调用 Rust 生态的urlcrate(依赖声明见 lua-api-crates/url-funcs/Cargo.toml)完成解析,任何解析失败都会携带原始输入字符串包装成 Lua 错误抛出,例如"relative URL without a base while parsing xxx as URL"。这意味着传入的字符串必须是绝对 URL(带 scheme),不能是foo/bar这类相对路径。
Url对象字段详解
Url对象代表一个已被解析的 URL,字段定义见 docs/config/lua/wezterm.url/Url.md,对应源码实现见 lua-api-crates/url-funcs/src/lib.rs。全部字段按语义整理如下:
| 字段 | 类型 | 含义 | 源码依据 |
|---|---|---|---|
scheme | string | URL 协议名,如"file"、"https" | lib.rs L48 |
file_path | string / nil | 解码path字段后的文件路径;URL 无路径段时为nil | lib.rs L60-L81 |
username | string | 用户名部分;未指定时为空字符串"" | lib.rs L49 |
password | string / nil | 密码部分;未指定时为nil | lib.rs L50-L52 |
host | string / nil | 主机名部分,IDNA 解码为 UTF-8;无主机时为nil | lib.rs L53 |
path | string | 路径部分,保留百分号编码原样 | lib.rs L59 |
fragment | string / nil | fragment(#之后的内容)部分 | lib.rs L56-L58 |
query | string / nil | query(?之后的内容)部分 | lib.rs L55 |
port | number / nil | 端口号;未指定时为nil(文档未列出,源码额外暴露) | lib.rs L54 |
官方文档给出的校验示例完整如下:
local wezterm = require 'wezterm' local url = wezterm.url.parse 'file://myhost/some/path%20with%20spaces' assert(url.scheme == 'file') assert(url.file_path == '/some/path with spaces') local url = wezterm.url.parse 'https://github.com/rust-lang/rust/issues?labels=E-easy&state=open' assert(url.scheme == 'https') assert(url.username == '') assert(url.password == nil) assert(url.host == 'github.com') assert(url.path == '/rust-lang/rust/issues') assert(url.query == 'labels=E-easy&state=open')注意两个容易混淆的点:
path与file_path的区别:path返回带百分号编码的原始路径(如/some/path%20with%20spaces),file_path返回解码后的真实路径(如/some/path with spaces)。需要把 URL 当作文件系统路径使用时,务必用file_path。username与password的缺省值不同:无用户名时username是空字符串"",而无密码时password是nil。判断"是否包含密码"时应使用if url.password ~= nil而非真值判断。
file_path的底层解码逻辑
file_path的实现(lib.rs L60-L81)比简单调用解码函数更细致:它遍历 URL 的每个路径段,为每段前补上/后逐段做百分号解码并拼接。此外还有一处针对 Windows 盘符的特判——当解码结果以字母加:或|结尾时(即盘符,如C:),会在末尾追加一个/,避免C:与后续内容粘连(源码注释 "A windows drive letter must end with a slash")。因此file_path在跨平台路径处理上比手写解码更稳妥。
Url对象还支持哪些操作
从源码看,Url对象还做了两件额外的事:
- 实现了 Lua 的
__tostring元方法(lib.rs L42-L44),直接tostring(url)即可得到完整的原始 URL 字符串; - 内部通过
Deref/DerefMut解引用到 Rust 的url::Url(lib.rs L27-L38),Rust 侧代码可以零成本复用urlcrate 的全部能力。
实战一:在open-uri中实现超链接点击行为
wezterm.url最典型的实战用法,是配合open-uri事件重写终端超链接的默认行为。仓库在 docs/recipes/hyperlinks.md 中给出了一份完整的可运行配置,核心逻辑如下:
local wezterm = require 'wezterm' local act = wezterm.action local config = wezterm.config_builder() wezterm.on('open-uri', function(window, pane, uri) local editor = 'nvim' if uri:find '^file:' == 1 and not pane:is_alt_screen_active() then -- 链接格式应为:file://[HOSTNAME]/PATH[#linenr] local url = wezterm.url.parse(uri) if is_shell(pane:get_foreground_process_name()) then local success, stdout, _ = wezterm.run_child_process { 'file', '--brief', '--mime-type', url.file_path, } if success then if stdout:find 'directory' then -- 目录:切换到该目录并列出内容 pane:send_text(wezterm.shell_join_args { 'cd', url.file_path } .. '\r') pane:send_text(wezterm.shell_join_args { 'ls', '-a', '-p', '--group-directories-first', } .. '\r') return false end if stdout:find 'text' then -- 文本文件:用编辑器打开,fragment 携带行号 local args = { editor } if url.fragment then table.insert(args, '+' .. url.fragment) end table.insert(args, url.file_path) pane:send_text(wezterm.shell_join_args(args) .. '\r') return false end end end end -- 不返回值则回落到 WezTerm 默认行为 end) return config这段代码展示了Url对象在真实场景中的价值:
url.file_path拿到解码后的真实路径,可直接传给file命令探测 MIME 类型;url.fragment提取行号,实现"点击链接直接在编辑器第 N 行打开文件";wezterm.shell_join_args负责路径转义,避免空格路径被 shell 拆词。
为了让超链接源真正可点击,还需要在 shell 里开启超链接输出,例如:
alias ls='ls --hyperlink --color=auto' alias delta="delta --hyperlinks --hyperlinks-file-link-format='file://{path}#{line}'" alias rg='rg --hyperlink-format=kitty'此外,docs/recipes/hyperlinks.md还提供了可选的鼠标绑定改造:默认单击即可打开链接,若担心误触,可要求按住CTRL才打开(通过OpenLinkAtMouseCursor动作实现),具体示例见 鼠标绑定配置。若使用 tmux,需要启用超链接终端特性并视配置加上Shift修饰键(set -sa terminal-features ",*:hyperlinks")。该配方的局限是:命令文本被直接注入当前 pane,因此要求 pane 正处于 shell 提示符而非编辑器等交互程序内。
实战二:在状态栏解析当前工作目录
第二个高价值场景是把Url对象用于状态栏。20240127-113634-bbcac864版本起,pane:get_current_working_dir()的返回值从 URI 字符串变更为Url对象(见 get_current_working_dir 文档 与 变更记录),其源码实现可见 lua-api-crates/mux/src/pane.rs:get_current_working_dir把底层url::Url包成url_funcs::Url返回。同时 PaneInformation.current_working_dir 字段也返回同一类型。
update-right-status中的典型用法(完整示例见 set_right_status 文档):
wezterm.on('update-right-status', function(window, pane) local cwd_uri = pane:get_current_working_dir() if cwd_uri then local cwd = '' local hostname = '' if type(cwd_uri) == 'userdata' then -- 新版本:拿到的是 Url 对象,字段直接可用 cwd = cwd_uri.file_path hostname = cwd_uri.host or wezterm.hostname() else -- 旧版本(20230712-072601-f4abf8fd 及更早):字符串,需手工解码 cwd_uri = cwd_uri:sub(8) local slash = cwd_uri:find '/' if slash then hostname = cwd_uri:sub(1, slash - 1) cwd = cwd_uri:sub(slash):gsub('%%(%x%x)', function(hex) return string.char(tonumber(hex, 16)) end) end end -- ... 组装 PowerLine 风格状态栏 end end)这段代码的两处关键设计值得学习:
- 类型判断兼容旧版本:用
type(cwd_uri) == 'userdata'区分新版的Url对象与旧版的普通字符串,旧分支里那行gsub('%%(%x%x)', ...)正是对 percent-encoding 的手工解码——新版用url.file_path一行替代,这也是官方引入该模块的初衷。 host可能为nil:file://不带主机名时host为nil,所以用cwd_uri.host or wezterm.hostname()回退到本机主机名。
要让get_current_working_dir能拿到远程主机名,需要在远端 shell 里启用 OSC 7 序列(见 shell-integration.md):
printf "\033]7;file://HOSTNAME/CURRENT/DIR\033\\"OSC 7 把工作目录以file://URL 形式上报给终端;本地 shell 未发送 OSC 7 时,WezTerm 会通过进程组与操作系统调用自行推断 cwd(Unix 与 Windows 均有支持)。
版本要求与兼容性注意
wezterm.url模块、wezterm.url.parse与Url对象均自20240127-113634-bbcac864起可用(见 index.markdown、parse.md 的since标注)。- 同一版本起
pane:get_current_working_dir()与PaneInformation.current_working_dir的返回值类型由字符串改为Url对象;跨版本分发的配置请沿用上文type(cwd_uri) == 'userdata'的兼容写法。 file_path对 Windows 盘符路径做了补/特判,跨平台配置可以直接使用,无需自行区分平台。
延伸阅读
- 模块入口与函数索引:index.markdown、parse.md、Url.md
- 底层实现:lua-api-crates/url-funcs/src/lib.rs(依赖
url与percent-encodingcrate) - 完整超链接配方:docs/recipes/hyperlinks.md
- 状态栏与兼容写法:set_right_status 文档、get_current_working_dir 文档
- OSC 7 工作目录协议:docs/shell-integration.md
- 相关变更记录:docs/changelog.md
【免费下载链接】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),仅供参考