Labeling code blocks in ox-hugo

By chance, I’v stumbled over an excellent article1 about labeling code blocks in hugo.
Roger’s article answers a major part of a question2 of mine:

How to visually distinguish between blocks of source code and result

Problems

There’s no not enough visual difference between the blocks of code and result

print("foo")
foo

The code’s filepath must be written out to be displayed to the reader.

Regardless if it’s already stored as tangle header argument3, the filepath must be written twice in order to be visible

That means alongside :tangle xyz.py, I must as well write as a comment # xyz.py to show what is meant.

#+begin_src python :tangle xyz.py
# xyz.py
print("foo")
#+end_src

Solution

We distinguish the code block by adding a label above it.

Before:

print("foo")

After:

xyz.py
print("foo")

What happens

Input org mode file:

#+begin_src python :tangle /tmp/foo.py
print("foo")
#+end_src

Output markdown file:

```python { tangle_filepath="/tmp/foo.py" }
print("foo")
```

Final rendered html:

/tmp/foo.py
print("foo")

If not necessary, we can easily disable4 the tangle function while still having access to the arguments value.

How it works

Instead of adding the filename verbatim as comment #xyz.py like in code block, we intercept the value of :tangle.
That intercepted value then is passed, parsed and rendered as an additional html element named <figcaption> right above the code block.

My contribution is in two parts:

Adding a custom markup renderer

By combining parts of Roger’s instructions5 and the example in the hugo documentation, I’ve come up whith his custom code block

/hugo-flex/layouts/_default/_markup/render-codeblock.html
{{- with .Attributes.tangle_filepath }}
<figcaption>
  <span>{{ . }}</span>
</figcaption>
{{- end }}
{{ $result := transform.HighlightCodeBlock . }}
{{ $result.Wrapped }}

Adding some new logic to ox-hugo.el

  1. First I’ve added a variable named tangle_filepath to the mighty ox-hugo.el6.
  2. Second I’ve added some logic to convert the :tangle parameter in the org mode file to an info-string7 in the rendered markdown.

Both additions are highlighted below

diff --git a/ox-hugo.el b/ox-hugo.el
index 469002a..0a66f6b 100644
--- a/ox-hugo.el
+++ b/ox-hugo.el
@@ -3471,6 +3471,11 @@ their Hugo site's config."
      ;; Regular src block.
      (t
       (let* (;; See `org-element-src-block-parser' for all SRC-BLOCK properties.
+             (tangle-filepath
+              (let ((tangle-value (cdr (assoc :tangle parameters))))
+                (if (or (null tangle-value) (string= tangle-value "no"))
+                    nil
+                  tangle-value)))
              (line-num-p (org-element-property :number-lines src-block)) ;Non-nil if -n or +n switch is used
              (linenos-style (or (cdr (assoc :linenos parameters))
                                 ;; If `org-hugo-src-block' is called from
@@ -3572,6 +3577,11 @@ their Hugo site's config."
               (setq code-attr-str (format "%s, hl_lines=%s" code-attr-str hl-lines))
             (setq code-attr-str (format "hl_lines=%s" hl-lines))))

+        (when tangle-filepath
+          (if (org-string-nw-p code-attr-str)
+              (setq code-attr-str (format "%s, tangle_filepath=\"%s\"" code-attr-str tangle-filepath))
+            (setq code-attr-str (format "tangle_filepath=\"%s\"" tangle-filepath))))
+
         (when code-refs
           (let* ((anchor-prefix (cdr code-refs-and-anchor))
                  (anchor-str (format "anchorlinenos=true, lineanchors=%s" anchor-prefix)))

CSS styling

Literally similar to Roger’s article1: “I’ll leave the styling (of the figcaption html element) as an exercise for the reader”.