Browse Source

Allow inline links in Discord embed descriptions

Tulir Asokan 2 years ago
parent
commit
5b715cd9e2
2 changed files with 28 additions and 17 deletions
  1. 21 10
      formatter.go
  2. 7 7
      portal.go

+ 21 - 10
formatter.go

@@ -55,24 +55,35 @@ func (b *indentableParagraphParser) CanAcceptIndentedLine() bool {
 	return true
 }
 
+var removeFeaturesExceptLinks = []any{
+	parser.NewListParser(), parser.NewListItemParser(), parser.NewHTMLBlockParser(), parser.NewRawHTMLParser(),
+	parser.NewSetextHeadingParser(), parser.NewATXHeadingParser(), parser.NewThematicBreakParser(),
+	parser.NewCodeBlockParser(),
+}
+var removeFeaturesAndLinks = append(removeFeaturesExceptLinks, parser.NewLinkParser())
+var fixIndentedParagraphs = goldmark.WithParserOptions(parser.WithBlockParsers(util.Prioritized(defaultIndentableParagraphParser, 500)))
+var discordExtensions = goldmark.WithExtensions(extension.Strikethrough, mdext.SimpleSpoiler, mdext.DiscordUnderline, ExtDiscordEveryone, ExtDiscordTag)
+
 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),
+	goldmark.WithParser(mdext.ParserWithoutFeatures(removeFeaturesAndLinks...)),
+	fixIndentedParagraphs, format.HTMLOptions, discordExtensions,
+)
+var discordRendererWithInlineLinks = goldmark.New(
+	goldmark.WithParser(mdext.ParserWithoutFeatures(removeFeaturesExceptLinks...)),
+	fixIndentedParagraphs, format.HTMLOptions, discordExtensions,
 )
 
-func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string) string {
+func (portal *Portal) renderDiscordMarkdownOnlyHTML(text string, allowInlineLinks bool) string {
 	text = escapeFixer.ReplaceAllStringFunc(text, escapeReplacement)
 
 	var buf strings.Builder
 	ctx := parser.NewContext()
 	ctx.Set(parserContextPortal, portal)
-	err := discordRenderer.Convert([]byte(text), &buf, parser.WithContext(ctx))
+	renderer := discordRenderer
+	if allowInlineLinks {
+		renderer = discordRendererWithInlineLinks
+	}
+	err := renderer.Convert([]byte(text), &buf, parser.WithContext(ctx))
 	if err != nil {
 		panic(fmt.Errorf("markdown parser errored: %w", err))
 	}

+ 7 - 7
portal.go

@@ -779,7 +779,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
 	}
 	if embed.Title != "" {
 		var titleHTML string
-		baseTitleHTML := portal.renderDiscordMarkdownOnlyHTML(embed.Title)
+		baseTitleHTML := portal.renderDiscordMarkdownOnlyHTML(embed.Title, false)
 		if embed.URL != "" {
 			titleHTML = fmt.Sprintf(embedHTMLTitleWithLink, html.EscapeString(embed.URL), baseTitleHTML)
 		} else {
@@ -788,7 +788,7 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
 		htmlParts = append(htmlParts, titleHTML)
 	}
 	if embed.Description != "" {
-		htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLDescription, portal.renderDiscordMarkdownOnlyHTML(embed.Description)))
+		htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLDescription, portal.renderDiscordMarkdownOnlyHTML(embed.Description, true)))
 	}
 	for i := 0; i < len(embed.Fields); i++ {
 		item := embed.Fields[i]
@@ -805,15 +805,15 @@ func (portal *Portal) convertDiscordRichEmbed(intent *appservice.IntentAPI, embe
 			headerParts := make([]string, len(splitItems))
 			contentParts := make([]string, len(splitItems))
 			for j, splitItem := range splitItems {
-				headerParts[j] = fmt.Sprintf(embedHTMLFieldName, portal.renderDiscordMarkdownOnlyHTML(splitItem.Name))
-				contentParts[j] = fmt.Sprintf(embedHTMLFieldValue, portal.renderDiscordMarkdownOnlyHTML(splitItem.Value))
+				headerParts[j] = fmt.Sprintf(embedHTMLFieldName, portal.renderDiscordMarkdownOnlyHTML(splitItem.Name, false))
+				contentParts[j] = fmt.Sprintf(embedHTMLFieldValue, portal.renderDiscordMarkdownOnlyHTML(splitItem.Value, true))
 			}
 			htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLFields, strings.Join(headerParts, ""), strings.Join(contentParts, "")))
 		} else {
 			htmlParts = append(htmlParts, fmt.Sprintf(embedHTMLLinearField,
 				strconv.FormatBool(item.Inline),
-				portal.renderDiscordMarkdownOnlyHTML(item.Name),
-				portal.renderDiscordMarkdownOnlyHTML(item.Value),
+				portal.renderDiscordMarkdownOnlyHTML(item.Name, false),
+				portal.renderDiscordMarkdownOnlyHTML(item.Value, true),
 			))
 		}
 	}
@@ -927,7 +927,7 @@ func (portal *Portal) convertDiscordTextMessage(intent *appservice.IntentAPI, ms
 		htmlParts = append(htmlParts, fmt.Sprintf(msgInteractionTemplateHTML, puppet.MXID, puppet.Name, msg.Interaction.Name))
 	}
 	if msg.Content != "" && !isPlainGifMessage(msg) {
-		htmlParts = append(htmlParts, portal.renderDiscordMarkdownOnlyHTML(msg.Content))
+		htmlParts = append(htmlParts, portal.renderDiscordMarkdownOnlyHTML(msg.Content, false))
 	}
 	previews := make([]*BeeperLinkPreview, 0)
 	for i, embed := range msg.Embeds {