From 0d3df5d449c04dbb21b41a828a4c634aff1ac6ef Mon Sep 17 00:00:00 2001 From: Daniel <845765@qq.com> Date: Wed, 16 Jul 2025 10:01:37 +0800 Subject: [PATCH] Revert ":technologist: Improve kernel API `/api/block/updateBlock` and `/api/block/batchUpdateBlock` https://github.com/siyuan-note/siyuan/issues/15301" This reverts commit d7c95e1b49f753ab5231d4ba98c2dcf3578067da. --- API.md | 16 +++- API_zh_CN.md | 16 +++- kernel/api/block_op.go | 151 +++++++++++++++++++++--------------- kernel/model/assets.go | 2 +- kernel/model/bookmark.go | 4 +- kernel/model/export.go | 29 ++++--- kernel/model/file.go | 4 +- kernel/model/format.go | 2 +- kernel/model/search.go | 2 +- kernel/model/tag.go | 4 +- kernel/model/transaction.go | 2 +- kernel/model/tree.go | 11 --- 12 files changed, 149 insertions(+), 94 deletions(-) diff --git a/API.md b/API.md index 45e0ad65d..14c548c35 100644 --- a/API.md +++ b/API.md @@ -782,7 +782,21 @@ Move documents by `id`: { "code": 0, "msg": "", - "data": null + "data": [ + { + "doOperations": [ + { + "action": "update", + "data": "
foobarbaz
", + "id": "20211230161520-querkps", + "parentID": "", + "previousID": "", + "retData": null + } + ], + "undoOperations": null + } + ] } ``` diff --git a/API_zh_CN.md b/API_zh_CN.md index cbf5ec36f..c9694fb25 100644 --- a/API_zh_CN.md +++ b/API_zh_CN.md @@ -776,7 +776,21 @@ { "code": 0, "msg": "", - "data": null + "data": [ + { + "doOperations": [ + { + "action": "update", + "data": "
foobarbaz
", + "id": "20211230161520-querkps", + "parentID": "", + "previousID": "", + "retData": null + } + ], + "undoOperations": null + } + ] } ``` diff --git a/kernel/api/block_op.go b/kernel/api/block_op.go index 353b4f7cb..c88bdb50e 100644 --- a/kernel/api/block_op.go +++ b/kernel/api/block_op.go @@ -25,6 +25,7 @@ import ( "github.com/88250/lute/ast" "github.com/88250/lute/parse" "github.com/gin-gonic/gin" + "github.com/siyuan-note/siyuan/kernel/filesys" "github.com/siyuan-note/siyuan/kernel/model" "github.com/siyuan-note/siyuan/kernel/treenode" "github.com/siyuan-note/siyuan/kernel/util" @@ -567,55 +568,62 @@ func updateBlock(c *gin.Context) { return } - oldTree, err := model.LoadTreeByBlockID(id) + block, err := model.GetBlock(id, nil) if err != nil { ret.Code = -1 - ret.Msg = "load tree failed: " + err.Error() + ret.Msg = "get block failed: " + err.Error() return } - node := treenode.GetNodeInTree(oldTree, id) - if nil == node { - ret.Code = -1 - ret.Msg = "block not found [id=" + id + "]" - return - } - - if ast.NodeDocument == node.Type { + var transactions []*model.Transaction + if "NodeDocument" == block.Type { + oldTree, err := filesys.LoadTree(block.Box, block.Path, luteEngine) + if err != nil { + ret.Code = -1 + ret.Msg = "load tree failed: " + err.Error() + return + } var toRemoves []*ast.Node + var ops []*model.Operation for n := oldTree.Root.FirstChild; nil != n; n = n.Next { toRemoves = append(toRemoves, n) + ops = append(ops, &model.Operation{Action: "delete", ID: n.ID}) } for _, n := range toRemoves { n.Unlink() } - - var toAppends []*ast.Node - for n := tree.Root.FirstChild; nil != n; n = n.Next { - toAppends = append(toAppends, n) - } - for _, n := range toAppends { - oldTree.Root.AppendChild(n) - } + ops = append(ops, &model.Operation{Action: "appendInsert", Data: data, ParentID: id}) + transactions = append(transactions, &model.Transaction{ + DoOperations: ops, + }) } else { - if ast.NodeListItem == node.Type && ast.NodeList == tree.Root.FirstChild.Type { + if "NodeListItem" == block.Type && ast.NodeList == tree.Root.FirstChild.Type { // 使用 API `api/block/updateBlock` 更新列表项时渲染错误 https://github.com/siyuan-note/siyuan/issues/4658 tree.Root.AppendChild(tree.Root.FirstChild.FirstChild) // 将列表下的第一个列表项移到文档结尾,移动以后根下面直接挂列表项,渲染器可以正常工作 tree.Root.FirstChild.Unlink() // 删除列表 tree.Root.FirstChild.Unlink() // 继续删除列表 IAL } tree.Root.FirstChild.SetIALAttr("id", id) - tree.Root.FirstChild.ID = id - node.InsertBefore(tree.Root.FirstChild) - node.Unlink() + + data = luteEngine.Tree2BlockDOM(tree, luteEngine.RenderOptions) + transactions = []*model.Transaction{ + { + DoOperations: []*model.Operation{ + { + Action: "update", + ID: id, + Data: data, + }, + }, + }, + } } - if err = model.WriteTreeUpsertQueue(oldTree); err != nil { - ret.Code = -1 - ret.Msg = "write tree upsert queue failed: " + err.Error() - return - } - model.ReloadProtyle(oldTree.ID) + model.PerformTransactions(&transactions) + model.FlushTxQueue() + + ret.Data = transactions + broadcastTransactions(transactions) } func batchUpdateBlock(c *gin.Context) { @@ -628,7 +636,16 @@ func batchUpdateBlock(c *gin.Context) { } blocksArg := arg["blocks"].([]interface{}) - blocks := map[string]*parse.Tree{} + + type updateBlockArg struct { + ID string + Data string + DataType string + Block *model.Block + Tree *parse.Tree + } + + var blocks []*updateBlockArg luteEngine := util.NewLute() for _, blockArg := range blocksArg { blockMap := blockArg.(map[string]interface{}) @@ -655,62 +672,72 @@ func batchUpdateBlock(c *gin.Context) { return } - blocks[id] = tree - } - - trees := map[string]*parse.Tree{} - for id, tree := range blocks { - oldTree, err := model.LoadTreeWithCache(id, &trees) + block, err := model.GetBlock(id, nil) if err != nil { ret.Code = -1 - ret.Msg = "load tree failed: " + err.Error() + ret.Msg = "get block failed: " + err.Error() return } - node := treenode.GetNodeInTree(oldTree, id) - if nil == node { - ret.Code = -1 - ret.Msg = "block not found [id=" + id + "]" - return - } + blocks = append(blocks, &updateBlockArg{ + ID: id, + Data: data, + DataType: dataType, + Block: block, + Tree: tree, + }) + } - if ast.NodeDocument == node.Type { + var ops []*model.Operation + tx := &model.Transaction{} + transactions := []*model.Transaction{tx} + for _, upBlock := range blocks { + block := upBlock.Block + data := upBlock.Data + tree := upBlock.Tree + id := upBlock.ID + if "NodeDocument" == block.Type { + oldTree, err := filesys.LoadTree(block.Box, block.Path, luteEngine) + if err != nil { + ret.Code = -1 + ret.Msg = "load tree failed: " + err.Error() + return + } var toRemoves []*ast.Node + for n := oldTree.Root.FirstChild; nil != n; n = n.Next { toRemoves = append(toRemoves, n) + ops = append(ops, &model.Operation{Action: "delete", ID: n.ID}) } for _, n := range toRemoves { n.Unlink() } - var toAppends []*ast.Node - for n := tree.Root.FirstChild; nil != n; n = n.Next { - toAppends = append(toAppends, n) - } - for _, n := range toAppends { - oldTree.Root.AppendChild(n) - } + ops = append(ops, &model.Operation{Action: "appendInsert", Data: data, ParentID: id}) } else { - if ast.NodeListItem == node.Type && ast.NodeList == tree.Root.FirstChild.Type { + if "NodeListItem" == block.Type && ast.NodeList == tree.Root.FirstChild.Type { // 使用 API `api/block/updateBlock` 更新列表项时渲染错误 https://github.com/siyuan-note/siyuan/issues/4658 tree.Root.AppendChild(tree.Root.FirstChild.FirstChild) // 将列表下的第一个列表项移到文档结尾,移动以后根下面直接挂列表项,渲染器可以正常工作 tree.Root.FirstChild.Unlink() // 删除列表 tree.Root.FirstChild.Unlink() // 继续删除列表 IAL } tree.Root.FirstChild.SetIALAttr("id", id) - tree.Root.FirstChild.ID = id - node.InsertBefore(tree.Root.FirstChild) - node.Unlink() + + data = luteEngine.Tree2BlockDOM(tree, luteEngine.RenderOptions) + ops = append(ops, &model.Operation{ + Action: "update", + ID: id, + Data: data, + }) } } - for _, tree := range trees { - if err := model.WriteTreeUpsertQueue(tree); nil != err { - ret.Code = -1 - ret.Msg = "write tree upsert queue failed: " + err.Error() - return - } - model.ReloadProtyle(tree.ID) - } + tx.DoOperations = ops + model.PerformTransactions(&transactions) + model.FlushTxQueue() + + ret.Data = transactions + broadcastTransactions(transactions) + } func deleteBlock(c *gin.Context) { diff --git a/kernel/model/assets.go b/kernel/model/assets.go index 207dc48e5..6dd1eb21a 100644 --- a/kernel/model/assets.go +++ b/kernel/model/assets.go @@ -321,7 +321,7 @@ func NetAssets2LocalAssets(rootID string, onlyImg bool, originalURL string) (err util.PushClearMsg(msgId) if 0 < files { msgId = util.PushMsg(Conf.Language(113), 7000) - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { return } util.PushUpdateMsg(msgId, fmt.Sprintf(Conf.Language(120), files), 5000) diff --git a/kernel/model/bookmark.go b/kernel/model/bookmark.go index aa38bfe3e..80ef3e136 100644 --- a/kernel/model/bookmark.go +++ b/kernel/model/bookmark.go @@ -66,7 +66,7 @@ func RemoveBookmark(bookmark string) (err error) { } util.PushEndlessProgress(fmt.Sprintf(Conf.Language(111), util.EscapeHTML(tree.Root.IALAttr("title")))) - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { util.ClearPushProgress(100) return } @@ -124,7 +124,7 @@ func RenameBookmark(oldBookmark, newBookmark string) (err error) { } util.PushEndlessProgress(fmt.Sprintf(Conf.Language(111), util.EscapeHTML(tree.Root.IALAttr("title")))) - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { util.ClearPushProgress(100) return } diff --git a/kernel/model/export.go b/kernel/model/export.go index e6bb4acfe..ccf92e8ba 100644 --- a/kernel/model/export.go +++ b/kernel/model/export.go @@ -310,7 +310,7 @@ func Export2Liandi(id string) (err error) { articleId = result.Data.(string) tree, _ = LoadTreeByBlockID(id) // 这里必须重新加载,因为前面导出时已经修改了树结构 tree.Root.SetIALAttr(liandiArticleIdAttrName, articleId) - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { return } } @@ -1994,7 +1994,7 @@ func ExportMarkdownContent(id string, refMode, embedMode int, addYfm, fillCSSVar } func exportMarkdownContent(id, ext string, exportRefMode int, defBlockIDs []string, singleFile bool, treeCache *map[string]*parse.Tree) (tree *parse.Tree, exportedMd string, isEmpty bool) { - tree, err := LoadTreeWithCache(id, treeCache) + tree, err := loadTreeWithCache(id, treeCache) if err != nil { logging.LogErrorf("load tree by block id [%s] failed: %s", id, err) return @@ -2788,7 +2788,7 @@ func resolveFootnotesDefs(refFootnotes *[]*refAsFootnotes, currentTree *parse.Tr footnotesDefBlock = &ast.Node{Type: ast.NodeFootnotesDefBlock} var rendered []string for _, foot := range *refFootnotes { - t, err := LoadTreeWithCache(foot.defID, treeCache) + t, err := loadTreeWithCache(foot.defID, treeCache) if nil != err { return } @@ -2924,7 +2924,7 @@ func blockLink2Ref(currentTree *parse.Tree, id string, treeCache *map[string]*pa if nil == b { return } - t, err := LoadTreeWithCache(b.RootID, treeCache) + t, err := loadTreeWithCache(b.RootID, treeCache) if nil != err { return } @@ -2974,7 +2974,7 @@ func collectFootnotesDefs(currentTree *parse.Tree, id string, refFootnotes *[]*r if nil == b { return } - t, err := LoadTreeWithCache(b.RootID, treeCache) + t, err := loadTreeWithCache(b.RootID, treeCache) if nil != err { return } @@ -3265,7 +3265,7 @@ func prepareExportTrees(docPaths []string) (defBlockIDs []string, trees *map[str continue } - tree, err := LoadTreeWithCache(rootID, treeCache) + tree, err := loadTreeWithCache(rootID, treeCache) if err != nil { continue } @@ -3307,7 +3307,7 @@ func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache if (*treeCache)[defBlock.RootID] != nil { defTree = (*treeCache)[defBlock.RootID] } else { - defTree, err = LoadTreeWithCache(defBlock.RootID, treeCache) + defTree, err = loadTreeWithCache(defBlock.RootID, treeCache) if err != nil { return ast.WalkSkipChildren } @@ -3331,7 +3331,7 @@ func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache if (*treeCache)[defBlock.RootID] != nil { defTree = (*treeCache)[defBlock.RootID] } else { - defTree, err = LoadTreeWithCache(defBlock.RootID, treeCache) + defTree, err = loadTreeWithCache(defBlock.RootID, treeCache) if err != nil { return ast.WalkSkipChildren } @@ -3370,7 +3370,7 @@ func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache if (*treeCache)[defBlock.RootID] != nil { defTree = (*treeCache)[defBlock.RootID] } else { - defTree, err = LoadTreeWithCache(defBlock.RootID, treeCache) + defTree, err = loadTreeWithCache(defBlock.RootID, treeCache) if err != nil { continue } @@ -3387,6 +3387,17 @@ func exportRefTrees(tree *parse.Tree, defBlockIDs *[]string, retTrees, treeCache *defBlockIDs = gulu.Str.RemoveDuplicatedElem(*defBlockIDs) } +func loadTreeWithCache(id string, treeCache *map[string]*parse.Tree) (tree *parse.Tree, err error) { + if tree = (*treeCache)[id]; nil != tree { + return + } + tree, err = LoadTreeByBlockID(id) + if nil == err && nil != tree { + (*treeCache)[id] = tree + } + return +} + func getAttrViewTable(attrView *av.AttributeView, view *av.View, query string) (ret *av.Table) { switch view.LayoutType { case av.LayoutTypeGallery: diff --git a/kernel/model/file.go b/kernel/model/file.go index c0fcf4e3e..bd3c51ddf 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -922,7 +922,7 @@ func loadNodesByMode(node *ast.Node, inputIndex, mode, size int, isDoc, isHeadin return } -func WriteTreeUpsertQueue(tree *parse.Tree) (err error) { +func writeTreeUpsertQueue(tree *parse.Tree) (err error) { size, err := filesys.WriteTree(tree) if err != nil { return @@ -944,7 +944,7 @@ func indexWriteTreeIndexQueue(tree *parse.Tree) (err error) { func indexWriteTreeUpsertQueue(tree *parse.Tree) (err error) { treenode.UpsertBlockTree(tree) - return WriteTreeUpsertQueue(tree) + return writeTreeUpsertQueue(tree) } func renameWriteJSONQueue(tree *parse.Tree) (err error) { diff --git a/kernel/model/format.go b/kernel/model/format.go index 35e99d0bb..2a324f47c 100644 --- a/kernel/model/format.go +++ b/kernel/model/format.go @@ -68,7 +68,7 @@ func AutoSpace(rootID string) (err error) { newTree.Path = tree.Path newTree.HPath = tree.HPath newTree.Box = tree.Box - err = WriteTreeUpsertQueue(newTree) + err = writeTreeUpsertQueue(newTree) if err != nil { return } diff --git a/kernel/model/search.go b/kernel/model/search.go index 19d60e623..e9168a273 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -932,7 +932,7 @@ func FindReplace(keyword, replacement string, replaceTypes map[string]bool, ids } } - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { return } updateNodes[id] = node diff --git a/kernel/model/tag.go b/kernel/model/tag.go index ba453ed40..d0d652ce6 100644 --- a/kernel/model/tag.go +++ b/kernel/model/tag.go @@ -96,7 +96,7 @@ func RemoveTag(label string) (err error) { n.Unlink() } util.PushEndlessProgress(fmt.Sprintf(Conf.Language(111), util.EscapeHTML(tree.Root.IALAttr("title")))) - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { util.ClearPushProgress(100) return } @@ -195,7 +195,7 @@ func RenameTag(oldLabel, newLabel string) (err error) { updateNodes[node.ID] = node } util.PushEndlessProgress(fmt.Sprintf(Conf.Language(111), util.EscapeHTML(tree.Root.IALAttr("title")))) - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { util.ClearPushProgress(100) return } diff --git a/kernel/model/transaction.go b/kernel/model/transaction.go index 5b827807c..0f943951d 100644 --- a/kernel/model/transaction.go +++ b/kernel/model/transaction.go @@ -1553,7 +1553,7 @@ func (tx *Transaction) begin() (err error) { func (tx *Transaction) commit() (err error) { for _, tree := range tx.trees { - if err = WriteTreeUpsertQueue(tree); err != nil { + if err = writeTreeUpsertQueue(tree); err != nil { return } diff --git a/kernel/model/tree.go b/kernel/model/tree.go index 5200f9303..cd26fb03b 100644 --- a/kernel/model/tree.go +++ b/kernel/model/tree.go @@ -207,17 +207,6 @@ func LoadTreeByBlockIDWithReindex(id string) (ret *parse.Tree, err error) { return } -func LoadTreeWithCache(id string, treeCache *map[string]*parse.Tree) (tree *parse.Tree, err error) { - if tree = (*treeCache)[id]; nil != tree { - return - } - tree, err = LoadTreeByBlockID(id) - if nil == err && nil != tree { - (*treeCache)[id] = tree - } - return -} - func LoadTreeByBlockID(id string) (ret *parse.Tree, err error) { if !ast.IsNodeIDPattern(id) { stack := logging.ShortStack()