Skip to content

ZedでVimの設定を再現する

ZedのVim Modeが思ったより充実していた。

充実しているだけじゃ移行しようとは思わなかったが、Claude CodeをACP経由で使えるのが決め手で一旦使ってみることにした。

具体は下記参照。

使ってみたらVim Modeの体験も、ACPの体験もよかったのでkeymapを設定してみた。

設定の全体は下記。

json
// Zed keymap
//
// For information on binding keys, see the Zed
// documentation: https://zed.dev/docs/key-bindings
//
// To see the default key bindings run `zed: open default keymap`
// from the command palette.
[
  {
    "bindings": {
      "cmd-m": ["agent::NewExternalAgentThread", { "agent": "claude_code" }],
      "cmd-l": "agent::ToggleFocus"
    }
  },
  // Insert mode cursor movement (vim style hjkl)
  {
    "context": "Editor && vim_mode == insert",
    "bindings": {
      "ctrl-h": "vim::Left",
      "ctrl-j": "vim::Down",
      "ctrl-k": "vim::Up",
      "ctrl-l": "vim::Right"
    }
  },
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "shift-h": "vim::StartOfLine",
      "shift-l": "vim::EndOfLine",
      "ctrl-j": "editor::JoinLines",
      "shift-j": [ "editor::MoveDownByLines", { "lines": 6 } ],
      "shift-k": [ "editor::MoveUpByLines", { "lines": 6 } ]
    }
  },
  {
    "context": "Editor && vim_mode == visual",
    "bindings": {
      "shift-h": "vim::StartOfLine",
      "shift-l": "vim::EndOfLine",
      "ctrl-j": "editor::JoinLines"
    }
  },
  // Window pane management
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "ctrl-w -": "pane::SplitDown",
      "ctrl-w \\": "pane::SplitRight",
      "ctrl-w c": "pane::CloseActiveItem",
      "ctrl-w j": "workspace::ActivatePaneDown",
      "ctrl-w k": "workspace::ActivatePaneUp",
      "ctrl-w h": "workspace::ActivatePaneLeft",
      "ctrl-w l": "workspace::ActivatePaneRight"
    }
  },
  // Project panel navigation
  {
    "context": "ProjectPanel",
    "bindings": {
      "m r": "project_panel::Rename",
      "m c": "project_panel::Copy",
      "m p": "project_panel::Paste",
      "m a": "project_panel::NewFile",
      "m d": "project_panel::Delete",
      "m f": "project_panel::NewDirectory",
      "enter": "project_panel::ExpandSelectedEntry"
    }
  },
  // Vim-style line navigation and LSP
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "g d": "editor::GoToDefinitionSplit",
      "g f": "editor::GoToDeclaration",
      "g r": "editor::FindAllReferences",
      "g i": "editor::GoToImplementation",
      "g a": "editor::ToggleCodeActions"
    }
  },
  // Terminal toggle
  {
    "bindings": {
      "cmd-j": "workspace::ToggleBottomDock"
    }
  },
  // File navigation
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "space e": "file_finder::Toggle",
      "space p": "pane::DeploySearch"
    }
  }
]

詳細

External Agentの設定

ACP経由でAI Agent呼ぶときのコマンド。

新規スレッドを作成するケースとFocus のトグルを定義している。

json
  {
    "bindings": {
      "cmd-m": ["agent::NewExternalAgentThread", { "agent": "claude_code" }],
      "cmd-l": "agent::ToggleFocus"
    }
  },

ウィンドウのペーン操作

Vim内でウィンドウ操作するときに使っているkeymap

json
  // Window pane management
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "ctrl-w -": "pane::SplitDown",
      "ctrl-w \\": "pane::SplitRight",
      "ctrl-w c": "pane::CloseActiveItem",
      "ctrl-w j": "workspace::ActivatePaneDown",
      "ctrl-w k": "workspace::ActivatePaneUp",
      "ctrl-w h": "workspace::ActivatePaneLeft",
      "ctrl-w l": "workspace::ActivatePaneRight"
    }
  },

ファイル操作

ファイル操作もhjlk移動しているのでそのままKeymapでファイル操作を対応させたくて適用した。

ここはVimで設定してなかったので使ったり使ってなかったり。

json
  // Project panel navigation
  {
    "context": "ProjectPanel",
    "bindings": {
      "m r": "project_panel::Rename",
      "m c": "project_panel::Copy",
      "m p": "project_panel::Paste",
      "m a": "project_panel::NewFile",
      "m d": "project_panel::Delete",
      "m f": "project_panel::NewDirectory",
      "enter": "project_panel::ExpandSelectedEntry"
    }
  },

LSP

lsp関連はほとんどデフォルトのKeybindだが、editor::GoToDefinitionSplit, editor::GoToImplementationSplitのような、splitして開くActionがあって便利なのでこれを採用している。

json
  // Vim-style line navigation and LSP
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "g d": "editor::GoToDefinitionSplit",
      "g f": "editor::GoToDeclaration",
      "g r": "editor::FindAllReferences",
      "g i": "editor::GoToImplementationSplit",
      "g a": "editor::ToggleCodeActions"
    }
  },

Terminal

下のペーンにTerminalを配置しており、邪魔なときは消したいのでToggleするようにしている。

json
  // Terminal toggle
  {
    "bindings": {
      "cmd-j": "workspace::ToggleBottomDock"
    }
  },

もともとtelescopeでfinder をspace e, searchをspace pで設定していたので適用した。

json
  // File navigation
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "space e": "file_finder::Toggle",
      "space p": "pane::DeploySearch"
    }
  }
]

邪道キーバインド

文頭、文末に移動する0, $が遠かったのでshift-h, shift-lにマッピングしている。

改行がなくて{, }で移動できないときにshift-j, shift-kで6行移動する。

このあたりはかなり邪道で近いうちにやめたいので参考にしないでください

json
  {
    "context": "Editor && vim_mode == normal",
    "bindings": {
      "shift-h": "vim::StartOfLine",
      "shift-l": "vim::EndOfLine",
      "ctrl-j": "editor::JoinLines",
      "shift-j": [ "editor::MoveDownByLines", { "lines": 6 } ],
      "shift-k": [ "editor::MoveUpByLines", { "lines": 6 } ]
    }
  },
  {
    "context": "Editor && vim_mode == visual",
    "bindings": {
      "shift-h": "vim::StartOfLine",
      "shift-l": "vim::EndOfLine",
      "ctrl-j": "editor::JoinLines"
    }
  },

Insert中にVimのキーバインドで移動する

これも邪道。

ecsするほどではないときにこれ使ってしまっている。

json
  // Insert mode cursor movement (vim style hjkl)
  {
    "context": "Editor && vim_mode == insert",
    "bindings": {
      "ctrl-h": "vim::Left",
      "ctrl-j": "vim::Down",
      "ctrl-k": "vim::Up",
      "ctrl-l": "vim::Right"
    }
  },