
开发工具【免费下载链接】which-key.nvim Create key bindings that stick. WhichKey helps you remember your Neovim keymaps, by showing available keybindings in a popup as you type.项目地址https://gitcode.com/gh_mirrors/wh/which-key.nvim点击查看免费下载which-key.nvim3.0 是一次从零开始的完整重写full rewrite作为作者开发的第一款插件这次重新出发带来了更快的性能、更简洁的映射规范以及围绕ModeChanged事件重构的触发机制。本文以官方 NEWS.md 发布的 3.0 更新说明为主线结合仓库源码config.lua、mappings.lua、presets.lua、triggers.lua、icons.lua 等逐项深入解读这些新特性帮助你理解新规范的用法、迁移旧配置以及每一项设计背后的实现原理。读完本文你将掌握 3.0 版本的完整配置体系从wk.add()映射规范、三种布局预设与排序器到图标规则、独立延迟与自动触发安全策略并能安全地把 v2 配置迁移到新版本。一、3.0 更新概览一次彻底的自我革新根据 NEWS.md 的官方说明3.0 版本包含以下核心变更完整重写性能与功能全面改进Visual 与 Operator Pending 模式集成改用ModeChanged事件不再需要为操作符operator做额外重映射简化映射移除了晦涩的秘密映射obscure secret mappings更安全的自动触发自动触发永远不会为除g、z之外的单键创建其余字母键均被视为不安全独立延迟delay与timeoutlen分开设置布局系统提供classic、modern、helix三种预设可按模式启用/禁用支持local、order、group、alphanum、mod、lower、icase、desc、manual等排序选项映射组可展开key与desc支持自定义字符串替换图标支持通过lazy.nvim自动识别键映射图标支持自定义图标规则与映射级图标规格绝不挡路弹窗避免与光标重叠新 Mapping Spec更贴近vim.keymap.set与lazy.nvim的键映射定义方式。接下来我们逐一拆解这些特性并结合源码说明它们为什么这样实现。二、Visual 与 Operator Pending 模式基于ModeChanged的全新触发机制3.0 之前要在 Visual 或 Operator Pending操作符待定模式下弹出 which-key往往需要额外的 operator 重映射繁琐且容易出错。3.0 改为监听 Neovim 的ModeChanged自动命令事件彻底移除了 operator 重映射的需求NEWS.md 原话Now usesModeChanged, eliminating the need for operator remappings。在 state.lua 中可以看到实现插件注册了ModeChangedautocmd在回调中先通过cooldown()做同一 tick 内的防重启保护再用M.safe()判断切换是否安全例如从命令行模式切出、录制宏期间、Visual Block 模式都会被判定为不安全最后在mode存在且当前处于 operator-pendingUtil.xo()时依据Config.triggers.modes[mode.mode]决定是否M.start()启动弹窗。这种机制还带来了defer选项——先隐藏、等到按下额外按键再显示弹窗。默认配置下defer只在V按行 Visual与C-V块 Visual模式下返回truedefer function(ctx) return ctx.mode V or ctx.mode C-V end,结合源码与 README.md 的解释当defer返回true时弹窗要等再按下一个键才出现。例如yafyank 到 f 标记按下y时 which-key 不会弹出按下ya之后才显示。你还可以按需延迟某些操作符比如让d、y这两个操作符都走延迟逻辑---param ctx { mode: string, operator: string } defer function(ctx) if vim.list_contains({ d, y }, ctx.operator) then return true end return vim.list_contains({ C-V, V }, ctx.mode) end,三、新 Mapping Spec与vim.keymap.set对齐的映射定义NEWS.md 强调3.0 引入了更新、更好的映射规范更符合vim.keymap.set以及 lazy.nvim 的键映射定义方式。这份规范对应 README 中的 mapping spec见 README.md。3.1 添加映射的两条途径映射既可以在配置的opts.spec中声明也可以在之后任意时刻、任意配置文件中通过require(which-key).add()多次追加。入口实现位于 init.luawk.add()会把 spec 放入_queue队列由 config.lua 在setup阶段统一处理。local wk require(which-key) wk.add({ { leaderf, group file }, -- 分组定义 leaderf 为 file 组 { leaderff, cmdTelescope find_filescr, desc Find File, mode n }, { leaderfb, function() print(hello) end, desc Foobar }, { leaderfn, desc New File }, { leaderf1, hidden true }, -- 隐藏这条键映射 { leaderw, proxy c-w, group windows }, -- 代理到窗口映射 { leaderb, group buffers, expand function() return require(which-key.extras).expand.buf() end }, })3.2 映射属性一览一个映射项支持以下属性完整清单见 README.md属性类型说明[1]stringlhs必需[2]string\|fun()rhs可选存在时会真正创建该键映射descstring\|fun():string描述非分组映射必需groupstring\|fun():string组名可选modestring\|string[]模式可选默认ncondboolean\|fun():boolean启用条件可选hiddenboolean是否隐藏可选iconstring\|wk.Icon\|fun():(wk.Icon\|string)图标规格可选proxystring代理到另一条映射可选expandfun():wk.Spec动态子映射可选其他—任何vim.keymap.set合法选项仅在创建映射时使用要点当desc、group、icon是函数时它们会在弹窗每次显示时重新求值见 README.md。cond为false或函数返回false时该映射会被直接跳过见 mappings.lua。3.3 嵌套映射与属性继承新规范支持任意深度的嵌套且大多数属性可以在任意层级继承或覆盖README 原文。如下例中mode { n, v }写在父级子映射无需重复指定wk.add({ { mode { n, v }, -- NORMAL 和 VISUAL 模式 { leaderq, cmdqcr, desc Quit }, -- 继承 mode { leaderw, cmdwcr, desc Write }, } })属性继承的实现在 mappings.lua解析子项时若父级字段标记了inherit true且子项没有同名字段就自动继承父值。从M.fieldsmappings.lua可以看到buffer、expr、mode、nowait、remap、silent、hidden、cond、icon等字段都支持继承而rhs、lhs、group、proxy、expand不继承。3.4proxy与expand两个高阶特性proxy让某个前缀代理到另一个已有的前缀。例如{ leaderw, proxy c-w, group windows }即leaderw直接借用c-w下的窗口映射集合对应源码 mappings.lua 中的proxy字段。expand用于生成动态映射且动态映射只支持函数形式的rhs。内置两个例子见 README.mdrequire(which-key.extras).expand.buf生成数字键到缓冲区的映射require(which-key.extras).expand.win生成数字键到窗口的映射。四、更安全的自动触发单键映射的保护策略NEWS.md 明确写道自动触发现在永远不会为单键创建g和z除外。其他所有字母都是不安全的。背景是如果 which-key 对某个已存在的内置单键映射例如a强行安装触发会破坏该键原本的功能。默认的opts.triggers是triggers { { auto, mode nxso }, },auto是一个特殊标记其处理逻辑见 config.lua解析后把对应 mode 记入triggers.modes并从实际触发列表中移除。它的语义是为每种模式自动设置触发键并在ModeChanged期间触发但绝不会为已存在的键映射创建自动触发其中包括 Neovim 内置的所有合法单键映射见 README.md 的说明。触发安装前会调用 triggers.lua 的M.is_mapped()检查maparg若目标键已有非 which-key 的映射Nop与带which-key-trigger描述的除外则跳过。若确实要在某个内置键上触发只能手动添加例如triggers { { auto, mode nixsotc }, { a, mode { n, v } }, }也可以完全关掉自动触发手动指定前缀触发triggers { { leader, mode { n, v } }, }五、独立延迟delay不再受timeoutlen约束NEWS.md 提到的新特性之一延迟可以独立于timeoutlen设置。 默认配置把延迟封装成一个函数见 config.lua---type number | fun(ctx: { keys: string, mode: string, plugin?: string }):number delay function(ctx) return ctx.plugin and 0 or 200 end,含义是如果当前按键组合属于某个插件plugin上下文立即0ms弹出否则等待 200ms。delay既可以是数字也可以是返回数字的函数从而支持按keys、mode、plugin上下文动态决定。这也对应 NEWS.md 中设置延迟独立于 timeoutlen的改进——旧版本中弹窗时机受全局timeoutlen影响现在完全可以自主控制。附带一提弹窗内部滚动键也独立配置在opts.keyskeys { scroll_down c-d, -- 弹窗内向下滚动 scroll_up c-u, -- 弹窗内向上滚动 },六、布局系统三种预设、按模式开关、排序与组展开3.0 的布局能力覆盖了预设、模式开关、排序、组展开与字符串替换五个维度NEWS.md 的 Layout 一节。6.1 三种预设classic、modern、helixopts.preset可取值false、classic、modern、helix默认classic。三种预设的实际窗口参数定义在 presets.lua预设窗口特征classic宽度math.huge尽量宽col 0左对齐border none高度{min4, max25}modern宽度0.9占父级 90%居中col 0.5border rounded标题居中helix宽度{min30, max60}右下角定位col -1, row -1border rounded标题居左padding {0,1}尺寸语义见 layout.lua 的M.dim()绝对值小于 1 的数字视为父级百分比负数表示从父级尺寸中减去{min, max}表则把结果钳制在区间内。这些规则有完整的单元测试佐证见 tests/layout_spec.lua。预设的合并顺序在 config.luadefaults→Presets[preset]→ 用户opts即预设可以整体覆盖默认值而用户配置永远优先。如果你不使用预设也可以直接自定义opts.win的全部窗口参数no_overlap、width、height、col、row、border、padding、title、title_pos、zindex、bo、wo完整默认值见 config.lua。6.2 按模式启用/禁用布局相关的triggers与defer选项共同决定了 which-key 在哪些模式下生效默认auto覆盖n/i/x/s/o/t/cnormal、insert、visual、select、operator-pending、terminal、command用户可通过修改opts.triggers精确控制每个模式的开关见 README Triggers 一节。6.3 排序器Sorters默认排序为{ local, order, group, alphanum, mod }config.lua。可选排序器README 与 config.lua 注释一致排序器含义local缓冲区局部映射优先order按条目顺序marks / registers 等插件使用group分组排在最后alphanum字母数字优先mod特殊修饰键排最后manual按映射添加顺序case小写优先映射会依次经过配置的排序器最后再按键的自然顺序排序。6.4 组展开Expand Groupsopts.expand默认0表示当分组内映射数 ≤ 该值时直接展开显示而不是折叠成组也可以传一个函数做更精细的判断例如展开所有没有描述的分组节点expand function(node) return not node.desc -- 展开所有无描述的节点 end,6.5 key / desc 字符串替换opts.replace用一组 Lua Pattern 或函数对key与desc做格式化。默认配置config.luareplace { key { function(key) return require(which-key.view).format(key) end, -- { Space, SPC }, }, desc { { Plug%(?(.*)%)?, %1 }, { ^%, }, { [cC]md, }, { [cC][rR], }, { [sS]ilent, }, { ^lua%s, }, { ^call%s, }, { ^:%s*, }, }, },例如它会把 desc 中多余的:call、lua、Cmd、CR、silent前缀清理掉让弹窗里的描述更干净。七、图标支持lazy.nvim 自动检测 自定义规则 映射级图标NEWS.md 的 Icon 一节总结了三条获取图标的途径详见 README.mdlazy.nvim 自动检测使用 lazy.nvim 时属于某些插件的键映射会被自动匹配图标。实现上icons.lua 会从lazy.core.handler的 keys handler 反查该映射所属插件名再查M.rules内置规则表中的plugin字段。自定义规则在opts.icons.rules中配置规则按插件名、desc 模式pattern、文件类型等匹配。规则匹配顺序为插件名 → 文件类型 → desc 模式见M._geticons.lua。映射级图标在 mapping spec 的任意层级指定icon属性例如在leaderg节点上给所有 git 键映射统一图标。icon属性可以是字符串也可以是wk.Icon对象其字段包括iconstring实际图标hlstring图标高亮组colorstringazure、blue、cyan、green、grey、orange、purple、red、yellow之一会映射到WhichKeyIconColor高亮catstringfile、filetype、extension之一namestring指定类别下的图标名。图标来源支持mini.icons与nvim-web-devicons两个 provider见 icons.lua按加载顺序优先采用可用者。若不想使用图标把opts.icons.mappings设为false即可全部关闭opts.icons.rules false则只关闭规则自动匹配保留映射中显式声明的图标。八、绝不挡路弹窗避开光标重叠NEWS.md 中Never Get in the Way对应默认窗口选项win.no_overlap trueconfig.lua 注释dont allow the popup to overlap with the cursor。开启后窗口定位会主动避开光标所在位置避免遮挡正在编辑的内容。这与row、col的显式定位配合使用设置了固定row/col时以显式定位为准。九、简化映射与新的 Bug开发者视角的诚实提示NEWS.md 还提到两点容易被忽略的变更Simplified Mappings移除了旧版那些晦涩的秘密映射obscure secret mappings键映射体系更透明、更好理解New Bugs官方以很多新鲜有趣的 bug 等着你去发现自嘲NEWS.md 原文Lots of new and exciting bugs to discover!提醒用户遇到异常时主动反馈。这两条共同传递的信息是3.0 是一个激进的重写版本升级后应重新验证自己的配置而不是假设行为完全向后兼容。十、从 v2 迁移字段变更与自动迁移工具新规范直接关系到迁移。README 明确警告mapping spec 在 v3 中变更了更新现有映射时请只使用新的add方法见 README.md。旧版register()已被标记为 deprecatedinit.lua它会把 spec 按version 1解析。仓库同时提供了自动迁移工具migrate.luaM.migrate(spec)会按 v1 语义解析旧 spec然后把旧字段如lhs/rhs、group布尔标记、prefix等改写为新格式——将lhs写入[1]、rhs写入[2]、group布尔值还原为group desc、按模式分组输出嵌套结构最终返回可直接使用的新版 spec 文本方便你核对差异后替换。另外config.lua 内置了旧选项的兼容检查与告警operators、key_labels、motions、popup_mappings、window、ignore_missing、hidden、triggers_nowait、triggers_blacklist、disable.trigger、modes等旧选项都被标记为 deprecated并给出了各自的替代项分别对应opts.defer、opts.replace、opts.keys、opts.win、opts.filter、opts.delay、opts.triggers等。如果检测到这些残留选项setup会通过:checkhealth which-key提示你排查。这也是升级后首先要做的事运行:checkhealth which-key检查配置问题见 README.md。十一、弹窗交互与内置插件3.0 的日常使用体验弹窗打开后交互方式见 README.md为按某个键打开分组或执行映射esc取消并关闭弹窗bs返回上一级c-d/c-u上下滚动对应opts.keys.scroll_down/scroll_up。3.0 还保留了四个内置插件plugins/init.lua 负责统一装载config.lua 提供开关Presets为 motions、text-objects、operators、windows、nav、z、g提供默认键位帮助且不创建任何真实键映射Marks在或上显示缓冲区局部与全局标记列表Registers在 NORMAL 模式按或在 INSERT 模式按c-r显示寄存器列表Spelling接管z把全屏拼写建议窗口替换为 which-key 内的建议列表suggestions默认显示 20 条。若需要类似 Hydra 的长按模式可以用require(which-key).show({ keys c-w, loop true })保持弹窗开启直到按下esc见 README.md。结语3.0 之于 which-key.nvim 是一次设计哲学上的转折用ModeChanged取代 operator 重映射、用对齐vim.keymap.set的新 spec 取代旧式表结构、用预设排序器替换规则构建可组合的布局体系同时通过delay独立化、自动触发白名单与no_overlap让插件安静地待在它该在的位置。理解这些设计意图能让你在升级后更快地重写配置也能更精准地利用排序器、图标规则与动态展开等进阶能力。本文涉及的全部配置默认值与源码位置均可从 config.lua 与 README.md 中进一步查阅若升级遇到问题请优先运行:checkhealth which-key。赞分享开发工具【免费下载链接】which-key.nvim Create key bindings that stick. WhichKey helps you remember your Neovim keymaps, by showing available keybindings in a popup as you type.项目地址https://gitcode.com/gh_mirrors/wh/which-key.nvim点击查看免费下载相关推荐which-key.nvim 图标系统完全指南打造个性化键位界面which key.nvim 图标系统完全指南打造个性化键位界面 想要让Neovim的键位提示界面更美观、更直观吗 which key.nvim的图标系开发工具Qwen3-8B-MLX-8bit工具调用与多语言能力实战Qwen3 8B MLX 8bit工具调用与多语言能力实战 本文深入探讨了Qwen3 8B MLX 8bit模型在工具调用、多语言支持和长文本处理方面的强大能力开发工具终极指南nvim-tree.lua与which-key.nvim集成实现可视化快捷键提示终极指南nvim tree.lua与which key.nvim集成实现可视化快捷键提示 想要在Neovim中获得更直观、更高效的文件管理体验吗nvim t开发工具上一篇Writing an OS in Rust搜索引擎优化技术博客推广策略下一篇cann-bench核心组件架构从数据加载到性能评分的全流程技术剖析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考