LV4AD/Ch/06 Basic Editing
Chapter 6: Basic Editing - LazyVim for Ambitious Developers
6.1. The Vim Command Mental Model Modal/Editing
The navigation commands such as
sandfandhjklandwebthat you already know are collectively known as motion commands. They move the cursor from its current location to a new location.Verbs come first, so the structure is always
<verb><count><motion>. Navigation is the “default” verb, so if you leave the verb blank (i.e. skip it), your cursor moves to the location indicated by the motion. We’ll discuss various important verbs in this chapter.
But the model keeps growing! It turns out, verbs can also be counted. The syntax becomes<count><verb><count><motion>. I have never in my life used all four of those in one command, however. Typically you would either do<count><verb><motion>or<verb><count><motion>.6.1.1. A Note on Insert Mode
Like all models, this one is not perfect. For example, you can use counts with the
i,I,a, andAcommands, but it’s clear that “enter Insert mode” is neither a motion nor a verb.
For example, if you type5ifoo<Escape>, nvim will insertfoofoofoofoofoofor you. That may not seem very useful, but if you ever want an 80 character*ruler to underline a heading,80i*<Escape>is pretty nifty!But the
<count>i“not-motion” commands cannot be combined with verbs like the navigation commands you’ve learned. So it’s important to know the limits of the model. In fact, as we’ll see later, vim uses this effect to its advantage, borrowing thea,i, andokeys to create object motions when combined with a verb.So now that you understand how the motions you already know can combine with verbs to perform actions other than navigation, you just need to learn some verbs.
- My Note In the Vim mental model, verbs are the actions you perform on the text between your current cursor position and where a motion would take you. You are currently at 20.27% of the document, which is exactly where the text begins to explain these verbs that can be combined with navigation motions.
- Here are the primary examples of verbs mentioned in this chapter:
- Delete (d): This verb deletes text from your cursor to the motion destination. For example, d3w deletes three words. You can also use dd as shorthand to delete an entire line.
- Change (c): This functions exactly like delete, but it automatically enters Insert mode once the text is gone, saving you a keystroke when you need to replace code.
- Delete Single Character (x): A shorthand verb that deletes the character under the cursor without requiring a separate motion command.
- Replace Character (r): This allows you to replace a single character by typing r followed by the new character; it briefly enters Insert mode for you and then snaps back to Normal mode.
- Join Lines (J): A verb used to delete the newline at the end of the current line, effectively merging it with the line below.
- Case Conversion (gU and gu): These are used to convert text to uppercase or lowercase based on the motion that follows.
- The power of this model is that if you leave the verb blank, Neovim assumes you just want to move the cursor, which is why your standard navigation keys work the way they do.
- My Note In the Vim mental model, verbs are the actions you perform on the text between your current cursor position and where a motion would take you. You are currently at 20.27% of the document, which is exactly where the text begins to explain these verbs that can be combined with navigation motions.
6.2. Deleting Text
I’ve previewed this a couple times already, and even if I hadn’t, you can probably guess that the verb for deleting text is
d.
So where<motion>will take you to a specific location in the code,d<motion>will delete all the text between the cursor and that location. Here are some examples:
•dhto delete the character to the left of the cursor.
•d3wto delete three words.
•3dwto delete one word, three separate times.
•d^to delete from the cursor to the beginning of the line.
•d2feto delete all text between the cursor location and the secondeafter the cursor, including that seconde.
•d2Tato delete all text between the cursor and the secondabehind the cursor, not including that seconda.
•dsfoosto delete text between the current cursor position and the labelsthat pops up when you use nvim/Plugin/flash.nvim Seek mode to seek tofoo. Note that Seek mode always jumps to the beginning of the word you searched for. This means that if thefooyou jump to is after the current cursor location, theoowill not be deleted, but thefwill. But if thefooyou jump to is before the current cursor location, all three letters offoowill be deleted.
6.3. Changing Text
This could easily be handled by combining the delete verb with Insert mode (e.g.
dwiwill delete a word and enter Insert mode.) However, you can save a keystroke by using thecverb, which means “change”. If you replace thedin each of the examples I outlined above with ac, you will effectively get “delete the text and immediately enter Insert mode.”
6.4. Operating to End of the Current Line
Yes you could
d$andc$to delete or change to the end of the line, since$is the “jump to end of line” motion. That is the “correct” format for the mental model. However, because this is such a common operation, you can “cheat” with one fewer keystrokes and just use the capitalizedDorCinstead.
There is no inverse shortcut verb for “delete to the beginning of the line”, so you’ll have to used^ord0instead, where^is the motion to jump to the first non-blank character and0is the motion to jump to the first column regardless of whether it is blank.
6.5. Operating on Entire Lines
In practice, this just means that
dddeletes an entire line andccdeletes it and enters Insert mode. These are nice and easy to type, so it makes for a nice shorthand.You can combine these bespoke motions with counts.
d3dwill delete three lines, and3ddwill delete one line three times (which is faster to type because you don’t have to move your finger off ofdto hit it twice). Yes, that has the same outcome either way, but the model is such that you can use either of them. Note that there are situations where the two formats may have subtly different behaviours, although in practice I have never encountered surprises.
6.6. Some Shortcuts for Modifying Individual Characters
The
xcommand can be used with a count, so if you want to delete five characters starting with the one under the cursor, just use5x.If you need to go the other direction and delete characters before the cursor, use a capital
X. This, too, can have a count, and it will basically delete that many characters to the left. I rarely use this, since the shift brings us up to two keystrokes anyway, andhxord4his no harder.One shortcut I do use frequently can delete the newline at the end of the current line. Use the
J(“Join Lines”) command from anywhere in the line. I use this one a lot. If you need to merge multiple consecutive lines together,Jtakes a count. It generally does the right thing around whitespace (replacing indentation with a single space), but if you need to do a join without modifying whitespace, use the two-character verbgJ.
6.7. Manipulating Case
If you need to convert a character or sequence of characters to uppercase, use the verb
gU(that’s a shiftedUfor the second character) followed by any standard navigation motion. I find this particular verb frustrating becausegis normally assigned to theGo Tomotions. In this case, (as withgJabove) it is a verb instead.
I guess you can think of it as “Go To and Convert to Uppercase” whereUis short forUppercase.
The inverse function to convert all text between the current cursor position and the motion destination is to use a lowercasegubefore the motion. Kind of weird to remember, but it does match the common vim idiom ofgumeans an action andgUmeans the same action BUT BIGGER.I don’t find these commands very useful. I more frequently use the
~command, which inverts the case of the character under the cursor.The duplicate commands
gUUandguudo the same thing as other duplicate verbs, applying the upper/lower case operation to the entire line.
6.8. Repeating Commands
LazyVim doesn’t have a multiple cursor mode. There are plugins to support multiple cursors, but in my experience they don’t work very well. The nvim developers have multiple cursors on their roadmap, so I am hoping they will come up with a paradigm that integrates nicely with the vim mental model.
Once you have performed any verb, you can navigate to another place in the document and repeat that verb with a single keypress:
.(That’s a period, although you will usually hear it referred to as “dot repeat” in this context).This highlights why
dandcneed to be separate verbs, as opposed to using something liked<motion>i. When you usec, the delete motion and the text you inserted is remembered, so you can repeat the entire change with a.command. For example, if you want to replace all instances of a variable namediwith a much better name ofindex, you could jump to the first instance ofiand typeclindex<Escape>to “change one character to index”. Then you can use navigation commands to go to the next use ofi. Now just type.to repeat the change. Then continue to the next instance.Like motions and verbs, the
.command can be given a count. However, counts with.are a little bit nuanced. Rather than blindly repeating the command<count>number of times, it will instead replace the count of the command being repeated.
This means that if you use the verb3ddto delete three lines, and the next operation you perform is2.(“2 dot”), the second operation will delete two lines, rather than six.
6.9. Recording Commands
To start a recording, press
qq. Sorry, but I have no mnemonic to rememberq. I have a feeling it was just the last available key on the keyboard!
After that, type whatever sequence of navigation, editing, and insertion commands you want to record. Delete words, insert text, change text, search for words (don’t use nvim/Plugin/flash.nvim Seek mode, as the replay mechanism will have no idea what label to jump to). Virtually anything you can do in vim (even:commands) can be recorded and replayed later.
When you are finished recording, just pressqagain. The recording will be stored ready for replay whenever you desire.6.9.1. Appending to a Recording
If you partially complete your recording and then realize you need some more information or need to make an edit before completing the recording, you can pause the recording using
qas usual and do the thing you need to do.
When you are ready to continue recording, useqQto record in append mode instead. The main tip here is that you need to make sure your cursor is in a location such that the merged recording will make sense. This usually means the same place it was when you stopped recording, although it may depend on what changes you made in the meantime.
6.10. Undo and Redo
Obviously, these are the most important operations in the whole book! Use the
ukey to undo your most recent change. Note that “most recent change” can be a pretty big whack of text, especially if you haven’t exited Insert mode for a while. For example, I wrote this entire paragraph in one Insert session. If I pressuthe entire paragraph will be lost.That’s ok, though, because I can redo using Key/Control-r. Like most developers, I use both of these extensively. (Did you know that in the old days of typewriters, secretaries had to get 100% accuracy scores on their typing tests? There was no backspace or delete key, you see).
It’s kind of the same concept as git branches, except your history is automatically tracked for every keystroke you make. Working with branches of undo history using raw nvim commands can feel pretty clumsy, though (read through
:help undo-branchesif you’re brave). Instead I recommend configuring and installing the nvim/Plugin/undotree plugin.