Introducing diagrams-haddock
I am quite pleased to announce the release of diagrams-haddock, a tool enabling you to easily include programmatically generated diagrams in your Haddock documentation. Why might you want to do this? “A picture is worth a thousand words”—in many instances a diagram or illustration can dramatically increase the comprehension of users reading your library’s documentation. The diagrams
project itself will be using this for documentation, beginning with the diagrams-contrib
package (for example, check out the documentation for Diagrams.TwoD.Path.IteratedSubset). But inline images can benefit the documentation of just about any library.
Before jumping into a more detailed example, here are the main selling points of diagrams-haddock
:
-
You get to create arbitrary images to enhance your documentation, using the powerful
diagrams
framework. -
The code for your images goes right into your source files themselves, alongside the documentation—there is no need to maintain a bunch of auxiliary files, or (heaven forbid) multiple versions of your source files.
-
Images are regenerated when, and only when, their definition changes—so you can include many diagrams in your documentation without having to recompile all of them every time you make a change to just one.
-
You have to do a little bit of work to integrate the generated images into your Cabal package, but it’s relatively simple and you only have to do it once per package. No one else needs to have
diagrams-haddock
installed in order to build your documentation with the images (this includes Hackage).
So, how does it work? (For full details, consult the diagrams-haddock
documentation.) Suppose we have some Haddock documentation that looks like this:
-- | The foozle function takes a widget and turns it into an
-- infinite list of widgets which alternate between red and
-- yellow.
--
foozle :: Widget -> [Widget]
foozle = ...
It would be really nice to illustrate this with a picture, don’t you think? First, we insert an image placeholder like so:
-- | The foozle function takes a widget and turns it into an
-- infinite list of widgets which alternate between red and
-- yellow.
--
-- <<dummy#diagram=foozleDia&width=300>>
--
foozle :: Widget -> [Widget]
foozle = ...
It doesn’t matter what we put in place of dummy
; diagrams-haddock
is going to shortly replace it anyway. The stuff following the #
is a list of parameters to diagrams-haddock
: we tell it to insert here an image built from the diagram called foozleDia
, and that it should have a width of 300 pixels.
Now we just have to give a definition for foozleDia
, which we do simply by creating a code block (set off with bird tracks) in a comment:
-- | The foozle function takes a widget and turns it into an
-- infinite list of widgets which alternate between red and
-- yellow.
--
-- <<dummy#diagram=foozleDia&width=300>>
--
foozle :: Widget -> [Widget]
foozle = ...
-- > widget =
-- > ( stroke (circle 1.25 <> circle 0.75 # reversePath)
-- > <> mconcat (iterateN 10 (rotateBy (1/10)) (square 0.5 # translateX 1.3))
-- > )
-- > # lw 0
-- >
-- > foozleDia =
-- > hcat' with {sep = 2}
-- > [ widget # fc black
-- > , hrule 4 # alignR <> triangle 1 # rotateBy (-1/4) # fc black
-- > , hcat' with {sep = 0.5} (zipWith fc (cycle [red, yellow]) (replicate 6 widget))
-- > ]
Note that this definition for foozleDia
isn’t in a Haddock comment, so it won’t be typeset in the Haddock output. (However, if you want users reading your documentation to see the code used to generate the pictures—as, e.g., we often do in the documentation for diagrams
itself—it’s as simple as sticking the definitions in a Haddock comment.) It also doesn’t have to go right after the definition of foozle
—for example, we could stick it all the way at the end of the source file if we didn’t want it cluttering up the code.
Now we simply run diagrams-haddock
on our file (or on the whole Cabal
project), and it will generate an appropriate SVG image and replace <<dummy#…>>
with something like <<diagrams/foozleDia.svg#…>>
. The Haddock documentation now displays something like
after the documentation for foozle
. Hooray! Note that diagrams-haddock
only replaces the stuff before the #
(the clever bit is that browsers will ignore everything after the #
). Running diagrams-haddock
again at this point will do nothing. If we change the definition of foozleDia
and then rerun diagrams-haddock
, it will regenerate the image.
Okay, but how will others (or, for that matter, Hackage) be able to see the diagram for foozle
when they build the documentation, without needing diagrams-haddock
themselves? It’s actually fairly straightforward—we simply include the generated images in the source tarball, and tell cabal
to copy the images in alongside the documentation when it is built, using either a custom Setup.hs
, or (once it is released and sufficiently ubiquitous) the new extra-html-files:
field in the .cabal
file. The diagrams-haddock
documentation has full details with step-by-step instructions.
I hope this silly example has piqued your interest; again, for full details please consult the diagrams-haddock
documentation. Now go forth and illustrate your documentation!