mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 14:32:24 -05:00 
			
		
		
		
	[chore] Text formatting overhaul (#1406)
* Implement goldmark debug print for hashtags and mentions * Minify HTML in FromPlain * Convert plaintext status parser to goldmark * Move mention/tag/emoji finding logic into formatter * Combine mention and hashtag boundary characters * Normalize unicode when rendering hashtags
This commit is contained in:
		
					parent
					
						
							
								271da016b9
							
						
					
				
			
			
				commit
				
					
						49beb17a8f
					
				
			
		
					 26 changed files with 826 additions and 1314 deletions
				
			
		|  | @ -19,11 +19,9 @@ | |||
| package text_test | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/suite" | ||||
| 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | ||||
| ) | ||||
| 
 | ||||
| var withCodeBlock = `# Title | ||||
|  | @ -77,6 +75,16 @@ const ( | |||
| 	mdWithStrikethroughExpected     = "<p>I have <del>mdae</del> made an error</p>" | ||||
| 	mdWithLink                      = "Check out this code, i heard it was written by a sloth https://github.com/superseriousbusiness/gotosocial" | ||||
| 	mdWithLinkExpected              = "<p>Check out this code, i heard it was written by a sloth <a href=\"https://github.com/superseriousbusiness/gotosocial\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">https://github.com/superseriousbusiness/gotosocial</a></p>" | ||||
| 	mdObjectInCodeBlock             = "@foss_satan@fossbros-anonymous.io this is how to mention a user\n```\n@the_mighty_zork hey bud! nice #ObjectOrientedProgramming software you've been writing lately! :rainbow:\n```\nhope that helps" | ||||
| 	mdObjectInCodeBlockExpected     = "<p><span class=\"h-card\"><a href=\"http://fossbros-anonymous.io/@foss_satan\" class=\"u-url mention\" rel=\"nofollow noreferrer noopener\" target=\"_blank\">@<span>foss_satan</span></a></span> this is how to mention a user</p><pre><code>@the_mighty_zork hey bud! nice #ObjectOrientedProgramming software you've been writing lately! :rainbow:\n</code></pre><p>hope that helps</p>" | ||||
| 	mdItalicHashtag                 = "_#hashtag_" | ||||
| 	mdItalicHashtagExpected         = "<p><em><a href=\"http://localhost:8080/tags/Hashtag\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hashtag</span></a></em></p>" | ||||
| 	mdItalicHashtags                = "_#hashtag #hashtag #hashtag_" | ||||
| 	mdItalicHashtagsExpected        = "<p><em><a href=\"http://localhost:8080/tags/Hashtag\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hashtag</span></a> <a href=\"http://localhost:8080/tags/Hashtag\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hashtag</span></a> <a href=\"http://localhost:8080/tags/Hashtag\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hashtag</span></a></em></p>" | ||||
| 	// BEWARE: sneaky unicode business going on. | ||||
| 	// the first ö is one rune, the second ö is an o with a combining diacritic. | ||||
| 	mdUnnormalizedHashtag         = "#hellöthere #hellöthere" | ||||
| 	mdUnnormalizedHashtagExpected = "<p><a href=\"http://localhost:8080/tags/hell%C3%B6there\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hellöthere</span></a> <a href=\"http://localhost:8080/tags/hell%C3%B6there\" class=\"mention hashtag\" rel=\"tag nofollow noreferrer noopener\" target=\"_blank\">#<span>hellöthere</span></a></p>" | ||||
| ) | ||||
| 
 | ||||
| type MarkdownTestSuite struct { | ||||
|  | @ -84,101 +92,112 @@ type MarkdownTestSuite struct { | |||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseSimple() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), simpleMarkdown, nil, nil, nil) | ||||
| 	suite.Equal(simpleMarkdownExpected, s) | ||||
| 	formatted := suite.FromMarkdown(simpleMarkdown) | ||||
| 	suite.Equal(simpleMarkdownExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithCodeBlock() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), withCodeBlock, nil, nil, nil) | ||||
| 	suite.Equal(withCodeBlockExpected, s) | ||||
| 	formatted := suite.FromMarkdown(withCodeBlock) | ||||
| 	suite.Equal(withCodeBlockExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithInlineCode() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), withInlineCode, nil, nil, nil) | ||||
| 	suite.Equal(withInlineCodeExpected, s) | ||||
| 	formatted := suite.FromMarkdown(withInlineCode) | ||||
| 	suite.Equal(withInlineCodeExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithInlineCode2() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), withInlineCode2, nil, nil, nil) | ||||
| 	suite.Equal(withInlineCode2Expected, s) | ||||
| 	formatted := suite.FromMarkdown(withInlineCode2) | ||||
| 	suite.Equal(withInlineCode2Expected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithHashtag() { | ||||
| 	foundTags := []*gtsmodel.Tag{ | ||||
| 		suite.testTags["Hashtag"], | ||||
| 	} | ||||
| 
 | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), withHashtag, nil, foundTags, nil) | ||||
