Files
hotdog-cms/internal/site/text.go
T
jcoffey-dev a8f0227a58 What the jcoffey.dev port needed: pagination, tags, redirects, RSS, search
Pagination for lists and tag pages; tag spellings merged regardless of hyphens and #, labelled by the spelling used most, with term_index_min for thin pages; redirects as fallback pages plus 301 rules in container images; RSS 2.0 feeds; markdown autolink, external_links: new_tab and trust_html; reading time and summaries computed from the Markdown; a page's lead image for its social card; per-collection search indexes; and template helpers (excerpt, termURL, formatDate, fileHash, imageSize, pageAt, concat, cond, email_off markers).
2026-10-10 13:42:46 -07:00

47 lines
1.4 KiB
Go

package site
import (
"regexp"
"strings"
)
var (
plainFenceRe = regexp.MustCompile("(?s)```.*?```")
plainImageRe = regexp.MustCompile(`!\[[^\]]*\]\([^)]*\)`)
plainLinkRe = regexp.MustCompile(`\[([^\]]*)\]\([^)]*\)`)
plainTagRe = regexp.MustCompile(`<[^>]+>`)
plainMarkRe = regexp.MustCompile("[#>*_`~]+")
plainSpaceRe = regexp.MustCompile(`\s+`)
wordRe = regexp.MustCompile(`\p{L}[\p{L}'\-]*`)
)
// PlainMarkdown strips Markdown to bare words: no code blocks, images, link
// targets, HTML tags or emphasis marks.
func PlainMarkdown(md string) string {
s := plainFenceRe.ReplaceAllString(md, " ")
s = plainImageRe.ReplaceAllString(s, " ")
s = plainLinkRe.ReplaceAllString(s, "$1")
s = plainTagRe.ReplaceAllString(s, " ")
s = plainMarkRe.ReplaceAllString(s, "")
return strings.TrimSpace(plainSpaceRe.ReplaceAllString(s, " "))
}
// CountWords counts words the way a reader would: runs of letters, with
// apostrophes and hyphens allowed inside a word.
func CountWords(s string) int { return len(wordRe.FindAllStringIndex(s, -1)) }
// Excerpt is the plain text of some Markdown, cut at a word boundary to at
// most limit characters, with an ellipsis if anything was cut.
func Excerpt(limit int, md string) string {
s := PlainMarkdown(md)
r := []rune(s)
if len(r) <= limit {
return s
}
cut := string(r[:limit])
if i := strings.LastIndex(cut, " "); i > 0 {
cut = cut[:i]
}
return strings.TrimRight(cut, " ,;:.") + "…"
}