diff --git a/kernel/api/history.go b/kernel/api/history.go
index 3d15ff5cd..432047916 100644
--- a/kernel/api/history.go
+++ b/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,
}
}
diff --git a/kernel/model/history.go b/kernel/model/history.go
index b244708b9..35ea1e350 100644
--- a/kernel/model/history.go
+++ b/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, "", "", false)
+ n.Tokens = gulu.Str.ToBytes(text)
+ if bytes.Contains(n.Tokens, []byte("search-mark")) {
+ n.Tokens = bytes.ReplaceAll(n.Tokens, []byte("\\"), []byte("\\\\"))
+ 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
}