From bdd6e6ea3e866734aaa75dbf5b9132aeecade710 Mon Sep 17 00:00:00 2001 From: Liang Ding Date: Wed, 31 Aug 2022 11:26:43 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E6=95=B0=E6=8D=AE=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E6=94=AF=E6=8C=81=E5=8F=AA=E8=AF=BB=E5=8F=AF?= =?UTF-8?q?=E8=A7=86=E5=8C=96=E9=A2=84=E8=A7=88=20https://github.com/siyua?= =?UTF-8?q?n-note/siyuan/issues/5735?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/api/history.go | 10 +++++-- kernel/model/history.go | 66 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 4 deletions(-) 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 }