| 	suite.Equal(withHashtagExpected, s) | ||||
| 	formatted := suite.FromMarkdown(withHashtag) | ||||
| 	suite.Equal(withHashtagExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithHTML() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithHTML, nil, nil, nil) | ||||
| 	suite.Equal(mdWithHTMLExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithHTML) | ||||
| 	suite.Equal(mdWithHTMLExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithCheekyHTML() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithCheekyHTML, nil, nil, nil) | ||||
| 	suite.Equal(mdWithCheekyHTMLExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithCheekyHTML) | ||||
| 	suite.Equal(mdWithCheekyHTMLExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithHashtagInitial() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithHashtagInitial, nil, []*gtsmodel.Tag{ | ||||
| 		suite.testTags["Hashtag"], | ||||
| 		suite.testTags["welcome"], | ||||
| 	}, nil) | ||||
| 	suite.Equal(mdWithHashtagInitialExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithHashtagInitial) | ||||
| 	suite.Equal(mdWithHashtagInitialExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseCodeBlockWithNewlines() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdCodeBlockWithNewlines, nil, nil, nil) | ||||
| 	suite.Equal(mdCodeBlockWithNewlinesExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdCodeBlockWithNewlines) | ||||
| 	suite.Equal(mdCodeBlockWithNewlinesExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithFootnote() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithFootnote, nil, nil, nil) | ||||
| 	suite.Equal(mdWithFootnoteExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithFootnote) | ||||
| 	suite.Equal(mdWithFootnoteExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseWithBlockquote() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithBlockQuote, nil, nil, nil) | ||||
| 	suite.Equal(mdWithBlockQuoteExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithBlockQuote) | ||||
| 	suite.Equal(mdWithBlockQuoteExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseHashtagWithCodeBlock() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdHashtagAndCodeBlock, nil, []*gtsmodel.Tag{ | ||||
| 		suite.testTags["Hashtag"], | ||||
| 	}, nil) | ||||
| 	suite.Equal(mdHashtagAndCodeBlockExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdHashtagAndCodeBlock) | ||||
| 	suite.Equal(mdHashtagAndCodeBlockExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseMentionWithCodeBlock() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdMentionAndCodeBlock, []*gtsmodel.Mention{ | ||||
| 		suite.testMentions["local_user_2_mention_zork"], | ||||
| 	}, nil, nil) | ||||
| 	suite.Equal(mdMentionAndCodeBlockExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdMentionAndCodeBlock) | ||||
| 	suite.Equal(mdMentionAndCodeBlockExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseSmartypants() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithSmartypants, []*gtsmodel.Mention{ | ||||
| 		suite.testMentions["local_user_2_mention_zork"], | ||||
| 	}, nil, nil) | ||||
| 	suite.Equal(mdWithSmartypantsExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithSmartypants) | ||||
| 	suite.Equal(mdWithSmartypantsExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseAsciiHeart() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithAsciiHeart, nil, nil, nil) | ||||
| 	suite.Equal(mdWithAsciiHeartExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithAsciiHeart) | ||||
| 	suite.Equal(mdWithAsciiHeartExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseStrikethrough() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithStrikethrough, nil, nil, nil) | ||||
| 	suite.Equal(mdWithStrikethroughExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithStrikethrough) | ||||
| 	suite.Equal(mdWithStrikethroughExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseLink() { | ||||
| 	s := suite.formatter.FromMarkdown(context.Background(), mdWithLink, nil, nil, nil) | ||||
| 	suite.Equal(mdWithLinkExpected, s) | ||||
| 	formatted := suite.FromMarkdown(mdWithLink) | ||||
| 	suite.Equal(mdWithLinkExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseObjectInCodeBlock() { | ||||
| 	formatted := suite.FromMarkdown(mdObjectInCodeBlock) | ||||
| 	suite.Equal(mdObjectInCodeBlockExpected, formatted.HTML) | ||||
| 	suite.Len(formatted.Mentions, 1) | ||||
| 	suite.Equal("@foss_satan@fossbros-anonymous.io", formatted.Mentions[0].NameString) | ||||
| 	suite.Empty(formatted.Tags) | ||||
| 	suite.Empty(formatted.Emojis) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseItalicHashtag() { | ||||
| 	formatted := suite.FromMarkdown(mdItalicHashtag) | ||||
| 	suite.Equal(mdItalicHashtagExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseItalicHashtags() { | ||||
| 	formatted := suite.FromMarkdown(mdItalicHashtags) | ||||
| 	suite.Equal(mdItalicHashtagsExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func (suite *MarkdownTestSuite) TestParseUnnormalizedHashtag() { | ||||
| 	formatted := suite.FromMarkdown(mdUnnormalizedHashtag) | ||||
| 	suite.Equal(mdUnnormalizedHashtagExpected, formatted.HTML) | ||||
| } | ||||
| 
 | ||||
| func TestMarkdownTestSuite(t *testing.T) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue