-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinline.go
More file actions
119 lines (104 loc) · 2.85 KB
/
Copy pathinline.go
File metadata and controls
119 lines (104 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package mdsend
import (
"bytes"
"fmt"
"io"
"regexp"
"slices"
"github.com/dkotik/mdsend/markdown"
"github.com/yuin/goldmark/parser"
"golang.org/x/net/html"
)
var (
reImageTagHTML = regexp.MustCompile(`<img[^>]+>`)
)
func inlineTemplateAttachments(
source []byte,
replacer func(AttachmentSource) (string, error),
) (_ []byte, err error) {
index := reImageTagHTML.FindAllIndex(source, -1)
if index == nil {
return source, nil
}
content := make([]byte, 0, len(source))
cutoff := 0
for _, imageRange := range index {
content = append(content, source[cutoff:imageRange[0]]...)
cutoff = imageRange[1]
tokenizer := html.NewTokenizer(bytes.NewReader(source[imageRange[0]:imageRange[1]]))
for {
tokenType := tokenizer.Next()
if tokenType == html.ErrorToken {
if tokenizer.Err() == io.EOF {
break
}
return source, fmt.Errorf("invalid <img> tag: %w", tokenizer.Err())
}
if tokenType == html.StartTagToken || tokenType == html.SelfClosingTagToken {
token := tokenizer.Token()
if token.Data == "img" {
content = append(content, []byte("<img ")...)
attachment := AttachmentSource{}
for _, attr := range token.Attr {
switch attr.Key {
case "alt":
if attachment.Name == "" {
attachment.Name = attr.Val
}
case "title":
attachment.Name = attr.Val
}
}
for i, attr := range token.Attr {
if attr.Key != "src" {
continue
}
attachment.Location = attr.Val
token.Attr[i].Val, err = replacer(attachment)
if err != nil {
return source, err
}
}
for _, attr := range token.Attr {
content = append(content, []byte(attr.Key+"=\"")...)
content = append(content, []byte(html.EscapeString(attr.Val))...)
content = append(content, []byte("\" ")...)
}
content = append(content, []byte("/>")...)
}
}
}
}
content = append(content, source[cutoff:]...)
return content, nil
}
func inlineMarkdownAttachments(
parser parser.Parser,
source []byte,
replacer func(AttachmentSource) (string, error),
) (_ string, err error) {
index := slices.Collect(markdown.IndexImages(parser, source))
if len(index) == 0 {
return string(source), nil
}
content := make([]byte, 0, len(source))
cutoff := 0
for _, imgDestination := range index {
content = append(content, source[cutoff:imgDestination.LocationAt]...)
cutoff = imgDestination.LocationAt + len(imgDestination.Location)
attachment := AttachmentSource{
Name: imgDestination.Title,
Location: imgDestination.Location,
}
if attachment.Name == "" {
attachment.Name = imgDestination.Alt
}
destination, err := replacer(attachment)
if err != nil {
return string(source), err
}
content = append(content, []byte(markdown.Escape(destination))...)
}
content = append(content, source[cutoff:]...)
return string(content), nil
}