🤘

うわっ…私のエディタ、ダサすぎ…?ナウなヤングにバカウケするCursor・VSCodeのイケイケ設定

2024/12/25に公開

はじめに

メリークリスマス🎅
2024年も残りわずかということで、最後にネタ記事を投稿して年を納めたいと思います。

突然ですが、いつも使う開発環境こだわっていますか?

自分は、一部の人たちにはVimを布教する熱心な信徒だと思われていますが、ただ布教するだけではその人にとって実用的ではありません。

個人的な観測に基づきますが、意外にもVimmerじゃない開発者は結構こだわりが薄かったり、エディタのテーマを変える程度だったりするので、今回は多くの人が使っているであろうCursorとVSCodeを対象とした実用的なカスタマイズ方法をご紹介します。

ただのカスタマイズ方法ではありません。ナウなヤングにバカウケするイケイケ設定です。

お断り

この記事を書くにあたっての経緯

エディタ変遷

Cursorに移行するまでのエディタ変遷は、

VSCode
↓
Vim
↓
VSCode Vim(拡張機能)
↓
NeoVim
↓
AstroNvim
↓
Zed(AI搭載前)
↓
AstroNvim
↓
NeoVide(GUI Client)

このような感じで右往左往したものの、概ねVimキーバインドを中心とした開発環境を使ってきました。

しかし、近年ではAIが発達しており、ちょっと前まではブラウザでChatGPTやClaudeを開いてエディタと行ったり来たりして開発していました。

モダンエディタの登場

そんな中で颯爽と顕れたのがCursorです。

https://www.cursor.com/

今でこそ当たり前に使っていますが、当時はエディタとAIの統合という点で非常に衝撃的でした。

Chatパネルも便利ですが、Copilot++のコード補完は本当に優秀で、このためだけにCursorを使っていると言っても過言ではないくらいスグレモノです。

加えて、VSCodeからフォークされているので既存のエコシステムが活かせるという点も、多くの開発者の関心を集めた理由の1つだと思っています。

モダンなエディタとしてZedもありますが、こちらは独自のプラグインを個別にインストールする必要があるので、VSCodeからの移行は中々ハードルが高いですね。

https://zed.dev/

Vimmerの苦悩

いきなり主語がでかいですが、Vim・NeoVimは特にカスタマイズの自由度が高いので、多くのユーザーはプラグインやらキーバインドやらLSPやらと、あれこれオレオレ設定を作って 「ぼくのかんがえたさいきょうのえでぃた」 を作りがちです。

これをVim盆栽と呼びます。テストに出ます。

自分もそのうちの一人で、 「AI機能を試してみたいけど、最強のエディタ(自称)があるからいいかな……」 と葛藤していました。

それもそのはずで、一度はZedに移行したものの、補完周りの挙動が怪しかったりLSPの動作が重かったり、当時は痒いところに手が届かず結局NeoVimに出戻りした経験があります。

とはいえ、開発環境を転々とする中で各環境ごとに 「こうしたい」「これいいな」 などの知見が溜まって段階的にブラッシュアップしてきたため、これまでの知見を活かしてカスタマイズをすれば 卍真に最強のエディタ卍 が完成するのでは?と考え、重い腰を上げて挑戦してみました。

最終ゴール

https://youtu.be/-k_Lwu2uB_Q

こだわりと執念のカスタマイズにより、さらにモダンでイケイケなCursorに生まれ変わりました。

カスタマイズ内容

ここからは具体的なカスタマイズ方法について解説していきます。

前提として、自分の設定の多くはAstroNvimに大きく影響を受けているので、ZedやCursorなど異なるエディタに移行しても、基本的にはAstroNvimのキーバインディングを元にカスタマイズしています。

https://astronvim.com/

しかし、Cursor・VSCode特有の問題や、ある程度割り切りが必要な箇所も少々あるため、あくまでも ”再現” であることに注意してください。

拡張機能Vimを導入する

これは人権です。まだ使っていない人は黙って入れましょう。

https://marketplace.visualstudio.com/items?itemName=vscodevim.vim

人によっては動作が重いそうですが、個人的にはゴリゴリにカスタマイズしてもそこまで重い印象は無いです。

