// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
// Copyright (C) 2024 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see
[long message cut off]"
}
part.Content.BeeperLinkPreviews = mc.convertURLPreviewToBeeper(ctx, msg.GetExtendedTextMessage())
return
}
func (mc *MessageConverter) parseFormatting(content *event.MessageEventContent, allowInlineURL, forceHTML bool) {
parsedHTML := parseWAFormattingToHTML(content.Body, allowInlineURL)
if forceHTML || parsedHTML != event.TextToHTML(content.Body) {
content.FormattedBody = parsedHTML
content.Format = event.FormatHTML
}
}
var italicRegex = regexp.MustCompile(`([\s>~*]|^)_(.+?)_([^a-zA-Z\d]|$)`)
var boldRegex = regexp.MustCompile(`([\s>_~]|^)\*(.+?)\*([^a-zA-Z\d]|$)`)
var strikethroughRegex = regexp.MustCompile(`([\s>_*]|^)~(.+?)~([^a-zA-Z\d]|$)`)
var inlineCodeRegex = regexp.MustCompile("([\\s>_*~]|^)`(.+?)`([^a-zA-Z\\d]|$)")
var inlineURLRegex = regexp.MustCompile(`\[(.+?)]\((.+?)\)`)
var orderedListItemRegex = regexp.MustCompile(`^(\d{1,2})\. `)
var waReplString = map[*regexp.Regexp]string{
italicRegex: "$1$2$3",
boldRegex: "$1$2$3",
strikethroughRegex: "$1$2$3",
inlineCodeRegex: "$1$2$3",
}
func parseWASubFormattingLineToHTML(text string, allowInlineURL bool) string {
text = html.EscapeString(text)
for regex, replacement := range waReplString {
text = regex.ReplaceAllString(text, replacement)
}
if allowInlineURL {
text = inlineURLRegex.ReplaceAllStringFunc(text, func(s string) string {
groups := inlineURLRegex.FindStringSubmatch(s)
return fmt.Sprintf(`%s`, groups[2], groups[1])
})
}
return text
}
func parseWASubFormattingToHTML(text string, allowInlineURL bool, output *strings.Builder) {
lines := strings.Split(text, "\n")
orderedListIdx := -1
inBulletedList := false
wasBlockQuote := false
for i, line := range lines {
if i != 0 && orderedListIdx < 0 && !inBulletedList && !wasBlockQuote {
output.WriteString("
")
}
wasBlockQuote = false
if strings.HasPrefix(line, "* ") || strings.HasPrefix(line, "- ") {
if orderedListIdx >= 0 {
orderedListIdx = -1
output.WriteString("")
}
if !inBulletedList {
output.WriteString("
%s", parseWASubFormattingLineToHTML(line[2:], allowInlineURL)) wasBlockQuote = true } else { if orderedListIdx >= 0 { orderedListIdx = -1 output.WriteString("
%s", html.EscapeString(content))
} else {
_, _ = fmt.Fprintf(&output, "%s", html.EscapeString(content))
}
}
if codeBlockPtr < len(text) {
parseWASubFormattingToHTML(text[codeBlockPtr:], allowInlineURL, &output)
}
return output.String()
}