Tufte style sidenotes & marginnotes in Pollen

When evaluating Pollen I complained about markdown/pandoc’s lack of sidenote handling. I have solved it for Pollen but felt it deserved it’s own post.

A caveat: I generated Tufte CSS style sidenotes and marginnotes which made it more complex than if I had simply generated “standard” sidenotes. If you want to adapt this yourself I’m sure you can simplify the code to fit your needs.

So in Pollen markup I want to be able to write this:

Lisp is a pretty nice ◊sn{cult} language.

◊ndef["cult"]{
    Some may say it's the language to rule them all.
}

To generate this:

The order of ◊sn and ◊ndef shouldn’t matter.

By having the sidenote span right in the middle of the text it allows us to toggle it without javascript. This appeals to me as a heavy noscript user but it has a significant drawback: you cannot have block level tags like div or p inside a span.

You also cannot use an aside instead of a span directly here as you cannot have it inside a paragraph tag.

Tufte has both sidenotes and marginnotes which we can implement in a general way. This is the markup:

This has a sidenote with numbers.◊sn{note}

This has a marginnote without numbers.◊mn{note}

◊ndef["note"]{
    The note itself
}

These are the Pollen tags with their markup difference:

We’ll get to the note-ref definition in a little bit.

We can use the same markup for sidenote and marginnote content. The idea is to store the content in a map and look it up and insert it into the markup later.

Simple enough right? If we want to apply post-processing, like adding paragraphs, we need to do some more work. Especially since we cannot have p tags inside the span! I solved this by instead wrapping paragraphs with a span I style like paragraphs. This is the actual code:

Here string-proc can contain smart quotes expansion or whatever extra decoding you want to use.

Now to another problem: we want to have refs before defs and vice versa. This means we might parse the references before we’ve registered the definitions. We can solve this by making a decode pass in the root tag and marking refs with a special symbol which we replace. This can be made very general:

Which is used like this:

Where root in Pollen allows you to transform the whole document.

And now we can get back to our reference tag:

It’s basically just registering a replacement function which returns the markup:

Are we done? Almost. This would create markup wrapped in a span, like:

The replacement function can only return a single element so we had to wrap it in something. In this particular case it’s not a big deal but it is indeed a general limitation of Pollen tags. Is it something we can get around?

Yes it is. We can add a special symbol in the markup:

And then do an extra post process step to replace it with it’s content, inline:

We need to do it after decode-elements since it doesn’t support such a transformation.

And we’re done! It wasn’t very straightforward to implement Tufte style notes but with Pollen you do get the ability to do it.