Hugo Code Block Folding

Strictly speaking, it is not folding, it just limits the maximum height of code blocks, though the effect is quite good.

Steps

All of the following operations are performed in the root directory of the blog site.

Control the layout with css

First add a code.css to assets/css/extended/code.css, which limits the maximum height of code blocks via css, and can be adjusted according to your own blog layout.

1
nano assets/css/extended/code.css

Content:

1
2
3
4
.post-content pre code {
    max-height: 52em; /* Set the max height of the code block to xx times the parent font size */
    overflow: auto; /* Show a scrollbar when the code block content exceeds the max height */
}

Implement synchronized scrolling with js

However, this introduces a problem: when scrolling through a code block, the code scrolls but the line numbers do not scroll in sync. You need to add js code to make them scroll together.

1
2
cp themes/PaperMod/layouts/partials/extend_footer.html layouts/partials/
nano layouts/partials/extend_footer.html

Content:

Line number positioning stopped working after some update. I don’t plan to maintain it; use the collapse shortcode instead.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{{- /* Footer custom content area start */ -}}
{{- /* Insert any custom code web-analytics, resources, etc. here */ -}}
{{- /* Footer custom content area end */ -}}

{{- if (and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") (.Param "ShowCodeCopyButtons")) }}
<script>
// Synchronize scrolling between the code block and the line numbers.
// After the page loads, match up the code block and line-number containers and bind scroll events
window.addEventListener('load', function () {
  // Get the code block and line-number container elements
  var codeContainers = document.querySelectorAll('.highlight code[class^="language-"]');
  var lineNumbersContainers = document.querySelectorAll('.highlight code[class^="hljs "]');

  // Add the scroll event listener
  var isScrollSyncing = false; // Flag indicating whether a scroll-sync operation is in progress

  codeContainers.forEach(function (container, index) {
    container.addEventListener('scroll', function () {
      if (!isScrollSyncing) {
        isScrollSyncing = true;
        // Set the line-number container's scroll position to the same value
        lineNumbersContainers[index].scrollTop = container.scrollTop;
        isScrollSyncing = false;
      }
    });
  });

  lineNumbersContainers.forEach(function (container, index) {
    container.addEventListener('scroll', function () {
      if (!isScrollSyncing) {
        isScrollSyncing = true;
        // Set the code block container's scroll position to the same value
        codeContainers[index].scrollTop = container.scrollTop;
        isScrollSyncing = false;
      }
    });
  });
});
</script>
{{- end }}

Additional Notes

Thanks to the extensibility of Hugo and the extension interface provided by the PaperMod theme, rich effects can be achieved quite easily.

I also reviewed my frontend coding style and was forced to debug the issue of scrolling not staying in sync. That is the nice thing about frontend development: what you see is what you get. With a browser you don’t even need to set up an environment, haha.

Finally, thanks to Sulv’s blog for the idea, see Git for Sulv’s Blog.

References