External Links
Hugo is a pretty good templating thing
The only complaint that I’ve had is that I tend to place a lot of links in my articles, and I’d like people to read those links, but eventually come back to my article.
So, I’d prefer if those links all, by default, opened in new tabs.
And I couldn’t figure out how to get the default []() links to open in a new window, so I added a Hugo-specific shortcode:
{{ <external-link "link_text" "link"> }}
that works, but is my only major break from using native markdown on this blog, and today, I just got tired of it, and decided to see if I could fix it properly.
Luckily, one prompt to Gemini told me that it was pretty easy, and the reason I was missing this easy fix is because by default, my Hugo theme does not expose how the markdown links are rendered (as it’s a pretty expected behavior that most people don’t change), and I just had to add a folder and make a specifically named file in it.
Here, I could define how a link is supposed to be handled, and here it is:
In themes/etche/layouts/_default/_markup/render-link.html,
put in
<a href="{{ .Destination }}"{{ with .Title }} title="{{ . }}"{{ end }} target="_blank" rel="noopener noreferrer">
{{ .Text | safeHTML }}
</a>
It did give me a warning that internal (within the site) links might end up being opened in new tabs, but I didn’t observe that behavior in a little bit of testing.
That came to be a problem, as there are a few links that do direct to my own site, or I might otherwise want to stay ‘within the tab’.
So, I needed to do some more work.
Some prompting came up with this solution:
{{- $url := .Destination -}}
{{- $target := "_blank" -}}
{{- $rel := "noopener noreferrer" -}}
{{- if strings.HasSuffix $url "#self" -}}
{{- $url = strings.TrimSuffix "#self" $url -}}
{{- $target = "" -}}
{{- $rel = "" -}}
{{- end -}}
<a href="{{ $url | safeURL }}"{{ with .Title }} title="{{ . }}"{{ end }}{{ with $target }} target="{{ . }}"{{ end }}{{ with $rel }} rel="{{ . }}"{{ end }}>{{ .Text | safeHTML }}</a>
Which just says if the url ends with #self (which is probably uncommon for an actual link), then it sets teh target to “”, so it opens in the same tab.
And to clean it up, it trims off the #self from the URL so the user doesn’t notice anything different.
And before I replaced all my shortcode links with native markdown ones, I had to specify that the existing links are to be #self links…
which involves regex.
No Vim macros this time! That actually didn’t do a bad job when I converted all the markdown links to my custom Hugo shortcodes
So, I search for
([^!])\[(.+?)\]\((.+?)\)
which finds all the (non-image) links with a non-empty link and a href
and I replace it with
$1[$2]($3#self)
(I need that preceding $1 group because ^! matches any character that isn’t a ! so it was removing preceding spaces and other characters from links)
And to avoid it including the theme sample pages, I constricted the files to include to just
./content/
Finally, I can convert all my existing links, and for that, I turn to even more regex.
With this (super-readable) string of gobbledeygook, I’m able to find and replace all the external-link tags I’ve written over the last year or two.
I search for
\{\s*\{\s*<\s*external-link\s*"(.*?)"\s*?"(.*?)"\s*>\s*\}\s*\}
(I had a variety of spacing situations with these external-link tags)
and I replace with
[$1]($2)
199 links converted in one fell swoop. Clean.
Now, if only I could add word-wrap to my codeblocks…