vim mode tips
Abstract
Lots of good tips for VIM.
Introduction
Vim is more than just a text editor. It’s a powerful tool that can boost your productivity and creativity.
You’ve probably heard the endless debates about Vim vs NeoVim, Vim vs Emacs, Vim vs IDEs, and editors vs IDEs. You’ve also probably wondered if you should customize Vim to act like an IDE or your IDE to act like Vim.
What if I told you that modern IDEs can emulate most of the Vim features you love, even some advanced ones? In this guide I’ll show you 90 tips to get familiar with Vim, focusing on Vim emulation on popular IDEs like VS Code and IntelliJ IDEA.
You’ll see that only a few of the frequently used features are not supported, and I’ll point them out for you. By the end, you’ll have a better idea of what Vim emulation can do, and you can use this knowledge to decide which environment is best for you.
If you are experienced with Vim, you can skip ahead and skim through the headlines. If something piques your interest, feel free to deep dive.
Resources
Other resources that you might want to keep in mind include:
- The official cheat sheet, “Quickref”.
- Vim tutor. An official 30-minute interactive tutorial built into Vim itself. (Now it’s built into the JetBrains Vim plugin too.)
- The Commands Index. An index containing every single Vim command.
- The “you don’t grok vi” answer on StackOverflow. Undoubtedly the greatest piece of literature on StackOverflow.
- The browser game Vim Adventures. The first level is free. For $25 you unlock a pretty legit learning experience to develop muscle memory.
- The guide “Learn Vim the Smart Way”.
- The Vim Wiki, the greatest repository of Vim tips.
- Throughout this guide you’ll see links to vimhelp.org, an HTML version of the Vim help pages which is kept up-to-date automatically with Vim’s built-in help.
Which Vim mode should you use?
For JetBrains editors (IntelliJ, WebStorm, PyCharm and others, and soon Fleet), there is an excellent Vim plugin called IdeaVim.
If you are using VSCode, there are two options: The first is the standard Vim plugin, which is very popular these days. The second is vscode-neovim, which creates a Vim mode by embedding NeoVim itself. Note that the standard Vim plugin also has an experimental embedding of NeoVim to enable some features.
It is worth noting that the JetBrains team has also considered embedding NeoVim, but it is not likely to happen in the near future, and they have their reasons.
In addition, many users praise the Vim plugin for Visual Studio, but I do not use that IDE myself, so I will not include it in this guide.
With that out of the way, let’s dive in!
Section 1: The first steps in Vim
1. The tilde (~) lines indicate lines not in the file
Maybe you were wondering what those funny symbols on the edge of your screen are when you open Vim on a terminal.
They are useful to differentiate empty lines from the abyss after the file ends. Sure, IDEs use line numbers to convey the same information, but Vim is classy enough to predate innovations like “line numbers are on by default.”
As an IDE user, you won’t see the tildes.
2. Vim is a “modal” editor
Vim is modal. That means that the editor behaves differently, depending on which mode you are in.
Most GUI editors are what is called “modeless,” in which all commands can be performed using the same set of keys at all times. They provide a more intuitive and user-friendly interface, especially when paired with innovations such as the mouse.
However, advanced users claim that modal is faster and more powerfull, even if there is a certain delay introduced by changing mode.
3. The main modes are “Normal mode” and “Insert Mode”
Here’s the full list of modes
In Normal mode the characters you type are commands. In Insert mode the characters are inserted as text.
Vim starts in Normal mode. There are several ways to go to Insert mode, the most common is the i
command (i for Insert). Then you can enter text. To go back to Normal mode (no matter what mode you are in), press <Esc>
.
Some users find that the <Esc>
key can be difficult to reach, so they remap it to a more accessible key like “Caps Lock.” I use a keyboard with a thumb cluster, so I have my <Esc>
key there.
The normal in other GUI editors is that you can enter text whenever you want. But in Vim, “normal” is typing commands. Welcome to the new normal.
To better tell that you are in Insert mode, Vim displays an --Insert--
text at the bottom of the screen and changes the look of the caret. The IDEs display it too.
4. Use “hjkl” to move around
Ah yes, the dreaded “hjkl” is a true test of courage. It’s the way to tell adults from kids in the Vim world.
You can use h
to go left, j
to go down, k
to go up, l
to go right:
Historically, this comes from the keyboard Bill Joy was using when he created “vi”, the predecessor of Vim in 1976:
ADM-3A keyboard (image credit vintagecomputer.ca)
The modern arrow keys are also available for Vim, but a lot of people think that the “hjkl” keys are more accessible for touch typing, as you don’t have to move the hands from the “home row.”
This is also true for non Qwerty users: Most people agree that the default locations of the “hjkl” key are also comfortable in both Colemak and Dvorak.
Are you still on Qwerty and don’t touch type? Consider upgrading your keyboard skills with this guide:
[
You’re Missing Out on The Best Keyboard Experience
It’s 2023. There’s no reason to use your grandparent’s keyboard any longer.
sebastiancarlos.com
](https://sebastiancarlos.com/youre-missing-out-on-the-best-keyboard-experience-d41fb21a23f8)
One way to remember these commands is that h
is on the left, l
is on the right and j
points down. But you can use whatever mnemotechnic you want. You’ll get used to them soon.
5. Delete characters with “x”
To delete a character under the cursor, press x
. (This is a throwback to the typewriter days, when you deleted by typing xxxx
over words.)
To delete a whole line, press dd
:
6. Delete line breaks with “J”
To delete a line break, thereby effectively joining two lines together, press J
anywhere on the first line:
Actually, there is no such thing as “lines” in text-based files. The fiction of lines is manufactured through special invisible characters called “line breaks,” usually represented as \n
.
Notation Interlude: CTRL-{char}
This notation represents typing a character, {char}, while holding the CTRL key down.
In modern times, you’ll probably see this as Ctrl + A
, but Vim likes to notate it as CTRL-A
.
In Vim, the case of {char} is ignored; thus CTRL-A
and CTRL-a
are equivalent.
7. Undo and redo
In most text editors, the undo and redo commands are performed using the CTRL-Z
and CTRL-SHIFT-Z
shortcuts respectively.
Vim instead uses u
and CTRL-R
respectively.
Additionally, Vim has a U
(undo line) command to undo all changes made to a line in one step. Note that the U
command is a change by itself, which can be undone and redone with u
and CTRL-R
.
IDEs on Vim mode allow you to use either u
/CTRL-R
or CTRL-Z
/CTRL-SHIFT-Z
. It’s up to you to go “full Vim” or to keep using familiar shortcuts. In this case, I prefer the Vim way because the u
key is very ergonomic.
Some VSCode users have encountered problems with Vim’s undo stack being out of sync with the IDE’s stack.
8. Other ways to insert text: “I”, “a”, “A”, “o”, “O”
Insertion is nice, and there are many ways to go about it:
i
— insert text before the cursor:
I
— insert text at the first non-blank on the line:
a
— append text after the cursor:
A
— append text at the end of the line:
o
— open a new line below the current line, append text:
O
— open a new line above the current line, append text:
Naturally, all of these commands put you in Insert mode.
9. Lowercase, uppercase, and g-prefixed commands.
As you noticed, single-character Vim commands can be lowercase, uppercase, and (as we’ll see later) g-prefixed.
Sometimes there is no relation between a lowercase command and an uppercase command using the same character. For example j
(move down) and J
(join lines).
But often the commands using the same character are related. In those cases there’s no rule of thumb, but you can think of the lowercase one as the “obvious” command, and the capitalised one can be either an “augmented” version (a
and A
) or a “reverse” version (o
and O
).
The g-prefixed commands tend to be the ones you use less.
10. Using a count
You can precede many commands with a number.
Instead of typing kkkkkkkkk
, you can enter the command 9k
.
To append three exclamation marks, you can do a!!!<Esc>
or 3a!<Esc>
.
11. Exiting Vim
All good things must come to an end, including the “I can’t exit Vim” meme.
To exit, use the ZZ
command. This command writes the file and exits.
To quit without saving changes, do :q!
. The colon (:
) enters Command-line mode, the q command tells the editor to quit, and the override command modifier (!
) is needed because Vim is a bit cheeky and doesn’t want to throw unsaved changes.
If you want to throw the changes but continue editing the file, the :e!
command reloads the original version of the file.
There’s also ZQ
, which does the same as :q!
. Pick your poison!
On IDEs, these commands won’t allow you to close the IDE itself. They just attempt to close the current file.
IDEs tend a lot more towards constant auto-save, so these commands are more permissive than their terminal Vim counterparts because you are more likely to find that your changes are already saved when you try to close a file.
12. Finding :help
To get help on a command, for example “x”, enter :help x
.
By default, the help system displays the normal-mode commands. If you want the help for the insert-mode version of a command, use the i_
prefix: :help i_CTRL-H
. A full list of mode prefixes is here, but honestly, I would just Google your question if it gets too complex.
On a JetBrains IDE, :help
will show the help on a browser, but the implementation is inconvenient because it lands on a search page. Currently, the VSCode Vim plugin doesn’t support :help
.
For now, I recommend opening Vim on the terminal if you just want to use :help
. Or you can go to vimhelp.org.
Section 2: Moving Around
13. Word movement: “w”, “b”, “e” and “ge”
To move the cursor forward one word, use the w
command. Like most commands, you can use a numeric prefix to move past multiple words.
This figure shows how it works:
Then the b
command goes to the previous word:
There is also the e
command that moves to the next end of a word and ge
, o
which moves to the previous end of a word:
If any of these commands reach the end of the line, it will move into the next or previous line accordingly.
14. Words vs WORDS
In Vim there are two kind of words: Words and WORDS.
The commands on the previous section work on “words,” soon we’ll see other commands that work on uppercase “WORDS”
But what is the difference between the two? A good rule of thumb is “word until punctuation, WORD until whitespace.” But if you want the gory technical details, read on:
A word is:
- A sequence of letters, digits, underscores, and some special ASCII characters (as specified in the default value of the
iskeyword
option:@,48–57,_,192–255
). - Or a sequence of non-blank characters that are not included in the
iskeyword
option. - Or an empty line.
A WORD is:
- A sequence of non-blank characters.
- Or an empty line.
For example, the line abc@#$ def%^&
contains 4 words and 2 WORDS:
Sometimes you will want to include a dash in keywords, so that commands
like w
consider “upper-case” to be one word. You can do it by modifying the isKeyword
option like this:
:set iskeyword+=-
15. WORD movement: “W”, “E”, “B” and “gE”
The commands for moving by WORDs are also uppercase, as this figure shows:
16. Moving to the end or start of a line: “$”, “^” and “0”
The $
command moves the cursor to the end of a line.
The ^
command moves to the first non-blank character of the line. The 0
command (zero) moves to the very first character of the line.
The $
command takes a count. It causes the editor to move to the end of a following line.
For some mysterious reason, the 0
and ^
commands don’t take a count. No one knows why. I guess this is the kind of bizarre behavior that you have to expect when using a 50 year old editor. In any case, most people don’t even use the $
count.
17. Single-character search commands: “f”, “F”, “t”, “T”
The command fx
searches forward in the line for the single character “x”. Note that you can search for any character you want, but it will search only in the current line. f
stands for “Find”.
F
does the same but it searches backwards.
t
and T
are very similar but they only go “till” one character before the searched command.
Any of these four commands can be repeated with ;
. ,
repeats the search in the other direction.
18. Matching a parenthesis or bracket with “%”
Let’s say you are on a parenthesis or bracket and you want to jump to its match, just press %
and you’re done.
Now, if you are not on a parenthesis or bracket, pressing %
will look for the next parenthesis forward on the current line, and try to jump to it’s match. This behaviour is a bit quirky for my tastes, so I try to only press %
when I’m on top of a parenthesis already.
On Vim, it’s recommended to install the “matchit package,” which enhances %
to allow jumping between HTML tags, etc. The only reason why it’s not installed by default is because of backward compatibility with vi. JetBrains supports it. VSCode doesn’t, but there’s an open issue and a plugin.
19. Moving to a specific line: “G”, “gg”, “H”, “M”, “L”
With a count, the G
command takes you to a specific line. 17G
takes you to line 17.
Without a count, G
takes you to the last line.
gg
is a shortcut for 1G
, which takes you to the first line. You can think that you just lost a match on League of Legends and you said “gg”, which means that you need to get back to work and go to the top of a file.
Another way to move to a line is using the %
command with a count. For
example 50%
moves you to halfway the file.
To navigate to the top, middle, or bottom of the visible screen, press H
(high), M
(middle) or L
(low). By default there is a scroll offset setting that prevents the cursor from reaching the very edge of the screen. I like this default, but you can change it if you want. On JetBrains you can change the scrolloff
option directly in the .ideavimrc
file, which we will discuss later on.
20. Telling where you are: the mystical power of line numbers.
Showing the line number in your editor? Are innovations like this really possible in our day and age?
They sure are, you can enable them by running the command :set number
, which sets the “number” option.
If you miss your prehistoric coding experience, just run :set nonumber
. Since “number” is a boolean option, prepending “no” to its name switches it off.
Some advanced users like to set the option :set relativenumber
, which shows the line numbers relative to the line that has the cursor. This is useful for vertical navigation with j
and k
preceded by a count: You can just type the relative number as the count. Personally, I prefer other ways to navigate vertically, as I’ll show you later.
Again, on IDEs you don’t have to worry about :set number
because line numbers are on by default. Both IDEs support :set relativenumber
.
21. Scrolling around: “CTRL-U/D”, “CTRL-E/Y”, “CTRL-B/F”
CTRL-U
moves your viewport window half a screen up, while CTRL-D
moves the viewport half a screen down. You will be using them all the time. You can remember them by thinking “Up, Down.”
If you want to move the viewport just by one line, use CTRL-E
to go forward and CTRL-Y
to go backwards.
If you want to go up and down by one full screen, you can do CTRL-B
(backwards) and CTRL-F
(forwards). But I don’t recommend these last two, they are pretty dizzying in practice.
22. Aligning the cursor with the viewport: “zz”, “zt”, “zb”
Sometimes your cursor is close to the bottom of your viewport but you want it on the center. Easy, just press zz
. Your cursor will remain on the same line but the viewport itself will scroll so that the line with the cursor is at the center of the screen.
Similarly, the zt
command puts the cursor line at the top, and zb
at the bottom.
23. Searches: “/”, “?”, “n”, “N”
Now we’re getting into the most advanced navigation technique in all of Vim.
To search for a string, use the /
command. If you want to find the word “include”, for example, type /include
, then press
To find the next occurrence of the same string use the n
command.
The ?
command works like /
but searches backwards.
The N
command repeats the last search in the opposite direction.
Search has a built-in history that works just like a shell history. If you press <Up>
on the middle of typing a search, you will land on the previous search that matches what you typed so far.
24. Searching for the word under your cursor: “*”, “#”
If you want to search for the next occurrence of the word under your cursor, press *
. To search for it backwards, do #
.
25. Searching for whole words
If you type /the
it will also match “there”. To only find words that end
in “the” use /the\>
.
The \>
item is a special marker that only matches at the end of a word. Similarly \<
only matches at the beginning of a word. Thus to search for
the word “the” only, use /\<the\>
.
Notice that the *
and #
commands use these start-of-word and end-of-word markers to only find whole words.
26. Highlighting search results and Incremental search
If you want to highlight all the matches when you are performing a search, just run :set hlsearch
.
The annoying thing here is that the highlight remains even after you are done with the search. But you get used to it. It’s no big deal.
And make sure you have the option :set incsearch
on, which will highlight the results while you are still typing the search. No one can live without this amenity.
At this point, you might be wondering why you should use the Vim search instead of your built-in IDE search. Well, Vim search can be faster because of its modal shortcuts, but the main advantage is that Vim search is a Vim motion, and motions enable advanced changes, as we’ll see in the next section.
27. Saving options on a .vimrc file
Now that you have a lot of options that you like, it might be a good idea to write them into a .vimrc
file so that they load every time you start Vim.
If you are using Vim mode on a JetBrains editor, it comes with it’s own .ideavimrc
. It creates it for you in your home directory.
If you are using Vim mode on VSCode, you need to change the settings manually, but there’s experimental support for a .vimrc
file too.
28. Using regular expressions on search
Yes, Vim search with the /
and ?
commands support regular expressions.
If you are familiar with regular expressions, you’ll find that they work pretty much as you would expect.
For instance, the ^
character matches the beginning of a line, and the $
character matches the end of a line. The .
(dot) character matches any character.
For full details, check here.
Keep in mind that, because of the regular expression support, the characters .*[]^%/\?~$
have special meanings. If you want to use them in a normal search you must “escape” them by putting a \
in front of them.
29. Using marks: `{mark}, CTRL-O, CTRL-I
When you make a jump to a position, say with the G
command, Vim remembers the position from before this jump. This position is called a mark. To go back where you came from, use the ``
command.
If you use the same command a second time you will jump back again. That is because the `
command is a jump on itself.
Generally, every time you do a command that can move the cursor further than within the same line, this is called a “jump”. j
and k
are not considered to be a jump, even when you use a count to make them move the cursor quite a long way away.
Pressing ``
repeatedly will bounce you back and forth between two single positions.
The CTRL-O
command jumps to older positions (Hint: O for older). CTRL-I
then jumps back to newer positions (Hint: for many common keyboard layouts, I is just next to O). These commands even take you across files.
The :jumps
command gives a list of positions you jumped to:
30. Named marks: m, ‘{mark}
Vim enables you to place your own marks in the text. The command ma
marks the place under the cursor as mark “a”. You can place 26 marks (a through z).
You can’t see them, it’s just a position that Vim remembers. Remember, Vim predates innovations like visual cues. In this case though, their invisibility is a practical delight, as setting invisible marks and using them with ease and grace in your complex navigations allows you to revel in your Vim skills.
If you insist on visualizing marks, there are Vim plugins like vim-signature. Later we’ll see that IDEs have some support for visualizing marks too.
To go to a mark, use the command `{mark}
, where “{mark}” is the mark letter. Thus to move to the “a” mark, type `a
.
Alternatively, the command ‘{mark}
moves you to the beginning of the line containing the mark. This differs from the `{mark}
command, which also moves you to the marked column.
The :marks
command gives you a list of marks on a file.
There are a few special marks:
‘
The cursor position before doing a jump (Equivalent to the`
mark from last section)..
The position of the last change.[
Start of the last change, and]
end of the last change. (You can use these to go to the edges after a large insert.)“
The cursor position when last exiting the current file. (A useless mark. You would use it to resume work when reopening a file, but every IDE — and even Vim — does this for you automatically, so don’t bother)Karl Marx
, German philosopher and co-author of The Communist Manifesto.
31. The EasyMotion Vim plugin
Real talk here: A lot of people are content with the built-in motions that we’ve seen so far.
I’m not one of them.
You see, there’s an alternative way to move in Vim that’s very popular, and that’s the EasyMotion plugin.
This plugin is a bit old these days, and a lot of people prefer descendant plugins like vim-sneak and leap.nvim, but they all operate on similar principles.
The basic idea is that, when you want to navigate somewhere, you type the key to activate “EasyMotion”, and then you type the characters on the screen that you want to jump into. If more then one destination is possible, you are prompted to type an automatically generated label that uniquely identifies your target.
Image from leap.nvim
It is my opinion that this is the single best way to navigate on text files using your keyboard, even if purist would like to see me six feet underground for this statement.
And I’m not the only one, as both Vim modes in JetBrains editors and VSCode support this. I heavily encourage you to enable it and never look back.
You might wonder, which key should you use to activate “EasyMotion”? It’s up to you, but the acclaimed author of leap.nvim suggests that the s
key is a reasonable choice for this kind of motion, even if you lose the “s = cl” shortcut, which we’ll see in the next section.
Section 3: Making Small Changes
32. Operators and motions: “d”
The dw
command deletes a word. You may recognize the w
command as the move word command. In fact, the d
command may be followed by any motion command, and it deletes from the current location to the place where the cursor winds up.
The 4w
command, for example, moves the cursor over four words. The d4w
command deletes four words:
There is a pattern here: operator-motion. You first type an operator command. Then you type a motion command.
You see, this is the core of the Vim grammar: Everything you learned about motions can be plugged into operators, which give you an exponential power bump for all your editing desires.
Congratulations, now you’re thinking in Vim.
33. Inclusive and Exclusive motions
For the detail oriented people out there, let’s note something: When doing dw
, Vim only deletes up to the position where the motion takes the cursor. That’s because Vim knows that you probably don’t want to delete the first character of the following word.
If you use the “e” command to move to the end of a word, Vim guesses that you do want to include that last character in the deletion.
The reference manual calls this “exclusive” when the character isn’t included and “inclusive” when it is.
Another example: The $
command moves to the end of a line. The d$
command deletes from the cursor to the end of the line. This is an inclusive motion.
34. Changing text: “c”
Another operator is c
, change. It acts just like the d
operator, except
it leaves you in Insert mode. For example, cw
changes a word. Or more
specifically, it deletes a word and then puts you in Insert mode:
Let’s break down the c2wbe<Esc>
command:
c
the change operator2w
move two words (they are deleted and Insert mode started)be
insert this text<Esc>
back to Normal mode
You will have noticed something strange: The space before “human” isn’t
deleted. The c
operator works just like the d
operator, with one exception: cw
. It actually works like ce
, change to end of word. This is an exception that dates back to the old Vi. Since many people are used to it now, the inconsistency has remained in Vim.
35. More changes: “cc”, “x”, “X”, “D”, “C”, “s”, “S”
Like dd
deletes a whole line, cc
changes a whole line.
Just like d$
deletes until the end of the line, c$
changes until the end
of the line.
Some operator-motion commands are used so often that they have been given a single-letter shortcut:
x
stands fordl
(delete character under the cursor)X
stands fordh
(delete character left of the cursor)D
stands ford$
(delete to end of the line)C
stands forc$
(change to end of the line)s
stands forcl
(change one character)S
stands forcc
(change a whole line)
36. Replacing with one character: “r”
The r
command is not an operator. It waits for you to type a character, and will replace the character under the cursor with it.
You could do the same with cl
or s
, but with r
you don’t have to press <Esc>
to get back out of insert mode.
37. Repeating a change: “.”
The .
(dot) command is one of the simplest yet powerful commands in Vim. It repeats the last change.
The .
command works for all changes you make, except for u
(undo), CTRL-R
(redo) and commands that start with a colon (:
).
38. Getting visual with Visual Mode: “v”
To delete simple items the “operator-motion” changes work quite well. But often it’s not so easy to decide which command will move over the text you want to change. Enter Visual mode.
You start Visual mode by pressing v
. You move the cursor over the text you want to work on. While you do this, the text is highlighted (using the full power of your GPU). Finally type the operator command.
For example, to delete from the middle of one word to the middle of another word:
If at any point you change your mind, press <Esc>
and you’ll leave Visual mode.
39. Visual Line Mode: “V”
If you want to work on whole lines, use “V” to start Visual Line Mode. You will see right away that the whole line is highlighted. When you move up or down, the selection is extended whole lines at a time.
40. Visual Block Mode: “CTRL-V”
If you want to work on a rectangular block of characters, use CTRL-V to start Visual Block Mode. This is not very useful, but I guess it’s useful when working on tables or on some fancy ASCII art.
Actually, this mode is quite good for inserting text on several lines simultaneously. We’ll show you how it works later.
41. Hello from the other side: “o”, “O”
If you have selected some text in Visual mode, and discover that you need to change the other end of the selection, use the o
command (Hint: o for other end). The cursor will go to the other end, and you can move the cursor to change where the selection starts. Pressing o
again brings you back to the other end.
When using blockwise selection, you have four corners. o
only takes you to one of the other corners, diagonally. Use O
to move to the other corner in the same line.
42. “Putting” it all together: “p”, “P”
When you delete something with d
, x
, or another command, the text is
saved. You can “paste” it back by using the p
command. (The Vim name for “paste” is “put”, if you go around saying “paste” you’re gonna sound like a newbie).
If you delete an entire line, the p
command puts the text line below
the cursor. If you delete part of a line (a word, for instance), the p
command puts it just after the cursor.
The P
command puts text like p
, but before the cursor.
43. “Yank” is the new “copy”: “y”, “yy”
To copy text from one place to another, you could delete it, use u
to undo
the deletion and then p
to put it somewhere else.
There is an easier way: yanking. The y
operator copies or “yanks” text into a “register”. Then a p
command can be used to put it. We’ll take a deeper look into registers later on, but you can think of them as “places to keep stuff”.
Yanking is just a Vim name for copying. The c
letter was already used for the change operator, and y
was still available. Calling this operator “yank” made it easier to remember to use the y
key.
Since y
is an operator, you use yw
to yank a word. Notice that yw
includes the white space after a word. If you don’t want this, use ye
.
The yy
command yanks a whole line, just like dd
deletes a whole line.
And remember, for the love of God, please enable the “yank highlighting” plugin, which allows you to visualize the thing that you just yanked. This is vital for getting a hang of the yank. Both VSCode and JetBrains editors support it.
44. Return to civilization — using the clipboard: “*
Operating systems have a system-wide “clipboard”, this is the thing that you copy and paste into, allowing a mind-blowing level of interoperation between different software tools.
You can “yank” and “put” into and from the clipboard. For that you can use the normal y
(yank) and p
(put) commands, but prepend “*
(double-quote star) before them.
What is this weird "*
syntax? Well, as we said, Vim has registers. The general syntax to get the content from a specific register is "a
, where a
is the register symbol. In this case, star (*
) is the symbol for the “selection register,” a special register that’s connected to the system clipboard.
45. Object-oriented programming: Text Objects
Get ready for one of the most important tools in your Vim toolset: Text Objects.
If the cursor is in the middle of a word and you want to delete that word, usually you need to move back to its start before you can do dw
.
But there is a simpler way, dawg. Just type daw
:
The d
of daw
is the delete operator. aw
is a text object. Hint: aw
stands for “A Word”. Thus daw
is “Delete A Word”. To be precise, the white
space after the word is also deleted (or the white space before the word if at
the end of the line).
Using text objects is the third way to make changes in Vim. We already had
“operator-motion” and “Visual mode”. Now we add “operator-text object”.
The magic is that it doesn’t matter where in the object the cursor
is. As long is it’s somewhere inside of it, we can select it as a text object.
To change a whole sentence use cis
. cis
consists of the c
(change) operator and the is
text object. This stands for “Inner Sentence”. There is also the as
(“A Sentence”) object. The difference — as is the case for all “A” and “Inner” objects — is that as
includes the white space after the sentence and is
doesn’t.
You can also use text objects in Visual mode. It will include the text object in the Visual selection. Visual mode continues, thus you can do this several
times.
You can find a long list of text objects here. Check it out! There’s a lot of really useful text objects, like blocks of all kinds (()
, {}
, []
, <>
) and quoted strings. For example, you can use di(
to delete everything inside a pair of parentheses, and da"
to delete everything in a double-quoted string, including the quotes.
46. Replace mode: “R”
The R
command causes Vim to enter replace mode. In this mode, each
character you type replaces the one under the cursor. This continues until
you type <Esc>
.
The R
command automatically extends the line if it runs out
of characters to replace.
47. Change case: “~”
Here’s a small useful command: Press ~
to change the case of the character under the cursor, and move the cursor to the next character.
48. The vim-surround plugin
Another popular plugin is vim-surround. It allows you to add, delete, and change surrounding characters like parentheses, brackets, quotes, and HTML tags. For example, to change surrounding double quotes to single quotes, you can do: cs”’
.
This works flawlessly on VSCode.
Unfortunately, it has some quirks on JetBrains, mainly when working with single-quotes. Also, watch for conflicts with other plugins like EasyMotion if using the key s
. I use \s
instead of s
on EasyMotion to prevent conflicts.
Section 4: Set Your Settings
49. The “vimrc” file
The vimrc file is the configuration file for Vim.
You might be wondering what’s the meaning of “rc” at the end of so many configuration files. Well, it’s an ancient Unix convention with an even older origin: The “RUNCOM” program, a predecessor of the “shell” created in 1963 for an operating system you never heard of, CTSS.
In any case, vimrc is the place to put all your favorite options and mappings. The vimrc file can contain any of the commands that you type on Command-line mode. Vim will automatically execute the vimrc commands when it starts.
” This is an example vimrc file.
” You can write comments by starting a line with double quotes (”)
” Here’s a command.
” Unlike Command-line mode, you don’t neet to type a colon (:) before.
set number
In Unix systems, this file is usually in your home directory: ~/.vimrc
. NeoVim is polite enough to follow recent conventions and avoid polluting your home directory: It puts the vimrc file in ~/.config/nvim/init.vim
.
As mentioned, VSCode has experimental vimrc support, but it only supports mappings. For options, you can just type them as commands and VSCode will preserve them for the next time you open the editor. Also, most of the options that you might want to configure for its Vim mode are already available as regular settings on the Vim extension.
In JetBrains editors, there is a very capable .ideavimrc
file in which you can add both options and mappings. This file is placed in your home directory, but you can edit it quickly with a button on the status bar. Also, .ideavimrc
comes pre-loaded with some options taken directly from Vim’s official [defaults.vim](https://vimhelp.org/usr_05.txt.html#defaults.vim-explained)
, a file with nice improvements for people who don’t care about backward compatibility with vi.
50. The “undofile” option: Persistent Undo
An underrated feature of Vim, which is off by default, is the undofile
option. This will store the undo information in a file. The result is that when you change a file, exit Vim, and edit the file again, you can undo the changes made previously.
When undofile
is on, the undo information is normally saved on a file in the same directory, which I find quite annoying. This can be changed with the undodir
option. You can find more information about undo persistence here.
Neither VSCode nor JetBrains editors support this feature, although there’s an open issue for VSCode. But to be fair, I think this IDE-like behavior is better served by an IDE feature that preserves the local history of your files: On JetBrains this is called “Local History”, and on VSCode it’s called “Timeline View”.
51. Getting rid of other annoying Vim files on your directory
Besides the undo files, using old-school Vim will also generate backup files (if enabled) and swap files to recover from crashes. You can configure Vim to use a different directory for these files to remove them from your directory.
Or just ignore them on your .gitignore
file to live in blissful ignorance:
Ignore vim files:
*~
*.swp
*.swo
But if you don’t use the original Vim at all, you don’t need to worry about this.
52. Sourcing with “source”
One of the commands that you can run in your vimrc file is “source”. This command “sources”, which is a fancy Linux way to say that it will execute the commands in another file. This is useful for splitting your vimrc file into multiple files, or for loading a file with mappings from another vimrc file.
JetBrains supports this. If you want to reuse you configuration between Vim and Vim mode, you can put the following on your .ideavimrc
file:
” Source your .vimrc
source ~/.vimrc
53. Vim command completion
Advanced Vim users are expected to type a lot of commands on Command-line mode. To help with that, Vim provides completion when pressing the <Tab>
key.
What’s more, as of Vim 9.0, there’s a new option, wildoptions=pum
, which shows the completions on a fancy popup menu right there on your terminal. This was only added recently because “this requires redrawing more of the display, but since computers are fast enough that is not a problem.” Lmao.
Unfortunately, command completion is very rudimentary on VSCode and it’s unlikely to change soon. On JetBrains there is no completion but there’s an open issue.
54. Simple mappings
A mapping enables you to bind a set of Vim commands to a single key. In short, if you can think of an operation as a series of Vim commands, nothing stops you from binding it to a single key.
This is the magic of extensible tools for power users: As long as you can think in the tool’s language, you can extend it. No one man should have all that power, but here we are.
Suppose, for example, that you need to surround certain words with curly braces. With the :map
command, you can tell Vim to do this when pressing F5:
:map
After you execute the :map
command, all you have to do to put {}
around a word is to put the cursor on the first character and press F5.
In this example, the trigger is a single key, but it can be any string. Keep in mind that when you use an existing Vim command, that command will no longer be available. One key that can be used without conflicts is the backslash (\
). You can follow it with other characters:
:map \p i(
:map \c i{
The :map
command (with no arguments) lists your current mappings for normal mode. The command with no arguments is supported by JetBrains but not yet by VSCode.
We’ll take a closer look into mappings later on.
55. Plugins and Packages
Vim’s functionality can be extended by adding plugins. A plugin is nothing more than a Vim script file loaded automatically when Vim starts.
There are some shenanigans to remember when using plugins, like the runtimepath
option, help files, and so on. To improve some of these issues, Vim 8 (released in 2016) introduced the concept of “package,” which is basically a collection of plugins that automate some of these pain points. One example of a package is the aforementioned “matchit” package.
Instead of dealing with plugins and packages directly, many Vim and Neovim users prefer to use package managers like vim-plug and lazy.nvim.
The plugin ecosystems and communities of both Vim and NeoVim are strong and active.
For Vim mode, the situation is much simpler as fewer plugins are available. In JetBrains, you can simply check the list of available plugins and follow the instructions for each one. Same for VSCode.
56. More about options
If you want to know all about Vim options, you have two options (no pun intended):
- You can check the full alphabetical list of options in the documentation. Lord have mercy.
- Or you can type
:options
on Vim, which opens a friendly UI to navigate all options grouped by sections.
In any case, expect only some options to be useful to you, and many won’t work on Vim mode.
57. Fix your wrapping with “whichwrap”
One of the options that you should change from the default is [whichwrap](https://vimhelp.org/options.txt.html#%27whichwrap%27)
.
You see, on every text editing software, pressing the left key at the beginning of a line will take you to the end of the previous line, and pressing right at the end of a line will take you to the beginning of the next line. Don’t believe me? Open notepad and try it. It’s very convenient.
But Vim is not like that. The cursor just stays there. To fix it, do this:
set whichwrap=b,s,<,>,h,l,[,]
This is supported on VSCode and JetBrains.
58. Restore options and get its current value
In case you have messed up an option value, you can set it back to the
default by putting an ampersand (&
) after the option name. Example:
:set iskeyword&
This works on JetBrains but not on VSCode.
To check what’s the current value of an option, append a question mark: :set isKeyword?
. This works on both VSCode and JetBrains.
Interlude: Syntax highlighting
An entire section of the Vim user manual is dedicated to syntax highlighting. As an IDE user, this is one of the Vim topics you can completely ignore. Your IDE should already have syntax highlighting and many custom themes.
Even modern Vim already has syntax highlighting on by default, so there’s no need to change anything.
Here’s a funny quote from the user manual: “Displaying text in color takes a lot of effort. If you find the displaying too slow, you might want to disable syntax highlighting for a moment.” Lol, I’m so glad to live in the future.
Yet, there are some nice developments in the field of efficient syntax highlighting: cutting-edge Vim users use tree-sitter, which provides state-of-the-art syntax highlighting. And it’s made in Rust, which makes it cool.
You might be interested to know that many people create and share different color schemes for Vim and NeoVim. Some of these are so beautiful that they make you forget you’re using a terminal:
Another funny tidbit from this section of the docs is :TOhhtml
, a weirdly capitalized command that turns whatever file you open into an HTML file with syntax highlighting. You could use it to share code with others, but I have no idea what’s a reasonable use case for it.
Section 5: Editing more than one file
59. Vim file commands that you can’t use in Vim mode
Vim has a lot of commands for working with multiple files and switching between them: :edit
, :hide
, :next
, :previous
, :args
, :first
, :last
and :saveas
.
No Vim mode fully supports these commands. And frankly, they don’t make much sense on IDEs anyway. At least, they won’t be practical until the IDEs implement related features like filename tab completion.
Naturally, your IDE already supports working with multiple files, usually through more sensible shortcuts and GUIs.
60. Jumping from file to file: CTRL-^
To quickly jump between two files, press CTRL-^
(or CTRL-6
). It’s a quick way to toggle between the current file and the last edited file.
It’s supported on JetBrains but not on VSCode.
61. File marks (aka Global marks)
Previously we saw that you can place your own named marks (a
through z
). That works within one file. Each file has its own set of marks, they are local to the file.
There are also marks with an uppercase letter. These are global, and they can be jumped to from any file.
It’s often useful to think of a simple connection between the mark letter and where it is placed. As a boomer example, you can use the H
mark in a header file, M
in a Makefile, and C
in a C code file.
Both editors support lowercase and uppercase marks:
- VSCode shows the marks on the gutter by enabling the “Show Marks in Gutter” setting.
- JetBrains shows the global marks on the gutter as they are integrated with the IDE’s “Mnemonic Bookmarks” feature, which is basically the same feature. There’s an issue to also show the lowercase marks on the gutter.
62. Using registers
When you want to copy several pieces of text from one file to another, it might save time to copy each piece of text to its own register.
Here we will use the registers named a
to z
(but just like Skywalker, soon you’ll find out there are others). To copy a sentence to the y
register, type “fyas
. The yas
command yanks a sentence like before (yas queen!). It’s the “f
that tells Vim to place the text in the f
register.
You can then paste from a specific register with “fp
. The text stays in the register until you yank something else into it, so you can put it in as many times as you desire.
As a reminder, the star (*
) register is a special register that allows to yank and put to the system clipboard (by doing "*
).
As another reminder, deleting and changing text also saves it to a register. For example, you can type "fdaw
to delete a word and save it to the f
register.
The :registers
command shows you the text on every register. This works on both VSCode and JetBrains.
Section 6: Splitting windows
63. Split your editor
Screens are big these days, so it makes sense to split them to see multiple files at the same time, or different parts of the same file at the same time.
Most editors can be split into different rectangular regions. On Vim, these regions are called “windows,” a term that should not be confused with the concept of overlapping windows on modern GUIs like operating systems.
To open a new window, you can use the :split
command (or CTRL-W s
), which splits the screen horizontally into two windows showing the same file. To split them vertically, use :vsplit
or CTRL-W v
.
CTRL-W w
can be used to jump between all the open windows. It wraps around once it reaches the last window.
You’ll notice that all the window commands on Vim have the form CTRL-W {char}
, in which you must press CTRL-W
first and then another character. (CTRL-W CTRL-{char}
does the same thing, in case you let go of the CTRL key a bit later.)
To close a window, use the :close
command (or CTRL-W c
).
The :only
command (or CTRL-W o
) closes all windows except the current one.
64. Changing window size
While there are commands to change a window size (CTRL-W +
and CTRL-W -
), they are extremely clumsy.
Fortunately, and to the surprise of everyone, the Vim documentation actually recommends using the mouse (!!) to resize windows. Yes, Vim has mouse support. Naturally, if Vim does it, you should feel no shame at all when resizing splits with the mouse on your IDE.
For any tmux user out there: Mouse resizing also works on tmux, but you need to enable it.
65. Moving between windows
Simply use CTRL-W
followed by any of the navigation keys (h
, j
, k
, l
).
If what you want to do is move the windows themselves because they are out of order, do CTRL-W
followed by the uppercase version of the navigation keys (H
, J
, K
, L
). Unfortunately, this is not supported in VSCode or JetBrains.
66. Vim diff
Vim has some diff functionality to see the difference between two files or between a modified file and its original version.
Neither Vim mode supports this. But let’s be honest: if you are using an IDE, you probably want to use its built-in diff. It’s one of those things that looks way better with a GUI.
Still, it’s worth remembering the CLI command vimdiff
(or nvim -d
for NeoVim) if you want to quickly see the diff between two files in your terminal. It’s better than the colorless diff
command.
67. Vim tabs
It must be observed that every single modern GUI editor known to humanity — including but not limited to Sublime Text, Atom, VSCode, and JetBrains editors — let you split the editor and then have tabs inside each split.
But Vim does the opposite — It has tabs that contain splits (aka windows):
This is just a design difference. There’s no one correct way to design the layout of an editor. Both have advantages and disadvantages.
In fact, Vim only visually doesn’t have tabs in each window — Vim users can still switch what file each window is displaying, and they usually don’t care about amenities like having a tab bar in each split.
You actually have more freedom in Vim because a file doesn’t belong to some window; they’re entirely independent. Any window can display any file.
The Vim tab system is not really a different or opposite way of doing it. It’s an additive feature on top of the usual windows: You can think of Vim tabs as different layouts (arrangements of windows) for different contexts. In fact a similar feature is called “Layouts” on JetBrains.
This diagram shows how Vim users think about their editing environment. It shows the distinction between layout elements (tabs and windows) and files (aka buffers):
Naturally, Vim mode plugins don’t support Vim-style tabs as they just don’t exist in IDEs. Still, the following Vim commands for tabs have been repurposed by both VSCode and JetBrains to work on the IDE-style tabs:
gt
Goes to the next tab. If preceded by a number, it goes to the tab with that number. (The first tab is 1, not 0.)gT
Goes to the previous tab.
If you want to close a tab, use any of the Vim commands that close files, because IDE tabs are basically just files.
Section 7: Using the GUI
68. Vim has an official GUI edition: gVim
Unknown to most (although some Vim users swear by it), Vim has a GUI edition called gVim. It’s the same experience, but with some improvements to bring Vim into the ’90s, like menus, scrollbars, and (gasp!) a toolbar.
As an IDE user, you are even deeper into the GUI life, so this information won’t affect you except for the satisfaction of knowing that even an old-school editor like Vim is flirting with the powers of graphics and non-monospaced fonts.
69. The forbidden mode: Select mode
Even more unknown is Vim’s elusive “select mode.” Most people who find themselves there do so by accident.
Select mode is like Visual mode, because it is also used to select text. But there is an obvious difference: When typing text, the selected text is deleted and the typed text replaces it.
You need to enable it to use it, but it’s enable by default on Windows when trying to select with the mouse.
In short, “select mode” is a haphazard mode added just to placate some Windows users who can’t handle an editor that does its own thing when selecting text with a mouse.
Section 8: Making big changes
70. Record and playback commands: Vim macros
Of all the Vim features we’ve seen, I guarantee that none will bring you more satisfaction than macros.
You already know that the .
(dot) command repeats the preceding change. But what if you want to repeat anything at all, like a sequence of multiple changes and movements?
That’s where macros, or “command recording,” come in. There are three steps:
- The
q{register}
command starts recording keystrokes into the register
named{register}
. The register name must be betweena
andz
. - Type your commands.
- To finish recording, press
q
(without any extra character).
You can now execute the macro by typing the command @{register}
.
Let’s look at an example. You have a list of filenames that look like this:
stdio.h
fcntl.h
unistd.h
stdlib.h
But you want them to look like this:
Easy, just type these commands:
qa
— Start recording a macro in registera
.^
— Move to the beginning of the line.i#include “<Esc>
— Insert the string#include “
at the beginning of the line.$
— Move to the end of the line.a”<Esc>
— Append the double quotation mark (“
) to the end of the line.j
— Go to the next line.q
— Stop recording the macro.
Now that you have a macro in your a
register, it’s time to run it by typing the command [@](http://twitter.com/a)a
three times. The @a
command can be preceded by a count, so in this case you can type 3@a
.
If you have done @a
once, you can run that macro again with @@
. That’s a bit easier to type. If you now execute register b with @b
, the next @@
will use register b
.
By the way, macros are recursive: You can put macros inside of macros (even if it’s the same macro).
71. Macros and registers
You might have noticed that registers are used both for macros and for yank and delete commands. This has some advantages.
Suppose you have recorded a few commands in register n
. Then, when you run @n
, you notice you did something wrong. You could try recording again, but perhaps you will make another mistake. Instead, use this trick:
G
— Go to the end of the file.o<Esc>
— Create an empty line.“np
— Put the text from then
register. You now see the commands you typed as text in the file.{edits}
— Change the commands that were wrong. This is just like editing text.0
— Go to the start of the line.“ny$
— Yank the corrected commands into the n register.dd
— Delete the scratch line.
Now you can execute the corrected commands with @n
.
This trick is a great example of the Unix and Vim philosophies: If you know how to modify text, and if everything is made out of text, then you can do anything.
72. Appending to a register
So far we have used a lowercase letter for the register name. To append to a register, you can use an uppercase letter.
Suppose you have recorded a macro in register c
. It works properly, but you would like to add a search for a word. This can be done with qC
, which appends to the c
register: qC/word<Enter>q
.
This works with macros, yank and delete commands. For example, “AY
will yank a line and append it to the a
register.
73. Saving macros: :let command
There are two ways of saving a macro for later use.
The simplest way occurs by default. Vim will automatically preserve your registers and restore them at startup. (Not supported by VSCode)
The second way (especially if you think you might overwrite it by accident) is to use a [:let](https://vimhelp.org/eval.txt.html#%3Alet-register)
command in your .vimrc
. For example: let @a=’0fa’
.
Remember that if your macro includes a carriage return or some other special character, you will need to write it explicitly n the :let
command, like <ENTER>
. But check the documentation for your editor and operating system because special characters are tricky.
The :let
command is supported by JetBrains but not by VSCode.
74. The “:substitute” command
The :substitute
command enables you to perform string replacements on a whole range of lines. The general form of this command is as follows:
:[range]substitute/from/to/[flags]
This command changes the from
string to the to
string in the lines specified in [range]
section.
The :substitute
command is almost never spelled out completely. Most of the time, people use the abbreviated version :s
.
If you put a %
as the [range]
section, the command will work on all lines. Without a range, :s
only works on the current line.
By default, the :substitute
command changes only the first occurrence on each line. To change every occurrence on a line, you need to add the g
(global) flag: :%s/from/to/g
And sure, you can record :substitute
(or any command-line command) in your macros.
75. Substitute with confirmation
The c
(confirm) flag tells :substitute
to ask you for confirmation before it performs each substitution. You will get the following prompt: replace with to (y/n/a/q)?
The confirm flag works on both VSCode and JetBrains.
76. Customizing the Substitute pattern
The from
part of the substitute command is actually a pattern. The same kind as used for the search command. So you can use regular expressions there.
If you are substituting with a from
or to
part that includes a slash, you need to put a backslash before it. A simpler way is to use another character instead of the slash. A “plus”, for example: :s+one/two+one or two+
Most characters (except alphanumerical ones) can be used as delimiters.
77. What are Ex commands?
By the way, you may have heard of the term “Ex commands” before. Both Ex commands and command-line commands are the same. They are the commands that start with a colon (:
). The :substitute
command is an example of an Ex command.
They are called Ex commands because they originally came from the Ex text editor — a descendant of the legendary ed editor — made by the same author of Vi.
Ex was a “line editor” for teleprinters. It predated screen-based editors. Still, that mode of editing prompted the creation of very useful commands which were later ported into Vi and Vim. Because of Vim’s ascendency, a lot of the Ex commands are also used in the Unix tool “sed”, so you are learning both Vim and sed!
We’ll see more Ex commands later on. But I’ll continue to refer to them as command-line commands in this article.
78. Command ranges
Let’s see what else we can do with the “range” section of a command.
The simple form of a range is {number},{number}
. For example, :1,5s/this/that/g
executes the substitute command on the lines 1 to 5 (line 5 included).
A number can be used to address one specific line.
Some commands (not :substitute
) work on the whole file when you do not specify a range. To make them work just on the current line, you can use the .
(dot) address.
The $
character refers to the last line. For example, to substitute in the lines from the cursor to the end, do :.,$s/yes/no/
.
The %
range that we used before, is actually a short way to say 1,$
.
79. Using patterns in command ranges
It’s time to look at an advanced example.
Suppose you are editing a chapter in a book, and want to replace all occurrences of “grey” with “gray”. But only in this chapter, not in the next one. You know that only chapter boundaries have the word “Chapter” in the first column. This command will work then:
:?^Chapter?,/^Chapter/s=grey=gray=g
You can see a search pattern is used twice. The first ?^Chapter?
finds the line above the current position that matches this pattern. Similarly, /^Chapter/
is used to search forward for the start of the next chapter. Note that the matching ?
and /
at the end of the search patterns are only used to separate the patterns from everything that follows.
To avoid confusion with the slashes, the =
character was used in the substitute command here. A slash or another character would have worked as well.
80. Add and subtract in command ranges
You can add an offset of lines to any item on a range.
Here, for example, we search for a pattern and then use the line above it: /Chapter/-1
And here we specify the range that starts three lines below the cursor and ends five lines before the last line in the file: .+3,$-5
81. Other range tricks: Marks, visual mode, and number of lines shortcut
Instead of figuring out the line numbers of certain positions, remembering them and typing them in a range, you can use marks: :’t,’b
You can select text with Visual mode. If you then press :
to start a colon command, you will see this: :’<,’>
The ‘<
and ‘>
are actually marks, placed at the start and end of the Visual selection. you can mix the marks with other items if you want: :’>,$
One cool trick: When you know how many lines you want to change, you can type the number and then :
. For example, when you type 5:
, you will get: :.,.+4
. Thus, it spans five lines.
82. The global command
The :global
command is one of the more powerful features of Vim. It allows you to find a match for a pattern and execute a command there. The general form is:
:[range]global/{pattern}/{command}
This is similar to the :substitute
command. But, instead of replacing the matched text with other text, the command {command}
is executed.
You can use any command that starts with a colon. A special one is the :normal
command, which allows you to use normal mode commands. Inception!
Suppose you want to change “foobar” to “barfoo”, but only in C++ style comments. These comments start with //
. Use this command:
:g+//+s/foobar/barfoo/g
Since the pattern we are looking for contains a slash, this uses the plus character to separate the pattern. Next comes the substitute command that changes “foobar” into “barfoo”. The default range for the global command is the whole file. Thus no range was specified in this example.
The global and normal commands are supported by JetBrains but not by VSCode.
83. Advanced Visual Block tricks: I, A, $, c, C, r, u, U, ~ J
Let’s go back for a moment to Visual Block mode and see what are some advanced tricks that you can do when a block of text is selected.
The command I{string}<Esc>
inserts the text {string} in each line, just
left of the visual block. As you type, the text appears on the first line only. After you press <Esc>
to end the insert, the text will magically be inserted in the rest of the lines contained in the visual selection.
The A
command works the same way, except that it appends after the right side of the block.
If you have a block selected, you can use $
to make the block extend to the end of each line.
The Visual block c
command deletes the block and then throws you into Insert mode. C
is the same but additionally deletes everything from the block to the end of the line.
To fill the entire selection with one character, use r
. To make all characters uppercase, use U
. For lowercase use u
. To swap case do ~
. To join all the lines in the use J
. Note that these commands work also on visual and visual line modes.
84. Shifting (aka Indentation)
To shift lines to the right or to the left, you have a few options.
In normal mode, press <<
or >>
. This only shift the current line.
In any visual mode, press <
or >
to shift all the lines in the selection.
The downside of the method above is that the selection is lost after shifting. A modern innovation on graphical editors is that the selection is preserved after every indentation, giving you the chance to play around until you find the spacing that you like.
Here’s a common addition to .vimrc
, which adds this conventional behavior:
"" visual shifting (builtin-repeat)
vnoremap <
gv
is a command that re-selects the last visual selection.
85. The :read and :write commands
The :read filename
command can be used to paste the content of an external file on the line under the cursor.
It can also be used to paste the output of an external program by running it like :read !ls
.
The :write
command is usually what you run to save the current file. Additionally, you can run :.,$write tempo.txt
to write a range of lines (which could be, for example, the current selection as we saw before) into an external file.
You can also do :write !wc
to send a range of the current file as the input for an external command.
Unfortunately, these features aren’t available on VSCode or JetBrains at the time of writing. VSCode does support :write
to an external file, but without ranges.
86. Formatting text with wordwidth and gq
When typing plain text — even in our age of fluid viewports — it’s nice if the length of each line is automatically trimmed.
You wouldn’t want this for code, as formatters like Prettier usually handle it in a standard way. But it’s very useful to make you paragraphs inside comment blocks more readable.
To make this happen while inserting text, set the textwidth
option: :set textwidth=72
.
As with any option, you can check the current value with :set textwidth
.
Now lines will be broken to take only up to 72 characters.
But when you insert text halfway through a line, or when you delete a few words, the lines will get too long or too short. Vim doesn’t automatically reformat the text. To tell Vim to format the current paragraph, do gqap
.
This starts with the gq
command, which is an operator. Following is ap
,
the text object that stands for “a paragraph”. A paragraph is separated from
the next paragraph by an empty line.
These commands work on VSCode, although there’s a bug that prevents running :set textwidth
directly — you need to change it on your extension settings.
Also, it’s worth noticing that having a textwidth on VSCode doesn’t change the insert behavior — It only affect the qg
command. I think this is a reasonable approach, as automatic indentation might be better handled by the IDE itself.
Unfortunately, these commands don’t work on JetBrains editors yet.
87. Advanced Changing Case tricks
You already know about ~
, but there are a few more tricks.
You have text with section headers in lowercase. You want to make the word “section” all uppercase. Do this with the gU
operator. Start with the cursor in the first column:
The gu
operator does exactly the opposite.
You can also use g~
to swap case. All these are operators, thus they work with any motion command, with text objects and in Visual mode.
To make an operator work on lines you double it. The delete operator is
d
, thus to delete a line you use dd
. Similarly, gugu
makes a whole line lowercase. This can be shortened to guu
. gUgU
is shortened to gUU
and g~g~
to g~~
.
Closing thoughts
These tips should get your Vim senses tingling. After enough practice, you’ll find that the techniques covered here are enough to bring your editing powers to the next level of productivity and comfort.
Stay tuned for part two, in which we’ll move to more advance Vim territories, without needing to abandon the convenience and safety of your IDE.