Vim
VSCode

割と突き詰めてやったvim->vscode移行

導入、動機

今まではvimをメンテナンスして開発してきました。
vscodeの話をされてもそんなのvimmerには関係ないと思っていました。
まぁそれでもこれだけvscodeが盛り上がっているのに食わず嫌いはよくないと思い使って見たところ、、、

VSCODE最高!

って感じになりました。

vimのkeybindは?どこまで移行できる?

あとは割と重要なことなのですがvimのkeybindをどこまで反映できるかというところが重要です。
今までruby mineだったり、atomも使って見たことはあるのですが
納得のいくほどvimのkeyを移行することができなかったので
結局vimを使うことになってました。がしかし、vscodeはかなり痒いところに手が届く気がします。

installするvim拡張

vscodevim

vimへ移行する前にこれだけはやっておきたいvscodeの設定

{
    //fontsizeを小さく
    "editor.fontSize":9,
    "terminal.integrated.fontSize": 9,

    //wrap
    "editor.wordWrap": "on",
    "files.trimTrailingWhitespace": true,

    //ミニマップをfalse
    "editor.minimap.enabled": false,

    //bookmarkをsidebarに表示する
    "bookmarks.treeview.visible": true,

    //twigとvueでも有効にします
    "emmet.includeLanguages": {"twig": "html", "vue-html": "html"},

}

vscodevimの設定

{  
    // システムのclipboardにコピー
    "vim.useSystemClipboard":true,

    // 検索に:を入れる
    "vim.cmdLineInitialColon": true,

    "vim.hlsearch": true,

    // 言わずもがなeasymotion
    "vim.easymotion": true,

    // カーソル上にあるワードを"*"で検索
    "vim.visualstar": true,

    // 諸々のctrlキーを使った操作が有効になる
    "vim.useCtrlKeys": true,
}

vim拡張でやらない設定

    "vim.otherModesKeyBindings": 

これで設定するとvscodeの中でうまく動かないときがある。
例えば下記のことをやろうとする

vscodeのなかのshellをトグルさせて表示させたい場合など
例えばvimであれば

nnoremap <Leader>t   :ToggleTerminal<CR>

これでshellをトグルさせることができる。
(*誰かの作ったライブラリか関数でToggleTerimnalを作っていたら)

vscodeの場合shellに一度入ってしまうと
以下のようにshellにキーバインドを取られないような設定を書かなければいけません。

 "terminal.integrated.commandsToSkipShell": [
        "editor.action.toggleTabFocusMode",
        "workbench.action.debug.continue",
        "workbench.action.debug.pause",
        "workbench.action.debug.restart",
        "workbench.action.debug.run",
        "workbench.action.debug.start",
        "workbench.action.debug.stop",
        "workbench.action.focusActiveEditorGroup",
        "workbench.action.focusFirstEditorGroup",
        "workbench.action.focusSecondEditorGroup",
        "workbench.action.focusThirdEditorGroup",
        "workbench.action.navigateDown",
        "workbench.action.navigateLeft",
        "workbench.action.navigateRight",
        "workbench.action.navigateUp",
        "workbench.action.openNextRecentlyUsedEditorInGroup",
        "workbench.action.openPreviousRecentlyUsedEditorInGroup",
        "workbench.action.quickOpen",
        "workbench.action.quickOpenPreviousEditor",
        "workbench.action.quickOpenView",
        "workbench.action.showCommands",
        "workbench.action.tasks.build",
        "workbench.action.tasks.restartTask",
        "workbench.action.tasks.runTask",
        "workbench.action.tasks.showLog",
        "workbench.action.tasks.showTasks",
        "workbench.action.tasks.terminate",
        "workbench.action.tasks.test",
        "workbench.action.terminal.clear",
        "workbench.action.terminal.copySelection",
        "workbench.action.terminal.deleteWordLeft",
        "workbench.action.terminal.deleteWordRight",
        "workbench.action.terminal.findWidget.history.showNext",
        "workbench.action.terminal.findWidget.history.showPrevious",
        "workbench.action.terminal.focus",
        "workbench.action.terminal.focusAtIndex1",
        "workbench.action.terminal.focusAtIndex2",
        "workbench.action.terminal.focusAtIndex3",
        "workbench.action.terminal.focusAtIndex4",
        "workbench.action.terminal.focusAtIndex5",
        "workbench.action.terminal.focusAtIndex6",
        "workbench.action.terminal.focusAtIndex7",
        "workbench.action.terminal.focusAtIndex8",
        "workbench.action.terminal.focusAtIndex9",
        "workbench.action.terminal.focusFindWidget",
        "workbench.action.terminal.focusNext",
        "workbench.action.terminal.focusPrevious",
        "workbench.action.terminal.hideFindWidget",
        "workbench.action.terminal.kill",
        "workbench.action.terminal.new",
        "workbench.action.terminal.paste",
        "workbench.action.terminal.runActiveFile",
        "workbench.action.terminal.runSelectedText",
        "workbench.action.terminal.scrollDown",
        "workbench.action.terminal.scrollDownPage",
        "workbench.action.terminal.scrollToBottom",
        "workbench.action.terminal.scrollToTop",
        "workbench.action.terminal.scrollUp",
        "workbench.action.terminal.scrollUpPage",
        "workbench.action.terminal.selectAll",
        "workbench.action.terminal.toggleTerminal",
        "workbench.action.togglePanel"
    ],

