Refactor tag rendering to avoid recreating goldmark instance for each message

This commit is contained in:
Tulir Asokan
2023-01-30 00:42:20 +02:00
parent 694733a4e9
commit e7615ef4be
3 changed files with 45 additions and 32 deletions

View File

@@ -33,9 +33,16 @@ import (
"maunium.net/go/mautrix/util/variationselector"
)
var discordExtensions = goldmark.WithExtensions(extension.Strikethrough, mdext.SimpleSpoiler, mdext.DiscordUnderline, &DiscordEveryone{})
// escapeFixer is a hacky partial fix for the difference in escaping markdown, used with escapeReplacement
//
// Discord allows escaping with just one backslash, e.g. \__a__,
// but standard markdown requires both to be escaped (\_\_a__)
var escapeFixer = regexp.MustCompile(`\\(__[^_]|\*\*[^*])`)
func escapeReplacement(s string) string {
return s[:2] + `\` + s[2:]
}
// indentableParagraphParser is the default paragraph parser with CanAcceptIndentedLine.
// Used when disabling CodeBlockParser (as disabling it without a replacement will make indented blocks disappear).
type indentableParagraphParser struct {
@@ -48,24 +55,24 @@ func (b *indentableParagraphParser) CanAcceptIndentedLine() bool {
return true
}
func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string) string {
text = escapeFixer.ReplaceAllStringFunc(text, func(s string) string {
return s[:2] + `\` + s[2:]
})
var discordRenderer = goldmark.New(
goldmark.WithParser(mdext.ParserWithoutFeatures(
parser.NewListParser(), parser.NewListItemParser(), parser.NewHTMLBlockParser(), parser.NewRawHTMLParser(),
parser.NewSetextHeadingParser(), parser.NewATXHeadingParser(), parser.NewThematicBreakParser(),
parser.NewLinkParser(), parser.NewCodeBlockParser(),
)),
goldmark.WithParserOptions(parser.WithBlockParsers(util.Prioritized(defaultIndentableParagraphParser, 500))),
format.HTMLOptions,
goldmark.WithExtensions(extension.Strikethrough, mdext.SimpleSpoiler, mdext.DiscordUnderline, ExtDiscordEveryone, ExtDiscordTag),
)
mdRenderer := goldmark.New(
goldmark.WithParser(mdext.ParserWithoutFeatures(
parser.NewListParser(), parser.NewListItemParser(), parser.NewHTMLBlockParser(), parser.NewRawHTMLParser(),
parser.NewSetextHeadingParser(), parser.NewATXHeadingParser(), parser.NewThematicBreakParser(),
parser.NewLinkParser(), parser.NewCodeBlockParser(),
)),
goldmark.WithParserOptions(parser.WithBlockParsers(util.Prioritized(defaultIndentableParagraphParser, 500))),
format.HTMLOptions, discordExtensions,
goldmark.WithExtensions(&DiscordTag{portal}),
)
func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string) string {
text = escapeFixer.ReplaceAllStringFunc(text, escapeReplacement)
var buf strings.Builder
err := mdRenderer.Convert([]byte(text), &buf)
ctx := parser.NewContext()
ctx.Set(parserContextPortal, portal)
err := discordRenderer.Convert([]byte(text), &buf, parser.WithContext(ctx))
if err != nil {
panic(fmt.Errorf("markdown parser errored: %w", err))
}