Smart search with :Subvert
:Subvert command lets us create a particular style of regular expressions with ease. It’s great for matching irregular singular and plural words in plain English and also for variable names that come in
This is part one of a three-part series on Tim Pope’s abolish plugin.
:Subvert - a supercharged search DSL
Vim’s search command is case-sensitive by default. I can demonstrate with this text by searching for
It matches this occurrence in lowercase, but not the mixedcase occurrence here. Vim provides a few options that allow you to tune the case-sensitivity of the search command, such as
smartcase. But I want to show you an alternative approach, as used by Tim Pope’s abolish plugin.
This plugin adds a command called
:Subvert. I’ll call it with the text
That matches both occurrences. But watch this: if I upcase the letter ‘k’, it no longer matches. Clearly, there’s some kind of case-sensitivity going on here. We can inspect the pattern by pasting it from the search-register:
\C (big-C) switch enforces case-sensitivity, overriding the value of settings such as
ignorecase. Then we get three variations of our specified text: uppercase, mixed-case, and lowercase. Nothing else will match.
You get the idea?
Now let’s try something a bit different. The
:Subvert command can accept a comma-seperated list of alternatives, wrapped in braces. Let’s try searching for a few different words with a single command:
This time, the generated pattern includes three variations for each of the specified words. That’s nifty!
Consider this: the word ‘mouse’ has an irregular plural: ‘mice’. With the subvert command, we can easily generate a pattern that will match the singular and plural forms.
The letter ’m' is common to both alternatives, so I’ve specified it outside of the comma-separated list. Admittedly, it doesn’t save a lot of typing in this case!
The subvert command is also handy if you want to find a variable name that appears in both
snake_case. For example, in ruby, module names and class names are given in
snake_case is used for naming the corresponding files.
require "parslet" require "vimprint/parser/insert_mode" require "vimprint/parser/visual_mode" require "vimprint/parser/cmdline_mode" module VimPrint class Parser < Parslet::Parser include InsertMode include VisualMode include CmdlineMode ... end end
If we run the
:Subvert command with the snake cased
insert_mode variable, it automatically matches the mixed case version too.
Again, we have three variations:
If we wanted to match these other variables, we could modify our
:Subvert command to use a comma-separated list:
Now here’s another neat little trick: the
cr mapping lets us quickly mutate between different styles of variable. If I press:
crc, it transforms the variable to camel case. (As a mnemonic, you can think of it as coerce to camel-case.)
cr-uses dashes to separate the words (I’ll undo that)
crmswitches to mixed case
If you’ve also installed Tim Pope’s repeat plugin, then the dot command will work as you would expect.
crsswitches back to snake case
How cool is that?
Using :Subvert across multiple files
So far, we’ve been using the
:Subvert command to search inside the current buffer, but we can easily make it search across multiple files. We just have to specify the path of the directory we want to look inside:
:S /vimprint/ lib/**/*.rb
It populates the quickfix list, just as though we’d run the
Of course, we could achieve the same effect by pasting the pattern register into the search field of the
:vimgrep command. We’re working with standard Vim regexes throughout, so the patterns generated by
:Subvert will work with any of Vim’s pattern based commands.
It’s unlikely that you would compose such a complex pattern as this by hand, but the
:Subvert command makes it trivially easy. I like to think that it provides a domain-specific language for generating a particular style of regular expression.