ちなみに類似の拡張機能としてVSCode NeoVimがありますが、こちらはNeoVimの設定を一部活かせるものの、部分的にVSCode向けに調整する必要があったり、導入しても自分のNeoVimと完全に同じ操作にはならなかったので使用していません。

むしろ既存のNeoVimの設定に依存しなくて良いですね。

Vimに関するキーバインドや設定内容などは後ほど紹介します。

テーマを導入する

ここはぶっちゃけなんでもいいです。自分が一番テンションの上がるやつを選ぶと良いでしょう。

自分の場合はNeoVimやiTerm2でもIcebergを気に入って使っているので、Cursorでも変わらず使用しています。

https://marketplace.visualstudio.com/items?itemName=cocopon.iceberg-theme

背景画像を設定する

テーマを導入するだけでも十分ですが、背景画像を設定するとなんか良い感じになります。

背景画像を設定できる拡張機能は色々と存在しますが、自分の環境では以下を使用しています。

https://marketplace.visualstudio.com/items?itemName=Katsute.code-background

アニメーションを付ける

エディタ変遷でも書きましたが、直近で使用した中でもNeoVimのGUIクライアントであるNeoVideは、カーソル移動やスクロールにおしゃんなアニメーションが付きます。

NeoVideの触り心地はとても良く、カーソル移動に伴うスクロールに対してもヌルッとアニメーションが付くので、無駄に移動したくなるほど気に入っています。

https://neovide.dev/features.html

以下の拡張機能を導入すると、このようなアニメーションをCursorでも再現可能になります。

https://marketplace.visualstudio.com/items?itemName=BrandonKirbyson.vscode-animations

注意点として、依存する拡張機能では Custom CSS and JS LoaderApc Customize UI++ のどちらかを選べますが、必ず後者の方にしてください。

https://marketplace.visualstudio.com/items?itemName=drcika.apc-extension

Cursorユーザーの場合、前者を選択してしまうと正しく動作しません。
詳しい設定方法に関しては拡張機能のREADMEを参照してください。

見た目をZedっぽくする

Zedは見た目がスッキリしていてモダンの権化って感じがして個人的には好きです。
なので、見た目の要素だけ取り入れることにしました。

と言っても超簡単で、この拡張機能を導入するだけです。

https://marketplace.visualstudio.com/items?itemName=enhancedjax.vscode-ayu-zed

コマンドパレット

ファイルアイコン

これだけでもVSCode臭さが解消されてオシャレ度爆上がり間違いなしです。

拡張機能LazyGit VSCodeを導入する

AstroNvimではデフォルトでLazyGitが使用でき Leader(Space) + g + g を入力すれば、フローティングパネルで呼び出せます。

Cursorのターミナルで直接LazyGitを呼び出すことも可能ですが、毎回ターミナルに移動して文字を入力するのが面倒くさいです。

そこで、以下の拡張機能を導入して同じキーバインドを設定すれば、Cursorでも似たように呼び出せるようになります。

https://marketplace.visualstudio.com/items?itemName=TomPollak.lazygit-vscode

LazyGit関連の拡張機能はいくつか存在しますが、こちらの拡張機能はLazyGitのconfigファイルのパスを設定できたり、拡張機能自体にいくつか設定可能な項目があるためこちらを選定しました。

余談として、これはCursor・VSCode両方に言えることですが、AstroNvimユーザーにとってフローティングパネルが存在しない点が一番苦痛でした。

拡張機能FindItFasterを導入する

先ほど余談で言いましたが、Cursor・VSCodeにはフローティングパネル(telescope)を使った操作ができないので、検索周りは特に不便で仕方ないです。

対して、AstroNvimでは以下の操作が可能で、telescope + fzfを用いることで快適かつ高速な検索を実現しています。

  • Leader(Space) + f + f でファイル検索
  • Leader(Space) + f + / でファイル内検索
  • Leader(Space) + f + w で全体検索

曖昧検索ができる上に、右側に選択中のファイルのプレビューが表示されます。

AstroNvimに慣れている自分にとっては必須のため、移行に躊躇していた最大の要因です。

そこで色々と探したところ、フローティングパネルではないものの、Cursor・VSCodeでも似た機能を実現するプラグインを発見しました。

