plain.go (3091B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package text 19 20 import ( 21 "bytes" 22 "context" 23 24 "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" 25 "github.com/superseriousbusiness/gotosocial/internal/log" 26 "github.com/yuin/goldmark" 27 "github.com/yuin/goldmark/extension" 28 "github.com/yuin/goldmark/parser" 29 "github.com/yuin/goldmark/renderer/html" 30 "github.com/yuin/goldmark/util" 31 ) 32 33 func (f *formatter) fromPlain( 34 ctx context.Context, 35 ptParser parser.Parser, 36 pmf gtsmodel.ParseMentionFunc, 37 authorID string, 38 statusID string, 39 plain string, 40 ) *FormatResult { 41 result := &FormatResult{ 42 Mentions: []*gtsmodel.Mention{}, 43 Tags: []*gtsmodel.Tag{}, 44 Emojis: []*gtsmodel.Emoji{}, 45 } 46 47 // Parse markdown into html, using custom renderer 48 // to add hashtag/mention links and emoji images. 49 md := goldmark.New( 50 goldmark.WithRendererOptions( 51 html.WithXHTML(), 52 html.WithHardWraps(), 53 ), 54 goldmark.WithParser(ptParser), // use parser we were passed 55 goldmark.WithExtensions( 56 &customRenderer{f, ctx, pmf, authorID, statusID, false, result}, 57 extension.Linkify, // turns URLs into links 58 ), 59 ) 60 61 var htmlContentBytes bytes.Buffer 62 if err := md.Convert([]byte(plain), &htmlContentBytes); err != nil { 63 log.Errorf(ctx, "error formatting plaintext to HTML: %s", err) 64 } 65 result.HTML = htmlContentBytes.String() 66 67 // Clean anything dangerous out of resulting HTML. 68 result.HTML = SanitizeHTML(result.HTML) 69 70 // Shrink ray! 71 var err error 72 if result.HTML, err = m.String("text/html", result.HTML); err != nil { 73 log.Errorf(ctx, "error minifying HTML: %s", err) 74 } 75 76 return result 77 } 78 79 func (f *formatter) FromPlain(ctx context.Context, pmf gtsmodel.ParseMentionFunc, authorID string, statusID string, plain string) *FormatResult { 80 ptParser := parser.NewParser( 81 parser.WithBlockParsers( 82 util.Prioritized(newPlaintextParser(), 500), 83 ), 84 ) 85 86 return f.fromPlain(ctx, ptParser, pmf, authorID, statusID, plain) 87 } 88 89 func (f *formatter) FromPlainNoParagraph(ctx context.Context, pmf gtsmodel.ParseMentionFunc, authorID string, statusID string, plain string) *FormatResult { 90 ptParser := parser.NewParser( 91 parser.WithBlockParsers( 92 // Initialize block parser that doesn't wrap in <p> tags. 93 util.Prioritized(newPlaintextParserNoParagraph(), 500), 94 ), 95 ) 96 97 return f.fromPlain(ctx, ptParser, pmf, authorID, statusID, plain) 98 }