From time to time I like to engage in a round of vimgolf. It can be enlightening.

How are they able to record all the keystrokes? That must be a vim feature. Anybody any idea how to do that. It could come in handy to record everything in certain circumstances.

  • 1
    I just found out that we have a pretty similar question here
    – statox
    Commented Dec 6, 2017 at 14:12

2 Answers 2


They probably use the built-in parameter -w, see :h -w:

-w {scriptout}  All the characters that you type are recorded in the file
        "scriptout", until you exit Vim.  This is useful if you want
        to create a script file to be used with "vim -s" or
        ":source!".  When the "scriptout" file already exists, new
        characters are appended.  See also |complex-repeat|.
        {scriptout} cannot start with a digit.
        {not in Vi}

Edit As @B Layer pointed out the actual code uses the -W parameter which is basically the same as -w but the log file is overwritten instead of appending the keystrokes to it (:h -W):

-W {scriptout}  Like -w, but do not append, overwrite an existing file.
        {not in Vi}
  • Good guess! It's -W not -w (see my answer) but still...
    – B Layer
    Commented Dec 6, 2017 at 12:38
  • @BLayer Well played I was too lazy to look at their code :-) I'll update with the doc for -W which is basically the same.
    – statox
    Commented Dec 6, 2017 at 12:40
  • 1
    Yep. Just append vs write.
    – B Layer
    Commented Dec 6, 2017 at 12:40
  • A (good) guess outvotes and gets accepted over a well-researched, fact-based answer? A grave injustice has been done. :( ... LOL
    – B Layer
    Commented Dec 8, 2017 at 19:46
  • 1
    'Tis a noble gesture. I humbly accept your vote, good sir or madam. Dilly dilly.
    – B Layer
    Commented Dec 11, 2017 at 20:40

I don't think it's quite that simple but you can look at the Ruby code yourself here:


I see a class for keylogging, for one.

Here's the command that is used to launch vim in lib/vimgolf/cli.rb:

 vimcmd = GOLFVIM.shellsplit + %W{-Z -n --noplugin --nofork -i NONE +0 
    -u #{challenge.vimrc_path} -U NONE -W #{challenge.log_path} #{challenge.work_path}}

@statox was (very nearly) right about -w outfile ... -W outfile, actually, which overwrites the file to which the typed characters are sent rather than appending to it. But as I said, not "quite that simple"...compare the contents of one of those files and what gets generated by the vimgolf tool. This is from an actual vimgolf problem...

-W output:

^VGI0. ^[gvg^AZZ

vimgolf displayed/uploaded output:

<C-V>GI0. <Esc>gvg<C-A>ZZ

Update: I spent a few minutes looking a bit closer at things. Here's how the raw form gets converted to the more readable Vimgolf format...

The keylogger class keylog.rb that I mention above is indeed a major piece of the puzzle but it's actually fairly straightforward. The keycodes that Vim saves to the -W log file are either one byte or three bytes long. The latter always start with the value 0x80 to distinguish them from one-byte codes.

To decode the one-byte keycodes a simple array lookup is done.

Example: If you press G the byte 0x47 is saved to the -W file. (Hex 47 is the ASCII code for the letter G.) In the lookup array the element at position 0x47 contains, naturally, G. For printable characters this is an obvious conversion but it's necessary for non-printable ASCII characters that we want to have a nice name like <Esc> and <CR>.

For multi-byte keycodes there is a hash table that maps bytes two and three to a human readable string.

Example: If you press Home the three-byte sequence 80 6B 68 is saved to the -W file. The last two bytes are converted to ASCII and concatenated: kh. In the hash table that string is mapped to the string <Home>.

There are some exceptions/corner-cases that are handled differently but most of the keycodes are resolved by one of the two methods described above.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.