Managed search and replace in many files using Vim and ag.
Posted on Mon 16 November 2015 in Programming
Recently I faced an interesting problem. I had to search for the redundant lines of code (about a hundred occurences), and replace some of them. The bad thing is that I couldn’t do that automatically, as each case had to be manually reviewed.
So, how to automate this task, while keeping the manual control?
The text what I was looking for were actually two consecutive lines:
self.assertEqual(response.status_code, ...)
self.assertContains(response, ...)
Let’s fire up the ag utility (a faster and feature-full fgrep replacement):
user@host:~/src$ ag 'self.assertEqual\(response.status.{0,100}\s*self.assertContains' . | vi -
The trick here is that ag uses multiline matching by default, therefore allowing us to search for several lines at once. And we pipe the search results to Vim, my editor of choice.
Now we have a Vim window with a bunch of lines like:
...
tests/test_client/tests.py:732: self.assertEqual(response.status_code, 200)
tests/test_client/tests.py:733: self.assertContains(response, 'This is a test')
tests/test_client/tests.py:743: self.assertEqual(response.status_code, 200)
tests/test_client/tests.py:744: self.assertContains(response, echoed_request_line)
tests/admin_views/tests.py:230: self.assertEqual(response.status_code, 200)
tests/admin_views/tests.py:231: self.assertContains(response, 'value="My Section"',
...
, and we definitely need a way to easily navigate to each file (preferably in the split window), analyze the case and make changes.
Vim superpowers to the rescue! Let’s make a convenient shortcut:
:nnoremap <CR> :vertical wincmd F<CR>
Simply put, we create a new mapping for the Vim’s normal (navigation) mode.
When we hit Enter
(or <CR>
), Vim makes a vertical split and executes the
window command F
, which is essentially to open a file under cursor and
navigate to the specified line.
So we basically scroll down the search results, hit Enter
on interesting
ones, and have them opened for editing in a split window. Cool? You bet.
Do you have some Vim find-n-replace tips? Share them in comments!