Practical Vim command workflow
In Vim, there’s a variety of commands that let you accomplish tasks in different ways. This can be overwhelming for beginners trying to figure out the most efficient keystrokes for editing. In this tutorial, I’ll share my approach to using Vim commands and offer some real life examples to help you improve your workflow.
Guidelines
Here are some general rules of my workflow:
- Don’t use mouse and arrow keys (unless you have a custom keyboard layout with arrows near the home row).
- Use relative jump (eg:
5k 12j
) for vertical movement inside screen. - Use
CTRL-U CTRL-D CTRL-B CTRL-F gg G
for vertical movement outside screen. - Use word-motion (
w W b B e E ge gE
) for short distance horizontal movement. - Use
f F t T 0 ^ $ , ;
for mid long distance horizontal movement. - Use
operator + motion/text-object
(eg:ci{ d5j
) whenever possible.
If you are not familiar with some of the commands and concepts, you can learn about them in Essential Vim commands for efficient text editing.
Examples
Here are 4 real situations I faced when creating a todo list website with javascript. I recommend you to think about how you would achieve the editing goal first and then see my approach.
Notes:
^
orv
points to the position of the cursor.- There are line number and relative line number on the left.
Situation 1
Goal: Change activeList
to this
and add a ;
at the end of the line.
// current mode: Normal
2 if (this.sortMethod === 'Name') {
1 activeList.uncheckedTodo.sort(sortWithName)
189 }
^
My approach: -cwthis<ESC>A;
-
: Go 1 line upward, on the first non-blank charactercwthis
: Change the word and typethis
.<ESC>
: Leave insert mode.A;
: Jump to the end of the line and type;
.
Situation 2
Goal: Change i-s+1
to d
and add new
before Date(y, m, d)
.
// current mode: Normal
454 console.log(Date(y, m, i-s+1));
^
My approach: Wct)d<C-o>FDnew
(<C-o>
means CTRL-O
)
W
: Go one word forward, ignore symbol.ct)d
: Change till before the occurrence of)
to the right and typed
.<C-o>
: Execute one command in Normal mode and then return to Insert mode.FD
: Go to the occurrence ofD
to the left.new
: Typenew
.
Situation 3
Goal: Add a line activeList.sortMethod = 'Date';
below document.querySelector('.sort-date')...
.
// current mode: Insert
1 document.querySelector('.sort-name').addEventListener('click', () => {
343 activeList.sortMethod = 'Name';
1 activeList.update(); ^
2 })
3
4 document.querySelector('.sort-date').addEventListener('click', () => {
5 activeList.update();
6 })
My approach: <ESC>yy4jpci'Date
<ESC>
: Leave insert mode.yy
: Yank current line.4j
: Go down 4 line.p
: Paste the line we just yanked.ci'Date
: Change the content inside single quote and typeDate
.
Situation 4
Goal: Move the whole block of //sort
to the beginning of update()
function.
// current mode: Normal
8 update() {
7 this.checkedTodo.forEach((todo) => {
6 this.element.insertBefore(todo.element, todoCreator.nextSibling);
5 });
4 this.uncheckedTodo.forEach((todo) => {
3 this.element.insertBefore(todo.element, todoCreator.nextSibling);
2 });
1 v
200 // sort
1 if(this.sortMethod === 'Name') {
2 this.uncheckedTodo.sort(sortWithName);
3 }
4 else if(this.sortMethod === 'Date') {
5 this.uncheckedTodo.sort(sortWithDate);
6 }
7
8 createCalendar(currentYear, currentMonth, this);
9 }
My approach: dap8kp
dap
: Delete around the paragraph.8k
: Go up 8 lines.p
: Paste the paragraph we just deleted.
Final Words
If you just start learning Vim operators, motions, it may take some times to think of what commands to use for each situation. However, If you keep practicing and using them, you’ll become faster and faster. After a while, you’ll develop muscle memory for using these commands.
If you are using Neovim, I recommend you to try out hardtime.nvim. It’s a plugin to help you establish good command workflow and display hints for better commands!