Procházet zdrojové kódy

:art: Improve embed blocks exporting https://github.com/siyuan-note/siyuan/issues/11725

Daniel před 1 rokem
rodič
revize
2589b009eb
2 změnil soubory, kde provedl 78 přidání a 68 odebrání
  1. 3 55
      kernel/model/export.go
  2. 75 13
      kernel/model/render.go

+ 3 - 55
kernel/model/export.go

@@ -1932,62 +1932,9 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold bool,
 	luteEngine := NewLute()
 	ret = tree
 	id := tree.Root.ID
-	var unlinks []*ast.Node
 
 	// 解析查询嵌入节点
-	ast.Walk(ret.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
-		if !entering || ast.NodeBlockQueryEmbed != n.Type {
-			return ast.WalkContinue
-		}
-
-		var defMd string
-		stmt := n.ChildByType(ast.NodeBlockQueryEmbedScript).TokensStr()
-		stmt = html.UnescapeString(stmt)
-		stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
-		embedBlocks := searchEmbedBlock(n.ID, stmt, nil, 0, false)
-		if 1 > len(embedBlocks) {
-			return ast.WalkContinue
-		}
-
-		defMdBuf := bytes.Buffer{}
-		for _, def := range embedBlocks {
-			defMdBuf.WriteString(renderBlockMarkdownR(def.Block.ID))
-			defMdBuf.WriteString("\n\n")
-		}
-		defMd = defMdBuf.String()
-
-		buf := &bytes.Buffer{}
-		lines := strings.Split(defMd, "\n")
-		for i, line := range lines {
-			if 0 == blockEmbedMode { // 原始文本
-				buf.WriteString(line)
-			} else { // Blockquote
-				buf.WriteString("> " + line)
-			}
-			if i < len(lines)-1 {
-				buf.WriteString("\n")
-			}
-		}
-		buf.WriteString("\n\n")
-
-		refTree := parse.Parse("", buf.Bytes(), luteEngine.ParseOptions)
-		var children []*ast.Node
-		for c := refTree.Root.FirstChild; nil != c; c = c.Next {
-			children = append(children, c)
-		}
-		for _, c := range children {
-			if ast.NodeDocument == c.Type {
-				continue
-			}
-			n.InsertBefore(c)
-		}
-		unlinks = append(unlinks, n)
-		return ast.WalkSkipChildren
-	})
-	for _, n := range unlinks {
-		n.Unlink()
-	}
-	unlinks = nil
+	resolveEmbedR(ret.Root, blockEmbedMode, luteEngine, &[]string{})
 
 	// 收集引用转脚注
 	var refFootnotes []*refAsFootnotes
@@ -1998,6 +1945,7 @@ func exportTree(tree *parse.Tree, wysiwyg, keepFold bool,
 		collectFootnotesDefs(ret.ID, &refFootnotes, &treeCache, &depth)
 	}
 
