Intertwingling AsciiDoc and Hugo ☯︎
Updated  2022-September-16

Page contents

News

2022-December-21  As of today, this evolving⁠[1] article has been on the web for 2 years.🎂🎂

2021-December-17  Hugo v0.91.0 released and, as of this version, asciidoctor must explicitly be allowed in a Hugo config file’s security block. Details are in Infinite Ink’s Configuring Security in Hugo.

 

1. My journey with AsciiDoc and Hugo

For a long time I’ve wanted to modernize the Infinite Ink website and in 2017,⁠[2] I tentatively decided to use the AsciiDoc markup language and the Hugo static site generator to do that. I chose AsciiDoc because I wanted to use a lightweight markup language that is richer and more standardized than Markdown. I chose Hugo because I wanted a generator that supports AsciiDoc and has no dependencies (other than an implementation of AsciiDoc such as Asciidoctor).

For more than two years, this decision was tentative and I wrote my articles in pure AsciiDoc. This involved…

In 2020, I decided to no longer be tentative about this and to no longer write in pure AsciiDoc. Instead, I now promiscuously use Hugo shortcodes throughout my writing. This means that for the Infinite Ink website, AsciiDoc and Hugo are intertwingled and if I ever decide to change either my markup language or site generator, it will be a PITA. In other words, I’m committed to this AsciiDoc+Hugo marriage and I hope it works out!🤞

 

2. Using Hugo’s markup.asciidocExt site variable to configure AsciiDoc

Starting with Hugo v0.74.0, which was released 2020-July-13, you can configure AsciiDoc in your Hugo config file. Here is an excerpt of Infinite Ink’s config.yaml:

markup:
 asciidocExt:
  preserveTOC: true
  workingFolderCurrent: false  # default is false
  attributes:
   toc: macro
   hide-uri-scheme: true@  # trailing @ means ok to override
   sectlinks: true
   octothorpe: #  # hash
   colon: :
   rsolidus: \  # backslash
   underscore: _

 

Note:

  • The hide-uri-scheme attribute hides the scheme part, such as https://, of a raw URI. For example, if https://www.ii.com is in a source file, it will be displayed as www.ii.com in the rendered destination file. An article where I turned off this attribute (via :!hide-uri-scheme:)⁠[4] is Infinite Ink’s AsciiDoc Kitchen Sink.

  • The emphasized workingFolderCurrent and sectlinks settings are discussed in section 5 below.

 

3. Highlighting code blocks

Asciidoctor supports code-block syntax highlighting, but it involves installing and maintaining a Ruby gem. Instead of messing around with Ruby, I prefer to use Hugo’s built-in highlight shortcode.

Here is the source code behind the YAML fragment in the previous section that is displayed with syntax highlighting.

{{< highlight yaml "hl_lines=4 8" >}}
markup:
 asciidocExt:
  preserveTOC: true
  workingFolderCurrent: false  # default is false
  attributes:
   toc: macro
   hide-uri-scheme: true@  # trailing @ means ok to override
   sectlinks: true
   octothorpe: &#35;  # hash
   colon: &#58;
   rsolidus: &#92;  # backslash
   underscore: &#95;
{{< /highlight >}}

The first and last lines of this source code call Hugo’s built-in highlight shortcode. To learn about this shortcode, see the highlight section of Infinite Ink’s Hugo Shortcodes.

 

4. Using Hugo shortcodes for reusable snippets

Before my decision to commit to AsciiDoc+Hugo, all my reusable content snippets were in AsciiDoc attributes and AsciiDoc includes. I now use Hugo shortcodes for some AsciiDoc content snippets. Below is an example of one of Infinite Ink’s snippets.

 

Example of a Hugo shortcode written in AsciiDoc markup

The following Hugo shortcode comprises pure AsciiDoc markup at the top and a Go Template comment block at the bottom.

Source of a shortcode named hugo-home-v-index.adoc
The home page layout file can be named either `home.html` or `index.html`.
I prefer to name it `home.html` because the word `index` is
https://wikipedia.org/wiki/Semantic_overload[semantically overloaded,title="'Semantic overload' at Wikipedia"]
in Hugo.

{{- /*

USAGE: {{% snippets/hugo-home-v-index %}}
PATH: layouts/shortcodes/snippets/hugo-home-v-index.adoc

N2S: This entire file is *published* in intertwingling-asciidoc-hugo

*/ -}}

This shortcode is rendered…

 

💡
  • This shortcode uses AsciiDoc syntax and is meant to be used in an AsciiDoc (.ad, .adoc, or .asciidoc) content source file and called with the {{% and %}} shortcode delimiters (not the {{< and >}} shortcode delimiters).

  • To use this snippet as a footnote, the following syntax works:
    footnote:[{{% snippets/hugo-home-v-index %}}]

  • To avoid whitespace problems, the snippet begins on the first line of the shortcode file and the comment, which is below the snippet, uses the Go Template trim-⁠whitespace comment style.

  • This shortcode is named hugo-home-v-index.adoc but, as far as I can tell, Hugo ignores its file extension (.adoc). The file extension is basically just a note to self in this particular situation.⁠[5]

 

