WezTerm Copy Mode 键位表深度解析:从默认键表到完全自定义的纯键盘选择方案
【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm
Copy Mode(复制模式)是 WezTerm 提供的一种基于键盘的文本选择模式,它让你无需触碰鼠标即可在滚动缓冲区(scrollback)中定位光标、以单元格/行/矩形方式框选文本并复制。本文以仓库中 docs/examples/default-copy-mode-key-table.markdown 提供的默认copy_mode键表为骨架,逐键位拆解其动作语义,并借助源码中的CopyModeAssignment枚举与键表加载机制,说明如何通过key_tables.copy_mode深度定制这套 Vim 风格的按键体系。读完本文,你将掌握 Copy Mode 的完整默认按键、每种动作的精确行为,以及用 Lua 配置自定义/扩展现有键表的方法。
Copy Mode 是什么
Copy Mode 允许你仅使用键盘完成区域选择与复制,其定位与 WezTerm 的 Quick Select 模式不同:Quick Select 面向“快速匹配常见模式”,而 Copy Mode 面向“基于键盘控制描述任意选择区域”。被高亮/选中文本的颜色可通过 外观配置中的自定义颜色 调整。
- 通过
ActivateCopyMode键分配进入 Copy Mode,默认绑定为CTRL-SHIFT-X(参见 config/src/keyassignment.rs 中ActivateCopyMode枚举项)。 - 进入后,标签页标题会添加
"Copy Mode"前缀,标签行为改变:键盘输入改为控制光标,并在需要时滚动视口,风格接近 Vim 编辑器。 - 将光标移动到选择区域起点,按
v进入选择模式(默认关闭),再移动到终点,按CTRL-SHIFT-C(Copy)即可复制到剪贴板。
完整默认 copy_mode 键表逐键解读
下述 Lua 代码即仓库中 docs/examples/default-copy-mode-key-table.markdown 的完整内容,它定义了key_tables.copy_mode下全部默认键位:
local wezterm = require 'wezterm' local act = wezterm.action return { key_tables = { copy_mode = { { key = 'Tab', mods = 'NONE', action = act.CopyMode 'MoveForwardWord' }, { key = 'Tab', mods = 'SHIFT', action = act.CopyMode 'MoveBackwardWord', }, { key = 'Enter', mods = 'NONE', action = act.CopyMode 'MoveToStartOfNextLine', }, { key = 'Escape', mods = 'NONE', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'Space', mods = 'NONE', action = act.CopyMode { SetSelectionMode = 'Cell' }, }, { key = '$', mods = 'NONE', action = act.CopyMode 'MoveToEndOfLineContent', }, { key = '$', mods = 'SHIFT', action = act.CopyMode 'MoveToEndOfLineContent', }, { key = ',', mods = 'NONE', action = act.CopyMode 'JumpReverse' }, { key = '0', mods = 'NONE', action = act.CopyMode 'MoveToStartOfLine' }, { key = ';', mods = 'NONE', action = act.CopyMode 'JumpAgain' }, { key = 'F', mods = 'NONE', action = act.CopyMode { JumpBackward = { prev_char = false } }, }, { key = 'F', mods = 'SHIFT', action = act.CopyMode { JumpBackward = { prev_char = false } }, }, { key = 'G', mods = 'NONE', action = act.CopyMode 'MoveToScrollbackBottom', }, { key = 'G', mods = 'SHIFT', action = act.CopyMode 'MoveToScrollbackBottom', }, { key = 'H', mods = 'NONE', action = act.CopyMode 'MoveToViewportTop' }, { key = 'H', mods = 'SHIFT', action = act.CopyMode 'MoveToViewportTop', }, { key = 'L', mods = 'NONE', action = act.CopyMode 'MoveToViewportBottom', }, { key = 'L', mods = 'SHIFT', action = act.CopyMode 'MoveToViewportBottom', }, { key = 'M', mods = 'NONE', action = act.CopyMode 'MoveToViewportMiddle', }, { key = 'M', mods = 'SHIFT', action = act.CopyMode 'MoveToViewportMiddle', }, { key = 'O', mods = 'NONE', action = act.CopyMode 'MoveToSelectionOtherEndHoriz', }, { key = 'O', mods = 'SHIFT', action = act.CopyMode 'MoveToSelectionOtherEndHoriz', }, { key = 'T', mods = 'NONE', action = act.CopyMode { JumpBackward = { prev_char = true } }, }, { key = 'T', mods = 'SHIFT', action = act.CopyMode { JumpBackward = { prev_char = true } }, }, { key = 'V', mods = 'NONE', action = act.CopyMode { SetSelectionMode = 'Line' }, }, { key = 'V', mods = 'SHIFT', action = act.CopyMode { SetSelectionMode = 'Line' }, }, { key = '^', mods = 'NONE', action = act.CopyMode 'MoveToStartOfLineContent', }, { key = '^', mods = 'SHIFT', action = act.CopyMode 'MoveToStartOfLineContent', }, { key = 'b', mods = 'NONE', action = act.CopyMode 'MoveBackwardWord' }, { key = 'b', mods = 'ALT', action = act.CopyMode 'MoveBackwardWord' }, { key = 'b', mods = 'CTRL', action = act.CopyMode 'PageUp' }, { key = 'c', mods = 'CTRL', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'd', mods = 'CTRL', action = act.CopyMode { MoveByPage = 0.5 }, }, { key = 'e', mods = 'NONE', action = act.CopyMode 'MoveForwardWordEnd', }, { key = 'f', mods = 'NONE', action = act.CopyMode { JumpForward = { prev_char = false } }, }, { key = 'f', mods = 'ALT', action = act.CopyMode 'MoveForwardWord' }, { key = 'f', mods = 'CTRL', action = act.CopyMode 'PageDown' }, { key = 'g', mods = 'NONE', action = act.CopyMode 'MoveToScrollbackTop', }, { key = 'g', mods = 'CTRL', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'h', mods = 'NONE', action = act.CopyMode 'MoveLeft' }, { key = 'j', mods = 'NONE', action = act.CopyMode 'MoveDown' }, { key = 'k', mods = 'NONE', action = act.CopyMode 'MoveUp' }, { key = 'l', mods = 'NONE', action = act.CopyMode 'MoveRight' }, { key = 'm', mods = 'ALT', action = act.CopyMode 'MoveToStartOfLineContent', }, { key = 'o', mods = 'NONE', action = act.CopyMode 'MoveToSelectionOtherEnd', }, { key = 'q', mods = 'NONE', action = act.Multiple { { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 't', mods = 'NONE', action = act.CopyMode { JumpForward = { prev_char = true } }, }, { key = 'u', mods = 'CTRL', action = act.CopyMode { MoveByPage = -0.5 }, }, { key = 'v', mods = 'NONE', action = act.CopyMode { SetSelectionMode = 'Cell' }, }, { key = 'v', mods = 'CTRL', action = act.CopyMode { SetSelectionMode = 'Block' }, }, { key = 'w', mods = 'NONE', action = act.CopyMode 'MoveForwardWord' }, { key = 'y', mods = 'NONE', action = act.Multiple { { CopyTo = 'ClipboardAndPrimarySelection' }, { CopyMode = 'ScrollToBottom' }, { CopyMode = 'Close' }, }, }, { key = 'PageUp', mods = 'NONE', action = act.CopyMode 'PageUp' }, { key = 'PageDown', mods = 'NONE', action = act.CopyMode 'PageDown' }, { key = 'End', mods = 'NONE', action = act.CopyMode 'MoveToEndOfLineContent', }, { key = 'Home', mods = 'NONE', action = act.CopyMode 'MoveToStartOfLine', }, { key = 'LeftArrow', mods = 'NONE', action = act.CopyMode 'MoveLeft' }, { key = 'LeftArrow', mods = 'ALT', action = act.CopyMode 'MoveBackwardWord', }, { key = 'RightArrow', mods = 'NONE', action = act.CopyMode 'MoveRight', }, { key = 'RightArrow', mods = 'ALT', action = act.CopyMode 'MoveForwardWord', }, { key = 'UpArrow', mods = 'NONE', action = act.CopyMode 'MoveUp' }, { key = 'DownArrow', mods = 'NONE', action = act.CopyMode 'MoveDown' }, }, }, }上述配置可直接放入~/.wezterm.lua(或WEZTERM_CONFIG_FILE指向的配置)作为return表返回。需要注意:一旦你定义了copy_mode键表,它将整体替换默认键表(详见下文“自定义方式”),所以完整复制并在此基础上修改是最稳妥的做法。
CopyMode 动作全集:每个动作的真实语义
上面键表中出现的每个动作字符串/表,都对应 config/src/keyassignment.rs 中CopyModeAssignment枚举的一个变体。该枚举即 Copy Mode 支持的全部动作集合,可归纳为以下几类:
光标移动类
| 动作 | 行为 | 默认键位 |
|---|---|---|
MoveLeft/MoveRight/MoveUp/MoveDown | 向对应方向移动一个单元格/一行 | h/l/k/j,方向键 |
MoveForwardWord | 向前移动一个单词 | w、Tab、Alt-f、Alt-RightArrow |
MoveBackwardWord | 向后移动一个单词 | b、Shift-Tab、Alt-b、Alt-LeftArrow |
MoveForwardWordEnd | 移动到下一个单词的末尾 | e |
MoveToStartOfLine | 移动到本行行首(第 0 列) | 0、Home |
MoveToStartOfLineContent | 移动到本行首个非空白字符处 | ^、Alt-m |
MoveToEndOfLineContent | 移动到本行内容末尾 | $、End |
MoveToStartOfNextLine | 移动到下一行行首 | Enter |
MoveByPage(f) | 按比例滚动,正数向下、负数向上 | Ctrl-d(0.5)、Ctrl-u(-0.5) |
PageUp/PageDown | 上/下翻一整屏 | PageUp/PageDown、Ctrl-b/Ctrl-f |
视口与滚动缓冲区定位类
| 动作 | 行为 | 默认键位 |
|---|---|---|
MoveToScrollbackTop | 跳到滚动缓冲区顶部 | g |
MoveToScrollbackBottom | 跳到滚动缓冲区底部 | Shift-G |
MoveToViewportTop | 跳到视口顶部行 | Shift-H |
MoveToViewportMiddle | 跳到视口中间行 | Shift-M |
MoveToViewportBottom | 跳到视口底部行 | Shift-L |
选择模式类
| 动作 | 行为 | 默认键位 |
|---|---|---|
SetSelectionMode(Cell) | 开启单元格(字符级)选择模式 | v、Space |
SetSelectionMode(Line) | 开启整行选择模式 | Shift-V |
SetSelectionMode(Block) | 开启矩形块选择模式 | Ctrl-v |
SetSelectionMode(None) | 关闭选择模式(取消框选) | — |
ClearSelectionMode | 清除选择模式状态 | — |
三种选择模式对应 config/src/keyassignment.rs 中的SelectionMode语义:Cell适合复制任意连续片段,Line适合整行提取,Block(矩形选择)适合对齐的表格/日志列数据;其中矩形选择自20220624-141144-bd1b7c5d版本起提供。
选择端点跳转类
| 动作 | 行为 | 默认键位 |
|---|---|---|
MoveToSelectionOtherEnd | 将光标移动到选择的另一端(锚点) | o |
MoveToSelectionOtherEndHoriz | 仅在水平方向移动选择另一端(矩形选择时尤为有用) | Shift-O |
JumpForward{prev_char} | 向前跳转到指定字符(类似 Vimf/t);prev_char=true表示落在字符前 | f/t |
JumpBackward{prev_char} | 向后跳转到指定字符(类似 VimF/T) | F/T |
JumpAgain | 重复上一次字符跳转 | ; |
JumpReverse | 反方向重复上一次字符跳转 | , |
收尾与组合动作
| 动作 | 行为 | 默认键位 |
|---|---|---|
CopyMode:Close | 退出 Copy Mode | — |
CopyMode:ScrollToBottom | 先滚回滚动缓冲区底部 | 作为退出时的“复位”步骤 |
CopyTo('ClipboardAndPrimarySelection') | 将当前选择同时复制到剪贴板与主选择区 | y |
值得注意的是默认键表中大量使用了act.Multiple { ... }组合:例如y被定义为先CopyTo再ScrollToBottom+Close,即“复制并退出且滚回底部”;Escape、Ctrl-c、Ctrl-g、q也都通过Multiple完成“复位视口 + 退出”。这与 docs/copymode.md 中“y复制并退出、Esc/Ctrl-c/Ctrl-g/q退出”的说明完全对应。
Copy Mode 键位速查表
综合 docs/copymode.md 的按键分配表与默认键表,常用操作速查如下:
| 操作 | 键位 |
|---|---|
| 进入 Copy Mode | Ctrl-Shift-X |
| 复制并退出 Copy Mode | y |
| 退出 Copy Mode | Esc、Ctrl-c、Ctrl-g、q |
| 单元格选择 | v(再按一次取消) |
| 行选择 | Shift-V |
| 矩形块选择 | Ctrl-V |
| 移动光标 | 方向键,或h/j/k/l |
| 向前/后一个单词 | Alt-右方向/Alt-左方向、Alt-f/Alt-b、Tab/Shift-Tab、w/b |
| 移动到单词末尾 | e |
| 行首 / 行首内容 / 行尾内容 | 0(Home) /^(Alt-m) /$(End) |
| 下一行行首 | Enter |
| 滚动缓冲区顶部 / 底部 | g/Shift-G |
| 视口顶部 / 中间 / 底部 | Shift-H/Shift-M/Shift-L |
| 上/下半屏 | Ctrl-u/Ctrl-d |
| 上/下整屏 | PageUp(Ctrl-b) /PageDown(Ctrl-f) |
| 跳转选择另一端点 | o(水平方向:Shift-O) |
| 字符跳转 f/t 与 F/T | f/t向前、F/T向后,;重复、,反向 |
| 复制到剪贴板(退出 Copy Mode 后) | Ctrl-Shift-C |
如何自定义 copy_mode 键表
两种自定义方式
自20220624-141144-bd1b7c5d版本起,Copy Mode 的键位由copy_mode这个 Key Table 指定,你可以通过两种方式自定义:
- 整体替换:在
~/.wezterm.lua中提供自己的copy_mode键表定义(即上文完整配置)。注意这种方式会整体替换默认表,因此需要把想保留的键位一并写入。 - 基于默认表扩展:先通过
wezterm.gui.default_key_tables()(参见 docs/config/lua/wezterm.gui/default_key_tables.md)取得当前版本的默认键表,再增删条目。这在较新版本中尤其有用,因为早期版本只能整体替换,无法局部覆盖。
查看你本机版本的默认键表
文档中给出的默认键表可能比你安装的版本更新,请用以下命令查看本机实际默认值:
wezterm show-keys --lua --key-table copy_mode键表与输入解析的底层机制
从源码角度,自定义之所以生效,是因为键表解析发生在 GUI 层:在 wezterm-gui/src/inputmap.rs 中,配置加载完成后,如果keys.by_name里没有copy_mode/search_mode条目,会自动用overlay::copy::copy_key_table()与search_key_table()注入默认表;一旦你的配置提供了同名键表,注入就会被跳过,你的定义成为唯一解析来源。
此外,Key Table 机制本身由key_tables配置项承载,配合ActivateKeyTable(含one_shot、timeout_milliseconds、replace_current等字段,见 config/src/keyassignment.rs)可构建复杂的键表激活栈;Copy Mode 的进入正是ActivateCopyMode动作触发对应键表的结果。
自定义实例:在默认键表上添加自定义动作
下面演示如何基于默认键表做局部修改——例如在保持全部默认键位不变的前提下,给Ctrl-n增加“向后滚动半屏”的绑定,并给Space追加CopyTo行为(注意这会改变Space的原语义,仅为演示Multiple的组合能力):
local wezterm = require 'wezterm' local act = wezterm.action local config = {} local copy_mode = wezterm.gui.default_key_tables().copy_mode table.insert(copy_mode, { key = 'n', mods = 'CTRL', action = act.CopyMode { MoveByPage = 0.5 } }) -- 演示:让 Space 先开启单元格选择,再追加复制行为(会覆盖默认 Space 语义) for i, entry in ipairs(copy_mode) do if entry.key == 'Space' then entry.action = act.Multiple { { CopyMode = { SetSelectionMode = 'Cell' } }, { CopyTo = 'ClipboardAndPrimarySelection' }, } end end config.keys = { { key = 'X', mods = 'CTRL|SHIFT', action = act.ActivateCopyMode }, } config.key_tables = { copy_mode = copy_mode } return config要点提示:
- 先执行
table.insert前可先print(wezterm.version)确认版本支持default_key_tables(); - 修改后的键表同样遵循键表解析规则:栈顶优先匹配,未命中继续向下查找(见 docs/config/key-tables.md 中关于激活栈的说明);
- 若在复杂键表中被卡住,可重新保存
~/.wezterm.lua触发配置重载,键表栈会自动清空,从而恢复默认状态。
常见问题与排查
- 为什么修改了 copy_mode 后部分按键失效?因为你整体替换了默认键表,遗漏的键位不再生效。请基于
wezterm.gui.default_key_tables().copy_mode修改,或对照本文完整默认键表逐条补齐。 - 如何确认当前键表内容?运行
wezterm show-keys --lua --key-table copy_mode即可输出本机生效的键表定义。 - 进入 Copy Mode 后标题没变化?Copy Mode 激活时标签标题应带
"Copy Mode"前缀;若未出现,确认ActivateCopyMode绑定未被其他键分配覆盖。 - 矩形选择不可用?
SetSelectionMode = 'Block'需要20220624-141144-bd1b7c5d及之后的版本;旧版本请升级。
参考路径
- 默认键表示例:docs/examples/default-copy-mode-key-table.markdown
- Copy Mode 使用文档:docs/copymode.md
- Key Table 机制说明:docs/config/key-tables.md
- 动作枚举源码:config/src/keyassignment.rs
- 键表默认注入逻辑:wezterm-gui/src/inputmap.rs
- 默认键表 API 文档:docs/config/lua/wezterm.gui/default_key_tables.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),仅供参考