From 857f8c97ebc5724f4c34931ba497425e7653894e Mon Sep 17 00:00:00 2001 From: nytpu Date: Thu, 4 Nov 2021 11:04:50 -0600 Subject: [PATCH] Generate anchor links for headings This will generate `id` attributes for all heading levels. The labels are generated using steps 1-4 of the gitlab flavored markdown algorithm which seems to be pretty standard for generating anchors: https://docs.gitlab.com/ee/user/markdown.html#header-ids-and-links A unique ID isn't appended to avoid having to store a list of previous headers to compare against. --- main.go | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 2b227a0..c96b8a1 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( "os" "strings" "time" + "unicode" "git.sr.ht/~adnano/go-gemini" "git.sr.ht/~sircmpwn/getopt" @@ -24,11 +25,11 @@ var gemtextPage = template.Must(template. "heading": func(line gemini.Line) *GemtextHeading { switch l := line.(type) { case gemini.LineHeading1: - return &GemtextHeading{1, string(l)} + return &GemtextHeading{1, string(l), createAnchor(string(l))} case gemini.LineHeading2: - return &GemtextHeading{2, string(l)} + return &GemtextHeading{2, string(l), createAnchor(string(l))} case gemini.LineHeading3: - return &GemtextHeading{3, string(l)} + return &GemtextHeading{3, string(l), createAnchor(string(l))} default: return nil } @@ -147,7 +148,7 @@ var gemtextPage = template.Must(template. {{- with . | heading }} {{- $isList = false -}} - {{.Text}} + {{.Text}} {{- end -}} {{- with . | link }} @@ -388,8 +389,24 @@ type InputContext struct { } type GemtextHeading struct { - Level int - Text string + Level int + Text string + Anchor string +} + +func createAnchor(heading string) string { + var anchor strings.Builder + prev := '-' + for _, c := range heading { + if unicode.IsLetter(c) || unicode.IsDigit(c) { + anchor.WriteRune(unicode.ToLower(c)) + prev = c + } else if (unicode.IsSpace(c) || c == '-') && prev != '-' { + anchor.WriteRune('-') + prev = '-' + } + } + return strings.ToLower(anchor.String()) } func proxyGemini(req gemini.Request, external bool, root *url.URL,