// Copyright (c) 2022 Tulir Asokan // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package format import ( "fmt" "strings" "github.com/yuin/goldmark" "github.com/yuin/goldmark/extension" "github.com/yuin/goldmark/renderer/html" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/format/mdext" ) const paragraphStart = "

" const paragraphEnd = "

" var Extensions = goldmark.WithExtensions(extension.Strikethrough, extension.Table, mdext.Spoiler) var HTMLOptions = goldmark.WithRendererOptions(html.WithHardWraps(), html.WithUnsafe()) var withHTML = goldmark.New(Extensions, HTMLOptions) var noHTML = goldmark.New(Extensions, HTMLOptions, goldmark.WithExtensions(mdext.EscapeHTML)) // UnwrapSingleParagraph removes paragraph tags surrounding a string if the string only contains a single paragraph. func UnwrapSingleParagraph(html string) string { html = strings.TrimRight(html, "\n") if strings.HasPrefix(html, paragraphStart) && strings.HasSuffix(html, paragraphEnd) { htmlBodyWithoutP := html[len(paragraphStart) : len(html)-len(paragraphEnd)] if !strings.Contains(htmlBodyWithoutP, paragraphStart) { return htmlBodyWithoutP } } return html } func RenderMarkdownCustom(text string, renderer goldmark.Markdown) event.MessageEventContent { var buf strings.Builder err := renderer.Convert([]byte(text), &buf) if err != nil { panic(fmt.Errorf("markdown parser errored: %w", err)) } htmlBody := UnwrapSingleParagraph(buf.String()) return HTMLToContent(htmlBody) } func HTMLToContent(html string) event.MessageEventContent { text := HTMLToMarkdown(html) if html != text { return event.MessageEventContent{ FormattedBody: html, Format: event.FormatHTML, MsgType: event.MsgText, Body: text, } } return event.MessageEventContent{ MsgType: event.MsgText, Body: text, } } func RenderMarkdown(text string, allowMarkdown, allowHTML bool) event.MessageEventContent { var htmlBody string if allowMarkdown { rndr := withHTML if !allowHTML { rndr = noHTML } return RenderMarkdownCustom(text, rndr) } else if allowHTML { htmlBody = strings.Replace(text, "\n", "
", -1) return HTMLToContent(htmlBody) } else { return event.MessageEventContent{ MsgType: event.MsgText, Body: text, } } }