Files
go_typecho/utils/markdown.go
T

117 lines
3.4 KiB
Go

package utils
import (
"bytes"
"html/template"
"regexp"
"strings"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"
goldmarkhtml "github.com/yuin/goldmark/renderer/html"
)
// markdownEngine 全局 Markdown 渲染引擎
// 启用 GFM 扩展(表格、删除线、任务列表、自动链接等)
// 启用 WithUnsafe 允许原始 HTML 透传,兼容旧文章中的 HTML 内容
var markdownEngine = goldmark.New(
goldmark.WithExtensions(extension.GFM),
goldmark.WithRendererOptions(
goldmarkhtml.WithUnsafe(),
goldmarkhtml.WithHardWraps(),
),
)
// RenderMarkdown 将 Markdown 文本渲染为 HTML
func RenderMarkdown(source string) template.HTML {
var buf bytes.Buffer
if err := markdownEngine.Convert([]byte(source), &buf); err != nil {
// 渲染失败时原样返回,避免页面空白
return template.HTML(source)
}
return template.HTML(buf.String())
}
// 全局预编译正则(保持不变,但移除冗余)
var (
// 标题
reHeading = regexp.MustCompile(`(?m)^\s*#{1,6}\s+`)
// 无序列表
reUnorderedList = regexp.MustCompile(`(?m)^\s*[-*+]\s+`)
// 有序列表
reOrderedList = regexp.MustCompile(`(?m)^\s*\d+[.)]\s+`)
// 块引用
reBlockquote = regexp.MustCompile(`(?m)^\s*>\s+`)
// 水平线
reHr = regexp.MustCompile(`(?m)^\s*[-*_]{3,}\s*$`)
// 脚注定义
reFootnoteDef = regexp.MustCompile(`(?m)^\[\^.+?\]:\s.*$`)
// 引用定义
reRefDef = regexp.MustCompile(`(?m)^\s*\[.+?\]:\s*(.*)$`)
// 图片
reImage = regexp.MustCompile(`(?s)!\[.*?\]\(.*?\)`)
// 引用图片
reRefImage = regexp.MustCompile(`!\[.*?\](\[.*?\])?`)
// 链接
reLink = regexp.MustCompile(`(?s)\[(.*?)\]\(.*?\)`)
// 引用式链接
reRefLink = regexp.MustCompile(`\[([^\s=\[\]/]+)\](\[.*?\])?`)
// 粗体
reBoldStar = regexp.MustCompile(`(?s)\*\*(.*?)\*\*`)
// 斜体
reItalicStar = regexp.MustCompile(`(?s)\*(.*?)\*`)
// 下划线粗体
reBoldUnderscore = regexp.MustCompile(`(?s)_(.*?)_`)
// 下划线斜体
reItalicUnderscore = regexp.MustCompile(`(?s)_(.*?)_`)
// HTML 标签
reHTMLTag = regexp.MustCompile(`<[^>]+>`)
// 多余空白
reMultiSpace = regexp.MustCompile(`\s+`)
)
// GenerateSearchableText 提取 Markdown 中的纯文本
func GenerateSearchableText(raw string) string {
if raw == "" {
return ""
}
text := raw
// 全角空格转半角
text = strings.ReplaceAll(text, "\u3000", " ")
// 移除块级标记(一次性替换多个)
text = reHr.ReplaceAllString(text, "")
text = reBlockquote.ReplaceAllString(text, "")
text = reUnorderedList.ReplaceAllString(text, "")
text = reOrderedList.ReplaceAllString(text, "")
text = reHeading.ReplaceAllString(text, "")
// 移除引用定义
text = reFootnoteDef.ReplaceAllString(text, "")
text = reRefDef.ReplaceAllString(text, "")
// 移除图片
text = reImage.ReplaceAllString(text, "")
text = reRefImage.ReplaceAllString(text, "")
// 处理链接:保留可见文字(先引用式后内联)
text = reRefLink.ReplaceAllString(text, "$1")
text = reLink.ReplaceAllString(text, "$1")
// 移除粗体
text = reBoldStar.ReplaceAllString(text, "")
text = reBoldUnderscore.ReplaceAllString(text, "")
// 移除斜体
text = reItalicStar.ReplaceAllString(text, "")
text = reItalicUnderscore.ReplaceAllString(text, "")
// 移除 HTML 标签
text = reHTMLTag.ReplaceAllString(text, "")
// 压缩空白
text = reMultiSpace.ReplaceAllString(text, " ")
return strings.TrimSpace(text)
}