A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
at lambda-fork/main 147 lines 4.3 kB view raw
1// SiYuan - Refactor your thinking 2// Copyright (c) 2020-present, b3log.org 3// 4// This program is free software: you can redistribute it and/or modify 5// it under the terms of the GNU Affero General Public License as published by 6// the Free Software Foundation, either version 3 of the License, or 7// (at your option) any later version. 8// 9// This program is distributed in the hope that it will be useful, 10// but WITHOUT ANY WARRANTY; without even the implied warranty of 11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12// GNU Affero General Public License for more details. 13// 14// You should have received a copy of the GNU Affero General Public License 15// along with this program. If not, see <https://www.gnu.org/licenses/>. 16 17package model 18 19import ( 20 "path" 21 "strings" 22 23 "github.com/88250/lute/ast" 24 "github.com/88250/lute/parse" 25 "github.com/siyuan-note/siyuan/kernel/sql" 26 "github.com/siyuan-note/siyuan/kernel/treenode" 27 "github.com/siyuan-note/siyuan/kernel/util" 28) 29 30func ListItem2Doc(srcListItemID, targetBoxID, targetPath, previousPath string) (srcRootBlockID, newTargetPath string, err error) { 31 FlushTxQueue() 32 33 srcTree, _ := LoadTreeByBlockID(srcListItemID) 34 if nil == srcTree { 35 err = ErrBlockNotFound 36 return 37 } 38 srcRootBlockID = srcTree.Root.ID 39 40 listItemNode := treenode.GetNodeInTree(srcTree, srcListItemID) 41 if nil == listItemNode { 42 err = ErrBlockNotFound 43 return 44 } 45 46 box := Conf.Box(targetBoxID) 47 listItemText := sql.GetContainerText(listItemNode) 48 listItemText = util.FilterFileName(listItemText) 49 50 moveToRoot := "/" == targetPath 51 toHP := path.Join("/", listItemText) 52 toFolder := "/" 53 54 if "" != previousPath { 55 previousDoc := treenode.GetBlockTreeRootByPath(targetBoxID, previousPath) 56 if nil == previousDoc { 57 err = ErrBlockNotFound 58 return 59 } 60 parentPath := path.Dir(previousPath) 61 if "/" != parentPath { 62 parentPath = strings.TrimSuffix(parentPath, "/") + ".sy" 63 parentDoc := treenode.GetBlockTreeRootByPath(targetBoxID, parentPath) 64 if nil == parentDoc { 65 err = ErrBlockNotFound 66 return 67 } 68 toHP = path.Join(parentDoc.HPath, listItemText) 69 toFolder = path.Join(path.Dir(parentPath), parentDoc.ID) 70 } 71 } else { 72 if !moveToRoot { 73 parentDoc := treenode.GetBlockTreeRootByPath(targetBoxID, targetPath) 74 if nil == parentDoc { 75 err = ErrBlockNotFound 76 return 77 } 78 toHP = path.Join(parentDoc.HPath, listItemText) 79 toFolder = path.Join(path.Dir(targetPath), parentDoc.ID) 80 } 81 } 82 83 newTargetPath = path.Join(toFolder, srcListItemID+".sy") 84 if !box.Exist(toFolder) { 85 if err = box.MkdirAll(toFolder); err != nil { 86 return 87 } 88 } 89 90 var children []*ast.Node 91 for c := listItemNode.FirstChild; nil != c; c = c.Next { 92 if c.IsMarker() { 93 continue 94 } 95 children = append(children, c) 96 } 97 if 1 > len(children) { 98 newNode := treenode.NewParagraph("") 99 children = append(children, newNode) 100 } 101 102 luteEngine := util.NewLute() 103 newTree := &parse.Tree{Root: &ast.Node{Type: ast.NodeDocument, ID: srcListItemID}, Context: &parse.Context{ParseOption: luteEngine.ParseOptions}} 104 for _, c := range children { 105 newTree.Root.AppendChild(c) 106 } 107 newTree.ID = srcListItemID 108 newTree.Path = newTargetPath 109 newTree.HPath = toHP 110 listItemNode.SetIALAttr("type", "doc") 111 listItemNode.SetIALAttr("id", srcListItemID) 112 listItemNode.SetIALAttr("title", listItemText) 113 listItemNode.RemoveIALAttr("fold") 114 newTree.Root.KramdownIAL = listItemNode.KramdownIAL 115 srcLiParent := listItemNode.Parent 116 listItemNode.Unlink() 117 if nil != srcLiParent && nil == srcLiParent.FirstChild { 118 srcLiParent.Unlink() 119 } 120 srcTree.Root.SetIALAttr("updated", util.CurrentTimeSecondsStr()) 121 if nil == srcTree.Root.FirstChild { 122 srcTree.Root.AppendChild(treenode.NewParagraph("")) 123 } 124 treenode.RemoveBlockTreesByRootID(srcTree.ID) 125 if err = indexWriteTreeUpsertQueue(srcTree); err != nil { 126 return "", "", err 127 } 128 129 newTree.Box, newTree.Path = targetBoxID, newTargetPath 130 newTree.Root.SetIALAttr("updated", util.CurrentTimeSecondsStr()) 131 newTree.Root.Spec = "1" 132 if "" != previousPath { 133 box.addSort(previousPath, newTree.ID) 134 } else { 135 box.addMinSort(path.Dir(newTargetPath), newTree.ID) 136 } 137 if err = indexWriteTreeUpsertQueue(newTree); err != nil { 138 return "", "", err 139 } 140 IncSync() 141 go func() { 142 RefreshBacklink(srcTree.ID) 143 RefreshBacklink(newTree.ID) 144 ResetVirtualBlockRefCache() 145 }() 146 return 147}