瀏覽代碼

:art: 数据历史文档支持只读可视化预览 https://github.com/siyuan-note/siyuan/issues/5735

Liang Ding 2 年之前
父節點
當前提交
bdd6e6ea3e
共有 2 個文件被更改,包括 72 次插入4 次删除
  1. 8 2
      kernel/api/history.go
  2. 64 2
      kernel/model/history.go

+ 8 - 2
kernel/api/history.go

@@ -116,7 +116,12 @@ func getDocHistoryContent(c *gin.Context) {
 	}
 
 	historyPath := arg["historyPath"].(string)
-	content, err := model.GetDocHistoryContent(historyPath)
+	k := arg["k"]
+	var keyword string
+	if nil != k {
+		keyword = k.(string)
+	}
+	content, isLargeDoc, err := model.GetDocHistoryContent(historyPath, keyword)
 	if nil != err {
 		ret.Code = -1
 		ret.Msg = err.Error()
@@ -124,7 +129,8 @@ func getDocHistoryContent(c *gin.Context) {
 	}
 
 	ret.Data = map[string]interface{}{
-		"content": content,
+		"content":    content,
+		"isLargeDoc": isLargeDoc,
 	}
 }
 

+ 64 - 2
kernel/model/history.go

@@ -17,6 +17,7 @@
 package model
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"io/fs"
@@ -30,10 +31,13 @@ import (
 
 	"github.com/88250/gulu"
 	"github.com/88250/lute"
+	"github.com/88250/lute/ast"
 	"github.com/88250/lute/parse"
+	"github.com/88250/lute/render"
 	"github.com/siyuan-note/filelock"
 	"github.com/siyuan-note/logging"
 	"github.com/siyuan-note/siyuan/kernel/conf"
+	"github.com/siyuan-note/siyuan/kernel/search"
 	"github.com/siyuan-note/siyuan/kernel/sql"
 	"github.com/siyuan-note/siyuan/kernel/treenode"
 	"github.com/siyuan-note/siyuan/kernel/util"
@@ -137,7 +141,7 @@ func ClearWorkspaceHistory() (err error) {
 	return
 }
 
-func GetDocHistoryContent(historyPath string) (content string, err error) {
+func GetDocHistoryContent(historyPath, keyword string) (content string, isLargeDoc bool, err error) {
 	if !gulu.File.IsExist(historyPath) {
 		return
 	}
@@ -147,6 +151,8 @@ func GetDocHistoryContent(historyPath string) (content string, err error) {
 		logging.LogErrorf("read file [%s] failed: %s", historyPath, err)
 		return
 	}
+	isLargeDoc = 1024*1024*1 <= len(data)
+
 	luteEngine := NewLute()
 	historyTree, err := parse.ParseJSONWithoutFix(data, luteEngine.ParseOptions)
 	if nil != err {
@@ -155,7 +161,63 @@ func GetDocHistoryContent(historyPath string) (content string, err error) {
 		return
 	}
 
-	content = luteEngine.Tree2BlockDOM(historyTree, luteEngine.RenderOptions)
+	renderTree := &parse.Tree{Root: &ast.Node{Type: ast.NodeDocument}}
+	keyword = strings.Join(strings.Split(keyword, " "), search.TermSep)
+	keywords := search.SplitKeyword(keyword)
+
+	var unlinks []*ast.Node
+	ast.Walk(historyTree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
+		if !entering {
+			return ast.WalkContinue
+		}
+
+		if ast.NodeBlockRef == n.Type {
+			appendRefTextRenderResultForBlockRef(n)
+			return ast.WalkSkipChildren
+		}
+
+		if ast.NodeText == n.Type {
+			if 0 < len(keywords) {
+				// 搜索高亮
+				text := string(n.Tokens)
+				text = search.EncloseHighlighting(text, keywords, "<span data-type=\"search-mark\">", "</span>", false)
+				n.Tokens = gulu.Str.ToBytes(text)
+				if bytes.Contains(n.Tokens, []byte("search-mark")) {
+					n.Tokens = bytes.ReplaceAll(n.Tokens, []byte("\\<span data-type=\"search-mark\">"), []byte("\\\\<span data-type=\"search-mark\">"))
+					linkTree := parse.Inline("", n.Tokens, luteEngine.ParseOptions)
+					var children []*ast.Node
+					for c := linkTree.Root.FirstChild.FirstChild; nil != c; c = c.Next {
+						children = append(children, c)
+					}
+					for _, c := range children {
+						n.InsertBefore(c)
+					}
+					unlinks = append(unlinks, n)
+					return ast.WalkContinue
+				}
+			}
+		}
+		return ast.WalkContinue
+	})
+
+	for _, unlink := range unlinks {
+		unlink.Unlink()
+	}
+
+	var appends []*ast.Node
+	for n := historyTree.Root.FirstChild; nil != n; n = n.Next {
+		appends = append(appends, n)
+	}
+	for _, n := range appends {
+		renderTree.Root.AppendChild(n)
+	}
+
+	if isLargeDoc {
+		formatRenderer := render.NewFormatRenderer(renderTree, luteEngine.RenderOptions)
+		content = gulu.Str.FromBytes(formatRenderer.Render())
+	} else {
+		content = luteEngine.Tree2BlockDOM(renderTree, luteEngine.RenderOptions)
+	}
 	return
 }