5. Using AsciiDoc includes for reusable snippets

An AsciiDoc include is better than a Hugo shortcode…

  • if the snippet resides somewhere other than a project’s layouts/shortcodes/ directory, which is where Hugo reusable shortcodes must reside,

  • or if you do not want the safety features that Hugo shortcodes (and Go Templates in general) enforce,

  • or if you want to use an AsciiDoc include feature, such as

    • indenting (or unindenting) lines,

    • level offsetting,

    • or including only specific lines.

 

Example of an AsciiDoc include

In the source code of section 3 of Infinite Ink’s Linkified Section Headings in Hugo-⁠Generated Web Pages, I use the following AsciiDoc include to display lines 1, 2, and 3 of the Infinite Ink render hook located at layouts/_default/_markup/render-heading.html.

include::layouts/_default/_markup/render-heading.html[lines=1..3]

To display all lines of an AsciiDoc include file, use the following syntax.

include::layouts/_default/_markup/render-heading.html[]

This second AsciiDoc include line is used in the source code of this section of this page and is rendered right here:

<h{{ .Level }} id="{{ .Anchor | safeURL }}">
         <a href="#{{ .Anchor | safeURL }}">{{ .Text | safeHTML }}</a>
</h{{ .Level }}>

{{- /* 

PATH: layouts/_default/_markup/render-heading.html
FORKED FROM: https://gohugo.io/getting-started/configuration-markup/#heading-link-example 

NOTE TO SELF:
* Lines 1-3 of this file are *published* in linkified-section-headings-in-hugo-generated-web-pages
* This entire file is *published* in intertwingling-asciidoc-hugo

*/ -}}

Note that this included file is a Hugo Markdown render hook and it does for Markdown what the sectlinks: true config setting (from section 2 above) does for AsciiDoc, i.e., linkify section headings. You can see it in action in Infinite Ink’s Ordinary and Extraordinary Markdown, which is an Infinite Ink page that’s written in Markdown rather than AsciiDoc or raw HTML.⁠[6]

 

  • In Asciidoctor and Hugo, forward slash (/) works as a directory path delimiter on any platform (including Windows).

  • In the above two AsciiDoc include directives, the relative path layouts/_default/_markup/ works…

    • because of the emphasized in workingFolderCurrent: false config setting (from section 2 above). This makes a path in an AsciiDoc include relative to the project’s root directory.

    • And because I cd to the project’s root directory before running the hugo command (as opposed to using hugo --source …).

  • In an AsciiDoc include file, Hugo shortcodes and Hugo emoji codes do not work.

 

Another example of an AsciiDoc include

In the source of Infinite Ink’s AsciiDoc Kitchen Sink, I use an include like this:

include::content/path/to/bundle/dir/include.forked.txt[leveloffset=+1]
                                                       ^^^^^^^^^^^^^^
                                                            Note

To learn about this, see:

 

6. Using Infinite Ink’s get-leaf-text shortcode to get a snippet in the current leaf bundle

If a snippet is used in only one page, you can turn that page into a Hugo bundle and put the snippet inside the bundle directory. This is what I did with the markup.asciidocExt snippet that is used in both sections 2 and 3 above. The directory structure of this page, which is a leaf bundle, looks like this:

2020-12-21-intertwingling-asciidoc-hugo/
├── index.adoc
└── markupdotasciidocext.yaml

 

In index.adoc, the source code of section 2 includes this fragment:

{{< highlight yaml "hl_lines=4 8" >}}
{{% get-leaf-text "markupdotasciidocext.yaml" %}}
{{< /highlight >}}

 

And the source code of section 3 includes this fragment:

[%nowrap]
----
{{</* highlight yaml "hl_lines=4 8" */>}}
{{% get-leaf-text "markupdotasciidocext.yaml" %}}
{{</* /highlight */>}}
----

Note:

 

To learn about Infinite Ink’s get-leaf-text custom shortcode, see the get-leaf-text section of Infinite Ink’s Hugo Shortcodes.

 

See also

Endnotes


1. Many Infinite Ink articles, including this one, are evergreen and regularly updated.
2. You can see the evolution of my thoughts about the modernization of the Infinite Ink website on Infinite Ink’s To-⁠Do, Doing, and Done Lists⁠👷‍♀ starting in the section ~2013–2016 and scrolling up.
3. An example of an AsciiDoc Document Header is in the AsciiDoc section of Infinite Ink’s Linkified Section Headings in Hugo-⁠Generated Web Pages.
4. :!hide-uri-scheme: is equivalent to :hide-uri-scheme!:.
5. In Hugo, a file extension is usually meaningful and affects how Hugo processes a file, but that does not seem to be the case in this situation.
6. All Infinite Ink pages published in the 1990s were written in raw HTML. Most Infinite Ink pages published in 2019, 2020, 2021 and 2022 were written in AsciiDoc. (If you’re wondering what happened in between, I was publishing via Blogger, Tumblr, Twitter, GitHub, GitBook, etc.)

Feedback 📝 🤔 👎 👍