Contents

【最佳实践】VSCode + Vim = 效率之神

导语
在 Visual Studio Code 中引入 Vim 模式,无疑可以极大程度上提高个人的编码效率。

I. VSCodeVim

VSCodeVim 是一款 vim 模拟器,它将 vim 的大部分功能都集成在了 VSCode 中,即一个嵌入在 VSCode 中的 vim。

正是由于 VSCodeVim 本质上只是一个 Vim 模拟器,而非真正的 Vim,导致原生 Vim 中的有些功能并不支持,具体支持情况见 roadmap。 尽管它现在还无法完全模拟 Vim,但这依然不妨碍它的优秀。

Status Command
Normal Mode
Insert Mode
Visual Mode
Visual Line Mode
Number Prefixes
. Operator
Searching with / and ?
Correct Undo/Redo
Command Remapping
⚠️ Marks
Text Objects
Visual Block Mode
Replace Mode
Multiple Select Mode
Macros
Buffer/Window/Tab

✅ - command done

⚠️ - some variations of the command are not supported


II. 安装

只需在 VSCode 的插件商店搜索 vim 就能找到该插件.

关闭 Mac 的重复键

当使用 Mac 时,需要输入以下代码,用以关闭 Mac 的重复键

1
2
3
4
5
6
# For VS Code
$ defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
# For VS Codium
$ defaults write com.vscodium ApplePressAndHoldEnabled -bool false
# If necessary, reset global default
$ defaults delete -g ApplePressAndHoldEnabled

III. 文件配置详解

VSCodeVim 的相关配置文件是放在 settings.json 中,而不是 vimrc 文件.

  • 对于非代码编辑区的热键将其定义在 keybindings.json
  • 对于代码编辑区且属于 vim 的热键将其定义在 settings.json 文件中

1. 基础配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// leader - prefix key
"vim.leader": "<space>",
// To improve performance
"extensions.experimental.affinity": { 
    "vscodevim.vim": 1 
},
// Easy motion
"vim.easymotion": true,
// Use system clipboard
"vim.useSystemClipboard": true,
// 由vim接管ctrl+any的按键,而不是vscode
"vim.useCtrlKeys": true,
"vim.replaceWithRegister": true,
// 忽略大小写
"vim.ignorecase": true,
"vim.smartcase": true,
// 智能行号
"vim.smartRelativeLine": true,
"vim.foldfix": true,
// Highlight search
"vim.hlsearch": true,
"vim.highlightedyank.enable": true,
"vim.highlightedyank.duration": 500,

// 由vscode进行处理,而不是vscode-vim插件
"vim.handleKeys": {
    "<C-d>": true, // 向下滚动半页
    "<C-f>": true, // 向下滚动一页
    "<C-e>": true, // 向下滚动一行
    "<C-s>": true,
    "<C-z>": false,
    "<C-a>": true,
    "<C-c>": true,
    "<C-v>": true,
    "<C-x>": true,
},

2. 快捷键配置

NORMAL Mode

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
"vim.normalModeKeyBindingsNonRecursive": [
    {   // 聚集 terminal
        "before": ["<C-j>"], 
        "commands": ["workbench.action.terminal.focus"]
    },
    {   // 语义级 重命名
        "before": ["leader", "r"],  
        "commands": [ "editor.action.rename"] 
    },
    {   // 
        "before": ["g", "h"],  
        "commands": [ "editor.action.showHover"]
    },
    {
        "before": ["g", "d"],
        "commands": ["editor.action.revealDefinition"]
    },
    {
        "before": ["g", "r"],
        "commands": ["editor.action.goToReferences"],
    },
    {
        "before": ["g", "i"],
        "commands": ["editor.action.goToImplementation"],
    },
    {
        "before": ["g", "b"],
        "commands": ["workbench.action.navigateBack"],
    },

    {
        "before": ["leader", "e", "f"],
        "commands": ["workbench.explorer.fileView.focus"],
    },

    {
        "before": [ "leader", "leader", "e", "f"],
        "commands": ["workbench.action.toggleActivityBarVisibility"]
    },

    {
        "before": ["leader", "g", "g"],
        "commands": ["workbench.action.quickOpen"],
    },
    {   // Global find
        "before": ["leader", "g", "f"],
        "commands": ["workbench.view.search"],
    },

    {
        "before": ["g", "[",], 
        "commands": ["editor.action.marker.prevInFiles"],
    },
    {
        "before": ["g", "]",],
        "commands": ["editor.action.marker.nextInFiles"],
    },
    {   // Source Control Git
        "before": [ "leader", "g", "i", "t" ],
        "commands": ["workbench.scm.focus"]
    },
    { // Start to debug
        "before": [ "leader", "d" ],
        "commands": ["workbench.action.debug.start"]
    },
    {
        "before": ["leader","w"],
        "commands": [":w!" ]
    },
    {
        "before": ["leader","q"],
        "commands": [":q" ]
    },
    {   // No highlight
        "before": ["leader", "n", "h"],
        "commands": [":nohl"]
    },
    {
        "before": ["H"],
        "after": ["^"]
    },
    {
        "before": ["L"], 
        "after": ["$"]
    },
    {   // Blockwise visual mode
        "before": ["\\"],
        "commands": ["extension.vim_ctrl+v"]
    },
    {
        "before": ["leader", "t"],
        "commands": [":terminal"] 
    }, 

    {
        "before": ["g", "t"],
        "commands": [":tabnext"]
    }, 
    {
        "before": ["g", "T"],
        "commands": [":tabprev"] 
    },
    {   // project-manager
        "before": ["leader", "p", "m"], 
        "commands": [{
            "command":"workbench.view.extension.project-manager",
            "when":"viewContainer.workbench.view.extension.project-manager.enabled"
        }]
    },
],

