The Path to Better Vi Skills

605px-Vimlogo.svg

Among software developers there is no single subject that will generate more opinions, controversy or discussion than that of “Favorite Code Editor”. It seems we all have a definitive preference and will agrue vehemently in favor of that choice.

At the same time, there is no *nix system to which you can connect today that does not include a version of Vi. It is the single most ubiquitous editor on the planet!

Each of us has, in varying degrees, some mastery of Vi. The command set seems to be larger than any other single application. Most of the commands are very arcane, peculiar and – as a result – difficult to remember.
The various cheatsheets available on the Internet are handy as a reference, but seriously lacking as a directed tutorial guide.

In a deliberate effort to increase my Code Editing Kata, I spent several weeks explicitly using Vi on a regular basis.

As you may guess from my other articles, I am a big fan of Nitrous.IO and having a linux box available to me from any computer and any location was a great aid in this pursuit.

I happily invite you along, offering an abbreviated (‘accelerated’ may be a more accurate description) replay of my adventure.

And I want to INTRODUCE TO THE WORLD my own set of mnemonics that lessen the steep learning curve associated (real or perceived) with Vi.

A bit of history

Vi (for ‘Visual’) traces its ancetry all the way back to the origin of Unix (in AT&T). As a ‘screen’ oriented version of the editor(s) used with teletype machines, it represented a step into modern computing. The name ‘vi’ is derived from the commmand that switches the line editor, ‘ex’ (Bill Joy’s editor, released as part of the first BSD Unix release in March of 1978), to visual mode.

Bram Moolenaar released VIM publicly around 1991, although he had begun writing it for his Amiga in the late 1980s. It was originally called VI iMitation and, later, VI iMproved.

For the sake of commonality, the following set of tutorial steps will assume you have very, very little experience with Vi. I would venture to say, though, regardless of your experience there is always something new to learn in this feature-rich software application.

Additionally, everything here is based on my personal experience. The terminology and descriptions are my own and I take full responsibility for them.

Modes of Operation

I have observed several clearly distinct operational ‘modes’ when working with Vi.

  • Command Mode
  • Edit Mode
  • Window Mode

Switching between these modes usually requires pressing ESC.

