Vim 模式
Zed 包含一个被称为“vim 模式”的 vim 模拟层。本文档旨在描述它的工作原理以及如何充分利用它。
理念
Zed 中的 Vim 模式主要“按预期执行”:它主要尝试完全复制 vim,但会在可用时使用 Zed 特定的功能来使事情更顺畅。
这意味着 Zed 永远不会 100% 与 Vim 兼容,但应该 100% 熟悉 Vim!我们希望我们的 Vim 模式已经能够应对您 90% 的工作流程,并且我们希望继续改进它。如果您发现 Vim 模式中无法完成的事情,但您在当前工作流程中依赖它们,请 提交问题。
Zed 特定功能
Zed 建立在现代基础之上,它(除其他外)使用 tree-sitter 和语言服务器来理解您正在编辑的文件的内容,并且开箱即用地支持多个光标。
Vim 模式有几个“核心 Zed”键绑定,它们将帮助您充分利用 Zed 的特定功能集。
# Language server
g d Go to definition
g D Go to type definition
g cmd-d Go to implementation
c d Rename (change definition)
g A Go to All references to the current word
g s Find symbol in current file
g S Find symbol in entire project
g ] Go to next diagnostic
g [ Go to previous diagnostic
] d Go to next diagnostic
[ d Go to previous diagnostic
g h Show inline error (hover)
g . Open the code actions menu
# Git
] c Go to next git change
[ c Go to previous git change
# Treesitter
] x Select a smaller syntax node
[ x Select a larger syntax node
# Multi cursor
g l Add a visual selection for the next copy of the current word
g L The same, but backwards
g > Skip latest word selection, and add next.
g < The same, but backwards
g a Add a visual selection for every copy of the current word
# Pane management
g / Open a project-wide search
g <space> Open the current search excerpt
<ctrl-w> <space> Open the current search excerpt in a split
<ctrl-w> g d Go to definition in a split
<ctrl-w> g D Go to type definition in a split
# Insert mode
i a / a a Select the function argument the cursor is in
ctrl-x ctrl-o Open the completion menu
ctrl-x ctrl-c Request GitHub Copilot suggestion (if configured)
ctrl-x ctrl-a Open the inline AI assistant (if configured)
ctrl-x ctrl-l Open the code actions menu
ctrl-x ctrl-z Hides all suggestions
# Ex commands
:E[xplore] Open the project panel
:C[ollab] Open the collaboration panel
:Ch[at] Open the chat panel
:A[I] Open the AI panel
:No[tif] Open the notifications panel
:fe[edback] Open the feedback window
:cl[ist] Open the diagnostics window
:te[rm] Open the terminal
:Ext[ensions] Open the extensions window
Vim 模式使用 Zed 来定义“括号”(用于 %
键)和“单词”(用于 w
和 e
等动作)等概念。这确实导致了一些差异,但它们大多是积极的。例如,%
在 Rust 等语言中将 |
视为括号;而 w
在 Javascript 等语言中将 $
视为单词字符。
Vim 模式使用 Zed 的多光标支持模拟可视块模式。这再次导致了一些差异,但功能更强大。
Vim 的宏支持(q
和 @
)是使用 Zed 的操作实现的。这让我们能够支持录制和重放自动完成的代码等。与 Vim 不同,Zed 不会重复使用 yank 寄存器来录制宏,它们是两个独立的命名空间。
最后,Vim 模式的搜索和替换功能是由 Zed 支持的。这意味着模式语法略有不同,有关详细信息,请参阅 Regex 差异 部分。
自定义键绑定
你可以使用 :keymap
编辑你的个人键绑定。对于 vim 特定的快捷方式,你可能会发现以下模板是一个很好的起点。
注意:我们在 Zed 版本
0.145.0
中进行了一些重大更改。对于较旧版本,请参阅 此文档的先前版本。
[
{
"context": "VimControl && !menu",
"bindings": {
// put key-bindings here if you want them to work in normal & visual mode
}
},
{
"context": "vim_mode == insert",
"bindings": {
// "j k": "vim::NormalBefore" // remap jk in insert mode to escape.
}
},
{
"context": "EmptyPane || SharedScreen",
"bindings": {
// put key-bindings here (in addition to above) if you want them to
// work when no editor exists
// "space f": "file_finder::Toggle"
}
}
]
如果你想模拟 vim 的 map
(nmap
等)命令,可以在正确的上下文中绑定到 workspace::SendKeystrokes
操作。
你可以 在此处 查看 vim 模式下默认启用的绑定。
上下文
只有当 "context"
与你屏幕上的位置匹配时,才会评估 Zed 的键盘绑定。位置是嵌套的,因此当你进行编辑时,你处于 "Workspace"
位置的顶部,其中包含一个 "Pane"
,该 "Pane"
包含一个 "Editor"
。一次只匹配一个级别的上下文。因此可以组合 Editor && vim_mode == normal
,但 Workspace && vim_mode == normal
永远不会匹配,因为我们在 Editor
级别设置了 vim 上下文。
Vim 模式向 Editor
添加了几个上下文
vim_mode
类似于当前模式,但并不相同。它从normal
、visual
、insert
或replace
之一开始(取决于你的模式)。如果你正在键入序列的中间,vim_mode
将是waiting
(如果它正在等待一个任意键,例如在键入f
或t
之后),或者operator
(如果它正在等待另一个绑定触发,例如在键入c
或d
之后)。vim_operator
设置为none
,除非vim_mode == operator
,在这种情况下,它设置为当前操作符的默认键绑定(例如在键入d
之后,vim_operator == d
)。"VimControl"
表示 vim 键绑定应该起作用。它当前是vim_mode == normal || vim_mode == visual || vim_mode == operator
的别名,但定义可能会随着时间的推移而改变。
恢复一些正常感
如果你在 Linux 或 Windows 上使用 Vim 模式,你可能会发现它覆盖了你不可或缺的键绑定。你可以通过将它们复制到你的键映射中来恢复它们的默认值
{
"context": "Editor && !menu",
"bindings": {
"ctrl-c": "editor::Copy", // vim default: return to normal mode
"ctrl-x": "editor::Cut", // vim default: increment
"ctrl-v": "editor::Paste", // vim default: visual block mode
"ctrl-y": "editor::Undo", // vim default: line up
"ctrl-f": "buffer_search::Deploy", // vim default: page down
"ctrl-o": "workspace::Open", // vim default: go back
"ctrl-a": "editor::SelectAll", // vim default: increment
}
},
命令面板
Vim 模式允许你使用 :
启用 Zed 的命令面板。这意味着你可以使用 vim 的命令面板运行 Zed 支持的任何操作。
此外,vim 模式包含许多流行 vim 命令的别名,以确保肌肉记忆起作用。例如,:w<enter>
将保存文件。
我们(还没有)模拟 vim 命令行的全部功能,特别是我们特殊处理特定模式,而不是使用 vim 的范围选择语法,并且我们还不支持命令参数。请在 GitHub 上联系我们,因为你发现命令面板中缺少的东西。
如上所述,需要注意的一件事是,在 :%s/a/b
中,正则表达式引擎与 vim 的略有不同。
当前支持的 vim 特定命令
# window management
:w[rite][!], :wq[!], :q[uit][!], :wa[ll][!], :wqa[ll][!], :qa[ll][!], :[e]x[it][!], :up[date]
to save/close tab(s) and pane(s) (no filename is supported yet)
:cq
to quit completely.
:vs[plit], :sp[lit]
to split vertically/horizontally (no filename is supported yet)
:new, :vne[w]
to create a new file in a new pane above or to the left
:tabedit, :tabnew
to create a new file in a new tab.
:tabn[ext], :tabp[rev]
to go to previous/next tabs
:tabc[lose]
to close the current tab
# navigating diagnostics
:cn[ext], :cp[rev], :ln[ext], :lp[rev]
to go to the next/prev diagnostics
:cc, :ll
to open the errors page
# jump to position
:<number>
to jump to a line number
:$
to jump to the end of the file
:/foo and :?foo
to jump to next/prev line matching foo
# replacement (/g is always assumed and Zed uses different regex syntax to vim)
:%s/foo/bar/
to replace instances of foo with bar
:X,Ys/foo/bar/
to limit replacement between line X and Y
other ranges are not yet implemented
# editing
:j[oin]
to join the current line (no range is yet supported)
:d[elete][l][p]
to delete the current line (no range is yet supported)
:s[ort] [i]
to sort the current selection (with i, case-insensitively)
由于任何 Zed 命令都可用,你可能会发现记住运行正确命令的助记符很有帮助。例如
:diff Toggle Hunk [Diff]
:diffs Toggle all Hunk [Diffs]
:revert Revert Selected Hunks
:cpp [C]o[p]y [P]ath to file
:crp [C]opy [r]elative [P]ath
:reveal [Reveal] in finder
:zlog Open [Z]ed Log
设置
Vim 模式默认情况下未启用。要启用 Vim 模式,你需要在设置文件中添加以下配置
{
"vim_mode": true
}
或者,你可以通过从命令面板中运行 切换 vim 模式
命令来启用 Vim 模式。
一些 vim 设置可用于修改默认 vim 行为
{
"vim": {
// "always": use system clipboard when no register is specified
// "never": don't use system clipboard unless "+ or "* is specified
// "on_yank": use system clipboard for yank operations when no register is specified
"use_system_clipboard": "always",
// Lets `f` and `t` motions extend across multiple lines
"use_multiline_find": true
}
}
如果你使用 vim 模式,还有一些 Zed 设置你可能也会喜欢
{
// disable cursor blink
"cursor_blink": false,
// use relative line numbers
"relative_line_numbers": true,
// hide the scroll bar
"scrollbar": { "show": "never" },
// allow cursor to reach edges of screen
"vertical_scroll_margin": 0,
"gutter": {
// disable line numbers completely:
"line_numbers": false
},
"command_aliases": {
"W": "w",
"Wq": "wq",
"Q": "q"
}
}
如果你想在编辑器和停靠区(终端、项目面板、AI 助手,...)之间导航,就像在拆分之间导航一样,可以使用以下键绑定
{
"context": "Dock",
"bindings": {
"ctrl-w h": ["workspace::ActivatePaneInDirection", "Left"],
"ctrl-w l": ["workspace::ActivatePaneInDirection", "Right"],
"ctrl-w k": ["workspace::ActivatePaneInDirection", "Up"],
"ctrl-w j": ["workspace::ActivatePaneInDirection", "Down"]
// ... or other keybindings
}
}
子词移动默认情况下未启用。要启用它,请将这些绑定添加到你的键映射中。
{
"context": "VimControl && !menu",
"bindings": {
"w": "vim::NextSubwordStart",
"b": "vim::PreviousSubwordStart",
"e": "vim::NextSubwordEnd",
"g e": "vim::PreviousSubwordEnd"
}
},
在可视模式下包围选择内容也没有默认启用(shift-s
通常的行为像 c
)。要启用它,请将以下内容添加到你的键映射中。
{
"context": "vim_mode == visual",
"bindings": {
"shift-s": [
"vim::PushOperator",
{
"AddSurrounds": {}
}
]
}
}
支持的插件
Zed 对一些 Vim 插件有新生的支持
- 从
vim-surround
,ys
、cs
和ds
可以工作。不过你无法添加新的 HTML 标记。 - 从
vim-commentary
,在可视模式下为gc
,在正常模式下为gcc
。不过你无法对任意对象进行操作。 - 从
netrw
,大多数键绑定在项目面板中都受支持。 - 从
vim-spider
/CamelCaseMotion
你可以使用如上所述的子词移动。
正则表达式差异
Zed 使用与 Vim 不同的正则表达式引擎。这意味着你必须对某些内容使用不同的语法。
值得注意的是
- Vim 使用
\(
和\)
来表示捕获组,在 Zed 中它们是(
和)
。 - 另一方面,
(
和)
表示字面上的括号,但在 Zed 中它们必须转义为\(
和\)
。 - 替换时,Vim 使用
\0
来表示整个匹配,在 Zed 中这是$0
,对于编号捕获组也是如此,\1
->$1
。 - Vim 使用
/g
来表示“一行上的所有匹配”,在 Zed 中这是隐含的 - Vim 使用
/i
来表示“不区分大小写”,在 Zed 中,你可以在模式的开头使用(?i)
或使用cmd-option-c
切换大小写敏感性。
为了帮助过渡,当运行 :%s//
时,命令面板将为你修复括号并替换组。因此,%s:/\(a\)(b)/\1/
将被转换为搜索 “(a)(b)”和替换为 “$1”。
有关 Zed 正则引擎支持的完整语法,请参阅 regex crate 文档。