INSERT Mode

1
2
3
4
5
6
"vim.insertModeKeyBindings": [
    {
        "before": ["j", "k"],
        "after": ["<Esc>"]
    }, 
],

VISUAL Mode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
"vim.visualModeKeyBindings": [
    {
        "before": ["H"],
        "after": ["^"] 
    },
    {
        "before": ["L"],
        "after": ["$"]
    },

    {
        "before": [">"],
        "commands": [ "editor.action.indentLines"]
    },
    {
        "before": ["<"],
        "commands": [ "editor.action.outdentLines"]
    },
],

COMMAND LINE Mode

1
2
"vim.commandLineModeKeyBindingsNonRecursive": [
],
`leader` 键注意事项
leader 键只在代码编辑区域生效,它无法做到全 VSCode 生效

3. 资源管理配置

keybindings.json 定义对于非代码编辑区的热键.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
[
    {
        "key": "cmd+h",
        "command": "workbench.action.focusLeftGroup"
    },
    {
        "key": "cmd+l",
        "command": "workbench.action.focusRightGroup"
    },

    {   // Rename file
        "key": "r",
        "command": "renameFile",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // New file
        "key": "a",
        "command": "explorer.newFile",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // New folder
        "key": "shift+a",
        "command": "explorer.newFolder",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // Delete file
        "key": "d",
        "command": "deleteFile",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // Copy
        "key": "y",
        "command": "filesExplorer.copy",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // Cut
        "key": "x",
        "command": "filesExplorer.cut",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // Paste
        "key": "p",
        "command": "filesExplorer.paste",
        "when": "explorerViewletVisible && filesExplorerFocus && !explorerResourceIsRoot && !explorerResourceReadonly && !inputFocus"
    },
    {   // 全局搜索后,在输入框按回车,即可聚焦到搜索结果列表
        "key": "enter",
        "command": "search.action.focusSearchList",
        "when": "inSearchEditor && inputBoxFocus && hasSearchResult || inputBoxFocus && searchViewletVisible && hasSearchResult"
    },
    {   // 在搜索结果列表,只需按 esc,就可回到搜索输入框
        "key": "escape",
        "command": "workbench.action.findInFiles",
        "when": "searchViewletVisible && hasSearchResult && searchViewletFocus"
    },
    {   // 在搜索输入框,只需按 esc,就可回到编辑器
        "key": "escape",
        "command": "workbench.action.focusFirstEditorGroup",
        "when": "inSearchEditor && inputBoxFocus|| inputBoxFocus && searchViewletVisible"
    },
    {   // 在文件浏览界面,只需按 esc,就可回到编辑器
        "key": "escape",
        "command": "workbench.action.focusFirstEditorGroup",
        "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
    },
    {
        "key": "tab",
        "command": "acceptSelectedSuggestion",
        "when": "suggestWidgetVisible && textInputFocus"
    },
    { // Next Suggestion
        "key": "tab",
        "command": "selectNextSuggestion",
        "when": "editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible"
    },
    { // Prev Suggestion
        "key": "shift+tab",
        "command": "selectPrevSuggestion",
        "when": "editorTextFocus && suggestWidgetMultipleSuggestions && suggestWidgetVisible"
    },
    {
        "key": "cmd+k",
        "command": "workbench.action.focusActiveEditorGroup",
        "when": "terminalFocus"
    }
]

Reference