例えばvscodeのユーザー設定に

        { "before": ["leader", "t"],
            "after": [],
            "commands": [
                {
                    "command": "workbench.action.terminal.toggleTerminal",
                    "args": []
                }
            ]
        },

と書いたならシェルのトグルができそうな気がしますがこれだとうまく動きません。
おそらくはvscodevimのコマンドとバッティングしているためだと思います。

    "vim.otherModesKeyBindings": 

現状、僕はkeymap.jsonに直接書いて対応しています。良い方法があったら教えていただけるとありがたいです。

vimのkeymapをどこまで持ってこれるか

keymapを持ってくる前にprefixを決めます。
僕の中では

ctrl + u //検索系もしくは開発系のコマンドのprefixです
ctrl + o //割とメタっぽい動作をしますコマンドパレットだったりdebugの実行だったり
leader // "\" にマッピングして使用してwindow操作系が多いです。

妥協したところ、まだ完成していないところがありますが
上記を踏まえた上でこんな感じになっています。

機能 vim vscode
プロジェクトルートからファイル検索 ctrl+u ctrl+u ctrl+u ctrl+u
検索したファイルの移動(下) ctrl+n ctrl+n
検索したファイルの移動(上) ctrl+p ctrl+p
実装している箇所に移動する ctrl+u ctrl+i ctrl+u ctrl+i
宣言している箇所に移動する ctrl+u ctrl+d ctrl+u ctrl+d
プロジェクトからgrep検索 ctrl+u ctrl+g ctrl+u ctrl+g
grep検索したファイルの移動(下) ctrl+n ctrl+n
grep検索したファイルの移動(上) ctrl+p ctrl+p
buffer(editor)間の移動(右) (vscodeだとeditor group関係なく移動します) ctrl+w l ctrl+w ctrl+l
buffer(editor)間の移動(左) (vscodeだとeditor group関係なく移動します) ctrl+w h ctrl+w ctrl+h
エクスプローラーのviewLetへの移動 ctrl+w h
insertモードへ入っているときにカーソルを右へ移動 ctrl+l ctrl+l
insertモードへ入っているときにカーソルを左へ移動 ctrl+h ctrl+h
ソースtreeのトグル \ v \ v
shellのトグル \ t \ t
コマンドラインパレットの表示 ctrl+o ctrl+o
git add g a g a
git status g s t
git commit g c o g c
ファイルの1行目に移動 g g g g
viewを洗濯して移動 ctrl+q ctrl+q

