Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Vanessa 2023-06-24 17:51:07 +08:00
commit 5e16149c4c
9 changed files with 212 additions and 21 deletions

View file

@ -21,6 +21,7 @@ mac:
extendInfo:
- NSMicrophoneUsageDescription: "This app requires microphone access to record audio."
entitlementsInherit: "../../entitlements.mas.plist"
minimumSystemVersion: "10.15"
extraResources:
- from: "kernel-darwin-arm64"
to: "kernel"

View file

@ -21,6 +21,7 @@ mac:
extendInfo:
- NSMicrophoneUsageDescription: "This app requires microphone access to record audio."
entitlementsInherit: "../../entitlements.mas.plist"
minimumSystemVersion: "10.15"
extraResources:
- from: "kernel-darwin"
to: "kernel"

View file

@ -44,7 +44,7 @@
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "~/Documents/SiYuan/"
"TextMarkTextContent": "~/SiYuan/"
},
{
"Type": "NodeText",

View file

@ -56,7 +56,7 @@
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "~/Documents/SiYuan/"
"TextMarkTextContent": "~/SiYuan/"
},
{
"Type": "NodeText",

View file

@ -55,7 +55,7 @@
"id": ""
},
"TextMarkType": "code",
"TextMarkTextContent": "~/Documents/SiYuan/"
"TextMarkTextContent": "~/SiYuan/"
},
{
"Type": "NodeText",

View file

@ -29,6 +29,7 @@ import (
"github.com/88250/lute/parse"
"github.com/araddon/dateparse"
"github.com/siyuan-note/siyuan/kernel/cache"
"github.com/siyuan-note/siyuan/kernel/sql"
"github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
)
@ -135,6 +136,13 @@ func setNodeAttrs(node *ast.Node, tree *parse.Tree, nameValues map[string]string
cache.PutBlockIAL(node.ID, parse.IAL2Map(node.KramdownIAL))
pushBroadcastAttrTransactions(oldAttrs, node)
go func() {
if !sql.IsEmptyQueue() {
sql.WaitForWritingDatabase()
}
refreshDynamicRefText(node, tree)
}()
return
}

View file

@ -502,7 +502,6 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
assetsDone := map[string]string{}
// md 转换 sy
i := 0
filepath.Walk(localPath, func(currentPath string, info os.FileInfo, walkErr error) error {
if strings.HasPrefix(info.Name(), ".") {
if info.IsDir() {
@ -538,9 +537,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
if info.IsDir() {
tree = treenode.NewTree(boxID, targetPath, hPath, title)
if err = indexWriteJSONQueue(tree); nil != err {
return io.EOF
}
importTrees = append(importTrees, tree)
return nil
}
@ -623,12 +620,7 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
})
reassignIDUpdated(tree)
indexWriteJSONQueue(tree)
i++
if 0 == i%4 {
util.PushEndlessProgress(fmt.Sprintf(Conf.Language(66), fmt.Sprintf("%d ", i)+util.ShortPathForBootingDisplay(tree.Path)))
}
importTrees = append(importTrees, tree)
return nil
})
} else { // 导入单个文件
@ -707,7 +699,23 @@ func ImportFromLocalPath(boxID, localPath string, toPath string) (err error) {
})
reassignIDUpdated(tree)
indexWriteJSONQueue(tree)
importTrees = append(importTrees, tree)
}
if 0 < len(importTrees) {
initSearchLinks()
convertWikiLinksAndTags()
buildBlockRefInText()
for i, tree := range importTrees {
indexWriteJSONQueue(tree)
if 0 == i%4 {
util.PushEndlessProgress(fmt.Sprintf(Conf.Language(66), fmt.Sprintf("%d/%d ", i, len(importTrees))+tree.HPath))
}
}
importTrees = []*parse.Tree{}
searchLinks = map[string]string{}
}
IncSync()
@ -909,3 +917,170 @@ func domAttrValue(n *html.Node, attrName string) string {
}
return ""
}
var importTrees []*parse.Tree
var searchLinks = map[string]string{}
func initSearchLinks() {
for _, tree := range importTrees {
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering || (ast.NodeDocument != n.Type && ast.NodeHeading != n.Type) {
return ast.WalkContinue
}
nodePath := tree.HPath + "#"
if ast.NodeHeading == n.Type {
nodePath += n.Text()
}
searchLinks[nodePath] = n.ID
return ast.WalkContinue
})
}
}
func convertWikiLinksAndTags() {
for _, tree := range importTrees {
convertWikiLinksAndTags0(tree)
}
}
func convertWikiLinksAndTags0(tree *parse.Tree) {
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering || ast.NodeText != n.Type {
return ast.WalkContinue
}
text := n.TokensStr()
length := len(text)
start, end := 0, length
for {
part := text[start:end]
if idx := strings.Index(part, "]]"); 0 > idx {
break
} else {
end = start + idx
}
if idx := strings.Index(part, "[["); 0 > idx {
break
} else {
start += idx
}
if end <= start {
break
}
link := path.Join(path.Dir(tree.HPath), text[start+2:end]) // 统一转为绝对路径方便后续查找
linkText := path.Base(link)
dynamicAnchorText := true
if linkParts := strings.Split(link, "|"); 1 < len(linkParts) {
link = linkParts[0]
linkText = linkParts[1]
dynamicAnchorText = false
}
link, linkText = strings.TrimSpace(link), strings.TrimSpace(linkText)
if !strings.Contains(link, "#") {
link += "#" // 在结尾统一带上锚点方便后续查找
}
id := searchLinkID(link)
if "" == id {
start, end = end, length
continue
}
linkText = strings.TrimPrefix(linkText, "/")
repl := "((" + id + " '" + linkText + "'))"
if !dynamicAnchorText {
repl = "((" + id + " \"" + linkText + "\"))"
}
end += 2
text = text[:start] + repl + text[end:]
start, end = start+len(repl), len(text)
length = end
}
text = convertTags(text) // 导入标签语法
n.Tokens = gulu.Str.ToBytes(text)
return ast.WalkContinue
})
}
func convertTags(text string) (ret string) {
pos, i := -1, 0
tokens := []byte(text)
for ; i < len(tokens); i++ {
if '#' == tokens[i] && (0 == i || ' ' == tokens[i-1] || (-1 < pos && '#' == tokens[pos])) {
if i < len(tokens)-1 && '#' == tokens[i+1] {
pos = -1
continue
}
pos = i
continue
}
if -1 < pos && ' ' == tokens[i] {
tokens = append(tokens, 0)
copy(tokens[i+1:], tokens[i:])
tokens[i] = '#'
pos = -1
i++
}
}
if -1 < pos && pos < i {
tokens = append(tokens, '#')
}
return string(tokens)
}
// buildBlockRefInText 将文本节点进行结构化处理。
func buildBlockRefInText() {
lute := NewLute()
for _, tree := range importTrees {
var unlinkTextNodes []*ast.Node
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
if !entering || ast.NodeText != n.Type {
return ast.WalkContinue
}
if nil == n.Tokens {
return ast.WalkContinue
}
t := parse.Inline("", n.Tokens, lute.ParseOptions) // 使用行级解析
var children []*ast.Node
for c := t.Root.FirstChild.FirstChild; nil != c; c = c.Next {
children = append(children, c)
}
for _, c := range children {
n.InsertBefore(c)
}
unlinkTextNodes = append(unlinkTextNodes, n)
return ast.WalkContinue
})
for _, node := range unlinkTextNodes {
node.Unlink()
}
}
}
func searchLinkID(link string) (id string) {
id = searchLinks[link]
if "" != id {
return
}
baseName := path.Base(link)
for searchLink, searchID := range searchLinks {
if path.Base(searchLink) == baseName {
return searchID
}
}
return
}
func cleanImport() {
importTrees = []*parse.Tree{}
searchLinks = map[string]string{}
}

