Skip to content

Commit 41481d7

Browse files
committed
🎨 Protyle 行级元素支持嵌套和交叉 siyuan-note/siyuan#2911
1 parent adfaaec commit 41481d7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1233
-1234
lines changed

ast/node.go

+11-3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ type Node struct {
115115

116116
KramdownIAL [][]string `json:"-"` // Kramdown 内联属性列表
117117
Properties map[string]string `json:",omitempty"` // 属性
118+
119+
// 文本标记
120+
TextMarkType string `json:",omitempty"` // 文本标记类型
121+
TextMarkAHref string `json:",omitempty"` // 文本标记超链接 data-href 属性
122+
TextMarkATitle string `json:",omitempty"` // 文本标记超链接 data-title 属性
123+
TextMarkInlineMathContent string `json:",omitempty"` // 文本标记内联数学公式内容 data-content 属性
124+
TextMarkBlockRefID string `json:",omitempty"` // 文本标记块引用 ID data-id 属性
125+
TextMarkBlockRefSubtype string `json:",omitempty"` // 文本标记块引用子类型(静态/动态锚文本) data-subtype 属性
126+
TextMarkFileAnnotationRefID string `json:",omitempty"` // 文本标记文件注解引用 ID data-id 属性
127+
TextMarkTextContent string `json:",omitempty"` // 文本标记文本内容
118128
}
119129

120130
// ListData 用于记录列表或列表项节点的附加信息。
@@ -816,9 +826,7 @@ const (
816826

817827
// <span data-type="mark">foo</span> 通用的行级文本标记,不能嵌套
818828

819-
NodeTextMark NodeType = 530 // 文本标记
820-
NodeTextMarkOpenMarker NodeType = 531 // 开始文本标记符 <span>
821-
NodeTextMarkCloseMarker NodeType = 532 // 开始文本标记符 </span>
829+
NodeTextMark NodeType = 530 // 文本标记,该节点因为不存在嵌套,所以不使用 Open/Close 标记符
822830

823831
// Protyle 挂件,<iframe data-type="NodeWidget">
824832

ast/nodetype_string.go

+7-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

util/caret.go editor/const.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
99
// See the Mulan PSL v2 for more details.
1010

11-
package util
11+
package editor
1212

1313
// Caret 插入符 \u2038。
1414
const Caret = "‸"
@@ -33,3 +33,14 @@ const FrontEndCaret = "<wbr>"
3333

3434
// FrontEndCaretSelfClose 前端自动闭合插入符。
3535
const FrontEndCaretSelfClose = "<wbr/>"
36+
37+
// IALValEscNewLine 属性值换行转义。
38+
const IALValEscNewLine = "_esc_newline_"
39+
40+
const (
41+
// Zwsp 零宽空格。
42+
Zwsp = "\u200b"
43+
44+
// Zwj 零宽连字。
45+
Zwj = "\u200d"
46+
)

h2m.go

+31-31
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,12 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
8686
return
8787
}
8888

89-
dataRender := lute.domAttrValue(n, "data-render")
89+
dataRender := util.DomAttrValue(n, "data-render")
9090
if "1" == dataRender {
9191
return
9292
}
9393

