Skip to content

Instantly share code, notes, and snippets.

@wojukasz
Last active January 25, 2026 17:30
Show Gist options
  • Select an option

  • Save wojukasz/d76ca3162debc66d4227b9dc6049789e to your computer and use it in GitHub Desktop.

Select an option

Save wojukasz/d76ca3162debc66d4227b9dc6049789e to your computer and use it in GitHub Desktop.
⚡ Quick Start: VS Code + Vim keybindings | Works with AntiGravity Cursor | Copy-paste ready config | 5-min setup | Full version: https://github.com/wojukasz/VimCode (50+ keybindings, LazyVim-inspired, multi-editor support)
[
// ╔══════════════════════════════════════════════════════════════════════════════════╗
// ║ VSCODE VIM LAZYVIM KEYBINDINGS ║
// ║ Modifier Key Bindings (Ctrl, Alt, Shift) ║
// ╚══════════════════════════════════════════════════════════════════════════════════╝
//
// This file contains keybindings that use modifier keys (Ctrl, Alt, Shift) and special
// characters that need VSCode's key binding system (not Vim's).
//
// IMPORTANT: DO NOT put space-leader bindings here (<leader>...)
// Those belong in settings.json under vim.normalModeKeyBindingsNonRecursive
//
// FILE ORGANIZATION:
// - Window navigation (Ctrl+h/j/k/l)
// - Buffer navigation (Shift+h/l, [b, ]b)
// - Diagnostic navigation ([d, ]d, [e, ]e)
// - Quickfix navigation ([q, ]q)
// - Git hunk navigation ([h, ]h)
// - Suggestion/autocomplete navigation
// - File explorer navigation
// - Terminal toggle
// - Line movement (Alt+j/k)
//
// SPECIAL KEY CODES:
// - oem_4 = [ (left bracket)
// - oem_6 = ] (right bracket)
// - oem_2 = / (forward slash)
// - oem_1 = ; (semicolon)
//
// For keyboard layout independence, you can use scan codes instead:
// - [BracketLeft] instead of oem_4
// - [BracketRight] instead of oem_6
// - [Slash] instead of oem_2
//
// WHEN CLAUSES:
// The "when" field controls when a binding is active. Common contexts:
// - editorTextFocus: cursor is in an editor
// - vim.active: Vim extension is active
// - vim.mode: current Vim mode (Normal, Insert, Visual)
// - suggestWidgetVisible: autocomplete menu is open
// - inQuickOpen: Quick Open (Ctrl+P) is open
// - terminalFocus: terminal is focused
// - listFocus: a list (explorer, search) has focus
//
// ══════════════════════════════════════════════════════════════════════════════════════
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ WINDOW NAVIGATION - Ctrl+h/j/k/l (LazyVim: <C-h/j/k/l>) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate between editor splits using Vim-style hjkl keys with Ctrl modifier.
// These work in Normal mode and are disabled when:
// - Terminal is focused (so Ctrl+h/j/k/l work normally in terminal)
// - Suggestion widget is visible (so Ctrl+j/k navigate suggestions)
// - Quick Open is active (so Ctrl+j/k navigate file list)
//
{
"key": "ctrl+h",
"command": "workbench.action.focusLeftGroup",
"when": "!terminalFocus && vim.active && vim.mode != 'Insert'"
},
{
"key": "ctrl+l",
"command": "workbench.action.focusRightGroup",
"when": "!terminalFocus && vim.active && vim.mode != 'Insert'"
},
{
"key": "ctrl+j",
"command": "workbench.action.focusBelowGroup",
"when": "!terminalFocus && !suggestWidgetVisible && !inQuickOpen && vim.active && vim.mode != 'Insert'"
},
{
"key": "ctrl+k",
"command": "workbench.action.focusAboveGroup",
"when": "!terminalFocus && !suggestWidgetVisible && !inQuickOpen && vim.active && vim.mode != 'Insert'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ WINDOW RESIZING - Ctrl+Arrow Keys (LazyVim: <C-Up/Down/Left/Right>) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Resize editor splits using Ctrl+Arrow keys. Only active in Normal mode to avoid
// interfering with text editing shortcuts (Ctrl+Left/Right normally jump words).
//
{
"key": "ctrl+up",
"command": "workbench.action.increaseViewHeight",
"when": "vim.active && vim.mode == 'Normal'"
},
{
"key": "ctrl+down",
"command": "workbench.action.decreaseViewHeight",
"when": "vim.active && vim.mode == 'Normal'"
},
{
"key": "ctrl+left",
"command": "workbench.action.decreaseViewWidth",
"when": "vim.active && vim.mode == 'Normal'"
},
{
"key": "ctrl+right",
"command": "workbench.action.increaseViewWidth",
"when": "vim.active && vim.mode == 'Normal'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ BUFFER NAVIGATION - Shift+h/l (LazyVim: <S-h>, <S-l>) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Switch between open editor tabs using Shift+H (previous) and Shift+L (next).
// Only active in Normal/Visual modes to avoid conflicts with text selection.
// Alternative: Use [b and ]b (defined below) for the same functionality.
//
{
"key": "shift+h",
"command": "workbench.action.previousEditor",
"when": "vim.active && vim.mode != 'Insert'"
},
{
"key": "shift+l",
"command": "workbench.action.nextEditor",
"when": "vim.active && vim.mode != 'Insert'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ LINE MOVEMENT - Alt+j/k (LazyVim: <A-j>, <A-k>) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Move lines up/down using Alt+J/K. Works in Normal and Visual modes.
// In Visual mode, moves the entire selection.
//
{
"key": "alt+j",
"command": "editor.action.moveLinesDownAction",
"when": "editorTextFocus && !editorReadonly"
},
{
"key": "alt+k",
"command": "editor.action.moveLinesUpAction",
"when": "editorTextFocus && !editorReadonly"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ SAVE FILE - Ctrl+s (LazyVim: <C-s>) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Standard save shortcut. Works in all modes.
//
{
"key": "ctrl+s",
"command": "workbench.action.files.save",
"when": "editorTextFocus"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ TERMINAL TOGGLE - Ctrl+/ (LazyVim: <C-/>) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Toggle terminal panel visibility using Ctrl+/.
// - If terminal is hidden: opens and focuses it
// - If terminal is visible and focused: closes it
// - If terminal is visible but not focused: focuses it
//
// Note: oem_2 is the / (forward slash) key
//
{
"key": "ctrl+oem_2",
"command": "workbench.action.terminal.toggleTerminal"
},
// Alternative terminal toggle that focuses terminal if not focused
{
"key": "ctrl+oem_2",
"command": "workbench.action.terminal.focus",
"when": "!terminalFocus"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ TERMINAL NAVIGATION - Ctrl+; (bidirectional toggle) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Use Ctrl+; to jump between editor and terminal without closing it:
// - When in editor: jumps to terminal (opens if closed)
// - When in terminal: jumps back to editor
//
{
"key": "ctrl+;",
"command": "workbench.action.terminal.focus",
"when": "!terminalFocus"
},
{
"key": "ctrl+;",
"command": "workbench.action.focusActiveEditorGroup",
"when": "terminalFocus"
}
// #TODO: EXPERIMENTAL - TO TEST AND VALIDATE!
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ SUGGESTION WIDGET NAVIGATION - Ctrl+j/k when autocomplete is visible │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate autocomplete suggestions using Vim-style j/k keys.
// These override the window navigation when suggestion widget is visible.
//
{
"key": "ctrl+j",
"command": "selectNextSuggestion",
"when": "suggestWidgetVisible"
},
{
"key": "ctrl+k",
"command": "selectPrevSuggestion",
"when": "suggestWidgetVisible"
},
{
"key": "ctrl+d",
"command": "selectNextPageSuggestion",
"when": "suggestWidgetVisible"
},
{
"key": "ctrl+u",
"command": "selectPrevPageSuggestion",
"when": "suggestWidgetVisible"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ QUICK OPEN NAVIGATION - Ctrl+j/k when file picker is open │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate Quick Open (Ctrl+P) file list using Vim-style j/k keys.
//
{
"key": "ctrl+j",
"command": "workbench.action.quickOpenSelectNext",
"when": "inQuickOpen"
},
{
"key": "ctrl+k",
"command": "workbench.action.quickOpenSelectPrevious",
"when": "inQuickOpen"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ DIAGNOSTICS NAVIGATION - [d, ]d (all files) and [e, ]e (current file) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim diagnostic navigation using bracket prefix:
// - [d / ]d = previous/next diagnostic across all files
// - [e / ]e = previous/next diagnostic in current file only
//
// SPECIAL KEY CODES:
// - oem_4 = [ (left bracket)
// - oem_6 = ] (right bracket)
//
// On non-US keyboards, you may need to use scan codes instead:
// - "key": "[BracketLeft] d" instead of "key": "oem_4 d"
//
// Only active in Normal mode to prevent conflicts when typing brackets in Insert mode.
//
{
"key": "oem_4 d", // [d = previous diagnostic (all files)
"command": "editor.action.marker.prevInFiles",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
{
"key": "oem_6 d", // ]d = next diagnostic (all files)
"command": "editor.action.marker.nextInFiles",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
{
"key": "oem_4 e", // [e = previous diagnostic (current file)
"command": "editor.action.marker.prev",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
{
"key": "oem_6 e", // ]e = next diagnostic (current file)
"command": "editor.action.marker.next",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ QUICKFIX/SEARCH RESULTS NAVIGATION - [q, ]q │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate search results using bracket prefix.
// Only active when search results exist and in Normal mode.
//
{
"key": "oem_4 q", // [q = previous search result
"command": "search.action.focusPreviousSearchResult",
"when": "hasSearchResult && vim.active && vim.mode == 'Normal'"
},
{
"key": "oem_6 q", // ]q = next search result
"command": "search.action.focusNextSearchResult",
"when": "hasSearchResult && vim.active && vim.mode == 'Normal'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ BUFFER NAVIGATION - [b, ]b (alternate method) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Alternative buffer navigation using bracket prefix (same as Shift+H/L).
// Some users prefer this LazyVim pattern for consistency with other bracket navigation.
//
{
"key": "oem_4 b", // [b = previous buffer/editor
"command": "workbench.action.previousEditor",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
{
"key": "oem_6 b", // ]b = next buffer/editor
"command": "workbench.action.nextEditor",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ GIT HUNK NAVIGATION - [h, ]h (requires Git or GitLens) │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate between git changes/hunks in the current file.
// Works with native VSCode git or GitLens extension.
//
{
"key": "oem_4 h", // [h = previous git change
"command": "workbench.action.editor.previousChange",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
{
"key": "oem_6 h", // ]h = next git change
"command": "workbench.action.editor.nextChange",
"when": "editorTextFocus && vim.active && vim.mode == 'Normal'"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ FILE EXPLORER NAVIGATION - Ctrl+h/j/k/l when explorer is focused │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate file explorer using Vim keys when it has focus:
// - j/k = down/up
// - h = collapse folder or go to parent
// - l = expand folder or open file
//
// IMPORTANT: These must come AFTER the window navigation bindings above.
// VSCode processes keybindings from bottom to top, so more specific contexts
// (explorerViewletVisible) override more general ones (!terminalFocus).
//
{
"key": "ctrl+j",
"command": "list.focusDown",
"when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
},
{
"key": "ctrl+k",
"command": "list.focusUp",
"when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
},
{
"key": "ctrl+h",
"command": "list.collapse",
"when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
},
{
"key": "ctrl+l",
"command": "list.select",
"when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
},
// Alternative: Use j/k without Ctrl for explorer navigation (more Vim-like)
// Uncomment these if you prefer plain j/k in the explorer:
// {
// "key": "j",
// "command": "list.focusDown",
// "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
// },
// {
// "key": "k",
// "command": "list.focusUp",
// "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
// },
// {
// "key": "h",
// "command": "list.collapse",
// "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
// },
// {
// "key": "l",
// "command": "list.select",
// "when": "explorerViewletVisible && filesExplorerFocus && !inputFocus"
// },
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ SEARCH/PROBLEMS PANEL NAVIGATION - j/k when panel has focus │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Navigate lists in search results and problems panel using j/k.
//
{
"key": "j",
"command": "list.focusDown",
"when": "listFocus && !inputFocus"
},
{
"key": "k",
"command": "list.focusUp",
"when": "listFocus && !inputFocus"
},
// Navigate in panels with Ctrl+j/k as alternative
{
"key": "ctrl+j",
"command": "list.focusDown",
"when": "panelFocus && !terminalFocus"
},
{
"key": "ctrl+k",
"command": "list.focusUp",
"when": "panelFocus && !terminalFocus"
},
// ┌────────────────────────────────────────────────────────────────────────────────────┐
// │ FOCUS EDITOR GROUPS - Ctrl+1/2/3 │
// └────────────────────────────────────────────────────────────────────────────────────┘
//
// Quickly jump to specific editor groups/splits.
// Useful when you have multiple splits and want to jump directly to one.
//
{
"key": "ctrl+1",
"command": "workbench.action.focusFirstEditorGroup"
},
{
"key": "ctrl+2",
"command": "workbench.action.focusSecondEditorGroup"
},
{
"key": "ctrl+3",
"command": "workbench.action.focusThirdEditorGroup"
},
{
"key": "ctrl+4",
"command": "workbench.action.focusFourthEditorGroup"
},
{
"key": "ctrl+5",
"command": "workbench.action.focusFifthEditorGroup"
}
// ══════════════════════════════════════════════════════════════════════════════════════
// TROUBLESHOOTING NOTES
// ══════════════════════════════════════════════════════════════════════════════════════
//
// BRACKET KEYS NOT WORKING ([d, ]d, etc.):
//
// 1. UK/Non-US Keyboard Layouts:
// If you're on a non-US keyboard, the oem_4 and oem_6 codes might not work.
// Replace them with scan codes:
// - "key": "[BracketLeft] d" instead of "key": "oem_4 d"
// - "key": "[BracketRight] d" instead of "key": "oem_6 d"
//
// 2. MacOS:
// Brackets might require different key codes. Try:
// - "key": "[BracketLeft] d"
// - "key": "[BracketRight] d"
//
// 3. Testing bracket keys:
// Open VSCode Keyboard Shortcuts UI (Ctrl+K Ctrl+S / Cmd+K Cmd+S)
// Try to record your bracket key to see what VSCode detects it as
//
// CONFLICTS WITH OTHER EXTENSIONS:
//
// If keybindings don't work, check for conflicts:
// 1. Open Keyboard Shortcuts UI (Ctrl+K Ctrl+S / Cmd+K Cmd+S)
// 2. Search for the key combination (e.g., "ctrl+h")
// 3. Look for duplicate bindings from other extensions
// 4. Either disable the conflicting extension or modify your binding
//
// WHEN CLAUSES NOT WORKING:
//
// To debug when clauses:
// 1. Open Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
// 2. Run "Developer: Inspect Context Keys"
// 3. This shows all active context keys for debugging
//
// VALIDATION CHECKLIST:
// □ Ctrl+h/j/k/l navigates between splits
// □ Shift+h/l switches buffers
// □ [d / ]d navigates diagnostics
// □ [b / ]b switches buffers
// □ Ctrl+j/k navigates suggestions when autocomplete is open
// □ Ctrl+j/k navigates file list when Quick Open is active
// □ Alt+j/k moves lines up/down
// □ Ctrl+/ toggles terminal
//
// ══════════════════════════════════════════════════════════════════════════════════════
]
{
// ╔══════════════════════════════════════════════════════════════════════════════════╗
// ║ VSCODE VIM LAZYVIM CONFIGURATION ║
// ║ Complete Settings for LazyVim Alignment ║
// ╚══════════════════════════════════════════════════════════════════════════════════╝
//
// This configuration provides LazyVim-style keybindings in VSCode using the Vim extension.
//
// REQUIRED EXTENSIONS:
// - vscodevim.vim (VSCode Vim) - Core requirement
//
// RECOMMENDED EXTENSIONS:
// - eamodio.gitlens (GitLens) - For git operations like blame, history
// - hoovercj.vscode-settings-cycler (Settings Cycler) - For line number toggling
// - VSpaceCode.whichkey (Which Key) - For keybinding discovery menus
// - usernamehw.errorlens (Error Lens) - Inline diagnostics display
//
// PERFORMANCE OPTIMIZATION:
// The extensions.experimental.affinity setting (at bottom of file) runs Vim extension
// in a separate thread to prevent typing lag. This is CRITICAL for performance.
//
// FILE ORGANIZATION:
// This file contains ALL space-leader keybindings (<leader>...). Standard VSCode keybindings
// that don't use the leader key go in keybindings.json to prevent conflicts.
//
// ══════════════════════════════════════════════════════════════════════════════════════
// ──────────────────────────────────────────────────────────────────────────────────────
// EDITOR SETTINGS - Visual appearance and behaviour
// ──────────────────────────────────────────────────────────────────────────────────────
"editor.lineNumbers": "relative", // Relative line numbers (Vim-style)
"editor.scrollBeyondLastLine": false, // Don't scroll past end of file
"editor.cursorSurroundingLines": 8, // Keep 8 lines above/below cursor (matches LazyVim scrolloff)
"editor.smoothScrolling": true, // Smooth scrolling animations
"editor.bracketPairColorization.enabled": true, // Colour matching brackets
"editor.guides.bracketPairs": true, // Show bracket pair guides
"editor.minimap.renderCharacters": false, // Simplified minimap
"editor.minimap.scale": 2, // Larger minimap scale
"editor.cursorBlinking": "solid", // Solid cursor (Vim-like)
"editor.formatOnSave": false, // Format on save (set to true if desired)
// ──────────────────────────────────────────────────────────────────────────────────────
// VIM EXTENSION CORE SETTINGS - Vim behaviour and plugin emulation
// ──────────────────────────────────────────────────────────────────────────────────────
"vim.leader": "<space>", // Space as leader key (LazyVim standard)
"vim.useSystemClipboard": true, // Use system clipboard for yank/paste
"vim.useCtrlKeys": true, // Enable Vim Ctrl key bindings
"vim.smartRelativeLine": true, // Absolute line numbers in insert mode
// Vim plugin emulations (built into VSCode Vim extension)
"vim.easymotion": true, // Enable EasyMotion (use <leader><leader>w etc)
"vim.sneak": true, // Enable vim-sneak (use s/S for 2-char search)
"vim.surround": true, // Enable vim-surround (ys/ds/cs commands)
"vim.foldfix": true, // Better folding support
// Search settings
"vim.incsearch": true, // Incremental search (show matches as you type)
"vim.hlsearch": true, // Highlight search results
"vim.searchHighlightColor": "rgba(180, 142, 173, 0.5)", // Search highlight colour
// Visual feedback
"vim.highlightedyank.enable": true, // Briefly highlight yanked text
"vim.highlightedyank.duration": 200, // Highlight duration in milliseconds
// ──────────────────────────────────────────────────────────────────────────────────────
// STATUS BAR COLORS - Visual mode indicators (LazyVim-inspired colours)
// ──────────────────────────────────────────────────────────────────────────────────────
"vim.statusBarColorControl": true, // Enable status bar colour changes
"vim.statusBarColors.normal": "#519aba", // Blue for normal mode
"vim.statusBarColors.insert": "#98c379", // Green for insert mode
"vim.statusBarColors.visual": "#c678dd", // Purple for visual mode
"vim.statusBarColors.visualline": "#c678dd", // Purple for visual line mode
"vim.statusBarColors.visualblock": "#c678dd", // Purple for visual block mode
"vim.statusBarColors.replace": "#e06c75", // Red for replace mode
// ──────────────────────────────────────────────────────────────────────────────────────
// HANDLE KEYS - Which keys are processed by Vim vs VSCode
// ──────────────────────────────────────────────────────────────────────────────────────
//
// IMPORTANT: This section determines whether a key combination is handled by the Vim
// extension (true) or passed to VSCode (false). This prevents conflicts between Vim
// commands and VSCode shortcuts.
//
// - true = Vim extension handles the key (e.g., <C-d> for page down in Vim)
// - false = VSCode handles the key (e.g., <C-f> for native find dialogue)
//
"vim.handleKeys": {
"<C-d>": true, // Vim page down (half-page scroll)
"<C-u>": true, // Vim page up (half-page scroll)
"<C-f>": false, // VSCode find (don't override with Vim's full page down)
"<C-b>": false, // VSCode sidebar toggle (don't override with Vim's page up)
"<C-h>": false, // VSCode window navigation (defined in keybindings.json)
"<C-j>": false, // VSCode window navigation (defined in keybindings.json)
"<C-k>": false, // VSCode window navigation (defined in keybindings.json)
"<C-l>": false, // VSCode window navigation (defined in keybindings.json)
"<C-w>": false, // VSCode close tab (don't override Vim's window commands)
"<C-s>": false, // VSCode save file (standard shortcut)
"<C-a>": false, // VSCode select all (standard shortcut)
"<C-c>": false, // VSCode copy (standard shortcut)
"<C-v>": false, // VSCode paste (standard shortcut)
"<C-z>": false // VSCode undo (standard shortcut)
},
// ──────────────────────────────────────────────────────────────────────────────────────
// INSERT MODE KEYBINDINGS - Escape alternatives
// ──────────────────────────────────────────────────────────────────────────────────────
"vim.insertModeKeyBindings": [
{
"before": ["j", "k"], // jk to escape (LazyVim default)
"after": ["<Esc>"]
},
{
"before": ["j", "j"], // jj to escape (alternative)
"after": ["<Esc>"]
}
],
// ──────────────────────────────────────────────────────────────────────────────────────
// NORMAL MODE KEYBINDINGS - Space-leader mappings (LazyVim alignment)
// ──────────────────────────────────────────────────────────────────────────────────────
//
// CRITICAL: All space-leader bindings (<leader>...) MUST be defined here in settings.json,
// NOT in keybindings.json. The Vim extension needs to intercept these before VSCode sees them.
//
// Pattern reference (matches LazyVim):
// <leader>f* = File operations
// <leader>s* = Search operations
// <leader>c* = Code actions (LSP)
// <leader>b* = Buffer management
// <leader>g* = Git operations
// <leader>w* = Window management
// <leader>x* = Diagnostics/Quickfix
// <leader>u* = UI toggles
//
"vim.normalModeKeyBindingsNonRecursive": [
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ GENERAL UTILITY MAPPINGS │
// └────────────────────────────────────────────────────────────────────────────────┘
{
"before": ["<leader>", "d"], // <leader>d = delete line (dd shortcut)
"after": ["d", "d"]
},
{
"before": ["<Esc>"], // Escape clears search highlight
"commands": [":nohl"]
},
{
"before": ["<leader>", "u", "r"], // <leader>ur = clear search (LazyVim "unredraw")
"commands": [":nohl"]
},
{
"before": ["<C-n>"], // Ctrl+n also clears search highlight
"commands": [":nohl"]
},
{
"before": ["K"], // K = show hover documentation (LSP)
"commands": ["editor.action.showHover"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ FILE OPERATIONS - <leader>f* prefix │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim file operations pattern for finding, creating, and managing files
//
{
"before": ["<leader>", "<space>"], // <leader><space> = find files (Quick Open)
"commands": ["workbench.action.quickOpen"]
},
{
"before": ["<leader>", ","], // <leader>, = switch buffer (Quick Open Editors)
"commands": ["workbench.action.showAllEditors"]
},
{
"before": ["<leader>", "/"], // <leader>/ = search in files (Live Grep equivalent)
"commands": ["workbench.action.findInFiles"]
},
{
"before": ["<leader>", "f", "f"], // <leader>ff = find files (same as <leader><space>)
"commands": ["workbench.action.quickOpen"]
},
{
"before": ["<leader>", "f", "r"], // <leader>fr = recent files
"commands": ["workbench.action.openRecent"]
},
{
"before": ["<leader>", "f", "n"], // <leader>fn = new file
"commands": ["workbench.action.files.newUntitledFile"]
},
{
"before": ["<leader>", "f", "b"], // <leader>fb = buffers (open editors)
"commands": ["workbench.action.showAllEditors"]
},
{
"before": ["<leader>", "f", "e"], // <leader>fe = file explorer (reveal active file)
"commands": ["workbench.files.action.showActiveFileInExplorer"]
},
{
"before": ["<leader>", "f", "t"], // <leader>ft = toggle terminal
"commands": ["workbench.action.terminal.toggleTerminal"]
},
{
"before": ["<leader>", "e"], // <leader>e = toggle sidebar
"commands": ["workbench.action.toggleSidebarVisibility"]
},
{
"before": ["<leader>", "E"], // <leader>E = focus file explorer
"commands": ["workbench.files.action.focusFilesExplorer"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ SEARCH OPERATIONS - <leader>s* prefix │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim search operations for finding text, symbols, and configuration
//
{
"before": ["<leader>", "s", "g"], // <leader>sg = grep/search in files
"commands": ["workbench.action.findInFiles"]
},
{
"before": ["<leader>", "s", "w"], // <leader>sw = search word under cursor
"commands": ["workbench.action.findInFiles"]
},
{
"before": ["<leader>", "s", "r"], // <leader>sr = search and replace in files
"commands": ["workbench.action.replaceInFiles"]
},
{
"before": ["<leader>", "s", "s"], // <leader>ss = goto symbol in file
"commands": ["workbench.action.gotoSymbol"]
},
{
"before": ["<leader>", "s", "S"], // <leader>sS = goto symbol in workspace
"commands": ["workbench.action.showAllSymbols"]
},
{
"before": ["<leader>", "s", "k"], // <leader>sk = keymaps (open keyboard shortcuts)
"commands": ["workbench.action.openGlobalKeybindings"]
},
{
"before": ["<leader>", "s", "c"], // <leader>sc = command palette
"commands": ["workbench.action.showCommands"]
},
{
"before": ["<leader>", "s", "h"], // <leader>sh = help (all commands)
"commands": ["workbench.action.showAllCommands"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ CODE ACTIONS - <leader>c* prefix (LSP operations) │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim code actions for LSP features like formatting, refactoring, diagnostics
//
{
"before": ["<leader>", "c", "a"], // <leader>ca = code action (quick fix)
"commands": ["editor.action.quickFix"]
},
{
"before": ["<leader>", "c", "A"], // <leader>cA = source action
"commands": ["editor.action.sourceAction"]
},
{
"before": ["<leader>", "c", "f"], // <leader>cf = format document
"commands": ["editor.action.formatDocument"]
},
{
"before": ["<leader>", "c", "F"], // <leader>cF = format selection
"commands": ["editor.action.formatSelection"]
},
{
"before": ["<leader>", "c", "r"], // <leader>cr = rename symbol
"commands": ["editor.action.rename"]
},
{
"before": ["<leader>", "c", "d"], // <leader>cd = line diagnostics (hover)
"commands": ["editor.action.showHover"]
},
{
"before": ["<leader>", "c", "l"], // <leader>cl = open problems panel
"commands": ["workbench.action.problems.focus"]
},
{
"before": ["<leader>", "c", "o"], // <leader>co = organise imports
"commands": ["editor.action.organizeImports"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ LSP NAVIGATION - g* prefix (goto definitions, references, etc.) │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// Standard Vim LSP navigation bindings (matches LazyVim defaults)
//
{
"before": ["g", "d"], // gd = goto definition
"commands": ["editor.action.revealDefinition"]
},
{
"before": ["g", "D"], // gD = goto declaration
"commands": ["editor.action.revealDeclaration"]
},
{
"before": ["g", "r"], // gr = goto references
"commands": ["editor.action.goToReferences"]
},
{
"before": ["g", "I"], // gI = goto implementation
"commands": ["editor.action.goToImplementation"]
},
{
"before": ["g", "y"], // gy = goto type definition
"commands": ["editor.action.goToTypeDefinition"]
},
{
"before": ["g", "K"], // gK = signature help (parameter hints)
"commands": ["editor.action.triggerParameterHints"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ BUFFER MANAGEMENT - <leader>b* prefix │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim buffer operations for managing open files/tabs
//
{
"before": ["<leader>", "b", "b"], // <leader>bb = switch buffer (show all editors)
"commands": ["workbench.action.showAllEditors"]
},
{
"before": ["<leader>", "b", "d"], // <leader>bd = delete buffer (close tab)
"commands": ["workbench.action.closeActiveEditor"]
},
{
"before": ["<leader>", "b", "D"], // <leader>bD = delete other buffers
"commands": ["workbench.action.closeOtherEditors"]
},
{
"before": ["<leader>", "b", "o"], // <leader>bo = close other editors (same as bD)
"commands": ["workbench.action.closeOtherEditors"]
},
{
"before": ["<leader>", "b", "p"], // <leader>bp = pin buffer (pin tab)
"commands": ["workbench.action.pinEditor"]
},
{
"before": ["<leader>", "b", "P"], // <leader>bP = unpin buffer
"commands": ["workbench.action.unpinEditor"]
},
{
"before": ["<leader>", "`"], // <leader>` = last buffer (alternate file)
"commands": ["workbench.action.quickOpenPreviousRecentlyUsedEditorInGroup"]
},
{
"before": ["<S-h>"], // Shift+h = previous buffer
"commands": [":bprev"]
},
{
"before": ["<S-l>"], // Shift+l = next buffer
"commands": [":bnext"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ GIT OPERATIONS - <leader>g* prefix (requires GitLens extension) │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim git operations. Most features require GitLens extension for full functionality.
// Without GitLens, basic git commands (gg, gs, gd) still work with native VSCode git.
//
{
"before": ["<leader>", "g", "g"], // <leader>gg = git status (open source control)
"commands": ["workbench.view.scm"]
},
{
"before": ["<leader>", "g", "s"], // <leader>gs = git status (same as gg)
"commands": ["workbench.view.scm"]
},
{
"before": ["<leader>", "g", "b"], // <leader>gb = git blame toggle (GitLens)
"commands": ["gitlens.toggleFileBlame"]
},
{
"before": ["<leader>", "g", "B"], // <leader>gB = git browse (open on remote - GitLens)
"commands": ["gitlens.openFileOnRemote"]
},
{
"before": ["<leader>", "g", "d"], // <leader>gd = git diff (show changes)
"commands": ["git.openChange"]
},
{
"before": ["<leader>", "g", "l"], // <leader>gl = git log (file history - GitLens)
"commands": ["gitlens.showQuickFileHistory"]
},
{
"before": ["<leader>", "g", "L"], // <leader>gL = git log (branch history - GitLens)
"commands": ["gitlens.showQuickRepoHistory"]
},
{
"before": ["<leader>", "g", "c"], // <leader>gc = git commits (show commit details - GitLens)
"commands": ["gitlens.showQuickCommitDetails"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ WINDOW MANAGEMENT - <leader>w* and <leader>-/| prefix │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim window/split operations
//
{
"before": ["<leader>", "w", "d"], // <leader>wd = close window (close split/editor)
"commands": ["workbench.action.closeActiveEditor"]
},
{
"before": ["<leader>", "w", "w"], // <leader>ww = switch window (focus other group)
"commands": ["workbench.action.focusNextGroup"]
},
{
"before": ["<leader>", "w", "m"], // <leader>wm = maximise window (toggle editor width)
"commands": ["workbench.action.toggleEditorWidths"]
},
{
"before": ["<leader>", "-"], // <leader>- = split window below
"commands": ["workbench.action.splitEditorDown"]
},
{
"before": ["<leader>", "|"], // <leader>| = split window right
"commands": ["workbench.action.splitEditorRight"]
},
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ DIAGNOSTICS/QUICKFIX - <leader>x* prefix and [ ] navigation │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim diagnostics and error navigation. Bracket prefix mappings ([d, ]d) are
// defined in keybindings.json because they use special key codes (oem_4, oem_6).
//
{
"before": ["<leader>", "x", "x"], // <leader>xx = diagnostics list (problems panel)
"commands": ["workbench.action.problems.focus"]
},
{
"before": ["<leader>", "x", "X"], // <leader>xX = workspace diagnostics
"commands": ["workbench.actions.view.problems"]
},
{
"before": ["<leader>", "x", "l"], // <leader>xl = location list (same as xx)
"commands": ["workbench.action.problems.focus"]
},
// Note: [d, ]d, [e, ]e navigation defined in keybindings.json
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ UI TOGGLES - <leader>u* prefix │
// └────────────────────────────────────────────────────────────────────────────────┘
//
// LazyVim UI toggle operations. Line number toggling requires Settings Cycler extension.
// Install: hoovercj.vscode-settings-cycler
// Configure settings.cycle in this file (see bottom section).
//
{
"before": ["<leader>", "u", "w"], // <leader>uw = toggle word wrap
"commands": ["editor.action.toggleWordWrap"]
},
{
"before": ["<leader>", "u", "z"], // <leader>uz = toggle zen mode
"commands": ["workbench.action.toggleZenMode"]
},
{
"before": ["<leader>", "u", "r"], // <leader>ur = redraw/clear search
"commands": [":nohl"]
},
// Requires Settings Cycler extension - uncomment after installing:
// {
// "before": ["<leader>", "u", "l"], // <leader>ul = toggle line numbers
// "commands": ["settings.cycle.lineNumbers"]
// },
// {
// "before": ["<leader>", "u", "L"], // <leader>uL = toggle relative numbers
// "commands": ["settings.cycle.relativeLineNumbers"]
// },
// ┌────────────────────────────────────────────────────────────────────────────────┐
// │ QUIT - <leader>q* prefix │
// └────────────────────────────────────────────────────────────────────────────────┘
{
"before": ["<leader>", "q", "q"], // <leader>qq = quit VSCode
"commands": ["workbench.action.closeWindow"]
},
{
"before": ["<leader>", "q", "a"], // <leader>qa = quit all windows
"commands": ["workbench.action.quit"]
}
],
// ──────────────────────────────────────────────────────────────────────────────────────
// VISUAL MODE KEYBINDINGS - Selection operations
// ──────────────────────────────────────────────────────────────────────────────────────
//
// Visual mode enhancements for better selection handling and LazyVim parity
//
"vim.visualModeKeyBindings": [
{
"before": ["<"], // < = indent left and reselect
"after": ["<", "g", "v"] // The 'gv' reselects the previous visual selection
},
{
"before": [">"], // > = indent right and reselect
"after": [">", "g", "v"]
},
{
"before": ["<leader>", "/"], // <leader>/ = search selected text
"commands": ["workbench.action.findInFiles"]
},
{
"before": ["<leader>", "c", "a"], // <leader>ca = code action on selection
"commands": ["editor.action.quickFix"]
},
{
"before": ["<leader>", "c", "f"], // <leader>cf = format selection
"commands": ["editor.action.formatSelection"]
},
{
"before": ["g", "c"], // gc = comment toggle
"commands": ["editor.action.commentLine"]
}
],
// ──────────────────────────────────────────────────────────────────────────────────────
// SETTINGS CYCLER CONFIGURATION (requires hoovercj.vscode-settings-cycler extension)
// ──────────────────────────────────────────────────────────────────────────────────────
//
// This provides LazyVim-style line number toggling with <leader>ul and <leader>uL.
// Install the extension, then uncomment the keybindings above in the UI TOGGLES section.
//
// "settings.cycle": [
// {
// "id": "lineNumbers",
// "values": [
// { "editor.lineNumbers": "on" }, // Absolute line numbers
// { "editor.lineNumbers": "relative" }, // Relative line numbers
// { "editor.lineNumbers": "off" } // No line numbers
// ]
// },
// {
// "id": "relativeLineNumbers",
// "values": [
// { "editor.lineNumbers": "relative" }, // Toggle between relative
// { "editor.lineNumbers": "on" } // and absolute only
// ]
// }
// ],
// ──────────────────────────────────────────────────────────────────────────────────────
// PERFORMANCE OPTIMISATION - CRITICAL for responsive typing
// ──────────────────────────────────────────────────────────────────────────────────────
//
// This runs the Vim extension in a dedicated thread to prevent typing lag and cursor
// delays. This is ESSENTIAL for a good Vim experience in VSCode.
//
"extensions.experimental.affinity": {
"vscodevim.vim": 1
}
// ──────────────────────────────────────────────────────────────────────────────────────
// ADDITIONAL NOTES AND TROUBLESHOOTING
// ──────────────────────────────────────────────────────────────────────────────────────
//
// MACOS USERS: Enable key repeat for hjkl navigation
// Run in terminal: defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
// Then restart VSCode.
//
// COMMON ISSUES:
//
// 1. Leader key not working:
// - Ensure "vim.leader": "<space>" is set
// - Verify bindings are in settings.json, NOT keybindings.json
// - Check no other extension is capturing space key
//
// 2. Typing lag or cursor delay:
// - Ensure extensions.experimental.affinity is set (see above)
// - Disable unused extensions
// - Check CPU usage in Task Manager
//
// 3. GitLens commands not working:
// - Install GitLens extension: eamodio.gitlens
// - Some commands are only available in git repositories
//
// 4. Bracket navigation ([d, ]d) not working:
// - These are defined in keybindings.json
// - Check your keybindings.json file is configured correctly
//
// 5. Line number toggle not working:
// - Install Settings Cycler: hoovercj.vscode-settings-cycler
// - Uncomment the settings.cycle section above
// - Uncomment the <leader>ul keybindings in UI TOGGLES section
//
// VALIDATION CHECKLIST:
// □ Space key triggers leader (doesn't move cursor)
// □ <leader>ff opens file picker
// □ <leader>/ searches in files
// □ gd navigates to definition
// □ K shows hover
// □ <leader>ca shows code actions
// □ Shift+H/L switches buffers
// □ No typing lag or cursor delays
//
// ══════════════════════════════════════════════════════════════════════════════════════
}

Changelog

[Migration Notice] - 2026-01

This gist is now synced with VimCode Repository 🚀

What Changed

  • Gist = Quick Start version of VimCode (copy-paste ready)
  • Repository = Full version with 50+ keybindings, docs, multi-editor support
  • Synced configurations - gist matches repo's core config
  • Easy upgrade path - start here, upgrade to full repo when ready

Why Upgrade to VimCode Repository?

  • 50+ keybindings vs ~20 in this gist
  • LazyVim conventions - complete implementation
  • Multi-editor support - VS Code, Cursor, Windsurf
  • Comprehensive docs - SETUP.md, KEYBINDINGS.md, TROUBLESHOOTING.md, TIPS_AND_TRICKS.md
  • Active community - Issues, Discussions, regular updates
  • Better organization - Logical file structure and documentation

Migration Path

  1. ✅ Use this gist for quick 5-minute setup
  2. 📖 Read VimCode docs
  3. ⭐ Star the repository
  4. 🔧 Upgrade to full config when you want more features

[2.0.0] - 2026-01-17 (Synced with VimCode v2.0.0)

This version syncs with VimCode Repository v2.0.0

Added

  • Enhanced Git integration
    • Pull command: <leader>gp
    • Push command: <leader>gP
    • File history: <leader>gh
  • New navigation shortcuts
    • Method boundaries: [m, ]m
    • Error navigation: [d, ]d
    • Definition jumping: ctrl+], ctrl+t
  • Split management
    • Resize shortcuts: alt+h, alt+l
    • Maximize toggle: ctrl+w m
    • Equal sizing: <C-w>=
  • Code folding commands
    • Fold: <leader>z
    • Unfold: <leader>Z
  • Tab navigation
    • Previous/Next: alt+[, alt+]
  • Workspace management
    • Close workspace: ctrl+shift+w
    • Copy file path: ctrl+k p
  • Enhanced panel navigation
    • Consistent ctrl+j/k in all panels
    • Improved terminal focus controls

Changed

  • Standardized sidebar toggling to use <leader>e
  • Improved comments and documentation
  • Reorganized keybindings into logical groups
  • Synced with VimCode repository structure

Fixed

  • Removed redundant keybindings
  • Standardized leader key usage
  • Improved context awareness for shortcuts

👉 For full changelog and latest updates, see VimCode CHANGELOG.md


[1.0.0] - 2025-01-22 (Gist-only release)

Added

  • Enhanced Git integration
    • Pull command: <leader>g p
    • Push command: <leader>g P
    • File history: <leader>g h
  • New navigation shortcuts
    • Method boundaries: [m, ]m
    • Error navigation: [d, ]d
    • Definition jumping: ctrl+], ctrl+t
  • Split management
    • Resize shortcuts: alt+h, alt+l
    • Maximize toggle: ctrl+w m
    • Equal sizing: <C-w>=
  • Code folding commands
    • Fold: <leader>z
    • Unfold: <leader>Z
  • Tab navigation
    • Previous/Next: alt+[, alt+]
  • Workspace management
    • Close workspace: ctrl+shift+w
    • Copy file path: ctrl+k p
  • Enhanced panel navigation
    • Consistent ctrl+j/k in all panels
    • Improved terminal focus controls

Changed

  • Standardized sidebar toggling to use <leader>e
  • Improved comments and documentation
  • Reorganized keybindings into logical groups

Fixed

  • Removed redundant keybindings
  • Standardized leader key usage
  • Improved context awareness for shortcuts

[0.1.0] - Initial Release

Added

  • Basic Vim keybindings
  • File explorer integration
  • Terminal shortcuts
  • Basic Git commands
  • Split navigation

Maintenance Notes

Gist Update Schedule:

  • This gist is updated when VimCode repository has major releases
  • For latest features and bug fixes, use the VimCode repository
  • Gist focuses on core, stable features for quick setup

Want to Contribute?

VS Code + Vim Keybindings - Quick Start ⚡

🚀 This gist is synced with VimCode v2.0.0 - same configs, streamlined docs!

💡 Want more? The VimCode repository adds comprehensive documentation, troubleshooting guides, tips & tricks, and multi-editor support (Cursor, Windsurf).

Star VimCode on GitHub | 📖 Full Docs | 🔧 Advanced Setup


About This Gist

This is a copy-paste ready Vim configuration for VS Code featuring:

Same configs as VimCode repository - keybindings.json and settings.json are identical
50+ LazyVim-inspired keybindings - Organized by prefix (<leader>f*, <leader>s*, etc.)
Full LSP integration - Code navigation, formatting, refactoring
Git operations - Powered by GitLens
5-minute setup - Copy, paste, reload, done!

Gist vs Repository - What's the Difference?

Feature This Gist VimCode Repository
Config files ✅ Same (synced) ✅ Same
Keybindings ✅ 50+ (identical) ✅ 50+ (identical)
Setup guide ⚡ Quick (5-min) 📚 Comprehensive
Documentation 📄 This README 📖 5 detailed guides
Troubleshooting ❌ Link to repo ✅ Full guide
Tips & tricks ❌ Link to repo ✅ Power user workflows
Multi-editor 💻 VS Code only 💻 VS Code + Cursor + Windsurf
Community ✅ Issues, Discussions, PRs
Updates 📅 Major releases 🔄 Active development

TL;DR: Same powerful configs, choose based on how much documentation you want!


5-Minute Setup

1. Install Required Extensions

# Essential (required)
code --install-extension vscodevim.vim
 
# Recommended (for full functionality)
code --install-extension eamodio.gitlens
code --install-extension ryuta46.multi-command

2. Copy Configuration Files

Copy settings.json and keybindings.json from this gist to your VS Code user directory:

macOS:

~/.config/Code/User/settings.json
~/.config/Code/User/keybindings.json

Linux:

~/.config/Code/User/settings.json
~/.config/Code/User/keybindings.json

Windows:

%APPDATA%\Code\User\settings.json
%APPDATA%\Code\User\keybindings.json

💡 Tip: If you already have custom configs, consider backing them up first!

3. Reload VS Code

Press Cmd/Ctrl + Shift + P → Type "Reload Window" → Enter

Done! 🎉 Try pressing <space> (leader key) to see available commands.


Essential Keybindings

Leader key: <space>

🗂️ File Operations

Keybinding Action
<leader>ff Find files
<leader>fg Find in files (grep)
<leader>fr Recent files
<leader>fb Find buffers
<leader>w Save file
<leader>q Close file

🔍 Search Operations

Keybinding Action
<leader>sg Search with grep
<leader>sw Search word under cursor
<leader>/ Search in current file

⚙️ Code Actions

Keybinding Action
gd Go to definition
gr Find references
<leader>ca Code actions
<leader>rn Rename symbol
<leader>cf Format code

🌳 Git Operations

Keybinding Action
<leader>gg Open Git panel
<leader>gb Git blame
<leader>gd Git diff
<leader>gp Git pull
<leader>gP Git push

🪟 Window Management

Keybinding Action
Ctrl+h/j/k/l Navigate splits
<leader>wv Vertical split
<leader>ws Horizontal split
<leader>wc Close window
<leader>wm Maximize toggle

🎯 UI Toggles

Keybinding Action
<leader>e Toggle file explorer
<leader>uf Toggle format on save
<leader>ul Toggle line numbers

👉 Complete reference: VimCode Keybindings Guide (all 50+ shortcuts with categories)


Quick Troubleshooting

Problem: Keybindings Don't Work

Solution:

  1. Verify VSCodeVim extension is installed: code --list-extensions | grep vim
  2. Check extension is enabled: Extensions panel → VSCodeVim → Make sure it's not disabled
  3. Reload VS Code: Cmd/Ctrl + Shift + P → "Reload Window"

Still not working? See the full troubleshooting guide

Problem: Conflicts with Existing Keybindings

Solution:

  1. Open Keyboard Shortcuts: Cmd/Ctrl + K, Cmd/Ctrl + S
  2. Search for the conflicting keybinding
  3. Right-click conflicting entry → "Remove Keybinding"

Need help resolving conflicts? Check the keybinding conflicts guide

Problem: Some Features Missing

Possible causes:

  • GitLens extension not installed (for Git features)
  • Multi-command extension not installed (for complex commands)

Solution: Install recommended extensions (see Setup step 1 above)


Files in This Gist

File Purpose Synced with Repo?
README.md This file - setup guide ✅ Optimized for quick start
settings.json VS Code settings + Vim config ✅ Identical to repo
keybindings.json All 50+ keyboard shortcuts ✅ Identical to repo
CHANGELOG.md Version history ✅ Summarized from repo

Why Upgrade to VimCode Repository?

You're Happy with This Gist If:

  • ✅ 5-minute setup is all you need
  • ✅ Configs are working great
  • ✅ You don't need troubleshooting help
  • ✅ You only use VS Code (not Cursor/Windsurf)

Upgrade to VimCode Repository If:

  • 📚 You want comprehensive documentation (SETUP.md, KEYBINDINGS.md, etc.)
  • 🐛 You need troubleshooting help (common issues, solutions)
  • 💡 You want tips & tricks (power user workflows, best practices)
  • 🎯 You use Cursor or Windsurf (multi-editor configurations)
  • 👥 You want community support (issues, discussions)
  • 🔄 You want latest updates (active development)
  • 🤝 You want to contribute (PRs welcome!)

Next Steps

1. Try It Out (5 min)

  • Open a file and try <leader>ff to find files
  • Navigate splits with Ctrl+h/j/k/l
  • Try code actions with <leader>ca
  • Use Git blame with <leader>gb

2. Learn More (15 min)

3. Get Involved (optional)


Related Resources

VimCode Documentation

Getting Help

External Resources


Sync Status

Last synced with VimCode: v2.0.0 (2026-01-17)

What this means:

  • ✅ Configs in this gist match VimCode repository v2.0.0
  • ✅ You have all 50+ keybindings from the repo
  • ✅ Future major releases will be synced here
  • 📅 This gist updates every major release (v3.0.0, v4.0.0, etc.)

Want bleeding edge? Use the VimCode repository directly!


Contributing

Found a bug? Want to suggest an improvement?

  1. 🐛 Report bugs
  2. 💡 Request features
  3. ⌨️ Report keybinding conflicts
  4. 🤝 Submit pull requests

All contributions go through the VimCode repository!


License

MIT License - Free to use and modify

See LICENSE in the VimCode repository.


Keep in Touch


⭐ If you find this useful, please star VimCode on GitHub!

🚀 Ready for the full experience? Visit VimCode Repository for comprehensive docs, troubleshooting, community support, and multi-editor configurations!

@w3sync
Copy link

w3sync commented Nov 29, 2023

how can i config this in my vscode

@LwveMike
Copy link

LwveMike commented Apr 4, 2024

how can i config this in my vscode

  1. Press cmd + shift + p or ctrl + shift +p.
  2. Write settings.
  3. Scroll to personal settings ( JSON ).
  4. Paste this config there.

@nicolidin
Copy link

hello it seems i can't have two keys after leader, only one works, how did you do?

@w3sync
Copy link

w3sync commented Sep 23, 2024

hey some features are missing like ctrl+f, ctrl+s,

@wojukasz
Copy link
Author

wojukasz commented Oct 2, 2024

@nicolidin you have to install multi-command plugin and add the multi-command settings https://gist.github.com/wojukasz/d76ca3162debc66d4227b9dc6049789e#file-settings-json

@wojukasz
Copy link
Author

hey some features are missing like ctrl+f, ctrl+s,

yeah, its not something I explored yet but I will try build upon this config over time

@DmitriiKozlov-Neura
Copy link

I changed the ', e' binding, to be able to input commas in terminal. Added !inputFocus to when:

 {
    // ", e": Toggles the sidebar's visibility when the text editor is not focused. <leader> + e
    "key": ", e",
    "command": "workbench.action.toggleSidebarVisibility",
    "when": "!editorTextFocus && !inputFocus"
  },

@wojukasz
Copy link
Author

I changed the ', e' binding, to be able to input commas in terminal. Added !inputFocus to when:

 {
    // ", e": Toggles the sidebar's visibility when the text editor is not focused. <leader> + e
    "key": ", e",
    "command": "workbench.action.toggleSidebarVisibility",
    "when": "!editorTextFocus && !inputFocus"
  },

Nice! thanks for sharing!

@Ibrahim-Azhar77
Copy link

hey some features are missing like ctrl+f, ctrl+s,

Hi!
I noticed the same when I first set up VimCode in VS Code. Some default shortcuts like Ctrl+F (search) or Ctrl+S (save) may not work if they are overridden by the Vim keybindings.

Here’s what I do:

  • Open Keyboard Shortcuts (Ctrl+K, Ctrl+S)
  • Search for the conflicting shortcut
  • Either reassign it or remove the conflict
  • Reload VS Code (Ctrl+Shift+P → Reload Window)

I also test all my keys after changes using this Free Keyboard Tester. It helps me quickly spot any missing shortcuts.

This keeps all essential shortcuts working while still enjoying Vim-style navigation!

@wojukasz
Copy link
Author

wojukasz commented Jan 17, 2026

Thanks, @Ibrahim-Azhar77. That's really good advice. I will take a look.

In this case, Ctrl + s works as a save file.

My take is to make this config Vim first and VS Code second, since I am coming from a Vim background. I am not planning to learn many VS Code shortcuts, but rather to adapt Vim to VS Code functionality.
More info in: https://github.com/wojukasz/VimCode

I am planning to keep this gist in sync with the repo, but mainly update keybindings and settings files to keep overhead minimal.

@Ibrahim-Azhar77
Copy link

Thanks for the explanation. I like the Vim-first approach, as it feels more natural to me. Using Ctrl + S as save makes sense, especially for beginners. Keeping the gist in sync with the repo also sounds like a clean and practical idea.

@wojukasz
Copy link
Author

thanks @Ibrahim-Azhar77 I am planning to refine as I go on and update, but if you find anything that is not working or you have suggestions for improvments please post in https://github.com/wojukasz/VimCode/issues

@Ibrahim-Azhar77
Copy link

Thanks for the update! I’ll keep an eye on it and post any issues or suggestions directly on this page: https://github.com/wojukasz/VimCode/issues. Keep up the great work!

@odezzshuuk
Copy link

  // ┌────────────────────────────────────────────────────────────────────────────────────┐
  // │ BUFFER NAVIGATION - Shift+h/l (LazyVim: <S-h>, <S-l>)                              │
  // └────────────────────────────────────────────────────────────────────────────────────┘
  //
  // Switch between open editor tabs using Shift+H (previous) and Shift+L (next).
  // Only active in Normal/Visual modes to avoid conflicts with text selection.
  // Alternative: Use [b and ]b (defined below) for the same functionality.
  //
  {
    "key": "shift+h",
    "command": "workbench.action.previousEditor",
    "when": "vim.active && vim.mode != 'Insert' && editorFocus"
  },
  {
    "key": "shift+l",
    "command": "workbench.action.nextEditor",
    "when": "vim.active && vim.mode != 'Insert' && editorFocus"
  },

I add editorFocus to buffer navigation when-expression to avoid tab switch when typing "L", "H" in copilot chat.

@wojukasz
Copy link
Author

Brilliant @odezzshuuk , I encountered that last week just didn't got around to fixing it, thanks will try it out coming week and update accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment