diff --git a/kernel/api/block.go b/kernel/api/block.go
index def886c0b..3d41e8d39 100644
--- a/kernel/api/block.go
+++ b/kernel/api/block.go
@@ -26,6 +26,7 @@ import (
"github.com/88250/lute/html"
"github.com/gin-gonic/gin"
"github.com/siyuan-note/logging"
+ "github.com/siyuan-note/siyuan/kernel/filesys"
"github.com/siyuan-note/siyuan/kernel/model"
"github.com/siyuan-note/siyuan/kernel/util"
)
@@ -320,7 +321,7 @@ func getContentWordCount(c *gin.Context) {
}
content := arg["content"].(string)
- ret.Data = model.ContentStat(content)
+ ret.Data = filesys.ContentStat(content)
}
func getBlocksWordCount(c *gin.Context) {
@@ -337,7 +338,7 @@ func getBlocksWordCount(c *gin.Context) {
for _, id := range idsArg {
ids = append(ids, id.(string))
}
- ret.Data = model.BlocksWordCount(ids)
+ ret.Data = filesys.BlocksWordCount(ids)
}
func getTreeStat(c *gin.Context) {
@@ -350,7 +351,7 @@ func getTreeStat(c *gin.Context) {
}
id := arg["id"].(string)
- ret.Data = model.StatTree(id)
+ ret.Data = filesys.StatTree(id)
}
func getDOMText(c *gin.Context) {
diff --git a/kernel/filesys/stat.go b/kernel/filesys/stat.go
new file mode 100644
index 000000000..c7538eb24
--- /dev/null
+++ b/kernel/filesys/stat.go
@@ -0,0 +1,223 @@
+// SiYuan - Refactor your thinking
+// Copyright (c) 2020-present, b3log.org
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package filesys
+
+import (
+ "bytes"
+ "github.com/88250/lute"
+ "github.com/88250/lute/ast"
+ "github.com/88250/lute/parse"
+ "github.com/siyuan-note/siyuan/kernel/av"
+ "github.com/siyuan-note/siyuan/kernel/treenode"
+ "github.com/siyuan-note/siyuan/kernel/util"
+)
+
+func ContentStat(content string) (ret *util.BlockStatResult) {
+ luteEngine := util.NewLute()
+ return contentStat(content, luteEngine)
+}
+
+func contentStat(content string, luteEngine *lute.Lute) (ret *util.BlockStatResult) {
+ tree := luteEngine.BlockDOM2Tree(content)
+ runeCnt, wordCnt, linkCnt, imgCnt, refCnt := tree.Root.Stat()
+ return &util.BlockStatResult{
+ RuneCount: runeCnt,
+ WordCount: wordCnt,
+ LinkCount: linkCnt,
+ ImageCount: imgCnt,
+ RefCount: refCnt,
+ }
+}
+
+func StatBlock(id string) (ret *util.BlockStatResult) {
+ trees := LoadTrees([]string{id})
+ if 1 > len(trees) {
+ return
+ }
+
+ tree := trees[id]
+ if nil == tree {
+ return
+ }
+
+ node := treenode.GetNodeInTree(tree, id)
+ if nil == node {
+ return
+ }
+
+ if ast.NodeDocument == node.Type {
+ return statTree(tree)
+ }
+
+ runeCnt, wordCnt, linkCnt, imgCnt, refCnt := node.Stat()
+ ret = &util.BlockStatResult{
+ runeCnt,
+ wordCnt,
+ linkCnt,
+ imgCnt,
+ refCnt,
+ 1,
+ }
+ return
+}
+
+func StatTree(id string) (ret *util.BlockStatResult) {
+ trees := LoadTrees([]string{id})
+ if 1 > len(trees) {
+ return
+ }
+
+ tree := trees[id]
+ if nil == tree {
+ return
+ }
+
+ return statTree(tree)
+}
+
+func statTree(tree *parse.Tree) (ret *util.BlockStatResult) {
+ blockCount := 0
+ var databaseBlockNodes []*ast.Node
+ ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
+ if !entering {
+ return ast.WalkContinue
+ }
+
+ if n.IsBlock() {
+ blockCount++
+ }
+
+ if ast.NodeAttributeView != n.Type {
+ return ast.WalkContinue
+ }
+
+ databaseBlockNodes = append(databaseBlockNodes, n)
+ return ast.WalkContinue
+ })
+
+ luteEngine := util.NewLute()
+ var dbRuneCnt, dbWordCnt, dbLinkCnt, dbImgCnt, dbRefCnt int
+ for _, n := range databaseBlockNodes {
+ if "" == n.AttributeViewID {
+ continue
+ }
+
+ attrView, _ := av.ParseAttributeView(n.AttributeViewID)
+ if nil == attrView {
+ continue
+ }
+
+ content := bytes.Buffer{}
+ for _, kValues := range attrView.KeyValues {
+ for _, v := range kValues.Values {
+ switch kValues.Key.Type {
+ case av.KeyTypeURL:
+ if v.IsEmpty() {
+ continue
+ }
+
+ dbLinkCnt++
+ content.WriteString(v.URL.Content)
+ case av.KeyTypeMAsset:
+ if v.IsEmpty() {
+ continue
+ }
+
+ for _, asset := range v.MAsset {
+ if av.AssetTypeImage == asset.Type {
+ dbImgCnt++
+ }
+ }
+ case av.KeyTypeBlock:
+ if v.IsEmpty() {
+ continue
+ }
+
+ if !v.IsDetached {
+ dbRefCnt++
+ }
+ content.WriteString(v.Block.Content)
+ case av.KeyTypeText:
+ if v.IsEmpty() {
+ continue
+ }
+ content.WriteString(v.Text.Content)
+ case av.KeyTypeNumber:
+ if v.IsEmpty() {
+ continue
+ }
+ v.Number.FormatNumber()
+ content.WriteString(v.Number.FormattedContent)
+ case av.KeyTypeEmail:
+ if v.IsEmpty() {
+ continue
+ }
+ content.WriteString(v.Email.Content)
+ case av.KeyTypePhone:
+ if v.IsEmpty() {
+ continue
+ }
+ content.WriteString(v.Phone.Content)
+ }
+ }
+ }
+
+ dbStat := contentStat(content.String(), luteEngine)
+ dbRuneCnt += dbStat.RuneCount
+ dbWordCnt += dbStat.WordCount
+ }
+
+ runeCnt, wordCnt, linkCnt, imgCnt, refCnt := tree.Root.Stat()
+ runeCnt += dbRuneCnt
+ wordCnt += dbWordCnt
+ linkCnt += dbLinkCnt
+ imgCnt += dbImgCnt
+ refCnt += dbRefCnt
+ return &util.BlockStatResult{
+ RuneCount: runeCnt,
+ WordCount: wordCnt,
+ LinkCount: linkCnt,
+ ImageCount: imgCnt,
+ RefCount: refCnt,
+ BlockCount: blockCount,
+ }
+}
+
+func BlocksWordCount(ids []string) (ret *util.BlockStatResult) {
+ ret = &util.BlockStatResult{}
+ trees := LoadTrees(ids)
+ for _, id := range ids {
+ tree := trees[id]
+ if nil == tree {
+ continue
+ }
+
+ node := treenode.GetNodeInTree(tree, id)
+ if nil == node {
+ continue
+ }
+
+ runeCnt, wordCnt, linkCnt, imgCnt, refCnt := node.Stat()
+ ret.RuneCount += runeCnt
+ ret.WordCount += wordCnt
+ ret.LinkCount += linkCnt
+ ret.ImageCount += imgCnt
+ ret.RefCount += refCnt
+ }
+ ret.BlockCount = len(ids)
+ return
+}
diff --git a/kernel/treenode/template.go b/kernel/filesys/template.go
similarity index 95%
rename from kernel/treenode/template.go
rename to kernel/filesys/template.go
index 0472a42f6..38654f39f 100644
--- a/kernel/treenode/template.go
+++ b/kernel/filesys/template.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
-package treenode
+package filesys
import (
"math"
@@ -25,6 +25,7 @@ import (
"github.com/Masterminds/sprig/v3"
"github.com/araddon/dateparse"
"github.com/siyuan-note/logging"
+ "github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/spf13/cast"
)
@@ -48,6 +49,7 @@ func BuiltInTemplateFuncs() (ret template.FuncMap) {
ret["parseTime"] = parseTime
ret["FormatFloat"] = FormatFloat
ret["getHPathByID"] = getHPathByID
+ ret["statBlock"] = StatBlock
return
}
@@ -73,7 +75,7 @@ func FormatFloat(format string, n float64) string {
}
func getHPathByID(id string) (ret string) {
- bt := GetBlockTree(id)
+ bt := treenode.GetBlockTree(id)
if nil == bt {
return
}
diff --git a/kernel/model/file.go b/kernel/model/file.go
index ce3dc59b4..d5b352348 100644
--- a/kernel/model/file.go
+++ b/kernel/model/file.go
@@ -17,7 +17,6 @@
package model
import (
- "bytes"
"errors"
"fmt"
"io/fs"
@@ -442,163 +441,6 @@ func ListDocTree(boxID, listPath string, sortMode int, flashcard, showHidden boo
return
}
-func ContentStat(content string) (ret *util.BlockStatResult) {
- luteEngine := util.NewLute()
- return contentStat(content, luteEngine)
-}
-
-func contentStat(content string, luteEngine *lute.Lute) (ret *util.BlockStatResult) {
- tree := luteEngine.BlockDOM2Tree(content)
- runeCnt, wordCnt, linkCnt, imgCnt, refCnt := tree.Root.Stat()
- return &util.BlockStatResult{
- RuneCount: runeCnt,
- WordCount: wordCnt,
- LinkCount: linkCnt,
- ImageCount: imgCnt,
- RefCount: refCnt,
- }
-}
-
-func BlocksWordCount(ids []string) (ret *util.BlockStatResult) {
- ret = &util.BlockStatResult{}
- trees := filesys.LoadTrees(ids)
- for _, id := range ids {
- tree := trees[id]
- if nil == tree {
- continue
- }
-
- node := treenode.GetNodeInTree(tree, id)
- if nil == node {
- continue
- }
-
- runeCnt, wordCnt, linkCnt, imgCnt, refCnt := node.Stat()
- ret.RuneCount += runeCnt
- ret.WordCount += wordCnt
- ret.LinkCount += linkCnt
- ret.ImageCount += imgCnt
- ret.RefCount += refCnt
- }
- ret.BlockCount = len(ids)
- return
-}
-
-func StatTree(id string) (ret *util.BlockStatResult) {
- FlushTxQueue()
-
- tree, _ := LoadTreeByBlockID(id)
- if nil == tree {
- return
- }
-
- blockCount := 0
- var databaseBlockNodes []*ast.Node
- ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
- if !entering {
- return ast.WalkContinue
- }
-
- if n.IsBlock() {
- blockCount++
- }
-
- if ast.NodeAttributeView != n.Type {
- return ast.WalkContinue
- }
-
- databaseBlockNodes = append(databaseBlockNodes, n)
- return ast.WalkContinue
- })
-
- luteEngine := util.NewLute()
- var dbRuneCnt, dbWordCnt, dbLinkCnt, dbImgCnt, dbRefCnt int
- for _, n := range databaseBlockNodes {
- if "" == n.AttributeViewID {
- continue
- }
-
- attrView, _ := av.ParseAttributeView(n.AttributeViewID)
- if nil == attrView {
- continue
- }
-
- content := bytes.Buffer{}
- for _, kValues := range attrView.KeyValues {
- for _, v := range kValues.Values {
- switch kValues.Key.Type {
- case av.KeyTypeURL:
- if v.IsEmpty() {
- continue
- }
-
- dbLinkCnt++
- content.WriteString(v.URL.Content)
- case av.KeyTypeMAsset:
- if v.IsEmpty() {
- continue
- }
-
- for _, asset := range v.MAsset {
- if av.AssetTypeImage == asset.Type {
- dbImgCnt++
- }
- }
- case av.KeyTypeBlock:
- if v.IsEmpty() {
- continue
- }
-
- if !v.IsDetached {
- dbRefCnt++
- }
- content.WriteString(v.Block.Content)
- case av.KeyTypeText:
- if v.IsEmpty() {
- continue
- }
- content.WriteString(v.Text.Content)
- case av.KeyTypeNumber:
- if v.IsEmpty() {
- continue
- }
- v.Number.FormatNumber()
- content.WriteString(v.Number.FormattedContent)
- case av.KeyTypeEmail:
- if v.IsEmpty() {
- continue
- }
- content.WriteString(v.Email.Content)
- case av.KeyTypePhone:
- if v.IsEmpty() {
- continue
- }
- content.WriteString(v.Phone.Content)
- }
- }
- }
-
- dbStat := contentStat(content.String(), luteEngine)
- dbRuneCnt += dbStat.RuneCount
- dbWordCnt += dbStat.WordCount
- }
-
- runeCnt, wordCnt, linkCnt, imgCnt, refCnt := tree.Root.Stat()
- runeCnt += dbRuneCnt
- wordCnt += dbWordCnt
- linkCnt += dbLinkCnt
- imgCnt += dbImgCnt
- refCnt += dbRefCnt
- return &util.BlockStatResult{
- RuneCount: runeCnt,
- WordCount: wordCnt,
- LinkCount: linkCnt,
- ImageCount: imgCnt,
- RefCount: refCnt,
- BlockCount: blockCount,
- }
-}
-
func GetDoc(startID, endID, id string, index int, query string, queryTypes map[string]bool, queryMethod, mode int, size int, isBacklink, highlight bool) (
blockCount int, dom, parentID, parent2ID, rootID, typ string, eof, scroll bool, boxID, docPath string, isBacklinkExpand bool, keywords []string, err error) {
//os.MkdirAll("pprof", 0755)
diff --git a/kernel/model/template.go b/kernel/model/template.go
index 56dedc417..93d15ad16 100644
--- a/kernel/model/template.go
+++ b/kernel/model/template.go
@@ -34,6 +34,7 @@ import (
"github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/av"
+ "github.com/siyuan-note/siyuan/kernel/filesys"
"github.com/siyuan-note/siyuan/kernel/search"
"github.com/siyuan-note/siyuan/kernel/sql"
"github.com/siyuan-note/siyuan/kernel/treenode"
@@ -43,7 +44,7 @@ import (
func RenderGoTemplate(templateContent string) (ret string, err error) {
tmpl := template.New("")
- tplFuncMap := treenode.BuiltInTemplateFuncs()
+ tplFuncMap := filesys.BuiltInTemplateFuncs()
sql.SQLTemplateFuncs(&tplFuncMap)
tmpl = tmpl.Funcs(tplFuncMap)
tpl, err := tmpl.Parse(templateContent)
@@ -254,7 +255,7 @@ func RenderDynamicIconContentTemplate(content, id string) (ret string) {
dataModel["alias"] = block.Alias
goTpl := template.New("").Delims(".action{", "}")
- tplFuncMap := treenode.BuiltInTemplateFuncs()
+ tplFuncMap := filesys.BuiltInTemplateFuncs()
sql.SQLTemplateFuncs(&tplFuncMap)
goTpl = goTpl.Funcs(tplFuncMap)
tpl, err := goTpl.Funcs(tplFuncMap).Parse(content)
@@ -304,7 +305,7 @@ func RenderTemplate(p, id string, preview bool) (tree *parse.Tree, dom string, e
}
goTpl := template.New("").Delims(".action{", "}")
- tplFuncMap := treenode.BuiltInTemplateFuncs()
+ tplFuncMap := filesys.BuiltInTemplateFuncs()
sql.SQLTemplateFuncs(&tplFuncMap)
goTpl = goTpl.Funcs(tplFuncMap)
tpl, err := goTpl.Funcs(tplFuncMap).Parse(gulu.Str.FromBytes(md))
diff --git a/kernel/sql/av.go b/kernel/sql/av.go
index aad44d1dd..16f1846fc 100644
--- a/kernel/sql/av.go
+++ b/kernel/sql/av.go
@@ -27,6 +27,7 @@ import (
"github.com/88250/lute/ast"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/av"
+ "github.com/siyuan-note/siyuan/kernel/filesys"
"github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
)
@@ -420,7 +421,7 @@ func RenderTemplateCol(ial map[string]string, rowValues []*av.KeyValues, tplCont
}
goTpl := template.New("").Delims(".action{", "}")
- tplFuncMap := treenode.BuiltInTemplateFuncs()
+ tplFuncMap := filesys.BuiltInTemplateFuncs()
SQLTemplateFuncs(&tplFuncMap)
goTpl = goTpl.Funcs(tplFuncMap)
tpl, err := goTpl.Parse(tplContent)