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 來定義概念,例如「括號」(適用於 % 鍵)和「字詞」(適用於動作,例如 we)。這確實會產生一些差異,但這些差異大多是正面的。例如,在 Rust 等語言中,%| 視為括號;在 Javascript 等語言中,w$ 視為字詞字元。

Vim 模式使用 Zed 的多重游標支援模擬視覺化區塊模式。這再次導致了一些差異,但功能強大得多。

Vim 巨集支援(q@)是使用 Zed 動作實作。這讓我們能夠支援自動完成碼的錄製及重播等。跟 Vim 不同,Zed 沒有重複使用 yank 暫存器來錄製巨集,而是使用兩個不同的名稱空間。

最後,Vim 模式的搜尋和替換功能是由 Zed 的功能做為後盾。這表示模式語法會稍微不同,詳情請參閱 正規表示式差異 段落。

自訂按鍵繫結

您可以使用 :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 的 mapnmap 等)指令,您可以繫結到 workspace::SendKeystrokes 動作在正確的內容中。

可以在 這裡 看到 vim 模式中預設開啟的繫結。

內容

Zed 的鍵盤繫結僅在 "context" 與您在螢幕上的位置相符時才會進行評估。位置會巢狀,所以當您在編輯時,您會在頂端的 "Workspace" 位置,其中包含一個包含 "Editor""Pane"。內容一次只能在一個層級中相符。因此可以結合 Editor && vim_mode == normal,但 Workspace && vim_mode == normal 因為我們在 Editor 層級設定 vim 內容,所以永遠不會相符。

Vim 模式會為 Editor 新增幾個內容

  • vim_mode 類似於目前的模式,但並非完全相同。它會從 normalvisualinsertreplace(依據您的模式)之一開始。如果您在輸入順序的過程中,vim_mode 會在等待任意鍵(例如,在輸入 ft 之後)時為 waiting,或是在等待另一個繫結觸發時(例如,在輸入 cd 之後)為 operator
  • 除非 vim_mode == operatorvim_operator 會設定為 none,此時它會設定為目前的運算子預設按鍵繫結(例如,在輸入 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
}

或者,你可以從指令面板執行 toggle vim mode 指令來啟用 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-surroundyscsds 可以運作。不過你還不能新增新的 HTML 標籤。
  • vim-commentarygc 在視覺模式,以及 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 正規表示式引擎支援的完整語法,請參閱 正則表示式 Crate 文件