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

This commit is contained in:
Vanessa 2023-04-03 12:16:17 +08:00
commit 6269cae2a9
7 changed files with 307 additions and 65 deletions

View file

@ -484,7 +484,7 @@ const initKernel = (workspace, port, lang) => {
errorWindowId = showErrorWindow("⚠️ 初始化工作空间失败 Failed to create workspace directory", "<div>初始化工作空间失败。</div><div>Failed to init workspace.</div>");
break;
case 26:
errorWindowId = showErrorWindow("⚠️ 文件系统读写错误 File system access error", "<div>请检查文件系统权限,并确保没有其他程序正在读写文件<br>请勿使用第三方同步盘进行数据同步否则数据会被损坏iCloud/OneDrive/Dropbox/Google Drive/坚果云/百度网盘/腾讯微云等)<br>解决方案:请将工作空间移动到其他路径后再打开</div><div>Please check file system permissions and make sure no other programs are reading or writing to the file;<br>Do not use a third-party sync disk for data sync, otherwise the data will be damaged (OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)<br>Solution: Please move the workspace to another path before opening it</div>");
errorWindowId = showErrorWindow("⚠️ 文件系统读写错误 File system access error", "<div>1. 请检查文件系统权限,并确保没有其他程序正在读写文件<br>2. 请勿使用第三方同步盘进行数据同步否则数据会被损坏iCloud/OneDrive/Dropbox/Google Drive/坚果云/百度网盘/腾讯微云等)<br><br>解决方案:请将工作空间移动到其他路径后再打开</div><div>1. Please check file system permissions and make sure no other programs are reading or writing to the file<br>2. Do not use a third-party sync disk for data sync, otherwise the data will be damaged (OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)<br><br>Solution: Please move the workspace to another path before opening it</div>");
break;
case 0:
break;

View file

@ -5,7 +5,7 @@
"Properties": {
"id": "20210615213222-vs5tzbd",
"title": "Data history",
"updated": "20220831210614"
"updated": "20230403114455"
},
"Children": [
{
@ -183,7 +183,7 @@
"ListData": {},
"Properties": {
"id": "20220501135308-30uwxvd",
"updated": "20220831210614"
"updated": "20230403114455"
},
"Children": [
{
@ -217,7 +217,7 @@
},
{
"Type": "NodeText",
"Data": " - "
"Data": " - "
},
{
"Type": "NodeTextMark",
@ -226,7 +226,7 @@
},
{
"Type": "NodeText",
"Data": " - "
"Data": " - "
},
{
"Type": "NodeTextMark",
@ -235,12 +235,16 @@
},
{
"Type": "NodeText",
"Data": " make adjustments), and the suffix of the history folder is "
"Data": " make adjustments), and the suffix of the history folder is "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-update"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -274,6 +278,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-sync"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -307,6 +315,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-delete"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -351,6 +363,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-clean"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -365,7 +381,7 @@
},
"Properties": {
"id": "20220501135308-wzazz01",
"updated": "20220628203717"
"updated": "20230403114455"
},
"Children": [
{
@ -373,7 +389,7 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20220501135308-xldpw4q",
"updated": "20220628203717"
"updated": "20230403114455"
},
"Children": [
{
@ -382,17 +398,69 @@
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkType": "block-ref",
"TextMarkBlockRefID": "20220628204454-hhxohv5",
"TextMarkBlockRefSubtype": "s",
"TextMarkTextContent": "Optimize typography"
},
{
"Type": "NodeText",
"Data": " function, a history will be generated, and the suffix of the history folder is "
"Data": ", a history will be generated, and the suffix of the history folder is "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-format"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
]
},
{
"ID": "20230403114321-4rwhj6j",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20230403114321-4rwhj6j",
"updated": "20230403114424"
},
"Children": [
{
"ID": "20230403114321-tou7etc",
"Type": "NodeParagraph",
"Properties": {
"id": "20230403114321-tou7etc",
"updated": "20230403114424"
},
"Children": [
{
"Type": "NodeText",
"Data": "When using "
},
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "Search replace"
},
{
"Type": "NodeText",
"Data": ", a history will be generated, and the suffix of the history folder "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-replace"
},
{
"Type": "NodeText",
"Data": ""
}
]
}

View file

@ -5,7 +5,7 @@
"Properties": {
"id": "20210615211733-v6rzowm",
"title": "数据历史",
"updated": "20220831210638"
"updated": "20230403114310"
},
"Children": [
{
@ -14,7 +14,7 @@
"HeadingLevel": 2,
"Properties": {
"id": "20220501134357-003dftr",
"updated": "20220501134417"
"updated": "20230403113939"
},
"Children": [
{
@ -183,7 +183,7 @@
"ListData": {},
"Properties": {
"id": "20210403160319-ufy7jta",
"updated": "20220831210638"
"updated": "20230403114310"
},
"Children": [
{
@ -217,7 +217,7 @@
},
{
"Type": "NodeText",
"Data": " - "
"Data": " - "
},
{
"Type": "NodeTextMark",
@ -226,7 +226,7 @@
},
{
"Type": "NodeText",
"Data": " - "
"Data": " - "
},
{
"Type": "NodeTextMark",
@ -235,12 +235,16 @@
},
{
"Type": "NodeText",
"Data": " 进行调整),历史文件夹后缀为 "
"Data": " 进行调整),历史文件夹后缀为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-update"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -268,24 +272,16 @@
"Children": [
{
"Type": "NodeText",
"Data": "云端"
},
{
"Type": "NodeText",
"Data": "同步时,本地被"
},
{
"Type": "NodeText",
"Data": "云端"
},
{
"Type": "NodeText",
"Data": "覆盖的数据会生成历史,历史文件夹后缀为 "
"Data": "云端同步时,本地被云端覆盖的数据会生成历史,历史文件夹后缀为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-sync"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -313,20 +309,16 @@
"Children": [
{
"Type": "NodeText",
"Data": "手动删除笔记本、文档和"
},
{
"Type": "NodeText",
"Data": "资源文件"
},
{
"Type": "NodeText",
"Data": "时会生成历史,历史文件夹后缀为 "
"Data": "手动删除笔记本、文档和资源文件时会生成历史,历史文件夹后缀为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-delete"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -371,6 +363,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-clean"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -385,7 +381,7 @@
},
"Properties": {
"id": "20220501134920-qb6wh0b",
"updated": "20220628203857"
"updated": "20230403114300"
},
"Children": [
{
@ -393,7 +389,55 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20220501134920-k403n1r",
"updated": "20220628203857"
"updated": "20230403114300"
},
"Children": [
{
"Type": "NodeText",
"Data": "使用"
},
{
"Type": "NodeTextMark",
"TextMarkType": "block-ref",
"TextMarkBlockRefID": "20220628204444-9n0y9h2",
"TextMarkBlockRefSubtype": "s",
"TextMarkTextContent": "优化排版"
},
{
"Type": "NodeText",
"Data": "时会生成历史,历史文件夹后缀为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-format"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
]
},
{
"ID": "20230403113929-44xkaoz",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20230403113929-44xkaoz",
"updated": "20230403114310"
},
"Children": [
{
"ID": "20230403113929-ud36ubv",
"Type": "NodeParagraph",
"Properties": {
"id": "20230403113929-ud36ubv",
"updated": "20230403114310"
},
"Children": [
{
@ -403,16 +447,20 @@
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "优化排版"
"TextMarkTextContent": "搜索替换"
},
{
"Type": "NodeText",
"Data": " 功能时会生成历史,历史文件夹后缀为 "
"Data": " 时会生成历史,历史文件夹后缀为 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-format"
"TextMarkTextContent": "-replace"
},
{
"Type": "NodeText",
"Data": ""
}
]
}

View file

@ -5,7 +5,7 @@
"Properties": {
"id": "20211226122707-8cr09co",
"title": "數據歷史",
"updated": "20220831210559"
"updated": "20230403114139"
},
"Children": [
{
@ -183,7 +183,7 @@
"ListData": {},
"Properties": {
"id": "20220501135134-p6jpw7s",
"updated": "20220831210559"
"updated": "20230403114139"
},
"Children": [
{
@ -217,7 +217,7 @@
},
{
"Type": "NodeText",
"Data": " - "
"Data": " - "
},
{
"Type": "NodeTextMark",
@ -226,7 +226,7 @@
},
{
"Type": "NodeText",
"Data": " - "
"Data": " - "
},
{
"Type": "NodeTextMark",
@ -235,12 +235,16 @@
},
{
"Type": "NodeText",
"Data": " 進行調整),歷史文件夾後綴為 "
"Data": " 進行調整),歷史文件夾後綴為 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-update"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -274,6 +278,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-sync"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -307,6 +315,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-delete"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -351,6 +363,10 @@
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-clean"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
@ -365,7 +381,7 @@
},
"Properties": {
"id": "20220501135134-6k05zq3",
"updated": "20220628203918"
"updated": "20230403114139"
},
"Children": [
{
@ -373,7 +389,55 @@
"Type": "NodeParagraph",
"Properties": {
"id": "20220501135134-o33eejl",
"updated": "20220628203918"
"updated": "20230403114139"
},
"Children": [
{
"Type": "NodeText",
"Data": "使用"
},
{
"Type": "NodeTextMark",
"TextMarkType": "block-ref",
"TextMarkBlockRefID": "20220628204420-ui79vkt",
"TextMarkBlockRefSubtype": "s",
"TextMarkTextContent": "優化排版"
},
{
"Type": "NodeText",
"Data": "時會生成歷史,歷史文件夾後綴為 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-format"
},
{
"Type": "NodeText",
"Data": ""
}
]
}
]
},
{
"ID": "20230403114032-wxsdrdw",
"Type": "NodeListItem",
"ListData": {
"BulletChar": 42,
"Marker": "Kg=="
},
"Properties": {
"id": "20230403114032-wxsdrdw",
"updated": "20230403114109"
},
"Children": [
{
"ID": "20230403114032-r5mnisa",
"Type": "NodeParagraph",
"Properties": {
"id": "20230403114032-r5mnisa",
"updated": "20230403114109"
},
"Children": [
{
@ -383,16 +447,20 @@
{
"Type": "NodeTextMark",
"TextMarkType": "kbd",
"TextMarkTextContent": "優化排版"
"TextMarkTextContent": "搜索替換"
},
{
"Type": "NodeText",
"Data": " 功能時會生成歷史,歷史文件夾後綴為 "
"Data": " 時會生成歷史,歷史文件夾後綴為 "
},
{
"Type": "NodeTextMark",
"TextMarkType": "code",
"TextMarkTextContent": "-format"
"TextMarkTextContent": "-replace"
},
{
"Type": "NodeText",
"Data": ""
}
]
}

View file

@ -266,6 +266,7 @@ export const openHistory = () => {
<option value="delete">delete</option>
<option value="format">format</option>
<option value="sync">sync</option>
<option value="replace">replace</option>
</select>
<span class="fn__space"></span>
<select data-type="notebookselect" class="b3-select" style="min-width: auto">

View file

@ -547,15 +547,20 @@ func (box *Box) recentModifiedDocs() (ret []string) {
}
const (
HistoryOpClean = "clean"
HistoryOpUpdate = "update"
HistoryOpDelete = "delete"
HistoryOpFormat = "format"
HistoryOpSync = "sync"
HistoryOpClean = "clean"
HistoryOpUpdate = "update"
HistoryOpDelete = "delete"
HistoryOpFormat = "format"
HistoryOpSync = "sync"
HistoryOpReplace = "replace"
)
func GetHistoryDir(suffix string) (ret string, err error) {
ret = filepath.Join(util.HistoryDir, time.Now().Format("2006-01-02-150405")+"-"+suffix)
return getHistoryDir(suffix, time.Now())
}
func getHistoryDir(suffix string, t time.Time) (ret string, err error) {
ret = filepath.Join(util.HistoryDir, t.Format("2006-01-02-150405")+"-"+suffix)
if err = os.MkdirAll(ret, 0755); nil != err {
logging.LogErrorf("make history dir failed: %s", err)
return
@ -584,7 +589,7 @@ func ReindexHistory() (err error) {
return
}
var validOps = []string{HistoryOpClean, HistoryOpUpdate, HistoryOpDelete, HistoryOpFormat, HistoryOpSync}
var validOps = []string{HistoryOpClean, HistoryOpUpdate, HistoryOpDelete, HistoryOpFormat, HistoryOpSync, HistoryOpReplace}
const (
HistoryTypeDocName = 0

View file

@ -20,8 +20,9 @@ import (
"bytes"
"errors"
"fmt"
"github.com/siyuan-note/siyuan/kernel/task"
"os"
"path"
"path/filepath"
"regexp"
"sort"
"strconv"
@ -35,10 +36,12 @@ import (
"github.com/88250/lute/lex"
"github.com/88250/lute/parse"
"github.com/jinzhu/copier"
"github.com/siyuan-note/filelock"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/siyuan/kernel/conf"
"github.com/siyuan-note/siyuan/kernel/search"
"github.com/siyuan-note/siyuan/kernel/sql"
"github.com/siyuan-note/siyuan/kernel/task"
"github.com/siyuan-note/siyuan/kernel/treenode"
"github.com/siyuan-note/siyuan/kernel/util"
"github.com/xrash/smetrics"
@ -215,16 +218,65 @@ func FindReplace(keyword, replacement string, ids []string, method int) (err err
ids = gulu.Str.RemoveDuplicatedElem(ids)
var renameRoots []*ast.Node
renameRootTitles := map[string]string{}
cachedTrees := map[string]*parse.Tree{}
historyDir, err := getHistoryDir(HistoryOpReplace, time.Now())
if nil != err {
logging.LogErrorf("get history dir failed: %s", err)
return
}
for _, id := range ids {
var tree *parse.Tree
tree, err = loadTreeByBlockID(id)
if nil != err {
bt := treenode.GetBlockTree(id)
if nil == bt {
continue
}
tree := cachedTrees[bt.RootID]
if nil != tree {
continue
}
tree, _ = loadTreeByBlockID(id)
if nil == tree {
continue
}
historyPath := filepath.Join(historyDir, tree.Box, tree.Path)
if err = os.MkdirAll(filepath.Dir(historyPath), 0755); nil != err {
logging.LogErrorf("generate history failed: %s", err)
return
}
var data []byte
if data, err = filelock.ReadFile(filepath.Join(util.DataDir, tree.Box, tree.Path)); err != nil {
logging.LogErrorf("generate history failed: %s", err)
return
}
if err = gulu.File.WriteFileSafer(historyPath, data, 0644); err != nil {
logging.LogErrorf("generate history failed: %s", err)
return
}
cachedTrees[bt.RootID] = tree
}
indexHistoryDir(filepath.Base(historyDir), util.NewLute())
for _, id := range ids {
bt := treenode.GetBlockTree(id)
if nil == bt {
continue
}
tree := cachedTrees[bt.RootID]
if nil == tree {
continue
}
node := treenode.GetNodeInTree(tree, id)
if nil == node {
return
continue
}
ast.Walk(node, func(n *ast.Node, entering bool) ast.WalkStatus {