+	var unlinks []*ast.Node
 	ast.Walk(ret.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
 		if !entering {
 			return ast.WalkContinue
@@ -2393,7 +2341,7 @@ func resolveFootnotesDefs(refFootnotes *[]*refAsFootnotes, rootID string, blockR
 					stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
 					sqlBlocks := sql.SelectBlocksRawStmt(stmt, 1, Conf.Search.Limit)
 					for _, b := range sqlBlocks {
-						subNodes := renderBlockMarkdownR0(b.ID, &rendered)
+						subNodes := renderBlockMarkdownR(b.ID, &rendered)
 						for _, subNode := range subNodes {
 							if ast.NodeListItem == subNode.Type {
 								parentList := &ast.Node{Type: ast.NodeList, ListData: &ast.ListData{Typ: subNode.ListData.Typ}}

+ 75 - 13
kernel/model/render.go

@@ -165,21 +165,83 @@ func renderBlockContentByNodes(nodes []*ast.Node) string {
 	return buf.String()
 }
 
-func renderBlockMarkdownR(id string) string {
-	var rendered []string
-	nodes := renderBlockMarkdownR0(id, &rendered)
-	buf := bytes.Buffer{}
-	buf.Grow(4096)
-	luteEngine := NewLute()
-	for _, n := range nodes {
-		md := treenode.FormatNode(n, luteEngine)
-		buf.WriteString(md)
-		buf.WriteString("\n\n")
+func resolveEmbedR(n *ast.Node, blockEmbedMode int, luteEngine *lute.Lute, resolved *[]string) {
+	var children []*ast.Node
+	if ast.NodeHeading == n.Type {
+		children = append(children, n)
+		children = append(children, treenode.HeadingChildren(n)...)
+	} else if ast.NodeDocument == n.Type {
+		for c := n.FirstChild; nil != c; c = c.Next {
+			children = append(children, c)
+		}
+	} else {
+		children = append(children, n)
 	}
-	return buf.String()
+
+	for _, child := range children {
+		var unlinks []*ast.Node
+		ast.Walk(child, func(n *ast.Node, entering bool) ast.WalkStatus {
+			if !entering || !n.IsBlock() {
+				return ast.WalkContinue
+			}
+
+			if ast.NodeBlockQueryEmbed == n.Type {
+				if gulu.Str.Contains(n.ID, *resolved) {
+					return ast.WalkContinue
+				}
+				*resolved = append(*resolved, n.ID)
+
+				stmt := n.ChildByType(ast.NodeBlockQueryEmbedScript).TokensStr()
+				stmt = html.UnescapeString(stmt)
+				stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
+				sqlBlocks := sql.SelectBlocksRawStmt(stmt, 1, Conf.Search.Limit)
+				for _, sqlBlock := range sqlBlocks {
+					md := sqlBlock.Markdown
+
+					if "d" == sqlBlock.Type {
+						subTree, _ := LoadTreeByBlockID(sqlBlock.ID)
+						md, _ = lute.FormatNodeSync(subTree.Root, luteEngine.ParseOptions, luteEngine.RenderOptions)
+					} // 标题块不需要再单独解析,直接使用 Markdown,函数开头处会处理
+
+					buf := &bytes.Buffer{}
+					lines := strings.Split(md, "\n")
+					for i, line := range lines {
+						if 0 == blockEmbedMode { // 使用原始文本
+							buf.WriteString(line)
+						} else { // 使用引述块
+							buf.WriteString("> " + line)
+						}
+						if i < len(lines)-1 {
+							buf.WriteString("\n")
+						}
+					}
+					buf.WriteString("\n\n")
+
+					subTree := parse.Parse("", buf.Bytes(), luteEngine.ParseOptions)
+					var inserts []*ast.Node
+					for subNode := subTree.Root.FirstChild; nil != subNode; subNode = subNode.Next {
+						if ast.NodeKramdownBlockIAL != subNode.Type {
+							inserts = append(inserts, subNode)
+						}
+					}
+					for _, insert := range inserts {
+						n.InsertBefore(insert)
+						resolveEmbedR(insert, blockEmbedMode, luteEngine, resolved)
+					}
+				}
+				unlinks = append(unlinks, n)
+				return ast.WalkSkipChildren
+			}
+			return ast.WalkContinue
+		})
+		for _, unlink := range unlinks {
+			unlink.Unlink()
+		}
+	}
+	return
 }
 
-func renderBlockMarkdownR0(id string, rendered *[]string) (ret []*ast.Node) {
+func renderBlockMarkdownR(id string, rendered *[]string) (ret []*ast.Node) {
 	if gulu.Str.Contains(id, *rendered) {
 		return
 	}
@@ -225,7 +287,7 @@ func renderBlockMarkdownR0(id string, rendered *[]string) (ret []*ast.Node) {
 				stmt = strings.ReplaceAll(stmt, editor.IALValEscNewLine, "\n")
 				sqlBlocks := sql.SelectBlocksRawStmt(stmt, 1, Conf.Search.Limit)
 				for _, sqlBlock := range sqlBlocks {
-					subNodes := renderBlockMarkdownR0(sqlBlock.ID, rendered)
+					subNodes := renderBlockMarkdownR(sqlBlock.ID, rendered)
 					for _, subNode := range subNodes {
 						inserts = append(inserts, subNode)
 					}