NeoVimユーザーがvscodeにも定住するためにやったこと
就活とか論文とか色々あり、実に半年ぶりの投稿です!
このブログでは以前、自分が使っているターミナル環境とエディタ環境を紹介しました。
今回の記事では、以前の記事で紹介したNeoVim環境に使用感の近いVisual Studio Code環境を構築した話を書いてみます。 表示系やコマンドモードなど細かい部分は詰め切れていないので、主にサイドバー(NERDTreeっぽく)、タブ移動、ターミナル周りを違和感なく使うためのショートカットの話を書いていきます。
※ 2021/02/04: vim.use<C-v>
で個別にctrlキーを有効化するオプションが削除されたようなので修正しました。またインサートモード中にctrl+h, ctrl+l
を使いたいときのためにkeybindingのwhen条件を修正しました。
もくじ
スポンサーリンク
1. 動機
筆者は普段、コンピュータビジョン, 画像処理, 数値計算系のコードをC++ (CMake), CUDA, Pythonで書いています。 開発環境を行き来することが多いので、インストールが簡単かつリモート接続でも軽いNeoVimを愛用しているのですが、最近少し不満に思うところも出てきました。
IDEの環境構築に手間がかかる
以前の記事で紹介したように、コード補完やlintはプラグインを導入することで簡単に環境構築できます。
しかし、インタラクティブなデバッグ(ブレークポイントを挿入したり、変数の値を確認したり)を行うためのプラグインは、デバッガーと密に連携するせいか、素直にインストールできないことが多いです。
根本的な原因は、そうしたプラグインの需要が低いことかなぁと思っています。 そもそもNeoVimをエディタとして使う人は少数派でしょうし、その中で特定の言語のIDEプラグインをメンテしてくれる人はさらに希少です。
よく使うデバッグ環境を1度組むだけならいいのですが、「ちょっと他の言語を試したい」「他の開発環境を間借りしたい」というとき、環境構築に時間を取られるのは億劫です。
ターミナルの環境構築に手間がかかる
NeoVimはコマンドラインアプリなので、何らかのターミナルソフトウェアを通して利用するわけですが、意外と文字化けや色の不整合が起こります。 日本人は文字列やコメントにマルチバイト文字を利用するので、等幅フォントで表示されなかったり、カーソル位置がズレたり、特殊文字が化けたり、文字コードの問題で文字化けしたりというトラブルが起こりやすいです。
特に、Windows環境のターミナル(PowerShell, TeraTerm, Git Bash, cmderなど)は、フォントのせいなのかターミナルの作り込みが甘いのかはわかりませんが、この手のトラブルを頻発する印象があります。 最近はPowerShellが随分まともになってきているのと、Microsoftが新たにWindows Terminalというものを開発しているので、将来的には改善されるかもしれませんが。。。
一部の機能にはGUIを使いたくなる
NeoVimの欠点というよりVisual Studio Codeの長所ですが、SSH接続先の管理やDockerコンテナの一覧表示、マウスホイールによるスクロールなど、一部の機能はCLIよりGUIの方が便利なことがあります。
2020年現在、こうしたニーズを満たしつつマルチプラットフォームに使えるエディタといえばVisual Studio Code一択でしょう。
そんなわけで、できるだけNeoVimの使用感をキープできるVisual Studio Code環境にトライしてみました。
2. 表示関連の設定
まずは表示系の設定です。
とりあえず、折返しを有効にし、特殊文字を可視化し、行番号を相対表示にし、minimapを消しておきます。
{ // 100文字を超える行は折り返して表示する "editor.wordWrap": "on", "editor.wordWrapColumn": 100, // 左端の行番号にカーソル位置からの距離を表示 "editor.lineNumbers": "relative", // 行頭・文字間ともに空白を'・'で可視化する "editor.renderWhitespace": "all", // LF, CR, EOFなどの制御文字を可視化する "editor.renderControlCharacters": true, // minimapは表示しない "editor.minimap.enabled": false, }
3. Vimプラグインを導入する
GitHub - VSCodeVim/Vim: Vim for Visual Studio Code
プラグインの詳細はREADMEで解説されているほか、vscodeのsettingsで各項目の説明が読めるので、そちらも参照してみてください。
3.1. 基本設定
キーバインドは、デフォルトのままでもほぼ問題なく使えます。
気を付ける点として、デフォルトではctrl+c
やctrl+v
がコピー&ペーストになっているので、Vimキーバインドを優先させる設定が必要になります。
下の例では一括で設定してますが、アップデートでできなくなったようです。"vim.use<C-d>": true
のように個別に設定することも可能です。
また、コマンドモード(:
から始まるやつ)のバックエンドに、Javascript実装ではなくNeoVim自体の実装を使うこともできます。
NeoVim実装に切り替えると、実行速度が若干速くなるほか、正規表現のエスケープ方法や複数行マッチングの挙動が変わります(多分Javascript実装のバグなのでいつか修正されるかも)。
{ // ctrl+cなどもVimキーバインドで上書きされる(macの場合はそもそもcommand+cなので変化なし) "vim.useCtrlKeys": true, // コマンドモードの動作にNeoVimを利用する(pathは環境に応じて調整) "vim.enableNeovim": true, "vim.neovimPath": "/usr/local/bin/nvim", }
他にも、検索結果のハイライトの設定やeasymotionの有効化など色々な設定があるので、一度ドキュメントに目を通すことをおすすめします。
3.2. カスタムショートカット
Vimキーバインドのプラグインを有効にすると、デフォルトで以下のショートカットが追加されます。
gd
: カーソル下の要素の定義下に移動(開発言語のプラグインが必要)gh
: カーソル下の要素の定義情報が表示される(開発言語のプラグインが必要)gq
: 範囲選択されたコメントや長い文字列を適切な長さに改行し直すgb
: 繰り返し押すことで、カーソルのあたった単語と同じ単語が矩形選択されていくaf
: visualモードに入ってから押すことで、()
や{}
で囲われたブロックの内部が範囲選択される。繰り返すことで範囲が広くなっていく
これに加えて、前回の記事で紹介した個人的趣味によるキーバインド設定もやっておきます。
init.vim
や.vimrc
の設定をJSON形式にするだけでokです。
{ "vim.leader": "<space>", "vim.normalModeKeyBindingsNonRecursive": [ { "before": [ "<leader>", "h" ], "after": [ "^" ] }, { "before": [ "<leader>", "l" ], "after": [ "$" ] }, { "before": [ ";" ], "after": [ ":" ] }, { "before": [ ":" ], "after": [ "." ] }, { "before": [ "." ], "after": [ ";" ] } ] }
"after"
の部分にはvscodeのコマンドも指定できるようです。
ただし、ここで設定したショートカットはあくまでVimキーバインドが有効なタブでしか使えません。
私の場合、タブ移動のショートカットは、画像ファイルのタブやsettingsタブなどVimキーバインドが無効なタブでも利用したいので、vscode自体のキーボードショートカット機能で設定することにしました。
ただし、ターミナルではctrl+l
とctrl+h
が別のコマンドにマッピングされているので、それを邪魔しないように条件を指定しています。
同じく、vimのインサートモード中の動作も邪魔しないようにしています。
[ // vim { "key": "ctrl+l", "command": "workbench.action.nextEditor", "when": "!terminalFocus && !sideBarFocus && vim.mode != 'Insert'" }, { "key": "ctrl+h", "command": "workbench.action.previousEditor", "when": "!terminalFocus && !sideBarFocus && vim.mode != 'Insert'" }, ]
4. サイドバーをNERDTreeっぽくする
次に、サイドバーをNERDTreeっぽく使うためのショートカットを設定していきます。
サイドバーを開きっぱなしにするかによって設定内容が若干変わりますが、ここでは「普段は隠しておいてファイル操作の間だけ開く」という想定で組んでいきます。 サイドバーを開きっぱなしにしたい場合は、以下の記事が参考になります。
なお簡易化のため、サイドバー>Explorer>ファイル一覧画面だけを利用することにし、開かれているファイルの一覧やGit, Dockerなどのツールバーにはショートカットを設定しないことにします。
ctrl+k, ctrl+s
でサイドバーを開き、[j,k]
で移動、o
でフォルダを開閉し、m+[r,c,p,a,d,f]
でファイル操作、t
もしくはEnterでファイルを開くと同時にサイドバーを閉じる、という設定です。
ファイルを[s, o]
で開く機能は、個人的に不要なので省いていますが、同じ要領で設定可能です。
{ // カーソル移動をNERDTreeと同じかんじに "workbench.list.keyboardNavigation": "simple", // ファイルプレビューは無効化(開かれたファイルタブを永続化) "workbench.editor.enablePreview": false, "workbench.editor.enablePreviewFromQuickOpen": false, // macrosプラグインを使って、ファイルを開くと同時にサイドバーを閉じるコマンドを登録 "macros": { "selectAndToggleSidebar": [ "list.select", "workbench.action.toggleSidebarVisibility" ] }, }
{ // explorer: toggle { "key": "ctrl+k ctrl+s", "command": "workbench.explorer.fileView.focus", "when": "!filesExplorerFocus" }, { "key": "ctrl+k ctrl+s", "command": "workbench.action.toggleSidebarVisibility", "when": "filesExplorerFocus" }, // explorer: open { "key": "Enter", "command": "macros.selectAndToggleSidebar", "when": "explorerViewletFocus && explorerViewletVisible && !explorerResourceIsFolder && !inputFocus" }, { "key": "t", "command": "macros.selectAndToggleSidebar", "when": "explorerViewletFocus && explorerViewletVisible && !explorerResourceIsFolder && !inputFocus" }, // explorer: move { "key": "Enter", "command": "list.toggleExpand", "when": "explorerViewletFocus && explorerViewletVisible && explorerResourceIsFolder && !inputFocus" }, // explorer: rename { "key": "m r", "command": "renameFile", "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus" }, // explorer: copy { "key": "m c", "command": "filesExplorer.copy", "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus" }, // explorer: paste { "key": "m p", "command": "filesExplorer.paste", "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus" }, // explorer: new file { "key": "m a", "command": "explorer.newFile", "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus" }, // explorer: delete file { "key": "m d", "command": "deleteFile", "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus" }, // explorer: new folder { "key": "m f", "command": "explorer.newFolder", "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus" }, }
5. 下部パネルのショートカットを調整する
最後に、下部パネルまわりのショートカットの設定です。
NeoVimでは、ターミナルをタブとして開くことができますが、vscodeでは下部パネルの一部として実装されています。 ターミナルをタブ化するアイデアもあったらしいですが、「画面が乱雑になる」「どうしてもやりたい場合はtmux使え」という意見により却下されたようです(https://github.com/microsoft/vscode/issues/10546)。 NeoVimと操作感の差ができてしまいますが、なるべく慣れやすいショートカットを組むことにしましょう。
下部パネルには、TERMINAL
のほかにもPROBLEMS
, OUTPUT
, DEBUG CONSOLE
のパネルが存在します。
これらのパネルにも移動できた方が楽なので、以下のようにショートカットを組んでみました。
ctrl+space, ctrl+space
: 下部パネルを開閉ctrl+space, ctrl+[p, o, d, t]
: 各パネルにフォーカス(下部パネルが閉じているときは開いた上でフォーカス)ctrl+space, ctrl+n
: 新しいターミナルを追加するctrl+space, ctrl+w
: 現在のターミナルを削除するctrl+space, ctrl+[h, l]
: ターミナルを移動する
ctrl+space
を活用するのは、NeoVimではまず使わないキーだからです。
頭の中でNeoVimとvscodeの使い勝手を区別できるなら、好きに設定していいと思います。
ちなみに、terminalからファイルを開くとき(NeoVimのnvr --remote-tab
に相当)はcode <filename>
でokです。
{ // panel(bottombar): toggle { "key": "ctrl+space ctrl+space", "command": "workbench.action.togglePanel" }, // panel(bottombar): focus { "key": "ctrl+space ctrl+t", "command": "workbench.panel.terminal.focus" }, { "key": "ctrl+space ctrl+d", "command": "workbench.debug.action.focusRepl" }, { "key": "ctrl+space ctrl+o", "command": "workbench.panel.output.focus" }, { "key": "ctrl+space ctrl+p", "command": "workbench.panel.markers.view.focus" }, // terminal: new { "key": "ctrl+space ctrl+n", "command": "workbench.action.terminal.new" }, // terminal: move { "key": "ctrl+space ctrl+l", "command": "workbench.action.terminal.focusNext", "when": "terminalFocus" }, { "key": "ctrl+space ctrl+h", "command": "workbench.action.terminal.focusPrevious", "when": "terminalFocus" }, // terminal: kill { "key": "ctrl+space ctrl+w", "command": "workbench.action.terminal.kill", "when": "terminalFocus" }, }
以上、簡単に自分の環境を解説してみました。
使い勝手のいい設定を見つけたら、また追記したいと思います。