Repeating the last ‘:’ (Ex) command in Vim

Sometimes I run a complicated search-and-replace (:s/../../) in Vim, and I then want to repeat it somewhere else. In the past, I have always hit :, up-arrow to retrieve the command from the history. It should be no surprise by now that there is an easier way!

@: in normal mode (at-sign, colon) will repeat the last : command. Once you have done @:, you can hit @@ to re-run the command. Quick and easy!

This works because the : register, ":, holds the last Ex command. @ runs a macro, and knows that using the : register means you want to repeat an Ex command. @@ runs the last macro, so works for @: just as it does for @a or any other normal-mode macro.

I found ": in :help registers when I was looking for a register that held the filename of the file open in another window, as opposed to the alternate filename in the current window. Details of ": are at :help ": (believe it or not! 😉 ).

Vim tips: curly quotes and visual selection

Curly quotes: because reasons.  😉  In Insert mode:

  • Ctl+K '6 will give you an open curly single quote, and Ctl+K '9 will give you the closing curly single quote.
  • Similarly, Ctl+K "6 will give you an open curly single quote, and Ctl+K "9 will give you the closing curly single quote.

Visual mode: turns out you can just hit o when in Visual mode to move the cursor to the other end of the selection.  Handy!

vim: cleaning up mixed indents

Thanks to the wiki for this.  If you run across a file that mixes tabs and spaces (ewww!), set the tab settings the way you want (e.g., ts=4 sts=4 sw=4 et ai) and run


to convert all the tabs to the right number of spaces.  This takes tab stops into account, which :%s/^I/    /g won’t.

This replaces what I used to do, which was /^I s<Tab><Esc> followed by a whole lot of n.n.n.n.n.n.n.n. … .  One command is much better 🙂 .  I’m not even going to try to count the keystroke savings on my current project (pym, a preprocessor written in Python).

Vim: joining lines having continuation markers

This handy file-renaming script at Perl Monks has source code with red “+” marks marking wrapped lines. I pasted it into Vim and wanted to wrap those lines back to the way they should be. After a bit of fiddling, I got:

:g/^+/execute "norm 0x" | .-1,.j!

The `g/^+/’ finds the lines beginning with a “+”. Then the `execute “norm 0x”‘ deletes the “+” (“0” moves to beginning of line; “x” deletes), “|” marks the next command, and `.-1,.j!’ joins (“j”) the current line (“.”) with the previous line (“.-1”) without whitespace (“!”) added between the lines.

I leave it to you whether I have too much time on my hands.

Adventures in vim

Just ran across this question on Stack Exchange by DJ McMayhem, which pointed out a great tip for commenting blocks of code. Say you have

int main()
  int answer=42;
  string question;
  for(int i=0; i&lt;answer; ++i) {
    question += "what do you get";
  return answer;

and want to comment out the question. I used to do that by putting the cursor on line 4 (string question), hitting ma to save my place in mark a, moving down to line 7 (the end of the for loop), and doing :'a,./s/^/\/\//<Enter>.

Thanks to DJ McMayhem, I can now do that by starting on line 4, hitting v3j to select the lines in question, and doing :norm0i//<Enter>. Result:

int main()
  int answer=42;
//  string question; 
//  for(int i=0; i<answer; ++i) {
//    question += "what do you get";
//  }
  return answer;

Original: 20 keystrokes (counting Enter, but not counting Shift presses as separate keystrokes)

New: 13 keystrokes 🙂

My next adventure is to wrap :normal in a function so I can use :N or some such, for a savings of a further three keystrokes!

Adventures in vim

Forgot to mention — if this is all Greek to you, don’t worry! I’ve been learning from fellow Vim users and sharing tips since the late 1990s. Give it time; it will come.

Following up on last time — you can also use motions like ip with : commands that normally take ranges.

Type v<motion>, where <motion> is ip or G or some other cursor motion command. Vim will highlight the text from the cursor to wherever <motion> takes you. (If only vim had a motion key for second star to the right and straight on ’til morning!) You can then issue any : command and it will operate on the selected text.

I often use external sort or fold utilities via filter commands. Those are even easier – you don’t even have to type the :. For example, vip!fold -s -w 70<Enter> folds long lines in the current paragraph. Sure beats what I used to do, which was {:.,/^$/!fold -s -w 70<Enter>! (Makes total sense, right? 🙂 )

Adventures in vim

Vim is my text editor of choice.  (emacs users, commence flaming!)  Yesterday I discovered ip and today I discovered Control-O.  Best shortcuts ever!

ip selects the current paragraph, delimited by blank lines unless you set the modes otherwise.  I used to select whole paragraphs with {y}, which copied extra lines and lost my cursor position.  Now I can copy with yip, which grabs just the paragraph text and keeps the cursor firmly planted.  Fantastic!  See :help object-select for more.

Control-O is a get-out-of-insert-mode-free card.  When inserting, hit Control-O and you’ll be back in command mode for the duration of one command.  That can be a colon or immediate command.  For example, <Ctrl-O>f, will jump you forward to the next comma — without leaving insert mode.  Esc, w or f or / or what have you, i has been my everyday for years. I am thrilled about saving one keystroke per such action times ~1e100 actions over my vimming life. More at :help ins-special-special.

Stay tuned for more adventures in vim!