55 lines
1.7 KiB
Go
55 lines
1.7 KiB
Go
package store
|
|
|
|
import (
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// linkPattern findet Verweise der Form [[slug]] im Inhalt eines Eintrags.
|
|
//
|
|
// Die Schreibweise stammt aus Wiki-Systemen und ist Menschen wie KI-Werkzeugen
|
|
// vertraut. Sie hat einen praktischen Vorzug gegenüber Markdown-Links: Sie
|
|
// enthält nur den Bezeichner, keine URL — die Verweise bleiben also gültig,
|
|
// wenn sich Adressen ändern, und sie sind ohne Kontextwissen erkennbar.
|
|
//
|
|
// Erlaubt ist derselbe Zeichenvorrat wie bei Slugs (siehe ValidSlug). Damit wird
|
|
// aus "[[siehe hier]]" kein Verweis — das ist gewollt, sonst würde jede eckige
|
|
// Klammer im Text zu einem Falschtreffer.
|
|
var linkPattern = regexp.MustCompile(`\[\[([a-z0-9][a-z0-9_-]{0,63})\]\]`)
|
|
|
|
// ExtractLinks liest alle [[slug]]-Verweise aus einem Text.
|
|
// Das Ergebnis ist sortiert und ohne Dubletten — ein zweiter Verweis auf dasselbe
|
|
// Ziel ist keine zusätzliche Information.
|
|
func ExtractLinks(content string) []string {
|
|
treffer := linkPattern.FindAllStringSubmatch(content, -1)
|
|
if len(treffer) == 0 {
|
|
return nil
|
|
}
|
|
|
|
gesehen := make(map[string]bool, len(treffer))
|
|
var ziele []string
|
|
|
|
for _, t := range treffer {
|
|
ziel := t[1]
|
|
if gesehen[ziel] {
|
|
continue
|
|
}
|
|
gesehen[ziel] = true
|
|
ziele = append(ziele, ziel)
|
|
}
|
|
|
|
sort.Strings(ziele)
|
|
return ziele
|
|
}
|
|
|
|
// ReplaceLinks ersetzt jeden [[slug]]-Verweis durch das Ergebnis von fn.
|
|
//
|
|
// Wird beim Rendern verwendet, um aus den Verweisen echte Links zu machen. Die
|
|
// Ersetzungsfunktion bekommt den Slug und liefert den Ersatztext.
|
|
func ReplaceLinks(content string, fn func(slug string) string) string {
|
|
return linkPattern.ReplaceAllStringFunc(content, func(treffer string) string {
|
|
slug := strings.TrimSuffix(strings.TrimPrefix(treffer, "[["), "]]")
|
|
return fn(slug)
|
|
})
|
|
}
|