From 3f62e43b705a9108eeb1d6491a64540819969508 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Fri, 5 Jan 2024 15:13:33 +0200 Subject: [PATCH] fix bad HTML when links overlap --- front/text/plain/convert.go | 28 +++++++++++++++++----------- front/text/plain/convert_test.go | 8 ++++++++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/front/text/plain/convert.go b/front/text/plain/convert.go index b1885c65..1f6b5dd0 100644 --- a/front/text/plain/convert.go +++ b/front/text/plain/convert.go @@ -117,25 +117,31 @@ func FromHTML(text string) (string, data.OrderedMap[string, string]) { return strings.TrimRight(res, " \n\r\t"), links } -func getPlainLinks(text string) map[string]struct{} { - links := map[string]struct{}{} - for _, link := range urlRegex.FindAllString(text, -1) { - links[link] = struct{}{} - } - return links -} - func ToHTML(text string, mentions []ap.Mention) string { if text == "" { return "" } - for link := range getPlainLinks(text) { - text = strings.ReplaceAll(text, link, fmt.Sprintf(`%s`, link, link)) + var b strings.Builder + + foundLink := false + for { + loc := urlRegex.FindStringIndex(text) + if loc == nil { + break + } + b.WriteString(text[:loc[0]]) + b.WriteString(fmt.Sprintf(`%s`, text[loc[0]:loc[1]], text[loc[0]:loc[1]])) + text = text[loc[1]:] + foundLink = true + } + if foundLink { + b.WriteString(text) + text = b.String() } if len(mentions) > 0 { - var b strings.Builder + b.Reset() mentions: for _, mention := range mentions { if mention.Type != ap.MentionMention { diff --git a/front/text/plain/convert_test.go b/front/text/plain/convert_test.go index 2a8162de..8c20416b 100644 --- a/front/text/plain/convert_test.go +++ b/front/text/plain/convert_test.go @@ -287,6 +287,14 @@ func TestToHTML_Link(t *testing.T) { assert.Equal(t, expected, html) } +func TestToHTML_OverlappingLink(t *testing.T) { + post := `this is a plain post with overlapping links: gemini://aa.bb.com/cc gemini://aa.bb.com/cc?dd=ee&ff=gg%20hh` + expected := `

this is a plain post with overlapping links: gemini://aa.bb.com/cc gemini://aa.bb.com/cc?dd=ee&ff=gg%20hh

` + + html := ToHTML(post, nil) + assert.Equal(t, expected, html) +} + func TestToHTML_LinkAndLineBreak(t *testing.T) { post := "this is a plain post with a link: gemini://aa.bb.com/cc?dd=ee&ff=gg%20hh\n... and a line break" expected := `

this is a plain post with a link: gemini://aa.bb.com/cc?dd=ee&ff=gg%20hh
... and a line break

`