From 6757da9122c584972544559c23a074f074ebade5 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 16:55:56 +0800 Subject: [PATCH 1/9] :art: Tag search supports space-separated keywords https://github.com/siyuan-note/siyuan/issues/14580 --- kernel/sql/span.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sql/span.go b/kernel/sql/span.go index d0b055cbb..26770cddc 100644 --- a/kernel/sql/span.go +++ b/kernel/sql/span.go @@ -101,7 +101,7 @@ func QueryTagSpansByKeyword(keyword string, limit int) (ret []*Span) { contentLikes := "" for _, k := range keywords { if contentLikes != "" { - contentLikes += " OR " + contentLikes += " AND " } contentLikes += "content LIKE '%" + k + "%'" } From 1b98f43be75c1fce357381eb1da5f2c8ff4ca6d5 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 17:13:15 +0800 Subject: [PATCH 2/9] :art: Support replacing inline tags with plain text https://github.com/siyuan-note/siyuan/issues/11238 --- kernel/model/search.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/model/search.go b/kernel/model/search.go index 9f4cd91f9..e48304dff 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -947,7 +947,13 @@ func replaceNodeTextMarkTextContent(n *ast.Node, method int, keyword, escapedKey replacement = strings.TrimSuffix(replacement, "#") } else { // 将标签转换为纯文本 if "tag" == n.TextMarkType { // 没有其他类型,仅是标签时直接转换 - n.InsertBefore(&ast.Node{Type: ast.NodeText, Tokens: []byte(n.TextMarkTextContent)}) + content := n.TextMarkTextContent + if strings.Contains(content, escapedKey) { + content = strings.ReplaceAll(content, escapedKey, replacement) + } else if strings.Contains(content, keyword) { + content = strings.ReplaceAll(content, keyword, replacement) + } + n.InsertBefore(&ast.Node{Type: ast.NodeText, Tokens: []byte(content)}) n.TextMarkTextContent = "" return } From b66558059dbc8c36884ff0476c903ab4a5b3c7f4 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 17:16:29 +0800 Subject: [PATCH 3/9] :art: Support replacing inline tags with plain text https://github.com/siyuan-note/siyuan/issues/11238 --- kernel/model/search.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/model/search.go b/kernel/model/search.go index e48304dff..6da54f800 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -945,7 +945,9 @@ func replaceNodeTextMarkTextContent(n *ast.Node, method int, keyword, escapedKey if strings.HasPrefix(replacement, "#") && strings.HasSuffix(replacement, "#") { replacement = strings.TrimPrefix(replacement, "#") replacement = strings.TrimSuffix(replacement, "#") - } else { // 将标签转换为纯文本 + } else { + // 将标签转换为纯文本 + if "tag" == n.TextMarkType { // 没有其他类型,仅是标签时直接转换 content := n.TextMarkTextContent if strings.Contains(content, escapedKey) { From 6c60a3726f382c027ed9c5f46533d766422c6706 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 17:47:40 +0800 Subject: [PATCH 4/9] :art: Reduce the probability of `tree not found` when deleting/renaming tags https://github.com/siyuan-note/siyuan/issues/14591 --- kernel/model/tag.go | 4 ++-- kernel/model/tree.go | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/kernel/model/tag.go b/kernel/model/tag.go index 729ad4d8a..07b1151c7 100644 --- a/kernel/model/tag.go +++ b/kernel/model/tag.go @@ -53,7 +53,7 @@ func RemoveTag(label string) (err error) { updateNodes := map[string]*ast.Node{} for treeID, blocks := range treeBlocks { util.PushEndlessProgress("[" + treeID + "]") - tree, e := LoadTreeByBlockID(treeID) + tree, e := LoadTreeByBlockIDWithReindex(treeID) if nil != e { util.ClearPushProgress(100) return e @@ -154,7 +154,7 @@ func RenameTag(oldLabel, newLabel string) (err error) { for treeID, blocks := range treeBlocks { util.PushEndlessProgress("[" + treeID + "]") - tree, e := LoadTreeByBlockID(treeID) + tree, e := LoadTreeByBlockIDWithReindex(treeID) if nil != e { util.ClearPushProgress(100) return e diff --git a/kernel/model/tree.go b/kernel/model/tree.go index 84cd2130c..cd26fb03b 100644 --- a/kernel/model/tree.go +++ b/kernel/model/tree.go @@ -178,8 +178,6 @@ var ( ) func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) { - // 仅提供给 getBlockInfo 接口使用 - if "" == id { logging.LogWarnf("block id is empty") return nil, ErrTreeNotFound @@ -192,8 +190,9 @@ func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) { return } - // 尝试从文件系统加载 - searchTreeInFilesystem(id) + // 尝试从文件系统加载并建立索引 + indexTreeInFilesystem(id) + bt = treenode.GetBlockTree(id) if nil == bt { if "dev" == util.Mode { @@ -243,7 +242,7 @@ func loadTreeByBlockTree(bt *treenode.BlockTree) (ret *parse.Tree, err error) { var searchTreeLimiter = rate.NewLimiter(rate.Every(3*time.Second), 1) -func searchTreeInFilesystem(rootID string) { +func indexTreeInFilesystem(rootID string) { if !searchTreeLimiter.Allow() { return } From 87709cd5a192f43f33e519b854cd81c9c19fe905 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 18:20:38 +0800 Subject: [PATCH 5/9] :art: Supports replacing tags with other inline elements https://github.com/siyuan-note/siyuan/issues/11238 --- kernel/model/search.go | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/kernel/model/search.go b/kernel/model/search.go index 6da54f800..13492699e 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -728,7 +728,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "em") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "em", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) mergeSamePreNext(n) @@ -738,7 +738,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "strong") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "strong", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) mergeSamePreNext(n) @@ -748,7 +748,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "kbd") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "kbd", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) } @@ -757,7 +757,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "mark") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "mark", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) mergeSamePreNext(n) @@ -767,7 +767,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "s") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "s", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) mergeSamePreNext(n) @@ -777,7 +777,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "sub") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "sub", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) } @@ -786,7 +786,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "sup") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "sup", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) } @@ -795,7 +795,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "tag") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "tag", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) } @@ -804,7 +804,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "u") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "u", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) mergeSamePreNext(n) @@ -853,7 +853,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return ast.WalkContinue } - replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "text") + replaceNodeTextMarkTextContent(n, method, keyword, escapedKey, replacement, r, "text", luteEngine) if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) mergeSamePreNext(n) @@ -935,7 +935,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids return } -func replaceNodeTextMarkTextContent(n *ast.Node, method int, keyword, escapedKey string, replacement string, r *regexp.Regexp, typ string) { +func replaceNodeTextMarkTextContent(n *ast.Node, method int, keyword, escapedKey string, replacement string, r *regexp.Regexp, typ string, luteEngine *lute.Lute) { if 0 == method { if strings.Contains(typ, "tag") { keyword = strings.TrimPrefix(keyword, "#") @@ -955,7 +955,21 @@ func replaceNodeTextMarkTextContent(n *ast.Node, method int, keyword, escapedKey } else if strings.Contains(content, keyword) { content = strings.ReplaceAll(content, keyword, replacement) } - n.InsertBefore(&ast.Node{Type: ast.NodeText, Tokens: []byte(content)}) + + tree := parse.Inline("", []byte(content), luteEngine.ParseOptions) + if nil == tree.Root.FirstChild { + return + } + parse.NestedInlines2FlattedSpans(tree, false) + + var replaceNodes []*ast.Node + for rNode := tree.Root.FirstChild.FirstChild; nil != rNode; rNode = rNode.Next { + replaceNodes = append(replaceNodes, rNode) + } + + for _, rNode := range replaceNodes { + n.InsertBefore(rNode) + } n.TextMarkTextContent = "" return } From e24ff7d8c4e2091e9e58dc29e4ada7170219ee4d Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 18:36:25 +0800 Subject: [PATCH 6/9] :technologist: Improve editor refresh for kernel API `/api/block/moveBlock` https://github.com/siyuan-note/siyuan/issues/14559 --- kernel/api/block_op.go | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/kernel/api/block_op.go b/kernel/api/block_op.go index 97261bee3..c88bdb50e 100644 --- a/kernel/api/block_op.go +++ b/kernel/api/block_op.go @@ -319,6 +319,13 @@ func moveBlock(c *gin.Context) { return } + currentBt := treenode.GetBlockTree(id) + if nil == currentBt { + ret.Code = -1 + ret.Msg = "block not found [id=" + id + "]" + return + } + var parentID, previousID string if nil != arg["parentID"] { parentID = arg["parentID"].(string) @@ -340,6 +347,19 @@ func moveBlock(c *gin.Context) { } } + var targetBt *treenode.BlockTree + if "" != previousID { + targetBt = treenode.GetBlockTree(previousID) + } else if "" != parentID { + targetBt = treenode.GetBlockTree(parentID) + } + + if nil == targetBt { + ret.Code = -1 + ret.Msg = "target block not found [id=" + parentID + "]" + return + } + transactions := []*model.Transaction{ { DoOperations: []*model.Operation{ @@ -356,8 +376,10 @@ func moveBlock(c *gin.Context) { model.PerformTransactions(&transactions) model.FlushTxQueue() - ret.Data = transactions - broadcastTransactions(transactions) + model.ReloadProtyle(currentBt.RootID) + if currentBt.RootID != targetBt.RootID { + model.ReloadProtyle(targetBt.RootID) + } } func appendBlock(c *gin.Context) { From 10d1735688ce534bd927991e9ee6e6a6a0ddc3f3 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 20:32:58 +0800 Subject: [PATCH 7/9] :art: Improve tag panel refresh https://github.com/siyuan-note/siyuan/issues/14593 --- kernel/model/search.go | 2 ++ kernel/util/websocket.go | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/kernel/model/search.go b/kernel/model/search.go index 13492699e..b4aa12115 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -799,6 +799,8 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids if "" == n.TextMarkTextContent { unlinks = append(unlinks, n) } + + util.PushReloadTag() } else if n.IsTextMarkType("u") { if !replaceTypes["u"] { return ast.WalkContinue diff --git a/kernel/util/websocket.go b/kernel/util/websocket.go index 6ba724266..a0638d5b0 100644 --- a/kernel/util/websocket.go +++ b/kernel/util/websocket.go @@ -182,6 +182,10 @@ func PushReloadFiletree() { BroadcastByType("filetree", "reloadFiletree", 0, "", nil) } +func PushReloadTag() { + BroadcastByType("main", "reloadTag", 0, "", nil) +} + type BlockStatResult struct { RuneCount int `json:"runeCount"` WordCount int `json:"wordCount"` From f25dcffa986fafef2bfe848e9291cf3e8d78f7c5 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 20:33:34 +0800 Subject: [PATCH 8/9] :technologist: Add an internal kernel API `/api/ui/reloadTag` https://github.com/siyuan-note/siyuan/issues/14594 --- kernel/api/router.go | 1 + kernel/api/ui.go | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/kernel/api/router.go b/kernel/api/router.go index 119bb09a1..ce237428f 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -477,4 +477,5 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/ui/reloadAttributeView", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reloadAttributeView) ginServer.Handle("POST", "/api/ui/reloadProtyle", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reloadProtyle) ginServer.Handle("POST", "/api/ui/reloadFiletree", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reloadFiletree) + ginServer.Handle("POST", "/api/ui/reloadTag", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reloadTag) } diff --git a/kernel/api/ui.go b/kernel/api/ui.go index f18ec8672..a125ce20e 100644 --- a/kernel/api/ui.go +++ b/kernel/api/ui.go @@ -25,6 +25,13 @@ import ( "github.com/siyuan-note/siyuan/kernel/util" ) +func reloadTag(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + util.PushReloadTag() +} + func reloadFiletree(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) From 7003ef15cb91bcbbf848c334a3881b0676d74b21 Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Sun, 13 Apr 2025 21:22:31 +0800 Subject: [PATCH 9/9] :art: Supports replacing tags with other inline elements https://github.com/siyuan-note/siyuan/issues/11238 --- kernel/model/search.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kernel/model/search.go b/kernel/model/search.go index b4aa12115..f92cf1fed 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -965,14 +965,27 @@ func replaceNodeTextMarkTextContent(n *ast.Node, method int, keyword, escapedKey parse.NestedInlines2FlattedSpans(tree, false) var replaceNodes []*ast.Node + var defIDs []string for rNode := tree.Root.FirstChild.FirstChild; nil != rNode; rNode = rNode.Next { replaceNodes = append(replaceNodes, rNode) + if blockRefID, _, _ := treenode.GetBlockRef(rNode); "" != blockRefID { + defIDs = append(defIDs, blockRefID) + } } for _, rNode := range replaceNodes { n.InsertBefore(rNode) } n.TextMarkTextContent = "" + + for _, defID := range defIDs { + bt := treenode.GetBlockTree(defID) + if nil == bt { + continue + } + + task.AppendAsyncTaskWithDelay(task.SetDefRefCount, util.SQLFlushInterval, refreshRefCount, bt.RootID, defID) + } return }