Vim
VSCode

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

2018-07-11

結構いいねされるので更新しました。

導入、動機

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

VSCODE最高!

って感じになりました。

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

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

installするvim拡張

vscodevim

 よくやる基本設定

{
    //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の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

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

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

が以外と重宝されると思います。
そしてグダグタ言わずにコピペさせてくれと言う方のために以下

keybindings.json
// Place your key bindings in this file to overwrite the defaults
[
    //  エスケープ設定
    ////////////////////////////////////////////
    {
        "key": "ctrl+u ctrl+i",
        "command": "editor.action.goToImplementation",
        "when": "editorFocus"
    },
    {
        "key": "ctrl+[",
        "command": "keybindings.editor.clearSearchResults",
        "when": "inKeybindings && inKeybindingsSearch"
    },
    {
        "key": "ctrl+[",
        "command": "gitlens.key.escape",
        "when": "gitlens:key:escape"
    },
    ////////////////////////////////////////////

    // コードジャンプ系
    ////////////////////////////////////////////
    {
        "key": "ctrl+[",
        "command": "search.action.cancel",
        "when": "listFocus && searchViewletVisible"
    },
    {
        "key": "ctrl+u ctrl+d",
        "command": "editor.action.goToDeclaration",
        "when": "editorFocus"
    },
    ////////////////////////////////////////////

    // grep検索
    {
        "key": "ctrl+u ctrl+g",
        "command": "workbench.action.findInFiles",
        "when": "!searchInputBoxFocus"
    },

    // エディターとエディターの移動
    {
        "key": "ctrl+w ctrl+h",
        "command": "workbench.action.previousEditor",
        "when": "editorFocus"
    },
    ////////////////////////////////////////////

    // エスケープ関連
    ////////////////////////////////////////////
    {
        "key": "ctrl+[",
        "command": "workbench.action.closeQuickOpen",
        "when": "inQuickOpen"
    },
    {
        "key": "ctrl+[",
        "command": "workbench.action.closeQuickOpen",
        "when": "inQuickOpen"
    },
    ////////////////////////////////////////////

    // editorからsidebarの移動
    ////////////////////////////////////////////
    {
        "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"
    },

    // カーソル移動
    // editorのテキストにfocusしている時のコマンドinsert modeでctrl + lを押すとcursorが移動します
    {
        "key": "ctrl+l",
        "command": "cursorRight",
        "when": "editorTextFocus && !editorReadOnly"
    },

    // サジェストの移動、確定
    ////////////////////////////////////////////
    {
        "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+n",
        "command": "workbench.action.interactivePlayground.arrowDown",
        "when": "interactivePlaygroundFocus && !editorTextFocus"
    },
    ////////////////////////////////////////////

    //snippet関連
    ////////////////////////////////////////////
    {
        "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+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' && vim.mode != 'Insert'"
    },
    {
        "key": "[IntlYen] v",
        "command": "workbench.action.toggleSidebarVisibility",
        "when": "explorerViewletVisible && !searchViewletVisible && !inDebugMode && vim.mode != 'SearchInProgressMode' && vim.mode != 'Insert'"

    },
    ////////////////////////////////////////////

    // コマンドパレット
    ////////////////////////////////////////////
    {
        "key": "ctrl+o ctrl+o",
        "command": "workbench.action.showCommands"
    },
    {
        "key": "ctrl+o o",
        "command": "workbench.action.showCommands"
    },
    {
        "key": "ctrl+o ctrl+v",
        "command": "workbench.action.quickOpenView"
    },
    {
        "key": "ctrl+o v",
        "command": "workbench.action.quickOpenView"
    },
    ////////////////////////////////////////////

    // エディター以外のviewからエディターへの移動
    ////////////////////////////////////////////
    {
        "key": "ctrl+w ctrl+w",
        "command": "workbench.action.focusActiveEditorGroup"
    },
    {
        "key": "ctrl+w h",
        "command": "workbench.action.focusSideBar",
        "when": "editorFocus"
    },
    ////////////////////////////////////////////

    {
        "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' && vim.mode != 'Insert'"
    },
    {
        "key": "[IntlYen] t",
        "command": "workbench.action.terminal.toggleTerminal",
        "when": "terminalFocus && vim.mode != 'SearchInProgressMode' && vim.mode != 'Insert'"
    },
    ////////////////////////////////////////////

    // git関連
    ////////////////////////////////////////////
    {
        "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'"
    },
    ////////////////////////////////////////////
]

グダグタ言わずにコピペしたいと言う方(僕の中ではまぁまぁTab周辺がvimに近くなったかなと思います。

settings.jso
 {
    // フォントサイズ
    "editor.fontsize":10,
    // コードの一行が長くなるための可読性向上
    "editor.wordwrap": "on",
    // ミニマップはいらない
    "editor.minimap.enabled": false,
    // tab キーを押すとスペースが挿入されます。
    "editor.insertspaces": true,
    // tabをデフォルトで2スペースにする
    "editor.tabsize": 2,
     // エディターで空白文字を表示する方法を制御します。'none'、'boundary' および 'all' が使用可能です。'boundary' オプションでは、単語間の単一スペースは表示されません。
    "editor.renderwhitespace": "boundary",
    // 有効な場合、ファイルを開くときに文字セット エンコードを推測します。言語ごとに構成することも可能
    "files.autoguessencoding": true,
    // 拡張子とファイルの関連付け
    "files.associations": {
        "*.sql": "sql",
        "*.vue": "vue"
    },
     // 有効にすると、ファイルの保存時に最終行以降の新しい行をトリミングします。
    "files.trimfinalnewlines": false,
    // 有効にすると、ファイルの保存時に末尾の空白をトリミングします。
    "files.trimtrailingwhitespace": true,

    // ソース管理プロバイダーのセクションを常に表示するかどうか。
    "scm.alwaysshowproviders": true,
    // エディターのラベルの書式を制御します。例としてこの設定を変更することでファイルの場所を理解しやすくなります:
    // - short: 'parent'
    // - medium: 'workspace/src/parent'
    // - long: '/home/user/workspace/src/parent'
    // - default: '.../parent',  別タブで、同じタイトルを共有する場合や、相対的なワークスペース パス タブが無効になっている場合
    "workbench.editor.labelformat": "short",
    // Controls the visibility of the activity bar in the workbench.
    "workbench.activityBar.visible": false,
    // 任意の表示グループが開かれた場合に、そこにエディターを表示するかどうかを制御します。無効にした場合、エディターは現在のアクティブなエディター グループに優先して開かれます。有効にした場合は、現在のアクティブなエディター グループにもう一度開くのではなく、既に開いているエディターが表示されます。特定のグループ内や現在アクティブなグループの横に強制的にエディターを開いた場合などに、この設定が無視される場合もあることにご注意ください。
    "workbench.editor.revealifopen": false,
    // 開いているエディターをアイコンで表示するかどうかを制御します。これには、アイコンのテーマを有効にする必要もあります。
    "workbench.editor.showicons": false,
    ////////////////////////////// 以下ワンセット https://code.visualstudio.com/docs/getstarted/userinterface#_working-without-tabs
    "workbench.editor.showtabs": true,
    "workbench.editor.enablepreview": true,
    "workbench.editor.enablepreviewfromquickopen": true,
    // { "key": "cmd+w", "command": "workbench.action.closeeditorsingroup" }
    // { "key": "ctrl+tab", "command": "workbench.action.openpreviouseditorfromhistory" },
    // { "key": "ctrl+tab", "command": "workbench.action.quickopennavigatenext", "when": "inquickopen" },
    ////////////////////////////// https://code.visualstudio.com/docs/getstarted/userinterface#_working-without-tabs
    // エディターのタブの大きさを制御します。常に完全なエディター ラベルを表示するのに足りるタブの大きさを維持するには 'fit' を設定します。すべてのタブを一度に表示するには利用可能なスペースが足りない場合に、タブを縮小可能にするには 'shrink' を設定します。
    "workbench.editor.tabsizing": "shrink",
    // エディター タブの閉じるボタンの位置を制御するか、[off] に設定した場合に無効にします。
    "workbench.editor.tabclosebutton": "off",
    // todo エディターグループにアクティブなエディターが一つしか存在できない
    // 前のセッションからエディターが復元されていない場合に、起動時に表示するかどうかを制御します。'none' を選択するとエディターなしで開始します。'welcomepage' を選択するとウェルカム ページを開きます (既定)。'newuntitledfile' を選択すると新しい無題のファイルを開きます (空のワークスペースを開いているときのみ)。
    "workbench.startupeditor": "none",
    // エディターを開く場所を制御します。'left' または 'right' を選択すると現在アクティブになっているエディターの左または右にエディターを開きます。'first' または 'last' を選択すると現在アクティブになっているエディターとは別個にエディターを開きます。
    "workbench.editor.openpositioning": "first",
    // アクティビティバーでよけいなスペースを取られるのでfalse
    "workbench.activitybar.visible": false,
    // [開いているエディター] ウィンドウに表示するエディターの数。
    "explorer.openeditors.visible": 0,

    // デバッグ中にエディターの行内に変数値を表示します
    "debug.inlinevalues": true,

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

    // 'float' の使用を避けてください。float は脆弱な css につながり、レイアウトの一部が変更されたときに css が破損しやすくなります。
    "css.lint.float": "error",
    // display によってプロパティを無視します。例: 'display: inline' の場合、width、height、margin-top、margin-bottom、float プロパティには効果がありません。
    "css.lint.propertyignoredduetodisplay": "error",
    // ユニバーサル セレクター (*) を使用すると処理速度が低下することが分かっています
    "css.lint.universalselector": "warning",

    // phpfixer
    "php-cs-fixer.executablepath": "php-cs-fixer",
    "php-cs-fixer.config": "$home/.php_cs",
    // execute php cs fixer on save
    "php-cs-fixer.onsave": true,
    // リンターを保存時に実行するか、入力時に実行するか。
    "php.validate.run": "onsave",
    // whether to enable/disable twig prettydiff formatting.
    "twig-language.formatting": true,
    // enable format blade file
    "blade.format.enable": true,


    // vimの設定
    // systemのclipboardを使用します
    "vim.usesystemclipboard":true,
    // 検索に:を入れることで何か困ったときに入れなおせる
    "vim.cmdlineinitialcolon": true,
    // hlsearchは必要だと思う
    "vim.hlsearch": true,
    // 検索をするときに見やすいモッサりすることなければこのまま
    "vim.easymotion": true,
    // wordを* or + で検索するでしょ?
    "vim.visualstar": true,
    "vim.usectrlkeys": true,
    // ignore case in search patterns.
    "vim.ignorecase": true,
    // show where a / search matches as you type it.
    "vim.incsearch": true,
    // enable the sneak plugin for vim.
    "vim.sneak": true,



    // 自動フェッチが有効かどうか
    "git.autofetch": true,
    // set the default
    "editor.formatonsave": false,
    // enable per-language
    "[javascript]": {
    "editor.formatonsave": true
    },

    // ターミナルの設定
    // 設定した場合、ターミナルで選択しているテキストはクリップボードにコピーされます。
    "terminal.integrated.copyonselection": true,
    // ターミナルのフォントサイズ
    "terminal.integrated.fontsize": 10,
    //terminalでも使用可能になるaction
    "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"
    ],
    "window.zoomLevel": -1,
    "go.formatTool": "goformat",
    "sync.lastDownload": "2018-07-10T16:38:45.944Z",
    "sync.forceDownload": false,
    "sync.gist": "080a554865a4070fe17e10f0656ac1ff",
    "sync.host": "",
    "sync.pathPrefix": "",
    "sync.quietSync": false,
    "sync.askGistName": false,
    "sync.removeExtensions": true,
    "sync.syncExtensions": true,
    "sync.autoDownload": false,
    "sync.autoUpload": false,
    "sync.lastUpload": "2018-07-10T16:35:43.144Z",
}

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