# 3.26 lightyears away

As I promised earlier I’d like to give you some insight into this blogs inner workings, in the hopes that it proofs useful to somebody else. To start of we get into the topic of my additionally keywords.

In my previous Jekyll setup I had added keywords to embed youtube and vimeo videos by writing the following (I only give you the youtube version, I trust in your imagination that get how it’s done for vimeo).

{% youtube $vid %} This would insert the following markup: <div class="elastic-container"> <iframe src="//www.youtube.com/embed/$vid$" frameborder="0" allowfullscreen/> </div> With some additional CSS voodoo for the elastic-container, you can read up on here, this makes a responsive video. Since I would probably forget the elstic-container 9 out of 10 times and resizing my browser before deploying the site will probably not find it’s way into my usual workflow, I had to rebuild this feature for Hakyll. ## Ad hoc parsing Doing this in Hakyll is quite easily done with regular expression magic. And since I programmed in perl for a long time, I could probably do that very quickly. Especially since I could just have lifted it from this description, of a similar use case. The bad thing about this ad hoc parsing is, that I would have to either hard code the substitution or go with some file reading process. And since the later would amount to about the same amount of work a proper solution would, I opted for a that. ## Parsec to the rescue What is a proper solution you might ask. The answer is easy I added a compiler stage before the pandoc compiler. I first rely on Hakyll to parse the Markdown files into a Compiler (Item String) and then parse the String for my Keywords which start with a §. With a little bit of Parsec magic this looks like this in Haskell: simpleIdParserGenerator :: String -> (String -> KeywordElement) -> Parser KeywordElement simpleIdParserGenerator identifier constructor = try$ do
void $string ("§"++ identifier ++ "(") id <- many1$ noneOf ")"
void $string ")§" return$ constructor id

slideshare :: Parser KeywordElement
slideshare = simpleIdParserGenerator "slideshare" SlideShare

vimeo :: Parser KeywordElement
vimeo = simpleIdParserGenerator "vimeo" Vimeo

As you can see I generalised a parser where you can take any Keyword that is just followed by an id and have a parser generated for you. This parser just takes a “§” followed by an identifier like “youtube” and “(” any string as an id followed by an “)§”. And returns whatever is generated by the supplied constructor. Should any service come up with the idea of using § in their id’s I’d have to change this so some form of escaping works inside of the ids, but that is currently not necessary (I think).

There are some additional parsers that deal with Chunks of text that do not contain §’s at all, Escaped §’s and Tikz pictures, which I will get to in a later post.

## Writing stage

After I now have a parsed String I simply need to write the matching substitution. And Since I didn’t want to hard code the output in the Haskell files, I had to come with a different solution. Fortunately Hakyll already provides a Template facility which is perfect for this purpose. Writing out a Youtube video than simply looks like this:


externalResource :: Identifier -> String -> String -> Compiler (Item String)
externalResource templateId fieldName id = do
makeItem ""
>>= loadAndApplyTemplate templateId (constField fieldName id)

youtube :: String -> Compiler (Item String)
youtube = externalResource "templates/youtube.html" "vid"

With the template being the example from above.

With similar code for Chunk, Youtube and Vimeo video and so on this results in a Compiler String for every parsed keyword. So in the end all of it has to be regrouped into a single Compiler (Item String) which this code snippet does.


applyKeywords :: Compiler (Item String)
applyKeywords = do
b <- getResourceBody
aplKeywords b

aplKeywords :: Item String -> Compiler (Item String)
aplKeywords item = do
body <- applyKeywords' $readKeywords$ itemBody item
return $itemSetBody body item applyKeywords' :: Keywords -> Compiler String applyKeywords' kws = do items <- sequence$ map applyKWs $unKeyword kws return$ concat $map itemBody items where applyKWs (Chunk c) = makeItem c applyKWs (Escaped) = makeItem "§" applyKWs m@(Youtube vid) = youtube vid applyKWs m@(Vimeo vid) = vimeo vid applyKWs t@(Tikz _ _) = makeItem$ processTikZs t
applyKWs (SlideShare sid) = slideShare sid


As you can see adding another Keyword is easy and so after I was done with the video snippets I added SlideShare embedding.

The idea and implementation is obviously heavily influenced by Hakyll’s own Template compiler, except maybe from slight changes in the writing phase.

So once again hooray for open source software.

The only thing remaining is to add applyKeywords to your compiler stage like this:

match "posts/*" $do route$ idRoute
compile $do pandocCompiler <$> applyKeywords
>>= loadAndApplyTemplate "templates/main.html" (taggedPostCtx tags)

(Disclaimer: I added more stuff to the compiler so you won’t find these exact lines in the code of this page)

## Show me the code

I’d really like you to build on this. And if you have additional Keywords you like to add, just do so and drop me a line, maybe they are useful for me too.

If you are interested, you can find the parsing stage here and writing out stage here. As well as the whole code of this blog in the surrounding github repository.

And now go and have fun with it.