An alternative to ESC is Ctrl [.
I find this much easier and quicker although I am having difficulty changing a long-standing habit of reaching for the ESCape key.

Command Mode

This is where you can issue commands to the editor to do things that I consider other than editing.

When in Command Mode the colon (:) is used to accept input for commands that are not editing nor navigation related.

Close

When I was an avid flyer of R/C planes we had a very popular 'meme' in my local club: "Take-offs are optional, landings are mandatory"

I would paraphrase that with respect to Vi and say that although OPENING the editor is optional, CLOSING it is mandatory.

As is 'true to form' for Vi, there are numerous ways to close and exit the editor.

zz is the quickest way to Save and Exit. I think of this as putting Vi to sleep (akin to the cartoon representation of sleep as a row of Zs)

:wq is the most common. This represents several discrete commands that are concatenated (which is a useful feature of the command mode):

  • w is to (w)rite to the currently open file
  • q is to (q)uit

I also like :x as a shortcut to save and close vi

If you wish to quit and discard any changes you have made, use the (q)uit command followed by shebang :q! This will ignore any changes and close the editor.

You can optionally provide a filename after the (w)rite command like this :w Gemfile. That will write the output to that file (creating it if necessary, on most systems).

Navigation

Navigating around the document is one of the most important functions of any editor.
I found it simpler than expected to master the essential commands for jumping through my code, in Vi, with a few mnemonic tricks.

Move the cursor Left, Right, Down, Up one character/line with h, l, j, k respectively. I found this is much, much quicker than trying to reach for the arrow keys (which, by the way, also work as expected)

By pressing b, in edit mode, the cursor will jump Back to the Beginning of the current word. Likewise, e will take the cursor to the End of the current word.
In a similar fashion w jumps to the next Word.

You can force the cursor to any location in the current line with the column number followed by the Pipe symbol. I think of 15| as "push the I-beam cursor to position 15".
Likewise, the Pipe symbol alone will move to the first character/column in the line. Actually | and 0| are equivalent. "Nothing" is interpreted as ZERO here.

Before leaving the commands for cursor movement, let's add these two:

  • + moves the cursor to the beginning of the next line. I think of it as Incrementing the line position
  • - moves the cursor to the beginning of the previous line, like Decrementing the line position

Scrolling the screen with Ctrl u (I think of Up) and Ctrl d (I remember Down). These only move the screen about half-width. A complete "next" screen is Ctrl f (Forward). And, as you might have guessed, Ctrl B (for Back) goes UP one screen.

You can Go to any line in the file with 32G. The "G", for GO, is preceded by the line number.

Since 8G will Go to line number 8, it is obvious that 1G will jump to the first line in the file. What is NOT apparent - but quite useful - is that G alone will jump to the last line in the file. Unlike the command for moving the cursor to the beginning of the line, "Nothing" represents The End in this case

A handy, but a bit obscure, command is z followed by RETURN, which sets the editor so the current line is the top line on the screen.

Editing Commands

Now that we are able to move the cursor freely about the screen and scroll through the currently open file, let's see how to make actual changes to the text.

I must admit, the mnemonics for these are not quite as straight-forward as others. But it is quite common to think of "X" as CROSS-OUT or Remove. So, bearing that in mind we have

  • x to delete the next character
  • X will delete the previous character
  • dd to delete the entire line

These can be preceded by a number to indicate that many characters. For example, 7x will eradicate the 7 characters after the cursor and 5X will delete the 5 characters to the left of the cursor.

Combining what we have seen from above, with respect to moving the cursor among words, if you use db or dw (preceded by a number) that many words will be deleted (before the cursor or after the cursor, respectively)

There is an anomaly, a 'shortcut' of sorts that I find myself using quite often. For that reason I will not complain about my inability to devise a proper mnemonic. It is D, which deletes all text to the right of the cursor - to the end of the line. {You could, perhaps, remember it as The BIG D that performs a BIG Delete, or imagine the shape leading to the right; the end of the line}

You instantiate Insert Mode with i. Of course, you lose the simplicity of moving the cursor with h/j/k/l - and I sometimes forget that fact.

Another command I find myself using most often is A, which also instantiates Insert mode but takes you to the very end of the line. I think of it as "insert After" the last character on the line.

Selections and Blocks of Text

There is another 'mode' in Vi (think of it a sub-Mode) that emulates the GUI operation of selecting large blocks of text.
The Visual mode is accessed with v and allows you to continue using the navigation keys (that is why I consider it a subordinate to Navigation) to make selections.

This is handy for a

  • Delete with dd
  • Yank (the term for copying) with y
  • Paste by using P to paste after the current cursor position and p to paste just before the cursor

You can indent a selected block of code with > and outdent it with <

Combining these for something useful, go to a line with lots of text (code) and try this
wwwhvbcREPLACED


And, each time you catch yourself shouting, "OOOPS!" (or something similar but less 'family-friendly') remember to use u for Undo.

I have occasionally become a bit overzealous with 'u' when I made several changes I wish to revert. In those cases I can Undo my Undo by applying the command for Redo, Ctrl r.


Opening Multiple Files

:e <path and filename>

If you are not sure of the precise path and/or filename just use a filespec.

:e . displays a menu-like list of files in the current directory (if you used 'dot', for example). You can navigate the filesystem (use the standard j, k and Enter

Shell Command

You can jump out of Vi and to the shell with :sh

This is handy for doing a quick chmod on a file or running irb.
When you exit from the shell you are back in Vi where you left.


Search and Replace

Every editor (of any kind) must include the essential ability to Search and Replace text. And Vi is not at all hesitant about being robust in this area.
Any search begins in Command mode.
The simplest is SLASH followed by a word. This /flower will find the first occurance of the word "flower". Using :n you can go to the next occurance.

In order to REPLACE text there are a few key options:

  • :s/SearchFor/ReplaceWith/g {The 'g' means Global. Without it the search is limited to the current line}
  • ?Find/Replace/gi will do the same operation in reverse {the 'i' modifier forces case-insensitive}

What's odd here is the letter 's' is used when you want to Search AND Replace. The mnemonic I use for this is to remember Search-and-Replace versus Find with just a Slash.

If you prefer confirmation on each replace action, just add the 'c' modifier, like this :s/Find with Confirmation/Each one/gc

You may notice the familiar Regular Expression modifiers (g, i). And, in fact, the Search and Replace commands will accept [many] Regular Expression evaluation characters.
There is a great detailed description of all the parameters at Vim Regular Expressions 101

I never knew this existed in Vi until I stumbled across it accidentally.
Jumping to Matching Braces (curly braces, square brackets or standard parentheses) is simply % when the cursor is on one of the braces. What a time-saver !!


Editor Windows

Buffers

Vi embraces the concept of Buffers and applies this to the management of multiple files. I have witnessed a Vi expert bouncing among numerous screens and in multiple files and been completely awe-struck.
You can be that Vi Wizard after some practice with these few, key, buffer commands

Each time you open a new file, with :e filename, it is loaded in a new (sequentially numbered) buffer.

All the buffer commands begin with b in command mode

  • :b# next buffer
  • :bf first buffer
  • :bl last buffer
  • :b4 switches to another buffer by its number (see callout)

Before you ask, “How do I know the number of the buffer I want?”, listing all the buffers in use is so simple. It is :ls. Just like the *nix command for a file listing.


Dealing with a Split Personality

Working with a split screen is only a slight modification to working with buffers. This is handy in Rails, for example, to work on a Controller and its view(s) simultaneously.

You can open another file, into a split screen with :split filename

If you are opening the editor, you can specify multiple files – which will be loaded into split screen(s) – with vi -o file1 file2...

You can rearrange the windows’ locations on the screen; but that is a bit beyond the scope of this article.

Switching windows is a matter of Ctrl w followed by Ctrl w to jump from window to window. If you remember the navigation keys (h, j, k, l) use them with to jump to a specific window based on its location on the screen relative to the current window.

Using Ctrl w followed by q will close (quit) the current window.
The currrent window can be split with Ctrl w followed by s.

If you ever lose track of which file you are currently editing, Ctrl g will display details about the file including its name.

Conclusion

That is enough to grasp for an introduction to this extremely feature-rich application. If you have been intimidated by Vi I really hope this has helped to make it more approachable. If you have a bit of experience with Vi, I hope this highlighted some new areas in which to grow your expertise.
It does not take very long before these commands become “muscle memory”.

I hope you will apply serious effort, on a regular basis, to practicing these few commands and I expect you to see improvements in your code development as a consequence of that effort.

R E V I E W

Applying the mnemonics I have presented here, practice each of these.

  • Just ESCape the editor (and begin issuing commands), then issue a Command by using the Colon (:)
  • On a page you can jump High, Low and Midway
  • To remove one character simply Cross (x) it out
  • To open a(nother) file, you Edit it (:e). If I don’t know the exact filename you can use a filespec
  • When I need to Insert some text, unless I want to begin After the last character on the line.
  • If I wish to delete the next word or delete the word before
  • You can delete the next 12 lines with 12dd
  • Any selected text can be changed with c
  • Selecting text is easy in visual mode by pressing v
  • You must Yank text (y) in order to later Paste it (p, or P)
  • Jumping out of Vi to the Shell is as simple as :sh
  • When you need to SPLIT the work among windows, switching windows is w
  • Bounce around the buffers with :b#, :bf,:blor:b3`
  • Get a List of all current buffers with :ls
  • When finished, remember exit (:x). Or just think of sleep (ZZ) and key ZZ

I encourage you to share, in the comments, any tricks or mnemonics you find helpful.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Jojo Jones

    Nice, I learned a few new commands.

    A few notes:

    :s/subject/target/g does not globally replace subject with target in the document. It’s constrained to the current line. Without the g, :s replaces the first occurrence it finds. With g, all occurrences on the line are substituted.

    To globally replace, select the entire document (ggVG -top of document, visual select lines, goto document bottom) then perform your substitution, with a g suffix, else only the first occurrence of each subject will be replaced on each line. A section of the document can be selected with V or v and cursor movement. My favorite? Ctrl-v for column selection.

    • Nick

      You can also perform a global replace with: :%s/subject/target/g
      No need to select the whole doc

    • Thom Parkin

      Thanks, Jojo. You are absolutely correct.
      As Nick explained (below), the intended command was %s.

      {I had some difficulty with the translation from my original Markdown to the HTML for the article. Many symbols did not render correctly and I apparently missed that one in my final scrub}

  • Michael McBain

    I think there is something not-quite-right with your global search-and-replace syntax. I frequently have to do massive global search-and-replace operations in vi, on text files with millions of records. The syntax I used [e.g. to replace organisaiton with organisation] is:
    :g/organisaiton/s//organisation/g
    The components of this are:
    1. :g apply to all lines in the file
    2 /organisaiton/ the search string
    3. s substitute
    4. /string to be replaced/ [between two / characters], *but* this can be blank [ // ] if it is the same as the search string, which is usually is. If you have a complicated search string, it avoids having to retype it
    4. /organisation/ the replacement string
    5 /g replace all occurrences of the to-be-replaced string in the line
    You need that initial g to do a global s&r, as JoJo Jones points out.

  • http://randyschneck.com/ randyschneck

    Nice vim overview! Here’s a few more vim commands that I find really useful.

    You can go to the beginning of a file with gg and move around the file with 32gg to go to line 32. I think that gg is much faster than G except for going to the end of the file. You can also do :32 in command mode to go to line 32. Also instead of ESC, I use ALT with h, j, k, or l depending on which direction I want the cursor to move. There are definately many ways to do everything with vim!

    A couple more helpful commands:
    The dot/period will repeat the last operation. And one of my favorites is macros. Typing qa will start recording all keystrokes in the ‘a’ register. Press q to end recording. Type @a to run the saved macro.

  • broddr

    You left out my favorite vi command: z.
    This makes the current line (where your cursor is located) the middle of the screen (i.e., moves the view up or down as necessary). This is great for when you need more context (either above or below) the line you’re examining.

  • Butch Anton

    A few corrections:

    - The quick command to write and exit is “ZZ” (capital Zs), not “zz”. The lowercase version “centers” the current line on the screen.
    - When you’re searching, you use ‘n’ to go to the next match, not “:n” (which would instead move you to the next file in a list of files being edited).
    - The command for search/replace is “:g///[g]“, where is the old string, is the new string, and the optional ‘g’ will replace globally (all instances) on a line. Without the optional ‘g’, only the first match on a line will be replaced.

    A few other tips related to ones you already mentioned:

    - You can use ‘I’ just like ‘A’ to insert at the beginning of a line instead of the end.
    - You can use ’0′ (zero) to go to the beginning of a line and ‘$’ to go to the end of a line.
    - You can use “:” to jump to a particular line. For example, “:32″ will go to line 32.
    - You can use ‘cw’ to _change_ words, much like ‘dw’ deletes them. The change happens in place, so it’s the equivalent of deleting and then inserting.
    - You can change the order of the count in a delete/change word sequence. For example, you can use “c3w” to change three words, or “3cw” to change three words.
    - You can use patterns in your deletions/changes. For example, “c/term” will start a replacement from the current position to the string “term”, and “d/term” will delete everything from the current position to the string “term”.

    Thanks for the excellent intro!

    • Thom Parkin

      Thanks, Butch, for pointing out the corrections and sharing other commands. I can see why they are among your list of favorites and will add them to my ‘frequently used’ shortcuts.

  • TutujWud

    I also liked to (m)ark the beginning/end of several lines to yank into a buffer. I have forgotten how to yank into a numbered buffer (that is to say, there are several. You can yank several things, and then paste them in whatever order you like…)