Making the world a better place, one line of code at a time

Writing the endraw tag in Jekyll code blocks

Posted on Monday, June 10, 2013

Last time, we saw how to write about Jekyll tags in Jekyll-based blog posts, using HTML entities or the {% raw %} block.

These techniques cannot be used in syntax-highlighted code blocks (Jekyll’s {% higlight %} tag or a Markdown code block), since such blocks are always HTML-escaped. Instead, you can wrap all of the code in the block with a Liquid {% raw %} tag. Since the Liquid tag is processed before Markdown or syntax highlighting, this works perfectly.

{% raw %}
Liquid uses tags like {% if %} or {% for %}.
It also supports variable interpolation: {{ someVariable }}
{% endraw %}

This approach works wonderfully, until you try to put the {% endraw %} tag in a code block. You can’t put that in a {% raw %} block, because it will close the block. You can’t use entities, because text within highlighted code blocks is always HTML-escaped.

One potential option would be to break apart the tag; something like

{% raw %}
This is how you show the termination of the `{% raw %}` tag inside itself: 
{% endraw %}

However, due to a bug in Liquid, this doesn’t work correctly. This markup is supposed to mean the following:

  1. Write the literal text {% within the {% raw %} block
  2. Terminate the {% raw %} block with {% endraw %}
  3. Write the rest of the of the tag (endraw %})
  4. Re-enter the {% raw %} block to continue with other markup

What actually happens is that Liquid ignores the actual {% endraw %} command, and treats the entire line as raw text. In other words, the code you see in the above example is (incorrectly) rendered exactly as written. The literal text {% before the {% endraw %} causes Liquid to ignore the tag completely, breaking this technique.

To work around this bug, we need to put the {% text outside the {% raw %} block. However, Liquid does not have any way to escape a {, and we can’t use HTML escaping inside the highlighted code block, so there is no obvious way to write the {% without breaking the parser.

Variables can help here. We can create a Liquid variable that holds the literal text {%, then interpolate this variable outside the {% raw %} block. For example:

{% assign openTag = '{%' %}
{% raw %}
This is how you show the termination of the `{% raw %}` tag inside itself: 
{% endraw %}{{ openTag }} endraw %}{% raw %}
This content is back inside the {% raw %} block
{% endraw %}

This code is parsed like this:

  1. Terminate the {% raw %} block with {% endraw %}
  2. Write the value of the openTag variable ({%) with {{ openTag }}
  3. Write the remainder of the {% endraw %} tag as literal text with  endraw %}
  4. Re-enter the {% raw %} block for additional raw content

This technique can also be used to write tags in inline code: `{{ openTag }} sometag %}`

If these workarounds seem complicated, writing this post itself (also in Liquid Markdown!) was even more complicated.
See the source to see how I did it.

Categories: Jekyll, Liquid, jekyll-hacks Tweet this post

comments powered by Disqus