Lists, Vim, and You

Teo Ljungberg

Vim truly excels at editing text, but some common text-editing tasks are more daunting than others to do from our favorite text editor. Today, we are going to cover the various ways you can search and replace bits of text, in your shell and beyond to Vim.

From the shell

From our dotfiles you can find a script named replace, which takes three arguments - the word you want to replace, its replacement, and the pattern for where you want to replace within. Easy, right?

% replace ugly funny-looking **/*.txt

If you do not want to install yet another script to your dotfiles, you can use sed(1), which is used under the hood by replace.

% git grep -l ugly | xargs sed -i "" "s/ugly/funny-looking/g"

For an extended overview on sed(1) and replacing text in your shell, I suggest reading sed 102: Replace In-Place.

Using Vim, from the shell

As you might be aware, Vim lets you search and replace by running: :s/ugly/funny-looking. The :s there comes from sed(1) which we used above. We are going to use the :%s version to search and replace across a buffer, which is what % means in Vim-land. So, how can we leverage that do search-and-replace over a set of files? Enter :argdo.

:argdo lets us run a given set of commands over our arguments list. What is the arguments list you might ask?

Take any directory, much like this one:

% ls
a.txt  b.txt  c.txt
% vim +args *.txt

We are greeted with the response:

[a.txt] b.txt c.txt

That means that our arguments list is populated with the three files listed above.

Now, with that new-found knowledge - let us see how we can search and replace over that set of files.

% vim $(grep -l ugly -r *) +"argdo %s/ugly/funny-looking/g | update"

That command is a bit of a mouthful, but do not fret. We will break it down bit by bit.

  • $(grep -l ugly): returns all files that contain the word “ugly”.
  • +"argdo %s/ugly/funny-looking/g": will run %s/ugly/funny-looking across all files in our arguments list.
  • ... | update: will save each file after the :%s command has finished running.

From inside of Vim

With the release of Vim 7.4.858 we got two new commands: :cdo and :cfdo. They work similarly to :argdo, but they operate over the quickfix list instead of the arguments list.

The quickfix list is populated when you run commands such as :grep. Which is great, because that is how I find my way around text documents.

First of all, we need a list of files to modify. From inside of Vim:

:grep ugly -r **/*.txt

That will populate our quickfix list with a list of files. You can use :copen or :clist to look at the files manually.

Now, for the fun part! We can use the same command as we did when replacing using argdo from the shell, but using :cfdo instead of argdo.

We are opting to use :cfdo instead of :cdo for the fact that :cdo will run a set of commands over each element in the quickfix list, while, :cfdo will run it over each file in the quickfix list. Therefore, we will not run the same command twice.

:cfdo %s/ugly/funny-looking/g | update

Voilà, we have now replaced all occurrences of “ugly” with “funny-looking” from the inside our favorite text editor.

Conclusion

With this newfound knowledge, we can now search and replace with ease using Vim’s various lists. The lists can be used for other tasks, as versatile as they are. I’m going to leave it as an exercise to the reader to find other use cases for them.