Key
✅ - command done
⚠️ - command partially implemented
⬇️ - command is low priority; open an issue (or thumbs up the relevant issue) if you want to see it sooner
❌ - command impossible with current VSCode API
🔢 - command accepts numeric prefix
Roadmap
These are the big Vim features, put generally in the order in which we plan to implement them.
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 |
Now follows an exhaustive list of every known Vim command that we could find.
Left-right motions
Status |
Command |
Description |
✅ |
🔢 h |
left (also: CTRL-H, BS, or Left key) |
✅ |
🔢 l |
right (also: Space or Right key) |
✅ |
0 |
to first character in the line (also: Home key) |
✅ |
^ |
to first non-blank character in the line |
✅ |
🔢 $ |
to the last character in the line (N-1 lines lower) (also: End key) |
✅ |
g0 |
to first character in screen line (differs from "0" when lines wrap) |
✅ |
g^ |
to first non-blank character in screen line (differs from "^" when lines wrap) |
✅ |
🔢 g$ |
to last character in screen line (differs from "$" when lines wrap) |
✅ |
gm |
to middle of the screen line |
✅ |
🔢 | |
to column N (default: 1) |
✅ |
🔢 f{char} |
to the Nth occurrence of {char} to the right |
✅ |
🔢 F{char} |
to the Nth occurrence of {char} to the left |
✅ |
🔢 t{char} |
till before the Nth occurrence of {char} to the right |
✅ |
🔢 T{char} |
till before the Nth occurrence of {char} to the left |
🔢 ; |
repeat the last "f", "F", "t", or "T" N times |
|
🔢 , |
repeat the last "f", "F", "t", or "T" N times in opposite direction |
|
Up-down motions
Status |
Command |
Description |
✅ |
🔢 k |
up N lines (also: CTRL-P and Up) |
✅ |
🔢 j |
up N lidown N lines (also: CTRL-J, CTRL-N, NL, and Down) |
✅ |
🔢 - |
up N lines, on the first non-blank character |
✅ |
🔢 + |
down N lines, on the first non-blank character (also: CTRL-M and CR) |
✅ |
🔢 _ |
down N-1 lines, on the first non-blank character |
✅ |
🔢 G |
goto line N (default: last line), on the first non-blank character |
✅ |
🔢 gg |
goto line N (default: first line), on the first non-blank character |
✅ |
🔢 % |
goto line N percentage down in the file; N must be given, otherwise it is the |
✅ |
🔢 gk |
up N screen lines (differs from "k" when line wraps) |
✅ |
🔢 gj |
own N screen lines (differs from "j" when line wraps) |
Text object motions
Status |
Command |
Description |
✅ |
🔢 w |
N words forward |
✅ |
🔢 W |
N blank-separated |
✅ |
🔢 e |
N words forward to the end of the Nth word |
✅ |
🔢 E |
N words forward to the end of the Nth blank-separated |
✅ |
🔢 b |
N words backward |
✅ |
🔢 B |
N blank-separated |
✅ |
🔢 ge |
N words backward to the end of the Nth word |
✅ |
🔢 gE |
N words backward to the end of the Nth blank-separated |
✅ |
🔢 ) |
N sentences forward |
✅ |
🔢 ( |
N sentences backward |
✅ |
🔢 } |
N paragraphs forward |
✅ |
🔢 { |
N paragraphs backward |
✅ |
🔢 ]] |
N sections forward, at start of section |
✅ |
🔢 [[ |
N sections backward, at start of section |
✅ |
🔢 ][ |
N sections forward, at end of section |
✅ |
🔢 [] |
N sections backward, at end of section |
✅ |
🔢 [( |
N times back to unclosed '(' |
✅ |
🔢 [{ |
N times back to unclosed '{' |
⬇️ |
🔢 [m |
N times back to start of method (for Java) |
⬇️ |
🔢 [M |
N times back to end of method (for Java) |
✅ |
🔢 ]) |
N times forward to unclosed ')' |
✅ |
🔢 ]} |
N times forward to unclosed '}' |
⬇️ |
🔢 ]m |
N times forward to start of method (for Java) |
⬇️ |
🔢 ]M |
N times forward to end of method (for Java) |
⬇️ |
🔢 [# |
N times back to unclosed "#if" or "#else" |
⬇️ |
🔢 ]# |
N times forward to unclosed "#else" or "#endif" |
⬇️ |
🔢 [* |
N times back to start of a C comment "/*" |
⬇️ |
🔢 ]* |
N times forward to end of a C comment "*/" |
Various motions
Status |
Command |
Description |
✅ |
% |
find the next brace, bracket, comment, or "#if"/ "#else"/"#endif" in this line and go to its match |
✅ |
🔢 H |
go to the Nth line in the window, on the first non-blank |
✅ |
M |
go to the middle line in the window, on the first non-blank |
✅ |
🔢 L |
go to the Nth line from the bottom, on the first non-blank |
🔢 go |
go to Nth byte in the buffer |
|
:[range]go[to] [off] |
go to [off] byte in the buffer |
|
These only work when 'wrap' is off:
Status |
Command |
Description |
❌ |
🔢 zh |
scroll screen N characters to the right |
❌ |
🔢 zl |
scroll screen N characters to the left |
❌ |
🔢 zH |
scroll screen half a screenwidth to the right |
❌ |
🔢 zL |
scroll screen half a screenwidth to the left |
Inserting text
Status |
Command |
Description |
✅ |
🔢 a |
append text after the cursor (N times) |
✅ |
🔢 A |
append text at the end of the line (N times) |
✅ |
🔢 i |
insert text before the cursor (N times) (also: Insert) |
✅ |
🔢 I |
insert text before the first non-blank in the line (N times) |
✅ |
🔢 gI |
insert text in column 1 (N times) |
✅ |
🔢 o |
open a new line below the current line, append text (N times) |
✅ |
🔢 O |
open a new line above the current line, append text (N times) |
in Visual block mode:
Status |
Command |
Description |
I |
insert the same text in front of all the selected lines |
|
A |
append the same text after all the selected lines |
|
Insert mode keys
leaving Insert mode:
Status |
Command |
Description |
✅ |
Esc |
end Insert mode, back to Normal mode |
✅ |
CTRL-C |
like Esc, but do not use an abbreviation |
⬇️ |
CTRL-O {command} |
execute {command} and return to Insert mode |
moving around:
Status |
Command |
Description |
✅ |
cursor keys |
move cursor left/right/up/down |
✅ |
shift-left/right |
one word left/right |
✅ |
shift-up/down |
one screenful backward/forward |
✅ |
End |
cursor after last character in the line |
✅ |
Home |
cursor to first character in the line |
Deleting text
Status |
Command |
Description |
✅ |
🔢 x |
delete N characters under and after the cursor |
✅ |
🔢 Del |
delete N characters under and after the cursor |
✅ |
🔢 X |
delete N characters before the cursor |
✅ |
🔢 d{motion} |
delete the text that is moved over with {motion} |
✅ |
{visual}d |
delete the highlighted text |
✅ |
🔢 dd |
delete N lines |
✅ |
🔢 D |
delete to the end of the line (and N-1 more lines) |
✅ |
🔢 J |
join N-1 lines (delete EOLs) |
{visual}J |
join the highlighted lines |
|
✅ |
🔢 gJ |
like "J", but without inserting spaces |
{visual}gJ |
like "{visual}J", but without inserting spaces |
|
:[range]d [x] |
delete [range] lines [into register x] |
|
Copying and moving text
Status |
Command |
Description |
⚠️ |
"{char} |
use register {char} for the next delete, yank, or put |
✅ |
"* |
use register * to access system clipboard |
:reg |
show the contents of all registers |
|
:reg {arg} |
show the contents of registers mentioned in {arg} |
|
✅ |
🔢 y{motion} |
yank the text moved over with {motion} into a register |
✅ |
{visual}y |
yank the highlighted text into a register |
✅ |
🔢 yy |
yank N lines into a register |
⚠️ |
🔢 Y |
yank N lines into a register |
✅ |
🔢 p |
put a register after the cursor position (N times) |
✅ |
🔢 P |
put a register before the cursor position (N times) |
✅ |
🔢 ]p |
like p, but adjust indent to current line |
✅ |
🔢 [p |
like P, but adjust indent to current line |
✅ |
🔢 gp |
like p, but leave cursor after the new text |
✅ |
🔢 gP |
like P, but leave cursor after the new text |
Changing text
Status |
Command |
Description |
⚠️ |
🔢 r{char} |
replace N characters with {char} |
🔢 gr{char} |
replace N characters without affecting layout |
|
⚠️ |
🔢 R |
enter Replace mode (repeat the entered text N times) |
🔢 gR |
enter virtual Replace mode: Like Replace mode but without affecting layout |
|
{visual}r{char} |
in Visual block mode: Replace each char of the selected text with {char} |
|
(change = delete text and enter Insert mode)
Status |
Command |
Description |
⚠️ |
🔢 c{motion} |
change the text that is moved over with {motion} |
✅ |
{visual}c |
change the highlighted text |
⚠️ |
🔢 cc |
change N lines |
⚠️ |
🔢 S |
change N lines |
⚠️ |
🔢 C |
change to the end of the line (and N-1 more lines) |
🔢 s |
change N characters |
|
{visual}c |
in Visual block mode: Change each of the selected lines with the entered text |
|
{visual}C |
in Visual block mode: Change each of the selected lines until end-of-line with the entered text |
|
⚠️ |
🔢 ~ |
switch case for N characters and advance cursor |
{visual}~ |
switch case for highlighted text |
|
{visual}u |
make highlighted text lowercase |
|
{visual}U |
make highlighted text uppercase |
|
g~{motion} |
switch case for the text that is moved over with {motion} |
|
gu{motion} |
make the text that is moved over with {motion} lowercase |
|
gU{motion} |
make the text that is moved over with {motion} uppercase |
|
⬇️ |
{visual}g? |
perform rot13 encoding on highlighted text |
⬇️ |
g?{motion} |
perform rot13 encoding on the text that is moved over with {motion} |
✅ |
🔢 CTRL-A |
add N to the number at or after the cursor |
✅ |
🔢 CTRL-X |
subtract N from the number at or after the cursor |
✅ |
🔢 <{motion} |
move the lines that are moved over with {motion} one shiftwidth left |
✅ |
🔢 << |
move N lines one shiftwidth left |
✅ |
🔢 >{motion} |
move the lines that are moved over with {motion} one shiftwidth right |
✅ |
🔢 >> |
move N lines one shiftwidth right |
🔢 gq{motion} |
format the lines that are moved over with {motion} to 'textwidth' length |
|
:[range]ce[nter] [width] |
center the lines in [range] |
|
:[range]le[ft] [indent] |
left-align the lines in [range] (with [indent]) |
|
:[range]ri[ght] [width] |
right-align the lines in [range] |
|
Visual mode
Status |
Command |
Description |
✅ |
v |
start highlighting characters |
✅ |
V |
start highlighting linewise |
CTRL-V |
start highlighting blockwise |
|
o |
exchange cursor position with start of highlighting |
|
gv |
start highlighting on previous visual area |
|
✅ |
v |
highlight characters or stop highlighting |
✅ |
V |
highlight linewise or stop highlighting |
CTRL-V |
highlight blockwise or stop highlighting |
|
Text objects (only in Visual mode or after an operator)
Status |
Command |
Description |
✅ |
🔢 aw |
Select "a word" |
✅ |
🔢 iw |
Select "inner word" |
✅ |
🔢 aW |
Select "a |
✅ |
🔢 iW |
Select "inner |
✅ |
🔢 as |
Select "a sentence" |
✅ |
🔢 is |
Select "inner sentence" |
🔢 ap |
Select "a paragraph" |
|
🔢 ip |
Select "inner paragraph" |
|
🔢 ab |
Select "a block" (from "[(" to "])") |
|
🔢 ib |
Select "inner block" (from "[(" to "])") |
|
🔢 aB |
Select "a Block" (from "[{" to "]}") |
|
🔢 iB |
Select "inner Block" (from "[{" to "]}") |
|
✅ |
🔢 a> |
Select "a <> block" |
✅ |
🔢 i> |
Select "inner <> block" |
🔢 at |
Select "a tag block" (from to ) |
|
🔢 it |
Select "inner tag block" (from to ) |
|
✅ |
🔢 a' |
Select "a single quoted string" |
✅ |
🔢 i' |
Select "inner single quoted string" |
✅ |
🔢 a" |
Select "a double quoted string" |
✅ |
🔢 i" |
Select "inner double quoted string" |
✅ |
🔢 a` |
Select "a backward quoted string" |
✅ |
🔢 i` |
Select "inner backward quoted string" |
Repeating commands
Status |
Command |
Description |
✅ |
🔢 . |
repeat last change (with count replaced with N) |
q{a-z} |
record typed characters into register {a-z} |
|
q{A-Z} |
record typed characters, appended to register {a-z} |
|
q |
stop recording |
|
🔢 @{a-z} |
execute the contents of register {a-z} (N times) |
|
🔢 @@ |
repeat previous @{a-z} (N times) |
|
:@{a-z} |
execute the contents of register {a-z} as an Ex command |
|
:@@ |
repeat previous :@{a-z} |
|
:[range]g[lobal]/{pattern}/[cmd] |
execute Ex command [cmd] (default: ":p") on the lines within [range] where {pattern} matches |
|
:[range]g[lobal]!/{pattern}/[cmd] |
execute Ex command [cmd] (default: ":p") on the lines within [range] where {pattern} does NOT match |
|
⬇️ |
:so[urce] {file} |
read Ex commands from {file} |
⬇️ |
:so[urce]! {file} |
read Vim commands from {file} |
⬇️ |
:sl[eep] [sec] |
don't do anything for [sec] seconds |
⬇️ |
🔢 gs |
goto Sleep for N seconds |
Marks and motions
Status |
Command |
Description |
✅ |
m{a-zA-Z} |
mark current position with mark {a-zA-Z} |
`{a-z} |
go to mark {a-z} within current file |
|
`{A-Z} |
go to mark {A-Z} in any file |
|
`{0-9} |
go to the position where Vim was previously exited |
|
`` |
go to the position before the last jump |
|
`" |
go to the position when last editing this file |
|
`[ |
go to the start of the previously operated or put text |
|
`] |
go to the end of the previously operated or put text |
|
`< |
go to the start of the (previous) Visual area |
|
`> |
go to the end of the (previous) Visual area |
|
`. |
go to the position of the last change in this file |
|
'{a-zA-Z0-9[]'"<>.} |
same as `, but on the first non-blank in the line |
|
:marks |
print the active marks |
|
🔢 CTRL-O |
go to Nth older position in jump list |
|
🔢 CTRL-I |
go to Nth newer position in jump list |
|
:ju[mps] |
print the jump list |
|
Complex changes
Status |
Command |
Description |
🔢 !{motion}{command} |
filter the lines that are moved over through {command} |
|
🔢 !!{command} |
filter N lines through {command} |
|
{visual}!{command} |
filter the highlighted lines through {command} |
|
:[range]! {command} |
filter [range] lines through {command} |
|
✅ |
🔢 ={motion} |
filter the lines that are moved over through 'equalprg' |
🔢 == |
filter N lines through 'equalprg' |
|
✅ |
{visual}= |
filter the highlighted lines through 'equalprg' |
⚠️ |
:[range]s[ubstitute]/{pattern}/{string}/[g][c] |
substitute {pattern} by {string} in [range] lines; with [g], replace all occurrences of {pattern}; with [c], confirm each replacement |
:[range]s[ubstitute] [g][c] |
repeat previous ":s" with new range and options |
|
& |
Repeat previous ":s" on current line without options |
|
⬇️ |
:[range]ret[ab][!] [tabstop] |
set 'tabstop' to new value and adjust white space accordingly |
Special keys in Insert mode
Status |
Command |
Description |
CTRL-V {char}.. |
insert character literally, or enter decimal byte value |
|
⚠️ |
NL or CR or CTRL-M or CTRL-J |
begin new line |
CTRL-E |
insert the character from below the cursor |
|
CTRL-Y |
insert the character from above the cursor |
|
CTRL-A |
insert previously inserted text |
|
CTRL-@ |
insert previously inserted text and stop Insert mode |
|
CTRL-R {0-9a-z%#:.-="} |
insert the contents of a register |
|
CTRL-N |
insert next match of identifier before the cursor |
|
CTRL-P |
insert previous match of identifier before the cursor |
|
CTRL-X ... |
complete the word before the cursor in various ways |
|
BS or CTRL-H |
delete the character before the cursor |
|
✅ |
Del |
delete the character under the cursor |
✅ |
CTRL-W |
delete word before the cursor |
CTRL-U |
delete all entered characters in the current line |
|
CTRL-T |
insert one shiftwidth of indent in front of the current line |
|
CTRL-D |
delete one shiftwidth of indent in front of the current line |
|
0 CTRL-D |
delete all indent in the current line |
|
^ CTRL-D |
delete all indent in the current line, restore indent in next line |
|
Scrolling
Status |
Command |
Description |
❌ |
🔢 CTRL-E |
window N lines downwards (default: 1) |
⚠️ |
🔢 CTRL-D |
window N lines Downwards (default: 1/2 window) |
❌ |
🔢 CTRL-F |
window N pages Forwards (downwards) |
❌ |
🔢 CTRL-Y |
window N lines upwards (default: 1) |
⚠️ |
🔢 CTRL-U |
window N lines Upwards (default: 1/2 window) |
❌ |
🔢 CTRL-B |
window N pages Backwards (upwards) |
❌ |
z CR or zt |
redraw, current line at top of window |
⚠️ |
z. or zz |
redraw, current line at center of window |
❌ |
z- or zb |
redraw, current line at bottom of window |
Special inserts
Status |
Command |
Description |
:r [file] |
insert the contents of [file] below the cursor |
|
:r! {command} |
insert the standard output of {command} below the cursor |
|
Window
Status |
Command |
Description |
⚠️ |
:e[dit] {file} |
Edit {file}. We will open file in a new Tab of current Grouped Editor instead of opening in current tab. |
⚠️ |
hl |
Switching between windows. As we don't have the concept of Window in VS Code, we are mapping these commands to switching between Grouped Editors. |
❌ |
:sp {file} |
Split current window in two. VS Code doesn't support split Window horizontally. |
:vsp {file} |
Split vertically current window in two. |
|
❌ |
:new |
Create a new window horizontally and start editing an empty file in it. |
:vne[w] |
Create a new window vertically and start editing an empty file in it. |
|
Tabs
Status |
Command |
Description |
✅ |
:tabn[ext] 🔢 |
Go to next tab page or tab page {count}. The first tab page has number one. |
{count}, {count}gt |
Same as above |
|
✅ |
:tabp[revious] 🔢 |
Go to the previous tab page. Wraps around from the first one to the last one. |
✅ |
:tabN[ext] 🔢 |
Same as above |
{count}, {count}gT |
Same as above |
|
✅ |
:tabfir[st] |
Go to the first tab page. |
✅ |
:tabl[ast] |
Go to the last tab page. |
⚠️ |
:tabe[dit] {file} |
Open a new tab page with an empty window, after the current tab page |
:[count]tabe[dit], :[count]tabnew |
Same as above |
|
⚠️ |
:tabnew {file} |
Open a new tab page with an empty window, after the current tab page |
:[count]tab {cmd} |
Execute {cmd} and when it opens a new window open a new tab page instead. |
|
⚠️ |
:tabc[lose][!] 🔢 |
Close current tab page or close tab page {count}. |
⚠️ |
:tabo[nly][!] |
Close all other tab pages. |
✅ |
:tabm[ove] [N] |
Move the current tab page to after tab page N. |
❌ |
:tabs |
List the tab pages and the windows they contain. |
:tabd[o] {cmd} |
Execute {cmd} in each tab page. |
|
options
Commands
Status |
Command |
Description |
:se[t] |
show all modified options |
|
:se[t] all |
show all non-termcap options |
|
:se[t] termcap |
show all termcap options |
|
✅ |
:se[t] {option} |
set boolean option (switch it on), show string or number option |
✅ |
:se[t] no{option} |
reset boolean option (switch it off) |
:se[t] inv{option} |
invert boolean option |
|
✅ |
:se[t] {option}={value} |
set string/number option to {value} |
:se[t] {option}+={value} |
append {value} to string option, add {value} to number option |
|
:se[t] {option}-={value} |
remove {value} to string option, subtract {value} from number option |
|
:se[t] {option}? |
show value of {option} |
|
:se[t] {option}& |
reset {option} to its default value |
|
:setl[ocal] |
like ":set" but set the local value for options that have one |
|
:setg[lobal] |
like ":set" but set the global value of a local option |
|
:fix[del] |
set value of 't_kD' according to value of 't_kb' |
|
:opt[ions] |
open a new window to view and set options, grouped by functionality, a one line explanation and links to the help |
|
Option list
Since the list is too long, now we just put those already supported options here.
Status |
Command |
Default Value |
Description |
✅ |
tabstop (ts) |
4. we use Code's default value tabSize instead of Vim |
number of spaces that in file uses |
✅ |
expandtab (et) |
True. we use Code's default value inserSpaces instead of Vim |
use spaces when is inserted |
Folding
Fold methods
The folding method can be set with the 'foldmethod' option. This is currently not possible as we are relying on Code's Fold logic.
Fold commands
Status |
Command |
Description |
❌ |
zf{motion} or {Visual}zf |
Operator to create a fold. |
❌ |
zF |
Create a fold for [count] lines. Works like "zf". |
❌ |
zd |
Delete one fold at the cursor. |
❌ |
zD |
Delete folds recursively at the cursor. |
❌ |
zE |
Eliminate all folds in the window. |
⚠️ ❌ |
zo |
Open one fold under the cursor.When a count is given, that many folds deep will be opened. |
✅ |
zO |
Open all folds under the cursor recursively. |
⚠️ ❌ |
zc |
Close one fold under the cursor. When a count is given, that many folds deep are closed. |
✅ |
zC |
Close all folds under the cursor recursively. |
❌ |
za |
When on a closed fold: open it. When on an open fold: close it and set 'foldenable'. |
❌ |
zA |
When on a closed fold: open it recursively. When on an open fold: close it recursively and set 'foldenable'. |
❌ |
zv |
View cursor line: Open just enough folds to make the line in which the cursor is located not folded. |
❌ |
zx |
Update folds: Undo manually opened and closed folds: re-apply 'foldlevel', then do "zv": View cursor line. |
❌ |
zX |
Undo manually opened and closed folds |
❌ |
zm |
Fold more: Subtract one from 'foldlevel'. |
✅ |
zM |
Close all folds: set 'foldlevel' to 0. 'foldenable' will be set. |
❌ |
zr |
Reduce folding: Add one to 'foldlevel'. |
✅ |
zR |
Open all folds. This sets 'foldlevel' to highest fold level. |
zn |
Fold none: reset 'foldenable'. All folds will be open. |
|
zN |
Fold normal: set 'foldenable'. All folds will be as they were before. |
|
zi |
Invert 'foldenable'. |
|
❌ |
[z |
Move to the start of the current open fold. |
❌ |
]z |
Move to the end of the current open fold. |
❌ |
zj |
Move downwards to the start of the next fold. |
❌ |
zk |
Move upwards to the end of the previous fold. |
Fold options
Status |
Command |
Description |
❌ |
foldlevel |
'foldlevel' is a number option: The higher the more folded regions are open. |
❌ |
foldtext |
'foldtext' is a string option that specifies an expression. This expression is evaluated to obtain the text displayed for a closed fold. |
❌ |
foldcolumn |
'foldcolumn' is a number, which sets the width for a column on the side of the window to indicate folds. |
foldenable fen |
Open all folds while not set. |
|
❌ |
foldexpr fde |
Expression used for "expr" folding. |
❌ |
foldignore fdi |
Characters used for "indent" folding. |
❌ |
foldmarker fmr |
Defined markers used for "marker" folding. |
❌ |
foldmethod fdm |
Name of the current folding method. |
❌ |
foldminlines fml |
Minimum number of screen lines for a fold to be displayed closed. |
❌ |
foldnestmax fdn |
Maximum nesting for "indent" and "syntax" folding. |
❌ |
foldopen fdo |
Which kinds of commands open closed folds. |
❌ |
foldclose fcl |
When the folds not under the cursor are closed. |