View file

@ -1059,7 +1059,7 @@ func (tx *Transaction) commit() (err error) {
return
}
}
refreshDynamicRefText(tx.nodes, tx.trees)
refreshDynamicRefTexts(tx.nodes, tx.trees)
IncSync()
tx.trees = nil
return
@ -1099,9 +1099,17 @@ func (tx *Transaction) writeTree(tree *parse.Tree) (err error) {
return
}
func refreshDynamicRefText(updatedDefNodes map[string]*ast.Node, updatedTrees map[string]*parse.Tree) {
// 这个实现依赖了数据库缓存,导致外部调用时可能需要阻塞等待数据库写入后才能获取到 refs
// refreshDynamicRefText 用于刷新引用块的动态锚文本。
// 该实现依赖了数据库缓存,导致外部调用时可能需要阻塞等待数据库写入后才能获取到 refs
func refreshDynamicRefText(updatedDefNode *ast.Node, updatedTree *parse.Tree) {
changedDefs := map[string]*ast.Node{updatedDefNode.ID: updatedDefNode}
changedTrees := map[string]*parse.Tree{updatedTree.ID: updatedTree}
refreshDynamicRefTexts(changedDefs, changedTrees)
}
// refreshDynamicRefTexts 用于批量刷新引用块的动态锚文本。
// 该实现依赖了数据库缓存,导致外部调用时可能需要阻塞等待数据库写入后才能获取到 refs
func refreshDynamicRefTexts(updatedDefNodes map[string]*ast.Node, updatedTrees map[string]*parse.Tree) {
treeRefNodeIDs := map[string]*hashset.Set{}
for _, updateNode := range updatedDefNodes {
refs := sql.GetRefsCacheByDefID(updateNode.ID)
@ -1183,9 +1191,7 @@ func flushUpdateRefTextRenameDoc() {
defer updateRefTextRenameDocLock.Unlock()
for _, tree := range updateRefTextRenameDocs {
changedDefs := map[string]*ast.Node{tree.ID: tree.Root}
changedTrees := map[string]*parse.Tree{tree.ID: tree}
refreshDynamicRefText(changedDefs, changedTrees)
refreshDynamicRefText(tree.Root, tree)
}
updateRefTextRenameDocs = map[string]*parse.Tree{}
}

View file

@ -57,7 +57,7 @@ func Boot() {
initMime()
initHttpClient()
workspacePath := flag.String("workspace", "", "dir path of the workspace, default to ~/Documents/SiYuan/")
workspacePath := flag.String("workspace", "", "dir path of the workspace, default to ~/SiYuan/")
wdPath := flag.String("wd", WorkingDir, "working directory of SiYuan")
port := flag.String("port", "0", "port of the HTTP server")
readOnly := flag.String("readonly", "false", "read-only mode")