39 min read / 6 for this part
VIM diary
Part: 1 | 2 | 3 | 4 | 5 | 6 | 7
While learning the basics of Vim over the course of a few months I kept a simple diary. I recorded what I had been Googling for and what I'd learned during my struggles.
# February 2024
The start of my sixth month of learning Vim.
At this point I feel like I should round-out this diary and bring things to a
close. I'm learning just as much about Core Utils and tmux as I am about Vim.
I'm familar enough now that I'm as productive as I used to be. Arguably more so in most (definitely not all) cases. On the whole, learning Vim has turned out to be a lot more fun that I had expected, and fun is a great motivator for continued learning.
I certainly didn't see that coming.
# Okay, so I'm not quite done yet
My .vimrc tinkering had died down a lot and I told myself I would revisit it
every 3-6 months perhaps.
Turns out that in March I did make big changes to my config, mostly to do with progressive enhancement. I really do want a config that I can drop-in anywhere and, even if I don't have the best features available because of versions or whatever, I'll have some okay fallbacks.
One of Vim's defining features is its availability on almost every platform, so to have a portable config takes maximum advantage of that.
I know this isn't the March entry, but some of the things I discovered in February would become part of this refactor: where if a plugin offered a great solution it would be preferred, otherwise a fallback would kick-in using (if possible) the same remaps.
# Every list, everywhere, all at once
Somehow I learned about all of these this month:
- QuickFix
- VimGrep
- Grep
- Arglist
Things related to searching and managing search results in Vim.
My use of vim-fugitive's file-history feature would drive my interest in
learning about QuickFix. I really hadn't made an effort to use it before, since
things like fuzzy-finders or running find or rg directly in a buffer
covered most of my needs (and still does.)
But having a dedicated window for persistent search-results was inviting, so QuickFix became a point of learning for a week or so, along with these Vim built-ins that use it: VimGrep and Grep.
The Arglist came along at the same time too.
# Grammar over Commands
One of the most useful features of both QuickFix and Arglist is being able to run commands against whatever is in the list:
" QuickFix
:cfdo %s/search/replace/g | update
" Arglist
:argdo %s/search/replace/g | update
There's no special syntax here. Whatever commands I would normally run against a single file can now be applied to many files.
Of course, in "single buffer mode" I tend to run commands one at a time, so the
pipe | seems to stand-out. But it can be used to run multiple commands
against a single buffer too.
This is one of the most magical things I have found about learning Vim: not so
much its commands, but its grammar. Picking up a new piece of grammar
suddenly opens up a huge number of possibilities I previously had no idea
about, and it cost almost nothing to learn.
It takes a while to get to this point of course (here we are at month six) but how many other tools can this be said about?
# Git File History
My dependence on vim-fugitive's file-history feature would last until the
middle of February when I would discover diffview.nvim, which is a much more
complete and intuitive solution to the problem.
(This would eventually turn into one of those "progressive enhancements" I mentioned earlier, where diffview would be used if installed, and a fugitive based remap would be the fallack.)
# Home on the Ranges
The second week of February was about ranges in Vim and in sed.
I'd never sat down and learned the full capability of sed before. It's just
that substitition command, right? Well, no: turns out there's a reason it's
called a "stream editor", because that's what it is.
It has its own grammar too, where you can specify not just a pattern to match, but a start and end range, and then a command to run against that range.
sed '/pattern/'
'/pattern/cmd\'
'/pattern/cmd\ { text to pass to cmd }'
'/start/, /end/ { cmd + text }'
commands = s///g = substitute
p\ = print
a\ = append
i\ = insert
d\ = delete
What a great refactoring tool this turned out to be.
rg -l 'syncFields' \
| xargs \
| sed -i \
'/const syncFields = \[/, /\]/ {
a\
const fieldValues = Object.keys(fields)
}'
- Range part:
/start/, /end/ - Group part:
{ ... }(stuff to run against the pattern) - Append command:
a\(followed immediately by text to append)
As for Vim ranges, I started here:
" Copy 5 lines, starting from -30 relative, to the current line
:-30,-25 copy .
The article linked was tough going to started with, but ended up being a great introduction.
# GNU parallel
If you've ever written a
script
and then afterwards found a built-in utility that does the same thing only
much, much better, then you'll know how I felt when I discovered parallel.
Unsurprisingly, it runs commands in parallel:
ls *.js | parallel "prettier --write {}"
Here we pipe-in a list of files from ls and then run prettier on each one,
with parallel taking care of the concurrency for us.
Notice the {} token. While not exactly defacto, this also appears in both
the find and xargs commands:
ls *.md | xargs -I{} echo {}
find src/ -name '*.js' -exec echo {} \;
ls *.js | parallel "prettier --write {}"
It's configurable for xargs, but I find it curious that the documentation
offers the same {} token in its examples.
# Commands Learned
- Ranges
s/search/\=commands()/narbitrary commands in a substitution, for example;s/search/\=setreg('A', submatch(0))/n- Vimgrep
- The Arglist
- The QuickFix list
- Discovered entr for running commands on file changes
29 Feb, 2024