94-
class := lute.domAttrValue(n, "class")
94+
class := util.DomAttrValue(n, "class")
9595
if strings.HasPrefix(class, "line-number") &&
9696
!strings.HasPrefix(class, "line-numbers" /* 简书代码块 https://github.com/siyuan-note/siyuan/issues/4361 */) {
9797
return
@@ -120,7 +120,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
120120
node.Tokens = bytes.ReplaceAll(node.Tokens, []byte("\n"), []byte(""))
121121
}
122122
node.Tokens = bytes.ReplaceAll(node.Tokens, []byte{194, 160}, []byte{' '}) // 将 &nbsp; 转换为空格
123-
if nil != n.Parent && atom.Span == n.Parent.DataAtom && ("" != lute.domAttrValue(n.Parent, "class")) {
123+
if nil != n.Parent && atom.Span == n.Parent.DataAtom && ("" != util.DomAttrValue(n.Parent, "class")) {
124124
if lastc := tree.Context.Tip.LastChild; nil == lastc || (ast.NodeText == lastc.Type && !bytes.HasSuffix(lastc.Tokens, []byte("**"))) {
125125
node.Tokens = []byte("**" + util.BytesToStr(node.Tokens) + "**")
126126
}
@@ -133,7 +133,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
133133

134134
if atom.Div == n.DataAtom {
135135
// 解析 GitHub 语法高亮代码块
136-
class := lute.domAttrValue(n, "class")
136+
class := util.DomAttrValue(n, "class")
137137
language := ""
138138
if strings.Contains(class, "-source-") {
139139
language = class[strings.LastIndex(class, "-source-")+len("-source-"):]
@@ -147,7 +147,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
147147
node.AppendChild(&ast.Node{Type: ast.NodeCodeBlockFenceInfoMarker})
148148
buf := &bytes.Buffer{}
149149
node.LastChild.CodeBlockInfo = []byte(language)
150-
buf.WriteString(lute.domText(n))
150+
buf.WriteString(util.DomText(n))
151151
content := &ast.Node{Type: ast.NodeCodeBlockCode, Tokens: buf.Bytes()}
152152
node.AppendChild(content)
153153
node.AppendChild(&ast.Node{Type: ast.NodeCodeBlockFenceCloseMarker, Tokens: util.StrToBytes("```"), CodeBlockFenceLen: 3})
@@ -191,11 +191,11 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
191191
defer tree.Context.ParentTip()
192192
case atom.Li:
193193
node.Type = ast.NodeListItem
194-
marker := lute.domAttrValue(n, "data-marker")
194+
marker := util.DomAttrValue(n, "data-marker")
195195
var bullet byte
196196
if "" == marker {
197197
if nil != n.Parent && atom.Ol == n.Parent.DataAtom {
198-
start := lute.domAttrValue(n.Parent, "start")
198+
start := util.DomAttrValue(n.Parent, "start")
199199
if "" == start {
200200
marker = "1."
201201
} else {
@@ -223,9 +223,9 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
223223
node.AppendChild(&ast.Node{Type: ast.NodeCodeBlockFenceOpenMarker, Tokens: util.StrToBytes("```"), CodeBlockFenceLen: 3})
224224
node.AppendChild(&ast.Node{Type: ast.NodeCodeBlockFenceInfoMarker})
225225
if atom.Code == firstc.DataAtom || atom.Span == firstc.DataAtom {
226-
class := lute.domAttrValue(firstc, "class")
226+
class := util.DomAttrValue(firstc, "class")
227227
if !strings.Contains(class, "language-") {
228-
class = lute.domAttrValue(n, "class")
228+
class = util.DomAttrValue(n, "class")
229229
}
230230
if strings.Contains(class, "language-") {
231231
language := class[strings.Index(class, "language-")+len("language-"):]
@@ -256,20 +256,20 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
256256
}
257257

258258
buf := &bytes.Buffer{}
259-
buf.WriteString(lute.domText(n))
259+
buf.WriteString(util.DomText(n))
260260
content := &ast.Node{Type: ast.NodeCodeBlockCode, Tokens: buf.Bytes()}
261261
node.AppendChild(content)
262262
node.AppendChild(&ast.Node{Type: ast.NodeCodeBlockFenceCloseMarker, Tokens: util.StrToBytes("```"), CodeBlockFenceLen: 3})
263263
tree.Context.Tip.AppendChild(node)
264264
} else {
265265
node.Type = ast.NodeHTMLBlock
266-
node.Tokens = lute.domHTML(n)
266+
node.Tokens = util.DomHTML(n)
267267
tree.Context.Tip.AppendChild(node)
268268
}
269269
}
270270
return
271271
case atom.Em, atom.I:
272-
text := lute.domText(n)
272+
text := util.DomText(n)
273273
if "" == strings.TrimSpace(text) {
274274
break
275275
}
@@ -281,7 +281,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
281281
tree.Context.Tip = node
282282
defer tree.Context.ParentTip()
283283
case atom.Strong, atom.B:
284-
text := lute.domText(n)
284+
text := util.DomText(n)
285285
if "" == strings.TrimSpace(text) {
286286
break
287287
}
@@ -297,7 +297,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
297297
return
298298
}
299299

300-
code := lute.domHTML(n)
300+
code := util.DomHTML(n)
301301
if bytes.Contains(code, []byte(">")) {
302302
code = code[bytes.Index(code, []byte(">"))+1:]
303303
}
@@ -329,7 +329,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
329329
defer tree.Context.ParentTip()
330330
case atom.A:
331331
node.Type = ast.NodeLink
332-
text := lute.domText(n)
332+
text := util.DomText(n)
333333
if "" == text && nil != n.Parent && (atom.H1 == n.Parent.DataAtom || atom.H2 == n.Parent.DataAtom || atom.H3 == n.Parent.DataAtom || atom.H4 == n.Parent.DataAtom || atom.H5 == n.Parent.DataAtom || atom.H6 == n.Parent.DataAtom) {
334334
// 丢弃标题中文本为空的链接,这样的链接可能是锚点 https://github.com/Vanessa219/vditor/issues/359
335335
return
@@ -344,11 +344,11 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
344344
tree.Context.Tip = node
345345
defer tree.Context.ParentTip()
346346
case atom.Img:
347-
imgClass := lute.domAttrValue(n, "class")
348-
imgAlt := lute.domAttrValue(n, "alt")
347+
imgClass := util.DomAttrValue(n, "class")
348+
imgAlt := util.DomAttrValue(n, "alt")
349349
if "emoji" == imgClass {
350350
node.Type = ast.NodeEmoji
351-
emojiImg := &ast.Node{Type: ast.NodeEmojiImg, Tokens: tree.EmojiImgTokens(imgAlt, lute.domAttrValue(n, "src"))}
351+
emojiImg := &ast.Node{Type: ast.NodeEmojiImg, Tokens: tree.EmojiImgTokens(imgAlt, util.DomAttrValue(n, "src"))}
352352
emojiImg.AppendChild(&ast.Node{Type: ast.NodeEmojiAlias, Tokens: util.StrToBytes(":" + imgAlt + ":")})
353353
node.AppendChild(emojiImg)
354354
} else {
@@ -360,13 +360,13 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
360360
}
361361
node.AppendChild(&ast.Node{Type: ast.NodeCloseBracket})
362362
node.AppendChild(&ast.Node{Type: ast.NodeOpenParen})
363-
src := lute.domAttrValue(n, "src")
363+
src := util.DomAttrValue(n, "src")
364364
if strings.HasPrefix(src, "data:image") {
365365
// 处理可能存在的预加载情况
366-
src = lute.domAttrValue(n, "data-src")
366+
src = util.DomAttrValue(n, "data-src")
367367
}
368368
node.AppendChild(&ast.Node{Type: ast.NodeLinkDest, Tokens: util.StrToBytes(src)})
369-
linkTitle := lute.domAttrValue(n, "title")
369+
linkTitle := util.DomAttrValue(n, "title")
370370
if "" != linkTitle {
371371
node.AppendChild(&ast.Node{Type: ast.NodeLinkSpace})
372372
node.AppendChild(&ast.Node{Type: ast.NodeLinkTitle, Tokens: []byte(linkTitle)})
@@ -425,7 +425,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
425425
var tableAligns []int
426426
if nil != n.FirstChild && nil != n.FirstChild.FirstChild && nil != n.FirstChild.FirstChild.FirstChild {
427427
for th := n.FirstChild.FirstChild.FirstChild; nil != th; th = th.NextSibling {
428-
align := lute.domAttrValue(th, "align")
428+
align := util.DomAttrValue(th, "align")
429429
switch align {
430430
case "left":
431431
tableAligns = append(tableAligns, 1)
@@ -466,7 +466,7 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
466466
defer tree.Context.ParentTip()
467467
case atom.Th, atom.Td:
468468
node.Type = ast.NodeTableCell
469-
align := lute.domAttrValue(n, "align")
469+
align := util.DomAttrValue(n, "align")
470470
var tableAlign int
471471
switch align {
472472
case "left":
@@ -490,28 +490,28 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
490490
}
491491
case atom.Font:
492492
node.Type = ast.NodeText
493-
node.Tokens = []byte(lute.domText(n))
493+
node.Tokens = []byte(util.DomText(n))
494494
node.Tokens = bytes.ReplaceAll(node.Tokens, []byte("\n"), nil)
495495
tree.Context.Tip.AppendChild(node)
496496
return
497497
case atom.Details:
498498
node.Type = ast.NodeHTMLBlock
499-
node.Tokens = lute.domHTML(n)
499+
node.Tokens = util.DomHTML(n)
500500
node.Tokens = bytes.SplitAfter(node.Tokens, []byte("</summary>"))[0]
501501
tree.Context.Tip.AppendChild(node)
502502
case atom.Summary:
503503
return
504504
case atom.Iframe, atom.Audio, atom.Video:
505505
node.Type = ast.NodeHTMLBlock
506-
node.Tokens = lute.domHTML(n)
506+
node.Tokens = util.DomHTML(n)
507507
tree.Context.Tip.AppendChild(node)
508508
return
509509
case atom.Noscript:
510510
return
511511
case atom.Figcaption:
512512
node.Type = ast.NodeParagraph
513513
node.AppendChild(&ast.Node{Type: ast.NodeHardBreak})
514-
node.AppendChild(&ast.Node{Type: ast.NodeText, Tokens: util.StrToBytes(lute.domText(n))})
514+
node.AppendChild(&ast.Node{Type: ast.NodeText, Tokens: util.StrToBytes(util.DomText(n))})
515515
tree.Context.Tip.AppendChild(node)
516516
return
517517
case atom.Figure:
@@ -538,8 +538,8 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
538538
case atom.A:
539539
node.AppendChild(&ast.Node{Type: ast.NodeCloseBracket})
540540
node.AppendChild(&ast.Node{Type: ast.NodeOpenParen})
541-
node.AppendChild(&ast.Node{Type: ast.NodeLinkDest, Tokens: util.StrToBytes(lute.domAttrValue(n, "href"))})
542-
linkTitle := lute.domAttrValue(n, "title")
541+
node.AppendChild(&ast.Node{Type: ast.NodeLinkDest, Tokens: util.StrToBytes(util.DomAttrValue(n, "href"))})
542+
linkTitle := util.DomAttrValue(n, "title")
543543
if "" != linkTitle {
544544
node.AppendChild(&ast.Node{Type: ast.NodeLinkSpace})
545545
node.AppendChild(&ast.Node{Type: ast.NodeLinkTitle, Tokens: util.StrToBytes(linkTitle)})
@@ -566,15 +566,15 @@ func (lute *Lute) genASTByDOM(n *html.Node, tree *parse.Tree) {
566566

567567
func appendSpace(n *html.Node, tree *parse.Tree, lute *Lute) {
568568
if nil != n.NextSibling {
569-
if nextText := lute.domText(n.NextSibling); "" != nextText {
569+
if nextText := util.DomText(n.NextSibling); "" != nextText {
570570
if runes := []rune(nextText); !unicode.IsSpace(runes[0]) {
571571
if unicode.IsPunct(runes[0]) || unicode.IsSymbol(runes[0]) {
572572
tree.Context.Tip.InsertBefore(&ast.Node{Type: ast.NodeText, Tokens: []byte(" ")})
573573
tree.Context.Tip.InsertAfter(&ast.Node{Type: ast.NodeText, Tokens: []byte(" ")})
574574
return
575575
}
576576

577-
if curText := lute.domText(n); "" != curText {
577+
if curText := util.DomText(n); "" != curText {
578578
runes = []rune(curText)
579579
if lastC := runes[len(runes)-1]; unicode.IsPunct(lastC) || unicode.IsSymbol(lastC) {
580580
tree.Context.Tip.InsertBefore(&ast.Node{Type: ast.NodeText, Tokens: []byte(" ")})

html/escape_encode.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,25 @@ import (
1515
"strings"
1616
"unicode/utf8"
1717

18+
"github.com/88250/lute/editor"
1819
"github.com/88250/lute/lex"
19-
"github.com/88250/lute/util"
2020
)
2121

2222
var (
23-
amp = util.StrToBytes("&amp;")
24-
lt = util.StrToBytes("&lt;")
25-
gt = util.StrToBytes("&gt;")
26-
quot = util.StrToBytes("&quot;")
23+
amp = []byte("&amp;")
24+
lt = []byte("&lt;")
25+
gt = []byte("&gt;")
26+
quot = []byte("&quot;")
2727
)
2828

2929
func UnescapeAttrVal(v string) string {
30-
v = strings.ReplaceAll(v, util.IALValEscNewLine, "\n")
30+
v = strings.ReplaceAll(v, editor.IALValEscNewLine, "\n")
3131
return UnescapeString(v)
3232
}
3333

3434
func EscapeAttrVal(v string) (ret string) {
35-
ret = util.BytesToStr(EscapeHTML(util.StrToBytes(v)))
36-
ret = strings.ReplaceAll(ret, "\n", util.IALValEscNewLine)
35+
ret = string(EscapeHTML([]byte(v)))
36+
ret = strings.ReplaceAll(ret, "\n", editor.IALValEscNewLine)
3737
return
3838
}
3939

@@ -42,11 +42,11 @@ func UnescapeHTMLStr(h string) string {
4242
}
4343

4444
func EscapeHTMLStr(h string) string {
45-
return util.BytesToStr(EscapeHTML(util.StrToBytes(h)))
45+
return string(EscapeHTML([]byte(h)))
4646
}
4747

4848
func UnescapeHTML(h []byte) (ret []byte) {
49-
return util.StrToBytes(UnescapeString(util.BytesToStr(h)))
49+
return []byte(UnescapeString(string(h)))
5050
}
5151

5252
func EscapeHTML(html []byte) (ret []byte) {

html/token.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ package html
77
import (
88
"bytes"
99
"errors"
10-
"github.com/88250/lute/util"
1110
"io"
1211
"strconv"
1312
"strings"
1413

14+
"github.com/88250/lute/editor"
1515
"github.com/88250/lute/html/atom"
1616
)
1717

@@ -88,8 +88,8 @@ func (t Token) tagString() string {
8888
}
8989
buf := bytes.NewBufferString(t.Data)
9090
for _, a := range t.Attr {
91-
if a.Key == util.CaretReplacement {
92-
buf.WriteString(util.CaretReplacement)
91+
if a.Key == editor.CaretReplacement {
92+
buf.WriteString(editor.CaretReplacement)
9393
continue
9494
}
9595
buf.WriteByte(' ')

0 commit comments

Comments
 (0)