あとは実際に僕の設定を載せるのですがたぶんケース漏れがあって不具合があると思います。参考までにどうぞ。
特にvscodevimを使用されている方だと

//vimのmodeを取得するために
vim.mode == 'SearchInProgressMode'
vim.mode == 'Normal'
//もしくは否定形
vim.mode != 'SearchInProgressMode'
vim.mode != 'Normal'

が以外と重宝されると思います。

    {
        "key": "ctrl+u ctrl+i",
        "command": "editor.action.goToImplementation",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+u ctrl+d",
        "command": "editor.action.goToDeclaration",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+u ctrl+g",
        "command": "workbench.action.findInFiles",
        "when": "!searchInputBoxFocus"
    },
    {
        "key": "ctrl+n",
        "command": "workbench.action.interactivePlayground.arrowDown",
        "when": "interactivePlaygroundFocus && !editorTextFocus"
    },
    {
        "key": "ctrl+w ctrl+h",
        "command": "workbench.action.focusPreviousGroup",
        "when": "editorFocus"
    },
    // エディターからサイドバーへの移動
    {
        "key": "ctrl+w h",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+w ctrl+l",
        "command": "workbench.action.navigateEditorGroups",
        "when": "!editorFocus"
    },
    {
        "key": "ctrl+w ctrl+l",
        "command": "workbench.action.focusFirstEditorGroup",
        "when": "!editorFocus"
    },
    {
        "key": "ctrl+w ctrl+l",
        "command": "workbench.action.nextEditor",
        "when": "editorFocus && vim.mode == 'Normal'"
    },
    // エディターfile検索以下のコマンドはfile mruと同等の機能が表示される
    {
        "key": "ctrl+u ctrl+u",
        "command": "workbench.action.quickOpen"
    },
    // エディターのテキストにフォーカスしている時のコマンドinsert modeでctrl + lを押すとカーソルが移動
    {
        "key": "ctrl+l",
        "command": "cursorRight",
        "when": "editorTextFocus && !editorReadOnly"
    },

    //候補系のkeybinding
    {
        "key": "ctrl+k",
        "command": "acceptSelectedSuggestion"
    },
    {
        "key": "ctrl+n",
        "command": "selectNextSuggestion",
        "when": "editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible"
    },
    {
        "key": "ctrl+p",
        "command": "selectPrevSuggestion",
        "when": "editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible"
    },
    {
        "key": "ctrl+n",
        "command": "settings.action.focusSettingsFile",
        "when": "inSettingsSearch"
    },
    {
        "key": "ctrl+n",
        "command": "showNextParameterHint",
        "when": "editorTextFocus && parameterHintsMultipleSignatures && parameterHintsVisible"
    },
    {
        "key": "ctrl+n",
        "command": "keybindings.editor.focusKeybindings",
        "when": "inKeybindings && inKeybindingsSearch"
    },
    {
        "key": "ctrl+n",
        "command": "list.focusDown",
        "when": "listFocus"
    },
    {
        "key": "ctrl+n",
        "command": "search.focus.nextInputBox",
        "when": "inputBoxFocus && searchViewletVisible"
    },
    {
        "key": "ctrl+[",
        "command": "settings.action.clearSearchResults",
        "when": "inSettingsSearch"
    },
    {
        "key": "ctrl+[",
        "command": "keybindings.editor.clearSearchResults",
        "when": "inKeybindings && inKeybindingsSearch"
    },
    {
        "key": "ctrl+[",
        "command": "search.action.cancel",
        "when": "listFocus && searchViewletVisible"
    },
    // スニペットのエクスパンド
    {
        "key": "ctrl+k",
        "command": "insertSnippet",
        "when": "editorTextFocus && hasSnippetCompletions && !editorTabMovesFocus && !inSnippetMode"
    },
    {
        "key": "ctrl+k",
        "command": "jumpToNextSnippetPlaceholder",
        "when": "editorTextFocus && hasNextTabstop && inSnippetMode"
    },
    {
        "key": "ctrl+h",
        "command": "jumpToPrevSnippetPlaceholder",
        "when": "editorTextFocus && hasPrevTabstop && inSnippetMode"
    },
    {
        "key": "ctrl+[",
        "command": "workbench.action.closeQuickOpen",
        "when": "inQuickOpen"
    },
    {
        "key": "ctrl+[",
        "command": "workbench.action.closeQuickOpen",
        "when": "inQuickOpen"
    },
    // サイドバーでソースツリーを開いている時のコマンド
    {
        "key": "l",
        "command": "explorer.openToSide",
        "when": "explorerViewletFocus && explorerViewletVisible"
    },
    {
        "key": "ctrl+r",
        "command": "renameFile",
        "when": "explorerViewletVisible && filesExplorerFocus"
    },
    {
        "key": "Enter",
        "command": "explorer.openToSide",
        "when": "explorerViewletVisible && filesExplorerFocus"
    },
    // どこにフォーカスしていても使いたいコマンド。
    {
        "key": "ctrl+o ctrl+d",
        "command": "workbench.view.debug"
    },
    {
        "key": "ctrl+o d",
        "command": "workbench.view.debug"
    },
    {
        "key": "ctrl+o ctrl+g",
        "command": "workbench.view.scm"
    },
    {
        "key": "ctrl+o g",
        "command": "workbench.view.scm"
    },
    // サイドバーの表示切り替え
    {
        "key": "[IntlYen] v",
        "command": "workbench.view.explorer",
        "when": "!explorerViewletVisible && vim.mode != 'SearchInProgressMode'"
    },

    {
        "key": "[IntlYen] v",
        "command": "workbench.action.toggleSidebarVisibility",
        "when": "explorerViewletVisible && !searchViewletVisible && !inDebugMode && vim.mode != 'SearchInProgressMode'"

    },
    // コマンドパレットオープン
    {
        "key": "ctrl+o ctrl+o",
        "command": "workbench.action.showCommands"
    },
    {
        "key": "ctrl+o o",
        "command": "workbench.action.showCommands"
    },
    // エディター以外のビューから抜けてくるときに
    {
        "key": "ctrl+w ctrl+w",
        "command": "workbench.action.focusActiveEditorGroup"
    },
    {
        "key": "tab",
        "command": "editor.emmet.action.expandAbbreviation",
        "when": "config.emmet.triggerExpansionOnTab && editorTextFocus && !editorReadonly && !editorTabMovesFocus"
    },
    {
    // パネルの表示切り替え
    {
        "key": "[IntlYen] t",
        "command": "workbench.action.terminal.toggleTerminal",
        "when": "!terminalFocus && vim.mode != 'SearchInProgressMode'"
    },
    {
        "key": "[IntlYen] t",
        "command": "workbench.action.terminal.toggleTerminal",
        "when": "terminalFocus && vim.mode != 'SearchInProgressMode'"
    },
    // git fugitiveの真似
    {
        "key": "g c",
        "command": "git.commit",
        "when": "editorTextFocus && vim.mode == 'Normal'"
    },
    {
        "key": "g a",
        "command": "git.stage",
        "when": "editorTextFocus && vim.mode == 'Normal'"
    },
    {
        "key": "g g",
        "command": "cursorTop",
        "when": "editorTextFocus && vim.mode == 'Normal'"
    },
    {
        "key": "ctrl+w h",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    }

そのほかにはphp-fixerをかける設定などや
Docker + php + xdebug + vscodeみたいな構成も割と簡単にできて満足しています!
VSCode最高ですね!
今のところは自分のvimとほとんど同じ挙動なので満足ですがバグはあるかもしれません!
次回Docker + php + xdebug + vscodeも共有したいと思います。