Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
5e16149c4c
9 changed files with 212 additions and 21 deletions
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
{
|
||||
"Type": "NodeTextMark",
|
||||
"TextMarkType": "code",
|
||||
"TextMarkTextContent": "~/Documents/SiYuan/"
|
||||
"TextMarkTextContent": "~/SiYuan/"
|
||||
},
|
||||
{
|
||||
"Type": "NodeText",
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
"id": ""
|
||||
},
|
||||
"TextMarkType": "code",
|
||||
"TextMarkTextContent": "~/Documents/SiYuan/"
|
||||
"TextMarkTextContent": "~/SiYuan/"
|
||||
},
|
||||
{
|
||||
"Type": "NodeText",
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
"id": ""
|
||||
},
|
||||
"TextMarkType": "code",
|
||||
"TextMarkTextContent": "~/Documents/SiYuan/"
|
||||
"TextMarkTextContent": "~/SiYuan/"
|
||||
},
|
||||
{
|
||||
"Type": "NodeText",
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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{}
|
||||
}
|
||||
|
|
|
@ -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{}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Add table
Reference in a new issue