Include code from a file with Hugo
First of all, all credit goes to Marcus Olsson [1] who pretty much wrote this Hugo Shortcode [2] which I only have made some small changes to.
I also refer to his post [3] for a good explaination on how it works.
Background
I prepare for some bigger posts with a lot of code examples where I only want to show fragments of a whole file. I found this shortcut and it fits my needs perfect.
Usage
My file, examples/main.c, has the following content:
1#include <stdio.h>
2
3//BEGIN foo
4void foo()
5{
6 printf("foo\n");
7}
8//END foo
9
10//BEGIN bar
11int bar()
12{
13 printf("foobar\n");
14 return 0;
15}
16//END bar
17
18
19// BEGIN main
20int main()
21{
22 printf("Hello world\n");
23 return 0;
24}
25// END main
It wraps each function in a BEGIN and END tag. Then
{{ < code language="C" source="examples/main.c" >}}
prints the whole file without the BEGIN & END tags:
1#include <stdio.h>
2
3void foo()
4{
5 printf("foo\n");
6}
7
8int bar()
9{
10 printf("foobar\n");
11 return 0;
12}
13
14
15int main()
16{
17 printf("Hello world\n");
18 return 0;
19}
Or I can use the id parameter to specify which snippet to display:
{{ < code language="C" source="examples/main.c" id="foo">}}
Which gives us:
1void foo()
2{
3 printf("foo\n");
4}
The shortcut
My changes
I wanted to be able to print the whole file without the BEGIN and END tags, so I simply remove them from then output snippet. That is pretty much it.
Shortcut
To use this shortut, create a new file at layout/shortcodes/code.html with the following content:
1{{ $language := .Get "language" }}
2{{ $source := .Get "source" }}
3{{ $options := .Get "options" }}
4{{ $id := .Get "id" }}
5
6{{ with $source | readFile }}
7 {{ $snippet := . }}
8 {{ $lines := split $snippet "\n" }}
9 {{ $startTag := printf "BEGIN %s" $id }}
10 {{ $endTag := printf "END %s" $id }}
11
12 {{ if $id }}
13 {{ $startl := -1 }}
14 {{ $endl := -1 }}
15
16 {{/* Find the lines that ends with the start and end tags. */}}
17 {{ range $index, $line := $lines }}
18 {{ if hasSuffix $line $startTag }}
19 {{ $startl = $index }}
20 {{ else if hasSuffix $line $endTag }}
21 {{ $endl = $index }}
22 {{ end }}
23 {{ end }}
24
25 {{/* Let's add some basic assertions. */}}
26 {{ if lt $startl 0 }}
27 {{ errorf "Named snippet is missing BEGIN tag" }}
28 {{ end }}
29
30 {{ if lt $endl 0 }}
31 {{ errorf "Named snippet is missing END tag" }}
32 {{ end }}
33
34 {{/* Size of the snippet in number of lines. */}}
35 {{ $snippetLen := sub (sub $endl $startl) 1 }}
36
37 {{/* Create slice with only the lines between the tags. */}}
38 {{ $includedLines := first $snippetLen (after (add $startl 1) $lines) }}
39
40 {{/* Join the lines into the final snippet. */}}
41 {{ $snippet = delimit $includedLines "\n" }}
42 {{else}}
43
44 {{ $snippet = "" }}
45 {{ range $index, $line := $lines }}
46 {{ if strings.Contains $line $startTag }}
47 {{ else if strings.Contains $line $endTag }}
48 {{ else }}
49 {{ $snippet = (print $snippet "\n" $line) }}
50 {{ end }}
51 {{ end }}
52
53 {{end}}
54 {{ highlight (trim $snippet "\n\r") $language $options }}
55{{ end }}
And you are ready to go.