teaching machines

Capturing snapshots of a text file in Vim

June 1, 2012 by . Filed under keystrokes, public.

To make a movie of textual development, I need a way to capture edits to a text file. Capturing needs to be done automatically and transparently; the developer shouldn’t have to trigger them. Otherwise, he’d forget.

My initial thoughts were to intercept every keystroke and record the changes elsewhere on disk. I didn’t really like this idea, given the extreme number of snapshots it would produce, so I went searching for something better. It turns out that the Vim editor recognizes a couple of events, CursorHold and CursorHoldI, that are triggered when the cursor stops moving. Moving cursors are a little different than text changes, but the location of the cursor is probably something I also want to track in the text movie. With Vim’s autocommands, I can register an event handler for these two events.

The following function, when called on a file named foo, starts listening for these CursorHold events. When the first is fired, the current text is written to foo00…0. The next to foo00…1. The next to foo00…2. They’ll be processed into a text movie later.

function! StartKeystrokes()
  " CursorHold* events are fired when the user doesn't move the cursor
  " for updatetime milliseconds.
  set updatetime=500

  " We're going to keep a counter for the number of events that are
  " fired. I'm sure we'll find some way to use it.
  let b:nupdates=0

  " Snapshots will be recorded to a directory. Let's put it in junk
  " so that it will automatically get wiped. Let's wipe any previous
  " session.
  let b:dir=$HOME . "/.junk/keystrokes/" . bufname("%")
  execute ":!rm -rf " . b:dir . " && mkdir -p " . b:dir

  " Attach to this buffer some event handlers. When the user stops
  " moving the cursor in either normal or insert mode, let's record
  " a snapshot out to disk.
  autocmd CursorHold,CursorHoldI <buffer>
  \ let b:nupdates=b:nupdates + 1|
  \ execute printf('write! %s/%s%010d', b:dir, bufname("%"), b:nupdates)
endfunction