https://marketplace.visualstudio.com/items?itemName=TomRijndorp.find-it-faster

ファイル検索

全体検索

ファイル内検索ができませんが、ファイル検索・全体検索は概ね満足できる仕上がりなので、同じキーバインドでこの拡張機能を呼び出せるように設定しました。

ファイル内検索に関しては自前のfzfコマンドをターミナルで叩くか、潔く諦めてVim標準の検索機能で済ましています。(本当は欲しい)

拡張機能を呼び出した際の表示崩れに対処する

この拡張機能の設定の1つとして、実行時にターミナルを最大高さに指定できます。

settings.json
"find-it-faster.general.showMaximizedTerminal": true 

しかし、時々ですが、ターミナルは最大高さになってもfzfが中途半端な高さで表示されてしまったり、色々と不便な点がありました。

そこで Multi-Command という拡張機能を導入することでこの問題を解消しました。

https://marketplace.visualstudio.com/items?itemName=ryuta46.multi-command

まず、settings.json に以下のような設定を行います。

settings.json
{
  "find-it-faster.general.showMaximizedTerminal": false, // default

  "multiCommand.commands": [
    {
      "command": "multiCommand.findFiles",
      "interval": 220,
      "sequence": [
        "workbench.action.toggleMaximizedPanel",
        "find-it-faster.findFiles"
      ]
    },
    {
      "command": "multiCommand.findWithinFiles",
      "interval": 220,
      "sequence": [
        "workbench.action.toggleMaximizedPanel",
        "find-it-faster.findWithinFiles"
      ]
    }
  }
}

あとは任意のキーバインドから呼び出すだけです。

