GHC-style note snippet for Vim

Published on

I am a big fan of GHC-style notes. Notes are a convention for long, in-depth comments that do not interrupt the flow of the code.

A note is a comment that is formatted to be easily searchable and recognizable:

{- Note [Extra args in rule matching]
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   If we find a matching rule, we return (Just (rule, rhs)),
   but the rule firing has only consumed as many of the input args
   as the ruleArity says.  It's up to the caller to keep track
   of any left-over args.  E.g. if you call
       lookupRule ... f [e1, e2, e3]
   and it returns Just (r, rhs), where r has ruleArity 2
   then the real rewrite is
       f e1 e2 e3 ==> rhs e3
-}

A note can be referenced in the code like this:

lookupRule :: (Activation -> Bool) -> InScopeSet
        -> Id -> [CoreExpr]
        -> [CoreRule] -> Maybe (CoreRule, CoreExpr)
-- See Note [Extra args in rule matching]
lookupRule is_active in_scope fn args rules
  = case go [] rules of
    []     -> Nothing
    (m:ms) -> Just (findBest (fn,args) m ms)

This convention for notes was originally developed for GHC, but it can be used in absolutely any project and in any programming language. You can read more about notes in the GHC commentary and in The Architecture of Open Source Applications.

The only issue I used to have with notes was that I could never remember how to format them properly, so every time I wanted to insert one, I would find and copy-paste one either from my own code or from the GHC source.

This motivated me to create a SnipMate snippet for Vim that automates the process.

Here are the steps:

  1. Install SnipMate

  2. Make sure it uses the new snippet parser. Put

    let g:snipMate = { 'snippet_version': 1 }

    in your ~/.vimrc.

  3. Run

    base64 -d >> ~/.vim/snippets/haskell.snippets <<EOF
    c25pcHBldCBOb3RlCgktLSBTZWUgTm90ZSBbJHsxOnRpdGxlfV0KCXstIE5vdGUgWyQxXQoJICAg
    fn5+fn5+fiR7MS8uL34vZ30KCSAgICR7Mjp0ZXh0fQoJLX0K
    EOF

    (The reason for base64 is to preserve the relevant tab characters.)

    This will install the following snippet:

    snippet Note
      -- See Note [${1:title}]
      {- Note [$1]
         ~~~~~~~${1/./~/g}
         ${2:text}
      -}

Now you are ready to insert a note. Open a Haskell file in Vim and type

Note<Tab>

This will expand into a template

-- See Note [title]
{- Note [title]
   ~~~~~~~~~~~~
   text
-}

Just start typing the title of the note, and it will replace both occurrences of title at the same time. Then press <Tab>, and start typing in the text of the note.

The snippet consists of two part: the note itself, and the reference to the note. You leave one in place and cut-and-paste the other one to where you want it to be.