Signed-off-by: Seongmin Lee boltlessengineer@proton.me
ERROR
appview/pages/markup/markdown.go
ERROR
appview/pages/markup/markdown.go
Failed to calculate interdiff for this file.
REVERTED
appview/pages/markup/markdown_at_extension.go
REVERTED
appview/pages/markup/markdown_at_extension.go
···
1
-
// heavily inspired by: https://github.com/kaleocheng/goldmark-extensions
2
-
3
-
package markup
4
-
5
-
import (
6
-
"regexp"
7
-
8
-
"github.com/yuin/goldmark"
9
-
"github.com/yuin/goldmark/ast"
10
-
"github.com/yuin/goldmark/parser"
11
-
"github.com/yuin/goldmark/renderer"
12
-
"github.com/yuin/goldmark/renderer/html"
13
-
"github.com/yuin/goldmark/text"
14
-
"github.com/yuin/goldmark/util"
15
-
)
16
-
17
-
// An AtNode struct represents an AtNode
18
-
type AtNode struct {
19
-
handle string
20
-
ast.BaseInline
21
-
}
22
-
23
-
var _ ast.Node = &AtNode{}
24
-
25
-
// Dump implements Node.Dump.
26
-
func (n *AtNode) Dump(source []byte, level int) {
27
-
ast.DumpHelper(n, source, level, nil, nil)
28
-
}
29
-
30
-
// KindAt is a NodeKind of the At node.
31
-
var KindAt = ast.NewNodeKind("At")
32
-
33
-
// Kind implements Node.Kind.
34
-
func (n *AtNode) Kind() ast.NodeKind {
35
-
return KindAt
36
-
}
37
-
38
-
var atRegexp = regexp.MustCompile(`(^|\s|\()(@)([a-zA-Z0-9.-]+)(\b)`)
39
-
40
-
type atParser struct{}
41
-
42
-
// NewAtParser return a new InlineParser that parses
43
-
// at expressions.
44
-
func NewAtParser() parser.InlineParser {
45
-
return &atParser{}
46
-
}
47
-
48
-
func (s *atParser) Trigger() []byte {
49
-
return []byte{'@'}
50
-
}
51
-
52
-
func (s *atParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
53
-
line, segment := block.PeekLine()
54
-
m := atRegexp.FindSubmatchIndex(line)
55
-
if m == nil {
56
-
return nil
57
-
}
58
-
atSegment := text.NewSegment(segment.Start, segment.Start+m[1])
59
-
block.Advance(m[1])
60
-
node := &AtNode{}
61
-
node.AppendChild(node, ast.NewTextSegment(atSegment))
62
-
node.handle = string(atSegment.Value(block.Source())[1:])
63
-
return node
64
-
}
65
-
66
-
// atHtmlRenderer is a renderer.NodeRenderer implementation that
67
-
// renders At nodes.
68
-
type atHtmlRenderer struct {
69
-
html.Config
70
-
}
71
-
72
-
// NewAtHTMLRenderer returns a new AtHTMLRenderer.
73
-
func NewAtHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
74
-
r := &atHtmlRenderer{
75
-
Config: html.NewConfig(),
76
-
}
77
-
for _, opt := range opts {
78
-
opt.SetHTMLOption(&r.Config)
79
-
}
80
-
return r
81
-
}
82
-
83
-
// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
84
-
func (r *atHtmlRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
85
-
reg.Register(KindAt, r.renderAt)
86
-
}
87
-
88
-
func (r *atHtmlRenderer) renderAt(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
89
-
if entering {
90
-
w.WriteString(`<a href="/@`)
91
-
w.WriteString(n.(*AtNode).handle)
92
-
w.WriteString(`" class="mention">`)
93
-
} else {
94
-
w.WriteString("</a>")
95
-
}
96
-
return ast.WalkContinue, nil
97
-
}
98
-
99
-
type atExt struct{}
100
-
101
-
// At is an extension that allow you to use at expression like '@user.bsky.social' .
102
-
var AtExt = &atExt{}
103
-
104
-
func (e *atExt) Extend(m goldmark.Markdown) {
105
-
m.Parser().AddOptions(parser.WithInlineParsers(
106
-
util.Prioritized(NewAtParser(), 500),
107
-
))
108
-
m.Renderer().AddOptions(renderer.WithNodeRenderers(
109
-
util.Prioritized(NewAtHTMLRenderer(), 500),
110
-
))
111
-
}
112
-
113
-
// FindUserMentions returns Set of user handles from given markup soruce.
114
-
// It doesn't guarntee unique DIDs
115
-
func FindUserMentions(source string) []string {
116
-
var (
117
-
mentions []string
118
-
mentionsSet = make(map[string]struct{})
119
-
md = NewMarkdown()
120
-
sourceBytes = []byte(source)
121
-
root = md.Parser().Parse(text.NewReader(sourceBytes))
122
-
)
123
-
ast.Walk(root, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
124
-
if entering && n.Kind() == KindAt {
125
-
handle := n.(*AtNode).handle
126
-
mentionsSet[handle] = struct{}{}
127
-
return ast.WalkSkipChildren, nil
128
-
}
129
-
return ast.WalkContinue, nil
130
-
})
131
-
for handle := range mentionsSet {
132
-
mentions = append(mentions, handle)
133
-
}
134
-
return mentions
135
-
}
ERROR
appview/pages/markup/sanitizer.go
ERROR
appview/pages/markup/sanitizer.go
Failed to calculate interdiff for this file.
ERROR
input.css
ERROR
input.css
Failed to calculate interdiff for this file.
NEW
appview/pages/markup/extension/atlink.go
NEW
appview/pages/markup/extension/atlink.go
···
1
+
// heavily inspired by: https://github.com/kaleocheng/goldmark-extensions
2
+
3
+
package extension
4
+
5
+
import (
6
+
"regexp"
7
+
8
+
"github.com/yuin/goldmark"
9
+
"github.com/yuin/goldmark/ast"
10
+
"github.com/yuin/goldmark/parser"
11
+
"github.com/yuin/goldmark/renderer"
12
+
"github.com/yuin/goldmark/renderer/html"
13
+
"github.com/yuin/goldmark/text"
14
+
"github.com/yuin/goldmark/util"
15
+
)
16
+
17
+
// An AtNode struct represents an AtNode
18
+
type AtNode struct {
19
+
handle string
20
+
ast.BaseInline
21
+
}
22
+
23
+
var _ ast.Node = &AtNode{}
24
+
25
+
// Dump implements Node.Dump.
26
+
func (n *AtNode) Dump(source []byte, level int) {
27
+
ast.DumpHelper(n, source, level, nil, nil)
28
+
}
29
+
30
+
// KindAt is a NodeKind of the At node.
31
+
var KindAt = ast.NewNodeKind("At")
32
+
33
+
// Kind implements Node.Kind.
34
+
func (n *AtNode) Kind() ast.NodeKind {
35
+
return KindAt
36
+
}
37
+
38
+
var atRegexp = regexp.MustCompile(`(^|\s|\()(@)([a-zA-Z0-9.-]+)(\b)`)
39
+
40
+
type atParser struct{}
41
+
42
+
// NewAtParser return a new InlineParser that parses
43
+
// at expressions.
44
+
func NewAtParser() parser.InlineParser {
45
+
return &atParser{}
46
+
}
47
+
48
+
func (s *atParser) Trigger() []byte {
49
+
return []byte{'@'}
50
+
}
51
+
52
+
func (s *atParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
53
+
line, segment := block.PeekLine()
54
+
m := atRegexp.FindSubmatchIndex(line)
55
+
if m == nil {
56
+
return nil
57
+
}
58
+
atSegment := text.NewSegment(segment.Start, segment.Start+m[1])
59
+
block.Advance(m[1])
60
+
node := &AtNode{}
61
+
node.AppendChild(node, ast.NewTextSegment(atSegment))
62
+
node.handle = string(atSegment.Value(block.Source())[1:])
63
+
return node
64
+
}
65
+
66
+
// atHtmlRenderer is a renderer.NodeRenderer implementation that
67
+
// renders At nodes.
68
+
type atHtmlRenderer struct {
69
+
html.Config
70
+
}
71
+
72
+
// NewAtHTMLRenderer returns a new AtHTMLRenderer.
73
+
func NewAtHTMLRenderer(opts ...html.Option) renderer.NodeRenderer {
74
+
r := &atHtmlRenderer{
75
+
Config: html.NewConfig(),
76
+
}
77
+
for _, opt := range opts {
78
+
opt.SetHTMLOption(&r.Config)
79
+
}
80
+
return r
81
+
}
82
+
83
+
// RegisterFuncs implements renderer.NodeRenderer.RegisterFuncs.
84
+
func (r *atHtmlRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
85
+
reg.Register(KindAt, r.renderAt)
86
+
}
87
+
88
+
func (r *atHtmlRenderer) renderAt(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
89
+
if entering {
90
+
w.WriteString(`<a href="/@`)
91
+
w.WriteString(n.(*AtNode).handle)
92
+
w.WriteString(`" class="mention">`)
93
+
} else {
94
+
w.WriteString("</a>")
95
+
}
96
+
return ast.WalkContinue, nil
97
+
}
98
+
99
+
type atExt struct{}
100
+
101
+
// At is an extension that allow you to use at expression like '@user.bsky.social' .
102
+
var AtExt = &atExt{}
103
+
104
+
func (e *atExt) Extend(m goldmark.Markdown) {
105
+
m.Parser().AddOptions(parser.WithInlineParsers(
106
+
util.Prioritized(NewAtParser(), 500),
107
+
))
108
+
m.Renderer().AddOptions(renderer.WithNodeRenderers(
109
+
util.Prioritized(NewAtHTMLRenderer(), 500),
110
+
))
111
+
}