settings.json
{
  "vim.normalModeKeyBindingsNonRecursive": [
    // ファイル検索
    {
      "before": ["<Leader>", "f", "f"],
      "commands": ["multiCommand.findFiles"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // 全体検索
    {
      "before": ["<Leader>", "f", "w"],
      "commands": ["multiCommand.findWithinFiles"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
  ]
}

やっていることはシンプルで、220ms 遅らせて順次実行させることで toggleMaximizedPanel を確実に実行してからFindItFasterを呼び出すようにしています。

これにより、設定前と比べて確実に実行できるようになったのでストレスが減りました。

再実行時のターミナルの高さがおかしい問題に対処する

これは厳密に問題を特定したわけではありませんが、ターミナルとこの拡張機能を併用する場合、何やらおかしな挙動がありました。

  • 問題なし🙆‍♀️:機能実行 → エディタにフォーカス → 機能実行(連続で実行)
  • 問題あり🙅‍♀️:機能実行 → ターミナルにフォーカスして最大化 → エディタにフォーカス → 機能実行

一度ターミナルに移動して何らかの操作を行った上で拡張機能を実行すると、 toggleMaximizedPaneltrue にも関わらず、ターミナルの高さが低い状態でfzfが実行されてしまいます。

色々と試しましたが、結局ジャストな解決方法が見つからず……

そこで、Cursor内のターミナルはFindItFaster専用にして、ターミナルアプリのWarpと併用することで対処しました。

https://www.warp.dev/

2画面以上を使用する前提になりますが、 「片方でCursor・もう片方はWarp」 のような使い方をしたところ、意外にも快適だったので最近はこの構成で作業しています。

実は過去に試したことがあって、NeoVim + Tmuxとの相性の悪さから一度は手放していましたが、ターミナルとしてのみ使用する分には十分実用的で良いと思います。

iTerm2やWezTermよりもクセはありますが、何より見た目が一番おしゃんなので選びました。

現在のファイルのパスを取得可能にする

元々はNeoVim + Copilotだったこともあり、利便性を考慮して現在のファイルのパスを取得できるように設定していました。

一方で、Cursorは何かと優秀なので基本的には困らないですが、補完されるファイルパスが時々異なる場合があったり、CursorとWarpを併用するため、Warp上でテストを実行する際に都度ファイルパスを指定するのは大変です。

そこで、現在フォーカスしているファイルのパスを簡単に取得できるように、以下の拡張機能を導入して設定しています。

https://marketplace.visualstudio.com/items?itemName=YoshinoriN.current-file-path

settings.json
{
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": ["<Leader>", "a"],
      "commands": ["currentFilePath.copy"]
    }
  ]
}

このように設定することで、ノーマルモード時に Leader(Space) + a を入力するだけでフルパスをコピーできるようになるため大変便利です。

設定ファイル

Vim周りの操作設定や上記で紹介した拡張機能に関するキーバインドなどは説明し出したらキリがないので、以下の settings.jsonkeybindings.json を各々参考にしてみてください。

settings.json
{
  "terminal.integrated.showExitAlert": false,
  "zenMode.restore": true,
  "zenMode.hideLineNumbers": false,
  "zenMode.fullScreen": true,
  "zenMode.hideActivityBar": true,
  "zenMode.showTabs": "multiple",
  "zenMode.centerLayout": false,
  "window.commandCenter": true,
  "editor.fontFamily": "'UDEV Gothic 35NF', Menlo, Monaco, 'Courier New', monospace",
  "explorer.compactFolders": false,
  "workbench.colorTheme": "Iceberg",
  "workbench.editor.revealIfOpen": false,
  "animations.Scrolling": "Fade",
  "animations.CursorAnimation": true,
  "apc.imports": [
    "file://${userHome}/.cursor/extensions/brandonkirbyson.vscode-animations-2.0.4/dist/updateHandler.js"
  ],
  "find-it-faster.findWithinFiles.fuzzRipgrepQuery": true,
  "find-it-faster.general.killTerminalAfterUse": true,
  "lazygit-vscode.configPath": "/your/config/path",
  "lazygit-vscode.autoMaximizeWindow": true,
  "go.lintTool": "golangci-lint",
  "go.lintFlags": ["--config=${workspaceFolder}/.golangci.yaml", "--fast"],
  "multiCommand.commands": [
    {
      "command": "multiCommand.formatAndFix",
      "sequence": ["editor.action.formatDocument", "multiCommand.formatTs"]
    },
    {
      "command": "multiCommand.formatTs",
      "sequence": [
        {
          "command": "eslint.executeAutofix",
          "when": "resourceLangId == javascript || resourceLangId == typescript || resourceLangId == json"
        }
      ]
    },
    {
      "command": "multiCommand.findFiles",
      "interval": 220,
      "sequence": [
        "workbench.action.toggleMaximizedPanel",
        "find-it-faster.findFiles"
      ]
    },
    {
      "command": "multiCommand.findWithinFiles",
      "interval": 220,
      "sequence": [
        "workbench.action.toggleMaximizedPanel",
        "find-it-faster.findWithinFiles"
      ]
    },
    // 自作の検索用スクリプトを実行するためのコマンド
    {
      "command": "multiCommand.findCurrentFile",
      "interval": 220,
      "sequence": [
        "workbench.action.toggleMaximizedPanel",
        {
          "command": "workbench.action.terminal.newWithProfile",
          "args": {
            "profileName": "zsh",
            "splitActiveTerminal": true,
            "splitTerminalDimension": {
              "split": "maxSize"
            }
          }
        },
        {
          "command": "workbench.action.terminal.sendSequence",
          "args": { "text": "buffer-search ${file}; exit\n" }
        }
      ]
    }
  ],
  "vim.leader": "<space>",
  "vim.useSystemClipboard": true,
  "vim.normalModeKeyBindingsNonRecursive": [
    {
      "before": ["u"],
      "commands": [
        {
          "command": "undo"
        }
      ]
    },
    {
      "before": ["<C-r>"],
      "commands": [
        {
          "command": "redo"
        }
      ]
    },
    {
      "before": ["<Leader>", "w"],
      "after": [],
      "commands": [
        {
          "command": "workbench.action.files.save",
          "args": []
        }
      ]
    },
    {
      "before": ["<Leader>", "q"],
      "after": [],
      "commands": [
        {
          "command": "workbench.action.closeActiveEditor",
          "args": []
        }
      ]
    },
    {
      "before": ["<leader>", "c"],
      "commands": ["workbench.action.closeActiveEditor"]
    },
    {
      "before": ["<Leader>", "a"],
      "commands": ["currentFilePath.copy"]
    },
    {
      "before": ["<Leader>", "."],
      "after": ["$"]
    },
    {
      "before": ["<Leader>", ","],
      "after": ["^"]
    },
    {
      "before": ["<Leader>", "m"],
      "after": ["%"]
    },
    // タブ間での移動
    {
      "before": ["<Leader>", "["],
      "commands": ["workbench.action.previousEditor"]
    },
    {
      "before": ["<Leader>", "]"],
      "commands": ["workbench.action.nextEditor"]
    },
    // ファイルツリーへの移動
    {
      "before": ["<Leader>", "o"],
      "commands": ["workbench.action.focusSideBar"]
    },
    // ファイルツリーの開閉
    {
      "before": ["<Leader>", "e"],
      "commands": ["workbench.action.toggleSidebarVisibility"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // ファイル検索
    {
      "before": ["<Leader>", "f", "f"],
      "commands": ["multiCommand.findFiles"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // 全体検索
    {
      "before": ["<Leader>", "f", "w"],
      "commands": ["multiCommand.findWithinFiles"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // ファイル内検索
    {
      "before": ["<Leader>", "f", "/"],
      "commands": ["multiCommand.findCurrentFile"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // lsp
    {
      "before": ["<Leader>", "l", "f"],
      "commands": ["multiCommand.formatAndFix"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    {
      "before": ["<Leader>", "l", "a"],
      "commands": ["editor.action.quickFix"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    {
      "before": ["<Leader>", "l", "r"],
      "commands": ["editor.action.rename"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    {
      "before": ["<Leader>", "l", "d"],
      "commands": ["editor.action.showHover"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // git
    {
      "before": ["<Leader>", "g", "l"],
      "commands": ["gitlens.showQuickFileHistory"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    {
      "before": ["<Leader>", "g", "g"],
      "commands": ["lazygit-vscode.toggle"],
      "when": [
        "editorFocus && !editorTextFocus && vim.mode == 'Normal'",
        "workbench.action.focusActiveEditorGroup"
      ]
    }
  ],
  "vim.insertModeKeyBindingsNonRecursive": [
    {
      "before": ["j", "j"],
      "after": ["<Esc>"]
    }
  ],
  "vim.visualModeKeyBindingsNonRecursive": [
    {
      "before": ["<Leader>", "j"],
      "after": ["<Esc>"]
    },
    {
      "before": ["<Leader>", "."],
      "after": ["$"]
    },
    {
      "before": ["<Leader>", ","],
      "after": ["^"]
    },
    {
      "before": ["<Leader>", "m"],
      "after": ["%"]
    },
    {
      "before": [">"],
      "commands": ["editor.action.indentLines"]
    },
    {
      "before": ["<"],
      "commands": ["editor.action.outdentLines"]
    },
    {
      "before": ["p"],
      "after": ["\"", "_", "d", "P"]
    },
    // ファイル検索
    {
      "before": ["<Leader>", "f", "f"],
      "commands": ["find-it-faster.findFiles"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    },
    // 全体検索
    {
      "before": ["<Leader>", "f", "w"],
      "commands": ["find-it-faster.findWithinFiles"],
      "when": ["editorFocus && vim.mode == 'Normal'"]
    }
  ],
  "cursor.cpp.enablePartialAccepts": true,
  "background.windowBackgrounds": [
    "your/background/image/path"
  ],
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "typescript.updateImportsOnFileMove.enabled": "always",
  "cursor.chat.premiumChatAutoScrollWhenAtBottom": true,
  "apc.electron": {
    "titleBarStyle": "hiddenInset",
    "trafficLightPosition": {
      "x": 7,
      "y": 5
    }
  },
  "apc.font.family": "Zed Sans",
  "apc.stylesheet": {
    ".quick-input-widget": {
      "position": "absolute !important",
      "top": "200px !important",
      "left": "50%",
      "border-radius": "10px",
      "border": "1px solid var(--vscode-textSeparator-foreground) !important",
      "box-shadow": "0 0 60px 0 rgba(0,0,0,0.2) !important"
    },
    // left title bar (controls)
    ".titlebar-left": {
      "max-width": "70px !important"
    },
    // center title bar
    ".titlebar-center": {
      "margin": "0 !important"
    },
    // arrow buttons
    ".action-item.menu-entry": {
      "display": "none !important"
    },
    // whole title bar command center container
    ".action-item.command-center-center": {
      "background-color": "transparent !important",
      "border": "none !important",
      "width": "fit-content !important"
    },
    // field
    ".quick-input-header": {
      "padding": "0 !important"
    },
    // input element container
    ".quick-input-header > .quick-input-and-message .monaco-inputbox": {
      "border-radius": "10px 10px 0 0 !important"
    },
    // actual input element
    ".quick-input-header > .quick-input-and-message > .quick-input-filter > .quick-input-box input": {
      "padding": "8px 10px !important"
    },
    // list of results
    ".quick-input-list > .monaco-list > .monaco-scrollable-element": {
      "padding": "2px !important"
    },
    // status bar set height
    "div:has(> .statusbar)": {
      "height": "25px !important",
      "top": "auto !important",
      "bottom": "0 !important"
    },
    ".statusbar": {
      "height": "25px !important"
    },
    // hides search icon
    ".codicon.codicon-search.search-icon": {
      "display": "none !important"
    },
    // empty editor background
    ".editor-group-container.empty.active": {
      "background-color": "var(--vscode-statusBar-background)"
    },
    "div:has(> .tabs-and-actions-container.tabs-border-bottom.empty)": {
      "background-color": "var(--vscode-statusBar-background) !important"
    }
  },
  "workbench.iconTheme": "ayu-mirage-zed",
  "javascript.updateImportsOnFileMove.enabled": "always",
  "editor.smoothScrolling": true,
  "terminal.integrated.smoothScrolling": true,
  "editor.cursorBlinking": "smooth",
  "workbench.list.smoothScrolling": true,
  "animations.Install-Method": "Apc Customize UI++",
  "update.mode": "manual",
  "[go]": {
    "editor.defaultFormatter": "golang.go"
  },
  "editor.formatOnPaste": true
}
keybindings.json
[
  //----------------------------------------------------------
  // 何も開いていない時の設定
  //----------------------------------------------------------
  // ファイル検索
  {
    "key": "space f f",
    "command": "multiCommand.findFile",
    "when": "!editorFocus && !terminalFocus && !inputFocus"
  },
  // 全体検索
  {
    "key": "space f w",
    "command": "multiCommand.findWithinFiles",
    "when": "!editorFocus && !terminalFocus && !inputFocus"
  },
  // サイドバーを表示
  {
    "key": "space e",
    "command": "workbench.action.focusSideBar",
    "when": "!editorFocus && !terminalFocus && !inputFocus"
  },
  // サイドバーへのフォーカス
  {
    "key": "space o",
    "command": "workbench.action.focusSideBar",
    "when": "!editorFocus && !terminalFocus && !inputFocus"
  },
  // Lazygitの起動
  {
    "key": "space g g",
    "command": "lazygit-vscode.toggle",
    "when": "!editorFocus && !terminalFocus && !inputFocus"
  },

  //----------------------------------------------------------
  // エディタにフォーカスしている時の設定
  //----------------------------------------------------------
  // エディタの最大化
  {
    "key": "ctrl+t z",
    "command": "workbench.action.togglePanel",
    "when": "editorFocus && vim.mode == 'Normal'"
  },
  // AIチャットへのフォーカス
  {
    "key": "ctrl+t l",
    "command": "aichat.focuschatpaneaction",
    "when": "editorFocus && vim.mode == 'Normal'"
  },
  // ターミナルへのフォーカス
  // {
  //   "key": "ctrl+t n",
  //   "command": "workbench.action.terminal.focus"
  // },
  {
    "key": "ctrl+t n",
    "command": "runCommands",
    "args": {
      "commands": ["workbench.action.terminal.focus"]
    },
    "when": "editorFocus && vim.mode == 'Normal' && activePanel"
  },
  {
    "key": "ctrl+t n",
    "command": "runCommands",
    "args": {
      "commands": [
        "workbench.action.terminal.focus",
        "workbench.action.toggleMaximizedPanel"
      ]
    },
    "when": "editorFocus && vim.mode == 'Normal' && !activePanel"
  },
  // エディタの縦分割
  {
    "key": "s v",
    "command": "workbench.action.splitEditor",
    "when": "editorTextFocus && vim.mode == 'Normal'"
  },
  // エディタの横分割
  {
    "key": "s h",
    "command": "workbench.action.splitEditorDown",
    "when": "editorTextFocus && vim.mode == 'Normal'"
  },
  // アクティブエディタの閉鎖
  {
    "key": "ctrl+t x",
    "command": "workbench.action.closeActiveEditor",
    "when": "editorFocus && vim.mode == 'Normal'"
  },
  // ファイルツリーへのフォーカス(左エディタグループ)
  {
    "key": "ctrl+w h",
    "command": "workbench.action.focusSideBar",
    "when": "editorFocus && vim.mode == 'Normal' && activeEditorGroupIndex == 1"
  },
  // エディタ間の移動(左へ)
  {
    "key": "ctrl+w h",
    "command": "workbench.action.focusLeftGroup",
    "when": "editorFocus && vim.mode == 'Normal' && activeEditorGroupIndex > 1"
  },
  // エディタ間の移動(右へ)
  {
    "key": "ctrl+w l",
    "command": "workbench.action.focusRightGroup",
    "when": "editorFocus && vim.mode == 'Normal' && activeEditorGroupIndex >= 1"
  },
  // エディタ間の移動(下へ)
  {
    "key": "ctrl+w j",
    "command": "workbench.action.focusBelowGroup",
    "when": "editorFocus && vim.mode == 'Normal'"
  },
  // エディタ間の移動(上へ)
  {
    "key": "ctrl+w k",
    "command": "workbench.action.focusAboveGroup",
    "when": "editorFocus && vim.mode == 'Normal'"
  },
  // Neovimの挿入モードからのエスケープ
  {
    "command": "vscode-neovim.compositeEscape1",
    "key": "j",
    "when": "neovim.mode == insert && editorTextFocus && !inputFocus",
    "args": "j"
  },
  // ホバー情報の表示
  {
    "key": "shift+k",
    "command": "editor.action.showHover",
    "when": "editorFocus && vim.mode == 'Normal'"
  },

  //----------------------------------------------------------
  // AIチャットにフォーカスしている時の設定
  //----------------------------------------------------------
  // エディタへの移動
  {
    "key": "ctrl+t h",
    "command": "workbench.action.focusActiveEditorGroup",
    "when": "workbench.panel.aichat.view.visible && !inputFocus"
  },
  // ターミナルへの移動
  {
    "key": "ctrl+t n",
    "command": "workbench.action.terminal.focus",
    "when": "workbench.panel.aichat.view.visible && !inputFocus"
  },
  // AIチャットのサイドバーを閉じる
  {
    "key": "ctrl+t x",
    "command": "aichat.close-sidebar",
    "when": "workbench.panel.aichat.view.visible && !inputFocus"
  },

  //----------------------------------------------------------
  // サイドバーにフォーカスしている時の設定
  //----------------------------------------------------------
  // リスト内で下へ移動
  {
    "key": "j",
    "command": "list.focusDown",
    "when": "listFocus && !inputFocus"
  },
  // リスト内で上へ移動
  {
    "key": "k",
    "command": "list.focusUp",
    "when": "listFocus && !inputFocus"
  },
  // リスト内で折りたたみ
  {
    "key": "h",
    "command": "list.collapse",
    "when": "listFocus && !inputFocus"
  },
  // リスト内で選択
  {
    "key": "l",
    "command": "list.select",
    "when": "listFocus && !inputFocus"
  },
  // エディタグループへのフォーカス
  {
    "key": "space o",
    "command": "workbench.action.focusActiveEditorGroup",
    "when": "listFocus && !inputFocus"
  },
  // サイドバーの表示切替
  {
    "key": "space e",
    "command": "workbench.action.toggleSidebarVisibility",
    "when": "listFocus && !inputFocus"
  },
  // 最初のエディタグループへのフォーカス
  {
    "key": "ctrl+w l",
    "command": "workbench.action.focusFirstEditorGroup",
    "when": "listFocus && !inputFocus"
  },
  // 新しいファイルの作成
  {
    "key": "a",
    "command": "explorer.newFile",
    "when": "listFocus && !inputFocus"
  },
  // 新しいフォルダの作成
  {
    "key": "shift+a",
    "command": "explorer.newFolder",
    "when": "listFocus && !inputFocus"
  },
  // ファイル・ディレクトリのリネーム
  {
    "key": "r",
    "command": "renameFile",
    "when": "listFocus && !inputFocus"
  },
  // ファイル・ディレクトリの削除
  {
    "key": "d",
    "command": "deleteFile",
    "when": "listFocus && !inputFocus"
  },
  // 隠しファイル・ディレクトリの表示切替
  {
    "key": "shift+h",
    "command": "toggleexcludedfiles.toggle",
    "when": "listFocus && !inputFocus"
  },
  // エクスプローラーの更新
  {
    "key": "shift+r",
    "command": "workbench.files.action.refreshFilesExplorer",
    "when": "listFocus && !inputFocus"
  },
  // エディタへの移動
  {
    "key": "ctrl+t l",
    "command": "workbench.action.focusActiveEditorGroup",
    "when": "listFocus && !inputFocus"
  },

  //----------------------------------------------------------
  // ターミナルにフォーカスしている時の設定
  //----------------------------------------------------------
  // エディタへの移動
  // {
  //   "key": "ctrl+t p",
  //   "command": "workbench.action.focusActiveEditorGroup",
  //   "when": "terminalFocus"
  // },
  // {
  //   "key": "ctrl+t p",
  //   "command": "runCommands",
  //   "args": {
  //     "commands": [
  //       "workbench.action.focusActiveEditorGroup",
  //       "workbench.action.focusActiveEditorGroup"
  //     ]
  //   },
  //   "when": "terminalFocus"
  // },
  {
    "key": "ctrl+t p",
    "command": "runCommands",
    "args": {
      "commands": [
        "workbench.action.focusActiveEditorGroup",
        "workbench.action.focusActiveEditorGroup",
        "workbench.action.togglePanel"
      ]
    },
    // "when": "terminalFocus && panelMaximized"
    "when": "terminalFocus"
  },
  // ターミナルの分割
  {
    "key": "ctrl+t shift+\\",
    "command": "workbench.action.terminal.split",
    "when": "terminalFocus"
  },
  // 新しいターミナルの作成
  {
    "key": "ctrl+t c",
    "command": "workbench.action.terminal.new",
    "when": "terminalFocus"
  },
  // ターミナル間での移動(左へ)
  {
    "key": "ctrl+t h",
    "command": "workbench.action.terminal.focusPreviousPane",
    "when": "terminalFocus"
  },
  // ターミナル間での移動(右へ)
  {
    "key": "ctrl+t l",
    "command": "workbench.action.terminal.focusNextPane",
    "when": "terminalFocus"
  },
  // ターミナルへのインデックス別フォーカス
  {
    "key": "ctrl+t 1",
    "command": "workbench.action.terminal.focusAtIndex1"
  },
  {
    "key": "ctrl+t 2",
    "command": "workbench.action.terminal.focusAtIndex2"
  },
  {
    "key": "ctrl+t 3",
    "command": "workbench.action.terminal.focusAtIndex3"
  },
  {
    "key": "ctrl+t 4",
    "command": "workbench.action.terminal.focusAtIndex4"
  },
  {
    "key": "ctrl+t 5",
    "command": "workbench.action.terminal.focusAtIndex5"
  },
  // ターミナルの最大化
  {
    "key": "ctrl+t z",
    "command": "workbench.action.toggleMaximizedPanel",
    "when": "terminalFocus"
  },
  // ターミナルの閉鎖
  {
    "key": "ctrl+t x",
    "command": "workbench.action.terminal.detachSession",
    "when": "terminalFocus"
  }
]

おわりに

ということで、 AstroNvim + NeoVide + Zed + VSCode + AI(Cursor) というカオスでキメラなエディタが無事完成しました。

見た目ヨシ!機能性ヨシ! なので、ナウなヤングにバカウケすること間違いないでしょう。

とはいえ概ね満足しているものの、ファイル内検索ができなかったり、所々マウス操作が必要な箇所があったりと、まだまだ改善できる点は挙げられます。

みなさんもイケイケな設定を参考にして 「ぼくのかんがえたさいきょうのえでぃた」 を作ってみてはいかがでしょうか?

Discussion