diff --git a/kernel/model/box.go b/kernel/model/box.go index f63dc0d71..a7d93f571 100644 --- a/kernel/model/box.go +++ b/kernel/model/box.go @@ -105,7 +105,7 @@ func ListNotebooks() (ret []*Box, err error) { continue } - if !util.IsIDPattern(dir.Name()) { + if !ast.IsNodeIDPattern(dir.Name()) { continue } @@ -329,7 +329,7 @@ func (box *Box) Move(oldPath, newPath string) error { return errors.New(msg) } - if oldDir := path.Dir(oldPath); util.IsIDPattern(path.Base(oldDir)) { + if oldDir := path.Dir(oldPath); ast.IsNodeIDPattern(path.Base(oldDir)) { fromDir := filepath.Join(boxLocalPath, oldDir) if util.IsEmptyDir(fromDir) { filelock.Remove(fromDir) diff --git a/kernel/model/file.go b/kernel/model/file.go index 165569ebd..68a3cac05 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -248,7 +248,7 @@ func ListDocTree(boxID, path string, sortMode int) (ret []*File, totals int, err var docs []*File for _, file := range files { if file.isdir { - if !util.IsIDPattern(file.name) { + if !ast.IsNodeIDPattern(file.name) { continue } diff --git a/kernel/model/graph.go b/kernel/model/graph.go index 161b2603e..f8314affd 100644 --- a/kernel/model/graph.go +++ b/kernel/model/graph.go @@ -18,8 +18,6 @@ package model import ( "bytes" - "github.com/88250/lute/parse" - "github.com/siyuan-note/siyuan/kernel/util" "math" "strings" "unicode/utf8" @@ -27,6 +25,7 @@ import ( "github.com/88250/gulu" "github.com/88250/lute/ast" "github.com/88250/lute/html" + "github.com/88250/lute/parse" "github.com/siyuan-note/logging" "github.com/siyuan-note/siyuan/kernel/sql" "github.com/siyuan-note/siyuan/kernel/treenode" @@ -690,7 +689,7 @@ func nodeTitleLabel(node *GraphNode, blockContent string) { func query2Stmt(queryStr string) (ret string) { buf := bytes.Buffer{} - if util.IsIDPattern(queryStr) { + if ast.IsNodeIDPattern(queryStr) { buf.WriteString("id = '" + queryStr + "'") } else { var tags []string diff --git a/kernel/model/import.go b/kernel/model/import.go index 8b39fdc9e..e2a207795 100644 --- a/kernel/model/import.go +++ b/kernel/model/import.go @@ -253,7 +253,7 @@ func ImportSY(zipPath, boxID, toPath string) (err error) { return err } - if info.IsDir() && util.IsIDPattern(info.Name()) { + if info.IsDir() && ast.IsNodeIDPattern(info.Name()) { renamePaths[path] = path } return nil diff --git a/kernel/model/search.go b/kernel/model/search.go index c28f39bab..d6f140836 100644 --- a/kernel/model/search.go +++ b/kernel/model/search.go @@ -534,7 +534,7 @@ func searchBySQL(stmt string, beforeLen int) (ret []*Block, matchedBlockCount, m func fullTextSearchRefBlock(keyword string, beforeLen int) (ret []*Block) { keyword = gulu.Str.RemoveInvisible(keyword) - if util.IsIDPattern(keyword) { + if ast.IsNodeIDPattern(keyword) { ret, _, _ = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+keyword+"'", 36) return } @@ -581,7 +581,7 @@ func fullTextSearchRefBlock(keyword string, beforeLen int) (ret []*Block) { func fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, typeFilter, orderBy string, beforeLen int) (ret []*Block, matchedBlockCount, matchedRootCount int) { query = gulu.Str.RemoveInvisible(query) - if util.IsIDPattern(query) { + if ast.IsNodeIDPattern(query) { ret, matchedBlockCount, matchedRootCount = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+query+"'", beforeLen) return } @@ -590,7 +590,7 @@ func fullTextSearchByQuerySyntax(query, boxFilter, pathFilter, typeFilter, order func fullTextSearchByKeyword(query, boxFilter, pathFilter, typeFilter string, orderBy string, beforeLen int) (ret []*Block, matchedBlockCount, matchedRootCount int) { query = gulu.Str.RemoveInvisible(query) - if util.IsIDPattern(query) { + if ast.IsNodeIDPattern(query) { ret, matchedBlockCount, matchedRootCount = searchBySQL("SELECT * FROM `blocks` WHERE `id` = '"+query+"'", beforeLen) return } @@ -660,7 +660,7 @@ func fullTextSearchByFTS(query, boxFilter, pathFilter, typeFilter, orderBy strin func fullTextSearchCount(query, boxFilter, pathFilter, typeFilter string) (matchedBlockCount, matchedRootCount int) { query = gulu.Str.RemoveInvisible(query) - if util.IsIDPattern(query) { + if ast.IsNodeIDPattern(query) { ret, _ := sql.Query("SELECT COUNT(id) AS `matches`, COUNT(DISTINCT(root_id)) AS `docs` FROM `blocks` WHERE `id` = '" + query + "'") if 1 > len(ret) { return diff --git a/kernel/sql/database.go b/kernel/sql/database.go index 35c83d946..a0e35aaa6 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -277,7 +277,7 @@ func refsFromTree(tree *parse.Tree) (refs []*Ref, fileAnnotationRefs []*FileAnno if treenode.IsBlockRef(n) { ref := buildRef(tree, n) refs = append(refs, ref) - } else if ast.NodeTextMark == n.Type && n.IsTextMarkType("file-annotation-ref") { + } else if treenode.IsFileAnnotationRef(n) { pathID := n.TextMarkFileAnnotationRefID idx := strings.LastIndex(pathID, "/") if -1 == idx { @@ -305,6 +305,9 @@ func refsFromTree(tree *parse.Tree) (refs []*Ref, fileAnnotationRefs []*FileAnno Type: treenode.TypeAbbr(n.Type.String()), } fileAnnotationRefs = append(fileAnnotationRefs, ref) + } else if treenode.IsEmbedBlockRef(n) { + ref := buildEmbedRef(tree, n) + refs = append(refs, ref) } return ast.WalkContinue }) @@ -338,6 +341,43 @@ func buildRef(tree *parse.Tree, refNode *ast.Node) *Ref { } } +func buildEmbedRef(tree *parse.Tree, embedNode *ast.Node) *Ref { + markdown := treenode.ExportNodeStdMd(embedNode, luteEngine) + defBlockID, text := getEmbedRef(embedNode) + var defBlockParentID, defBlockRootID, defBlockPath string + defBlock := treenode.GetBlockTree(defBlockID) + if nil != defBlock { + defBlockParentID = defBlock.ParentID + defBlockRootID = defBlock.RootID + defBlockPath = defBlock.Path + } + + return &Ref{ + ID: ast.NewNodeID(), + DefBlockID: defBlockID, + DefBlockParentID: defBlockParentID, + DefBlockRootID: defBlockRootID, + DefBlockPath: defBlockPath, + BlockID: embedNode.ID, + RootID: tree.ID, + Box: tree.Box, + Path: tree.Path, + Content: text, + Markdown: markdown, + Type: treenode.TypeAbbr(embedNode.Type.String()), + } +} + +func getEmbedRef(embedNode *ast.Node) (queryBlockID, refText string) { + queryBlockID = treenode.GetEmbedBlockRef(embedNode) + if "" == queryBlockID { + return + } + + refText = getRefText(queryBlockID) + return +} + func fromTree(node *ast.Node, tree *parse.Tree) (blocks []*Block, spans []*Span, assets []*Asset, attributes []*Attribute) { rootID := tree.Root.ID boxID := tree.Box diff --git a/kernel/treenode/node.go b/kernel/treenode/node.go index c662ca3a2..be06e58a9 100644 --- a/kernel/treenode/node.go +++ b/kernel/treenode/node.go @@ -18,7 +18,6 @@ package treenode import ( "bytes" - util2 "github.com/siyuan-note/siyuan/kernel/util" "strings" "sync" @@ -30,10 +29,62 @@ import ( "github.com/88250/lute/lex" "github.com/88250/lute/parse" "github.com/88250/lute/render" - "github.com/88250/lute/util" + "github.com/88250/vitess-sqlparser/sqlparser" "github.com/siyuan-note/logging" + "github.com/siyuan-note/siyuan/kernel/util" ) +func GetEmbedBlockRef(embedNode *ast.Node) (blockRefID string) { + if nil == embedNode || ast.NodeBlockQueryEmbed != embedNode.Type { + return + } + + scriptNode := embedNode.ChildByType(ast.NodeBlockQueryEmbedScript) + if nil == scriptNode { + return + } + + stmt := scriptNode.TokensStr() + parsedStmt, err := sqlparser.Parse(stmt) + if nil != err { + return + } + + switch parsedStmt.(type) { + case *sqlparser.Select: + slct := parsedStmt.(*sqlparser.Select) + if nil == slct.Where || nil == slct.Where.Expr { + return + } + + switch slct.Where.Expr.(type) { + case *sqlparser.ComparisonExpr: // WHERE id = '20060102150405-1a2b3c4' + comp := slct.Where.Expr.(*sqlparser.ComparisonExpr) + switch comp.Left.(type) { + case *sqlparser.ColName: + col := comp.Left.(*sqlparser.ColName) + if nil == col || "id" != col.Name.Lowered() { + return + } + } + switch comp.Right.(type) { + case *sqlparser.SQLVal: + val := comp.Right.(*sqlparser.SQLVal) + if nil == val || sqlparser.StrVal != val.Type { + return + } + + idVal := string(val.Val) + if !ast.IsNodeIDPattern(idVal) { + return + } + blockRefID = idVal + } + } + } + return +} + func GetBlockRef(n *ast.Node) (blockRefID, blockRefText, blockRefSubtype string) { if !IsBlockRef(n) { return @@ -52,6 +103,17 @@ func IsBlockRef(n *ast.Node) bool { return ast.NodeTextMark == n.Type && n.IsTextMarkType("block-ref") } +func IsFileAnnotationRef(n *ast.Node) bool { + if nil == n { + return false + } + return ast.NodeTextMark == n.Type && n.IsTextMarkType("file-annotation-ref") +} + +func IsEmbedBlockRef(n *ast.Node) bool { + return "" != GetEmbedBlockRef(n) +} + func NodeStaticMdContent(node *ast.Node, luteEngine *lute.Lute) (md, content string) { md = ExportNodeStdMd(node, luteEngine) content = NodeStaticContent(node, nil) @@ -111,7 +173,7 @@ func NodeStaticContent(node *ast.Node, excludeTypes []string) string { var linkDestStr, ocrText string if nil != linkDest { linkDestStr = linkDest.TokensStr() - ocrText = util2.GetAssetText(linkDestStr) + ocrText = util.GetAssetText(linkDestStr) } linkText := n.ChildByType(ast.NodeLinkText) @@ -370,7 +432,7 @@ func IsChartCodeBlockCode(code *ast.Node) bool { return false } - language := util.BytesToStr(code.Previous.CodeBlockInfo) + language := gulu.Str.FromBytes(code.Previous.CodeBlockInfo) language = strings.ReplaceAll(language, editor.Caret, "") return render.NoHighlight(language) } diff --git a/kernel/util/path.go b/kernel/util/path.go index 95d7eca43..106afd793 100644 --- a/kernel/util/path.go +++ b/kernel/util/path.go @@ -52,40 +52,6 @@ func ShortPathForBootingDisplay(p string) string { return p } -func IsIDPattern(str string) bool { - if len("20060102150405-1a2b3c4") != len(str) { - return false - } - - if 1 != strings.Count(str, "-") { - return false - } - - parts := strings.Split(str, "-") - idPart := parts[0] - if 14 != len(idPart) { - return false - } - - for _, c := range idPart { - if !('0' <= c && '9' >= c) { - return false - } - } - - randPart := parts[1] - if 7 != len(randPart) { - return false - } - - for _, c := range randPart { - if !('a' <= c && 'z' >= c) && !('0' <= c && '9' >= c) { - return false - } - } - return true -} - var LocalIPs []string func GetLocalIPs() (ret []string) {