Saturday, January 16

importing workings-book to the p1k3 tree

For a chunk of last year, I was keeping workings-book as a kind of technical logbook:

I’ve been working on a short book on the basics of the command line. This one is something else altogether. It’s a long-form technical logbook or journal, capturing the outlines of problems and their solutions as I encounter them. It is dry, incomplete, and sometimes wrong. It is unlikely to be useful for the general reader. I’m compiling it because I want a record of what I learn, and I hope that writing documentation will help me do cleaner, more reproducible work. If it helps people with similar problems along the way, so much the better.

Todd recently reminded me of this when he started updating his own version of this idea. It’s something I’d like to pick back up, both for the benefit of my own shaky memory and as a low-key contribution to general knowledge.

Thinking about it, though, the current format (one long HTML document with a table of contents) got cumbersome after more than a handful of entries. Since I already have one long-running blog with a lot of nerd stuff, I might as well just merge workings-book into p1k3, and publish future technical notes here.

I could do this by hand, but would it make sense to automate the process? Maybe. workings-book is laid out like so:

/home/brennen/code/workings-book/
▾ entries/
    0-introduction.md
    2014-12-03.md
    2014-12-05.md
    ...
    copy.sh
    ...

I was about to go into writing a script to copy the entries/yyyy-mm-dd.md files into p1k3 entries (which are stored in files like archives/yyyy/mm/dd), first making sure there’d be no collision with an existing entry. Then I noticed copy.sh, which looks like so:

#!/usr/bin/env bash

cp 2014-12-03.md ~/p1k3/archives/2014/12/3
cp 2014-12-05.md ~/p1k3/archives/2014/12/5
cp 2014-12-07.md ~/p1k3/archives/2014/12/7
cp 2014-12-08.md ~/p1k3/archives/2014/12/8
...

It seems like I must have started in on this process once already. If I had to guess, I’d bet that instead of writing logic for the problem, I just copied a directory listing into Vim and then used blockwise visual select to double the column of filenames, insert ~/p1k3/archives/, chop off the trailing .md, and replace - with /. I’m not sure how I checked for collisions, but it may have been as simple as hitting Ctrl-W f with the cursor on each target filename, or running the script and checking git status on the p1k3 repo.

Here’s an annotated sequence of keystrokes that (more or less) repeats the process:

:r !ls ~/code/workings-book/entries^M
You can read the output of a shell command into the current buffer with `:r !command`
kkd}{jddkdd
Up, up, delete to end of block, top of block, down, delete a line, up, delete a line. (Trimming some uninteresting filenames from the list.)
^V}yA ^[p
You can enter blockwise visual select mode with Ctrl-V and select a column of text with } or {. You can copy this, like any visual selection, with y Jumping to the end of a line and hitting p will then paste the selected lines in a blockwise fashion as well—appending them to existing lines instead of after the current line. The first time you try this, it's sort of magical.
^Vjjjjjjjjjjjjjjjjjjjjjjjjjjlllllllll
Lazily selects just the date-formatted portion of the second filename column with movement keys.
:s/\%V-/\//g^M
I had to look this up again, but you can restrict a substitution command to just the blockwise selection by using something like :s/\%V-/\//g. (By default, substitutions usually just apply to each line in the selection, which is super confusing.)
^Vkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk>
Selects all the lines and indents them one level with >. I could have used regular line-wise selection or just indented the whole block or whatever, but I didn't.
^Vjjjjjjjjjjjjjjjjjjjjjjjjjjjjscp^[
Selects the first space and replaces it with cp.
$hh^Vjjjjjjjjjjjjjjjjjjjjjjjjjj$d
Jumps to the end of the line, blockwise selects all the trailing .md extensions, zaps them. There are cleverer ways to do this, but it most always takes me longer to think up a substitution regex than it does to just delete some columns of characters.

Anyhow, this kind of script-munging is a pattern I’ve leaned on a lot without ever really talking about it much that I can recall. I’d be willing to bet it’s a common practice for a lot of Unix types. It’s somewhere in-between classical scripting and whatever it is that people are doing when they bash data around in a spreadsheet with mouse and keyboard commands.

Part of my nerd brain thinks it’s more “correct” to solve problems like this one in code. It’s not like it would be much code—a shell one-liner would do it, or a few lines of Perl if I wanted something more readable and reusable. Then again, there’s something to be said for levering your way through a problem with the low-level, almost-physical indirections provided by tools like Vim’s visual selection modes. It can spare programmer-brain cycles for more important tasks, and its utility probably says something about how software like Excel has become so essential to people who need to do data manipulation but don’t have general-purpose programming languages or robust databases in their working toolsets.