ðŸŠī\zansh.in\blog

39 min read / 7 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.

# November 2023

A wild month of Vim digestion theatre. Towards the end of it I would make my first changes to a large project at work, including using vim-fugitive to push them up.

But it didn't feel like I would get there from here.

The first week of November was spent looking into things like LSPs, linters and formatters, Git integration, discovering fzf, and also taking the time - 2 months in - to run through Vimtutor from start to finish. I looked for ways of breaking out of INSERT mode without using ESC or remapping it to the CAPS-LOCK key. I was trying to keep as "vanilla" a mindset as I could bear.

# Refactoring

I hit my first major refactoring frustration that I consider very straightforward in VSCode, which is...

// ...turning this:
api.first()
api.second()
api.third()
// ...into this:
const { first, second, third } = api
first()
second()
third()

Trying to solve this without multiple cursors took a fair bit of thinking about. The first working and memorable solution I came up with used markers and a macro, and worked something like this:

// Step 1: Insert an empty const at the top
const {} = api; // Step 2: Place a marker here. I used `a` for "anchor"

With this preamble in place, I recorded a macro to search for api., delete it, copy the word that had followed it, then paste it above the a marker using P. I'd then repeat the macro to complete the task.

I discovered I could also cast this magic spell:

:let @a="" | g/api\.\w\+/ exec "norm! 2w\"AyiwBd2w" | let @a=@a.', '

But appending to registers with let isn't supported in the VSCode Vim Extension, and VSCode was still my main workhorse at the office.

# Registers and Macros

Around this time I discovered that the registers used for yanking (copying) and putting (pasting) are the same registers used to record macros to. This explains why you can paste a macro into a page, and why you can run yanked-text as a macro.

In other words, the interface for editing a macro is your current buffer.

Not that I arrived that this realisation happily. Despite progress it did feel like I was reaching a ceiling with how far Vim could be depended-on to maintain a large project. VSCode has sophisticated refactoring tools built-in, nevermind what can be done with extensions.

Later I would discover that the combination of markers, text-objects, and relative movement that Vim offers is decent for tackling a range of tricker refactoring jobs. More up-front thought is involved, but execution is quick, so the more files you have deal with the more it pays off.

I was also yet to realise just how powerful CLI tools can be for refactoring, and how easily those can be integrated into Vim without the need for plugins.


Into the second week more revelations about the grammar of Vim was trickling in. Not only could I format text = after selecting it, but I could instruct format = to operate on a text-object. The most difficult grammatical concept for me (so far) is understanding repeated steps: For example, opening o multiple blank lines at once, or incrementing CTRL-A a range of numbers all at once within a selection:

Before | After
---------------|----------------
one = 0 | one = 1
two = 0 | two = 2
three = 0 | three = 3
four = 0 | four = 4
five = 0 | five = 5
six = 0 | six = 6
seven = 0 | seven = 7
eight = 0 | eight = 9

I was tripping over myself often enough that I put together a plan of deliberate practice focused on only a few Vim commands (which are actually Ex commands) or movements at a time.


# Project

At the start of the third week I discovered a project I could use as a vehicle for practicing Vim at work. I was glad to have the excuse, as I was noticing ever more bugs and missing features while using the VSCode + Vim Extension. I couldn't move away completely (yet?) but since I write my notes using Markdown I could use vanilla Vim for that.

Denote is a file-format and note-taking plugin for Emacs written by Protesilaos Stavrou. I learned about it from a Reddit user who wrote themselves a simple plugin that offered some of Denote's basic features in Vim.

Seeing how it could help me maintain my own notes, I decided to write a shell-script version with the intention of also creating a companion VimScript plugin to integrate with it. I would focus only on the Markdown with YAML front-matter version of Denote, since that's essentially what I was trying to do with my own system.

# denote-md's help output (once I'd written it)
Usage: denote <command> [<args>]
new [tags] [title]
get filename [identifier]
get title note.md
replace title [new_title] *.md
list tags [*.md]
list notes [tags]
list recent [num_notes]
list backlinks note.md
list heading [heading] [tags]
list actions [tags]
add tag [tag] *.md
remove tag [tag] *.md
rename tag [tag] [new_name] *.md
replace tags [new_tags] *.md
refresh *.md
env Print environment variables

At the same time I also threw together a JavaScript to rewrite the file-names and front-matter of my existing notes to the Denote format.

These little projects were great for practicing what I was learning and discovering new ways of doing things.

# Trees: Both Undo and File ones

Despite struggling to really "click" with Vim, at this point it was getting hard to imagine life without undo-tree.

It's a plugin that puts a UI around Vim's amazing built-in undo system. If you adjust your .vimrc slightly to boost your undo-history and persist it to disk, nothing you type is lost. It feels like you have automatic local version control.

Speaking of trees, I notice that I'm avoiding installing anything to replace Netrw, such as NERDTree. I believe if I get used to buffer management, splits, the standard :find * command, and fuzzy-finders, and even just dipping in-and-out of the shell, I'll lean on file-trees a little less.

Yes, file-trees really are great for casually browsing a project, and there's something cathartic about opening and closing those little folders.

But what if I miss out on better ways of doing things by falling back into old habits? I had yet to realise I could :cd :pwd and :r!find ... (that's the POSIX find, not the Vim command mentioned two paragraphs up) to paste all or part of my entire project into a buffer and just gf and <C-i> / <C-o> around it to my hearts content.

All that, plus the frustration that led up to such revelations, was still ahead of me.

# Commands Learned

Next part →

30 Nov, 2023

Google it:

ðŸŒļ POSIX find command 🌚 Vim Ex commands 🌷 Vim find command ðŸŒŧ Vim History with Ex and Ed 🌞 Vim Registers vs. Macros ðŸŒđ Vim Undo Persist 💐 Vim Undo Size