Gemini and Hugo
For a few years, I have been using Hugo, a static site generator, to produce these pages.
At the same time very fast and corresponding perfectly to my needs, it is above all very modular. I was therefore little surprised to see that it was quite easy to convert, with little effort, my site for the Gemini protocol. Let’s see how!
Declaring Gemini as an output format
Hugo can output content in multiple formats: most of them are already predefined, but it is also possible to create your own. This is what we are going to do for Gemini.
First, in the configuration file config.yml
we will declare a new type text/gemini
with the file suffix .gmi
:
mediaTypes:
text/gemini:
suffixes:
- "gmi"
Once this is done, we declare a new output format, which uses this type, which is given the name GEMINI
.
This is an opportunity to specify the protocol for our links (gemini://
) and to build the site to a separate folder (gemini
) which will make it easier to export the files to our server:
outputFormats:
Gemini:
name: GEMINI
isPlainText: true
isHTML: false
mediaType: text/gemini
protocol: "gemini://"
permalinkable: true
path: "gemini/"
Finally, it only remains to ask Hugo to generate pages for the different contents. For example, in my case:
outputs:
home: ["HTML", "RSS", "GEMINI"]
page: ["HTML", "GEMINI"]
Layouts
To be able to generate the files, it is now necessary to create layouts to see how to display them!
To start with the index, we can start with layout/index.gmi
. In my case, it’s a simple text, followed by a list of posts:
Hello world!
{{ range (where .Site.Pages "Section" "articles") }}
=> {{ replace .Permalink "/gemini" "" 1}} {{ .Title }}
{{ end }}
As you noted, I have to manually remove references to the /gemini
subpath to prevent them from appearing in the links.
For posts, we can create a layout/_default/single.gmi
. Basically, it would suffice to display the title and content:
# {{ .Title }}
{{ .RawContent }}
Nevertheless, it is possible to process it with some filters to adapt the content in markdown. For example, the following lines allow you to remove the inline code or italics :
{{ $content := .RawContent -}}
{{ $content := $content | replaceRE "`(.+?)`" "$1" -}}
{{ $content := $content | replaceRE "`" "```" -}}
{{ $content := $content | replaceRE "\\*(.+?)\\*" "$1" -}}
{{ $content }}
Finally, I use these two following lines for the links. The first one converts an inline link into a gemini link, isolated. The second converts links that are already on an isolated line into a gemini link more easily.
{{ $content := $content | replaceRE " \\[(.+?)\\]\\((.+?)\\)" "\n\n=> $2 $1\n\n" -}}
{{ $content := $content | replaceRE "\\[(.+?)\\]\\((.+?)\\)" "=> $2 $1" -}}
I also like to add links for previous and next articles with:
{{ if .Next }}=> {{ replace .Next.Permalink "/gemini" "" 1}} ← Newer: {{ .Next.Title }}{{ end }}
{{ if .Prev -}}=> {{ replace .Prev.Permalink "/gemini" "" 1}} → Older: {{ .Prev.Title }}{{- end }}
Export
I use rsync
to easily export my files to the server. The public
folder locally should be exported to /var/www
remotely, without public/gemini
, which should be exported to /var/gemini
. I use:
hugo
rsync -avz --no-perms --no-owner --no-group \
--no-times --delete --exclude "gemini" \
public/ myserver:/var/www/sylvaindurand
rsync -avz --no-perms --no-owner --no-group \
--no-times --delete \
public/gemini/ vps:/var/gemini
rm -rf public
This last folder is then read by a gemini server, as explained in the previous article: