tree.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SiYuan - Build Your Eternal Digital Garden
  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. package treenode
  17. import (
  18. "crypto/sha256"
  19. "fmt"
  20. "path"
  21. "sort"
  22. "strings"
  23. "github.com/88250/gulu"
  24. "github.com/88250/lute"
  25. "github.com/88250/lute/ast"
  26. "github.com/88250/lute/parse"
  27. util2 "github.com/88250/lute/util"
  28. "github.com/siyuan-note/siyuan/kernel/util"
  29. )
  30. func StatTree(tree *parse.Tree) (ret *util.BlockStatResult) {
  31. runeCnt, wordCnt, linkCnt, imgCnt, refCnt := tree.Root.Stat()
  32. return &util.BlockStatResult{
  33. RuneCount: runeCnt,
  34. WordCount: wordCnt,
  35. LinkCount: linkCnt,
  36. ImageCount: imgCnt,
  37. RefCount: refCnt,
  38. }
  39. }
  40. func NodeHash(node *ast.Node, tree *parse.Tree, luteEngine *lute.Lute) string {
  41. ialArray := node.KramdownIAL
  42. sort.Slice(ialArray, func(i, j int) bool {
  43. return ialArray[i][0] < ialArray[j][0]
  44. })
  45. ial := parse.IAL2Tokens(ialArray)
  46. var md string
  47. if ast.NodeDocument != node.Type {
  48. md = FormatNode(node, luteEngine)
  49. }
  50. hpath := tree.HPath
  51. data := tree.Path + hpath + string(ial) + md
  52. return fmt.Sprintf("%x", sha256.Sum256(gulu.Str.ToBytes(data)))[:7]
  53. }
  54. func TreeRoot(node *ast.Node) *ast.Node {
  55. for p := node; nil != p; p = p.Parent {
  56. if ast.NodeDocument == p.Type {
  57. return p
  58. }
  59. }
  60. return &ast.Node{Type: ast.NodeDocument}
  61. }
  62. func NewTree(boxID, p, hp, title string) *parse.Tree {
  63. id := strings.TrimSuffix(path.Base(p), ".sy")
  64. root := &ast.Node{Type: ast.NodeDocument, ID: id}
  65. root.SetIALAttr("title", title)
  66. root.SetIALAttr("id", id)
  67. root.SetIALAttr("updated", util.TimeFromID(id))
  68. ret := &parse.Tree{Root: root}
  69. ret.Box = boxID
  70. ret.Path = p
  71. ret.HPath = hp
  72. ret.Root.Spec = "1"
  73. newPara := &ast.Node{Type: ast.NodeParagraph, ID: ast.NewNodeID()}
  74. newPara.SetIALAttr("id", newPara.ID)
  75. newPara.SetIALAttr("updated", util.TimeFromID(newPara.ID))
  76. ret.Root.AppendChild(newPara)
  77. return ret
  78. }
  79. func IsEmptyBlockIAL(n *ast.Node) bool {
  80. if ast.NodeKramdownBlockIAL != n.Type {
  81. return false
  82. }
  83. if util2.IsDocIAL(n.Tokens) {
  84. return false
  85. }
  86. if nil != n.Previous {
  87. if ast.NodeKramdownBlockIAL == n.Previous.Type {
  88. return true
  89. }
  90. return false
  91. }
  92. return true
  93. }
  94. func IALStr(n *ast.Node) string {
  95. if 1 > len(n.KramdownIAL) {
  96. return ""
  97. }
  98. return string(parse.IAL2Tokens(n.KramdownIAL))
  99. }