diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json
index a8f965d74..54dcc76d2 100644
--- a/app/appearance/langs/en_US.json
+++ b/app/appearance/langs/en_US.json
@@ -507,9 +507,6 @@
"useDefault": "Open with default program",
"previous": "Previous",
"next": "Next",
- "lockFile0": "Unable to access data",
- "lockFile1": "The data file has been locked by another program",
- "lockFile2": "If the problem still occurs frequently in subsequent use, please report it via GitHub Issues ",
"kernelFault0": "Kernel connection interrupted...",
"kernelFault1": "Please check if the network connection and kernel process is normal",
"kernelFault2": "If the problem still occurs after restarting, please report it via GitHub Issues ",
diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json
index d7acfc047..6000987df 100644
--- a/app/appearance/langs/es_ES.json
+++ b/app/appearance/langs/es_ES.json
@@ -507,9 +507,6 @@
"useDefault": "Abrir con el programa por defecto",
"previous": "Anterior",
"next": "Siguiente",
- "lockFile0": "No se puede acceder a los datos",
- "lockFile1": "El archivo de datos ha sido bloqueado por otro programa",
- "lockFile2": "Si el problema sigue ocurriendo con frecuencia en el uso posterior, infórmelo a través de Problemas en GitHub ",
"kernelFault0": "Conexión del kernel interrumpida...",
"kernelFault1": "Verifique si la conexión de red y los procesos del kernel son normales",
"kernelFault2": "Si el problema sigue produciéndose después de reiniciar, comuníquelo a través de Problemas en GitHub ",
diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json
index 2880d944a..697058ded 100644
--- a/app/appearance/langs/fr_FR.json
+++ b/app/appearance/langs/fr_FR.json
@@ -507,9 +507,6 @@
"useDefault": "Ouvrir avec le programme par défaut",
"previous": "Précédent",
"next": "Prochain",
- "lockFile0": "Impossible d'accéder aux données",
- "lockFile1": "Le fichier de données a été verrouillé par un autre programme",
- "lockFile2": "Si le problème se produit encore fréquemment lors d'une utilisation ultérieure, veuillez le signaler via GitHub Issues ",
"kernelFault0": "Connexion au noyau interrompue...",
"kernelFault1": "Veuillez vérifier si la connexion réseau et les processus du noyau sont normaux",
"kernelFault2": "Si le problème persiste après le redémarrage, veuillez le signaler via GitHub Issues ",
diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json
index c4780ecc5..540e1eeb8 100644
--- a/app/appearance/langs/zh_CHT.json
+++ b/app/appearance/langs/zh_CHT.json
@@ -507,9 +507,6 @@
"useDefault": "使用預設程式打開",
"previous": "上一個",
"next": "下一個",
- "lockFile0": "無法存取資料",
- "lockFile1": "資料檔案已被其他程式鎖定",
- "lockFile2": "如果後續使用仍然頻繁出現該問題,請通過這裡回饋 ",
"kernelFault0": "kernel連接中斷...",
"kernelFault1": "請檢查網絡連接和內核進程是否正常",
"kernelFault2": "如果重啟後仍然出現該問題,請通過這裡回饋 ",
diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json
index 38881655a..ba05194e6 100644
--- a/app/appearance/langs/zh_CN.json
+++ b/app/appearance/langs/zh_CN.json
@@ -507,9 +507,6 @@
"useDefault": "使用默认程序打开",
"previous": "上一个",
"next": "下一个",
- "lockFile0": "无法存取数据",
- "lockFile1": "数据文件已被其他程序锁定",
- "lockFile2": "如果后续使用仍然频繁出现该问题,请通过这里反馈 ",
"kernelFault0": "内核连接中断...",
"kernelFault1": "请检查网络连接和内核进程是否正常",
"kernelFault2": "如果重启后仍然出现该问题,请通过这里反馈 ",
diff --git a/app/electron-builder.yml b/app/electron-builder.yml
index 011c01a70..a9ad3c970 100644
--- a/app/electron-builder.yml
+++ b/app/electron-builder.yml
@@ -36,7 +36,9 @@ nsis:
createStartMenuShortcut: true
shortcutName: "SiYuan"
license: "../LICENSE"
- include: "installer.nsh"
+ include: "nsis/installer.nsh"
+ installerSidebar: "nsis/installerSidebar.bmp"
+ uninstallerSidebar: "nsis/uninstallerSidebar.bmp"
extraResources:
- from: "appearance/boot"
diff --git a/app/installer.nsh b/app/nsis/installer.nsh
similarity index 100%
rename from app/installer.nsh
rename to app/nsis/installer.nsh
diff --git a/app/nsis/installerSidebar.bmp b/app/nsis/installerSidebar.bmp
new file mode 100644
index 000000000..f2c3a76a4
Binary files /dev/null and b/app/nsis/installerSidebar.bmp differ
diff --git a/app/nsis/uninstallerSidebar.bmp b/app/nsis/uninstallerSidebar.bmp
new file mode 100644
index 000000000..a05bb19a2
Binary files /dev/null and b/app/nsis/uninstallerSidebar.bmp differ
diff --git a/app/pandoc/pandoc-darwin-amd64.zip b/app/pandoc/pandoc-darwin-amd64.zip
index 9d2efc826..6678fe6bf 100644
Binary files a/app/pandoc/pandoc-darwin-amd64.zip and b/app/pandoc/pandoc-darwin-amd64.zip differ
diff --git a/app/pandoc/pandoc-linux-amd64.zip b/app/pandoc/pandoc-linux-amd64.zip
index aa64f1597..54a43f26c 100644
Binary files a/app/pandoc/pandoc-linux-amd64.zip and b/app/pandoc/pandoc-linux-amd64.zip differ
diff --git a/app/pandoc/pandoc-windows-amd64.zip b/app/pandoc/pandoc-windows-amd64.zip
index 82486b014..a083af433 100644
Binary files a/app/pandoc/pandoc-windows-amd64.zip and b/app/pandoc/pandoc-windows-amd64.zip differ
diff --git a/app/src/block/Panel.ts b/app/src/block/Panel.ts
index 44fdf3674..44fe70728 100644
--- a/app/src/block/Panel.ts
+++ b/app/src/block/Panel.ts
@@ -10,7 +10,6 @@ import {openNewWindowById} from "../window/openNewWindow";
/// #endif
import {disabledProtyle} from "../protyle/util/onGet";
import {fetchPost} from "../util/fetch";
-import {lockFile} from "../dialog/processSystem";
import {showMessage} from "../dialog/message";
export class BlockPanel {
@@ -245,11 +244,6 @@ export class BlockPanel {
private initProtyle(editorElement: HTMLElement) {
const index = parseInt(editorElement.getAttribute("data-index"));
fetchPost("api/block/getBlockInfo", {id: this.nodeIds[index]}, (response) => {
- if (response.code === 2) {
- // 文件被锁定
- lockFile(response.data);
- return false;
- }
if (response.code === 3) {
showMessage(response.msg);
return;
diff --git a/app/src/dialog/processSystem.ts b/app/src/dialog/processSystem.ts
index 1197fb377..f7e86f0cc 100644
--- a/app/src/dialog/processSystem.ts
+++ b/app/src/dialog/processSystem.ts
@@ -1,7 +1,6 @@
import {Constants} from "../constants";
import {fetchPost} from "../util/fetch";
/// #if !MOBILE
-import {getAllModels} from "../layout/getAll";
import {exportLayout} from "../layout/util";
/// #endif
/// #if !BROWSER
@@ -29,47 +28,6 @@ export const lockScreen = () => {
/// #endif
};
-export const lockFile = (id: string) => {
- const html = `
-
-
-
-
${window.siyuan.languages.lockFile1}
-
${window.siyuan.languages.lockFile2}
-
-
-
${window.siyuan.languages.closeTab}
-
-
${window.siyuan.languages.retry}
-
-
`;
- let logElement = document.getElementById("errorLog");
- if (logElement) {
- logElement.innerHTML = html;
- } else {
- document.body.insertAdjacentHTML("beforeend", `${html}
`);
- logElement = document.getElementById("errorLog");
- }
- logElement.querySelector(".b3-button--cancel").addEventListener("click", () => {
- /// #if !MOBILE
- getAllModels().editor.find((item) => {
- if (item.editor.protyle.block.rootID === id) {
- item.parent.parent.removeTab(item.parent.id, false, false);
- return true;
- }
- });
- logElement.remove();
- /// #endif
- });
- logElement.querySelector(".b3-button--text").addEventListener("click", () => {
- fetchPost("/api/filetree/lockFile", {id}, (response) => {
- if (response.code === 0) {
- window.location.reload();
- }
- });
- });
-};
-
export const kernelError = () => {
let iosReStart = "";
if (window.siyuan.config.system.container === "ios" && window.webkit?.messageHandlers) {
@@ -162,10 +120,6 @@ export const exitSiYuan = () => {
};
export const transactionError = (data: { code: number, data: string }) => {
- if (data.code === 1) {
- lockFile(data.data);
- return;
- }
if (document.getElementById("transactionError")) {
return;
}
diff --git a/app/src/editor/util.ts b/app/src/editor/util.ts
index b1cb3417b..41319684f 100644
--- a/app/src/editor/util.ts
+++ b/app/src/editor/util.ts
@@ -19,7 +19,7 @@ import {pushBack} from "../util/backForward";
import {Asset} from "../asset";
import {Layout} from "../layout";
import {hasClosestBlock, hasClosestByAttribute, hasClosestByClassName,} from "../protyle/util/hasClosest";
-import {lockFile, setTitle} from "../dialog/processSystem";
+import {setTitle} from "../dialog/processSystem";
import {zoomOut} from "../menus/protyle";
import {countBlockWord, countSelectWord} from "../layout/status";
import {showMessage} from "../dialog/message";
@@ -34,11 +34,6 @@ export const openFileById = (options: {
removeCurrentTab?: boolean
}) => {
fetchPost("/api/block/getBlockInfo", {id: options.id}, (data) => {
- if (data.code === 2) {
- // 文件被锁定
- lockFile(data.data);
- return;
- }
if (data.code === 3) {
showMessage(data.msg);
return;
diff --git a/app/src/mobile/editor.ts b/app/src/mobile/editor.ts
index d73863ec4..575f2d5ce 100644
--- a/app/src/mobile/editor.ts
+++ b/app/src/mobile/editor.ts
@@ -7,7 +7,6 @@ import {disabledProtyle, onGet} from "../protyle/util/onGet";
import {addLoading} from "../protyle/ui/initUI";
import {focusBlock} from "../protyle/util/selection";
import {scrollCenter} from "../util/highlightById";
-import {lockFile} from "../dialog/processSystem";
import {hasClosestByAttribute} from "../protyle/util/hasClosest";
import {setEditMode} from "../protyle/util/setEditMode";
import {hideElements} from "../protyle/ui/hideElements";
@@ -40,11 +39,6 @@ export const openMobileFileById = (id: string, action = [Constants.CB_GET_HL]) =
}
fetchPost("/api/block/getBlockInfo", {id}, (data) => {
- if (data.code === 2) {
- // 文件被锁定
- lockFile(data.data);
- return;
- }
if (data.code === 3) {
showMessage(data.msg);
return;
diff --git a/app/src/protyle/export/index.ts b/app/src/protyle/export/index.ts
index d3e63855b..89e917076 100644
--- a/app/src/protyle/export/index.ts
+++ b/app/src/protyle/export/index.ts
@@ -11,7 +11,6 @@ import {confirmDialog} from "../../dialog/confirmDialog";
import {getThemeMode, setInlineStyle} from "../../util/assets";
import {fetchPost} from "../../util/fetch";
import {Dialog} from "../../dialog";
-import {lockFile} from "../../dialog/processSystem";
import {pathPosix} from "../../util/pathName";
import {replaceLocalPath} from "../../editor/rename";
import {setStorageVal} from "../util/compatibility";
@@ -468,11 +467,6 @@ const getExportPath = (option: { type: string, id: string }, removeAssets?: bool
fetchPost("/api/block/getBlockInfo", {
id: option.id
}, (response) => {
- if (response.code === 2) {
- // 文件被锁定
- lockFile(response.data);
- return;
- }
if (response.code === 3) {
showMessage(response.msg);
return;
diff --git a/app/src/protyle/util/onGet.ts b/app/src/protyle/util/onGet.ts
index 20da2f73f..c5b1a86c0 100644
--- a/app/src/protyle/util/onGet.ts
+++ b/app/src/protyle/util/onGet.ts
@@ -1,4 +1,4 @@
-import {lockFile, setTitle} from "../../dialog/processSystem";
+import {setTitle} from "../../dialog/processSystem";
import {Constants} from "../../constants";
import {hideElements} from "../ui/hideElements";
import {genEmptyElement} from "../../block/util";
@@ -36,12 +36,6 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[]
}
protyle.notebookId = data.data.box;
protyle.path = data.data.path;
- if (data.code === 2) {
- // 文件被锁定
- protyle.block.rootID = data.data;
- lockFile(data.data);
- return;
- }
if (data.data.eof) {
if (action.includes(Constants.CB_GET_BEFORE)) {
diff --git a/app/src/protyle/wysiwyg/transaction.ts b/app/src/protyle/wysiwyg/transaction.ts
index bd41ff9d6..23b2c0ff5 100644
--- a/app/src/protyle/wysiwyg/transaction.ts
+++ b/app/src/protyle/wysiwyg/transaction.ts
@@ -6,7 +6,6 @@ import {blockRender} from "../markdown/blockRender";
import {processRender} from "../util/processCode";
import {highlightRender} from "../markdown/highlightRender";
import {hasClosestBlock, hasClosestByAttribute} from "../util/hasClosest";
-import {lockFile} from "../../dialog/processSystem";
import {setFold} from "../../menus/protyle";
import {onGet} from "../util/onGet";
/// #if !MOBILE
@@ -69,10 +68,7 @@ const promiseTransaction = () => {
} else {
promiseTransaction();
}
- if (response.code === 1) {
- lockFile(protyle.block.rootID);
- return;
- }
+
countBlockWord([], protyle.block.rootID, true);
/// #if MOBILE
if ((0 !== window.siyuan.config.sync.provider || (0 === window.siyuan.config.sync.provider && !needSubscribe(""))) &&
diff --git a/app/src/util/backForward.ts b/app/src/util/backForward.ts
index 7436f1c3a..82ba8a4ad 100644
--- a/app/src/util/backForward.ts
+++ b/app/src/util/backForward.ts
@@ -10,7 +10,6 @@ import {Tab} from "../layout/Tab";
import {Editor} from "../editor";
import {onGet} from "../protyle/util/onGet";
import {scrollCenter} from "./highlightById";
-import {lockFile} from "../dialog/processSystem";
import {zoomOut} from "../menus/protyle";
import {showMessage} from "../dialog/message";
import {saveScroll} from "../protyle/scroll/saveScroll";
@@ -39,11 +38,6 @@ const focusStack = async (stack: IBackStack) => {
}
if (wnd) {
const info = await fetchSyncPost("/api/block/getBlockInfo", {id: stack.id});
- if (info.code === 2) {
- // 文件被锁定
- lockFile(info.data);
- return false;
- }
if (info.code === 3) {
showMessage(info.msg);
return;
diff --git a/app/src/window/openNewWindow.ts b/app/src/window/openNewWindow.ts
index dfcba7a08..9e42e5755 100644
--- a/app/src/window/openNewWindow.ts
+++ b/app/src/window/openNewWindow.ts
@@ -6,7 +6,6 @@ import {getCurrentWindow} from "@electron/remote";
import {Constants} from "../constants";
import {Tab} from "../layout/Tab";
import {fetchPost} from "../util/fetch";
-import {lockFile} from "../dialog/processSystem";
import {showMessage} from "../dialog/message";
export const openNewWindow = (tab: Tab) => {
@@ -23,11 +22,6 @@ export const openNewWindow = (tab: Tab) => {
export const openNewWindowById = (id: string) => {
fetchPost("api/block/getBlockInfo", {id}, (response) => {
- if (response.code === 2) {
- // 文件被锁定
- lockFile(response.data);
- return false;
- }
if (response.code === 3) {
showMessage(response.msg);
return;
diff --git a/kernel/api/block.go b/kernel/api/block.go
index 8c818315f..9570529b4 100644
--- a/kernel/api/block.go
+++ b/kernel/api/block.go
@@ -194,12 +194,6 @@ func checkBlockExist(c *gin.Context) {
id := arg["id"].(string)
b, err := model.GetBlock(id, nil)
- // TODO 文件被锁的情况已经在 filelock 中做了退出进程处理,不会走到应用层,所以 code 为 2 的情况应该移除
- //if errors.Is(err, filelock.ErrUnableAccessFile) {
- // ret.Code = 2
- // ret.Data = id
- // return
- //}
if errors.Is(err, model.ErrIndexing) {
ret.Code = 0
ret.Data = false
@@ -405,11 +399,6 @@ func getBlockInfo(c *gin.Context) {
id := arg["id"].(string)
tree, err := model.LoadTreeByID(id)
- //if errors.Is(err, filelock.ErrUnableAccessFile) {
- // ret.Code = 2
- // ret.Data = id
- // return
- //}
if errors.Is(err, model.ErrIndexing) {
ret.Code = 3
ret.Msg = model.Conf.Language(56)
@@ -438,11 +427,6 @@ func getBlockInfo(c *gin.Context) {
}
root, err := model.GetBlock(block.RootID, tree)
- //if errors.Is(err, filelock.ErrUnableAccessFile) {
- // ret.Code = 2
- // ret.Data = id
- // return
- //}
if errors.Is(err, model.ErrIndexing) {
ret.Code = 3
ret.Data = model.Conf.Language(56)
diff --git a/kernel/api/filetree.go b/kernel/api/filetree.go
index 4dbf1f7af..c4116dd94 100644
--- a/kernel/api/filetree.go
+++ b/kernel/api/filetree.go
@@ -501,24 +501,6 @@ func createDocWithMd(c *gin.Context) {
pushCreate(box, p, id, arg)
}
-func lockFile(c *gin.Context) {
- ret := gulu.Ret.NewResult()
- defer c.JSON(http.StatusOK, ret)
-
- arg, ok := util.JsonArg(c, ret)
- if !ok {
- return
- }
-
- id := arg["id"].(string)
- locked := model.TryAccessFileByBlockID(id)
- if !locked {
- ret.Code = -1
- ret.Msg = fmt.Sprintf(model.Conf.Language(75))
- ret.Data = map[string]interface{}{"closeTimeout": 5000}
- }
-}
-
func getDocCreateSavePath(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
@@ -689,11 +671,6 @@ func getDoc(c *gin.Context) {
}
blockCount, content, parentID, parent2ID, rootID, typ, eof, scroll, boxID, docPath, isBacklinkExpand, err := model.GetDoc(startID, endID, id, index, keyword, mode, size, isBacklink)
- //if errors.Is(err, filelock.ErrUnableAccessFile) {
- // ret.Code = 2
- // ret.Data = id
- // return
- //}
if model.ErrBlockNotFound == err {
ret.Code = 3
return
diff --git a/kernel/api/router.go b/kernel/api/router.go
index b0f20efb3..dffd6c0ee 100644
--- a/kernel/api/router.go
+++ b/kernel/api/router.go
@@ -89,7 +89,6 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/filetree/getDocCreateSavePath", model.CheckAuth, getDocCreateSavePath)
ginServer.Handle("POST", "/api/filetree/getRefCreateSavePath", model.CheckAuth, getRefCreateSavePath)
ginServer.Handle("POST", "/api/filetree/changeSort", model.CheckAuth, model.CheckReadonly, changeSort)
- ginServer.Handle("POST", "/api/filetree/lockFile", model.CheckAuth, lockFile)
ginServer.Handle("POST", "/api/filetree/createDocWithMd", model.CheckAuth, model.CheckReadonly, createDocWithMd)
ginServer.Handle("POST", "/api/filetree/createDailyNote", model.CheckAuth, model.CheckReadonly, createDailyNote)
ginServer.Handle("POST", "/api/filetree/createDoc", model.CheckAuth, model.CheckReadonly, createDoc)
@@ -263,6 +262,7 @@ func ServeAPI(ginServer *gin.Engine) {
ginServer.Handle("POST", "/api/setting/getCustomCSS", model.CheckAuth, getCustomCSS)
ginServer.Handle("POST", "/api/setting/setCustomCSS", model.CheckAuth, model.CheckReadonly, setCustomCSS)
ginServer.Handle("POST", "/api/setting/setEmoji", model.CheckAuth, model.CheckReadonly, setEmoji)
+ ginServer.Handle("POST", "/api/setting/setFlashcard", model.CheckAuth, model.CheckReadonly, setFlashcard)
ginServer.Handle("POST", "/api/graph/resetGraph", model.CheckAuth, model.CheckReadonly, resetGraph)
ginServer.Handle("POST", "/api/graph/resetLocalGraph", model.CheckAuth, model.CheckReadonly, resetLocalGraph)
diff --git a/kernel/api/setting.go b/kernel/api/setting.go
index 8f67456f5..ce33153e1 100644
--- a/kernel/api/setting.go
+++ b/kernel/api/setting.go
@@ -29,6 +29,43 @@ import (
"github.com/siyuan-note/siyuan/kernel/util"
)
+func setFlashcard(c *gin.Context) {
+ ret := gulu.Ret.NewResult()
+ defer c.JSON(http.StatusOK, ret)
+
+ arg, ok := util.JsonArg(c, ret)
+ if !ok {
+ return
+ }
+
+ param, err := gulu.JSON.MarshalJSON(arg)
+ if nil != err {
+ ret.Code = -1
+ ret.Msg = err.Error()
+ return
+ }
+
+ flashcard := &conf.Flashcard{}
+ if err = gulu.JSON.UnmarshalJSON(param, flashcard); nil != err {
+ ret.Code = -1
+ ret.Msg = err.Error()
+ return
+ }
+
+ if 1 > flashcard.DailyNewCardLimit {
+ flashcard.DailyNewCardLimit = 1
+ }
+
+ if 1 > flashcard.DailyReviewCardLimit {
+ flashcard.DailyReviewCardLimit = 1
+ }
+
+ model.Conf.Flashcard = flashcard
+ model.Conf.Save()
+
+ ret.Data = flashcard
+}
+
func setAccount(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
diff --git a/kernel/go.mod b/kernel/go.mod
index 95b8f9ff1..1db10d92d 100644
--- a/kernel/go.mod
+++ b/kernel/go.mod
@@ -37,12 +37,13 @@ require (
github.com/mitchellh/go-ps v1.0.0
github.com/mssola/user_agent v0.6.0
github.com/olahol/melody v1.1.3
+ github.com/open-spaced-repetition/go-fsrs v0.1.0
github.com/panjf2000/ants/v2 v2.7.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/radovskyb/watcher v1.0.7
github.com/sashabaranov/go-gpt3 v1.4.0
github.com/shirou/gopsutil/v3 v3.23.2
- github.com/siyuan-note/dejavu v0.0.0-20230315034343-e9513a7e1999
+ github.com/siyuan-note/dejavu v0.0.0-20230319084158-c8c1eaadf7bd
github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75
github.com/siyuan-note/eventbus v0.0.0-20230216103454-41885eac6c2b
github.com/siyuan-note/filelock v0.0.0-20230319015503-9ac4a0ee675b
@@ -66,7 +67,7 @@ require (
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
- github.com/aws/aws-sdk-go v1.44.221 // indirect
+ github.com/aws/aws-sdk-go v1.44.224 // indirect
github.com/bytedance/sonic v1.8.5 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
@@ -107,14 +108,13 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/onsi/ginkgo/v2 v2.9.1 // indirect
- github.com/open-spaced-repetition/go-fsrs v0.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/qiniu/go-sdk/v7 v7.14.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
- github.com/quic-go/qtls-go1-19 v0.2.1 // indirect
- github.com/quic-go/qtls-go1-20 v0.1.1 // indirect
+ github.com/quic-go/qtls-go1-19 v0.3.0 // indirect
+ github.com/quic-go/qtls-go1-20 v0.2.0 // indirect
github.com/quic-go/quic-go v0.33.0 // indirect
github.com/restic/chunker v0.4.0 // indirect
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect
@@ -128,7 +128,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
- golang.org/x/exp v0.0.0-20230314191032-db074128a8ec // indirect
+ golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
diff --git a/kernel/go.sum b/kernel/go.sum
index 24a9540af..ab4899a94 100644
--- a/kernel/go.sum
+++ b/kernel/go.sum
@@ -37,8 +37,8 @@ github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhP
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de/go.mod h1:DCaWoUhZrYW9p1lxo/cm8EmUOOzAPSEZNGF2DK1dJgw=
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef h1:2JGTg6JapxP9/R33ZaagQtAM4EkkSYnIAlOG5EI8gkM=
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII=
-github.com/aws/aws-sdk-go v1.44.221 h1:yndn4uvLolKXPoXIwKHhO5XtwlTnJfXLBKXs84C5+hQ=
-github.com/aws/aws-sdk-go v1.44.221/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
+github.com/aws/aws-sdk-go v1.44.224 h1:09CiaaF35nRmxrzWZ2uRq5v6Ghg/d2RiPjZnSgtt+RQ=
+github.com/aws/aws-sdk-go v1.44.224/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.5 h1:kjX0/vo5acEQ/sinD/18SkA/lDDUk23F0RcaHvI7omc=
github.com/bytedance/sonic v1.8.5/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
@@ -250,10 +250,10 @@ github.com/qiniu/go-sdk/v7 v7.14.0/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFs
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
-github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
-github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
-github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
-github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
+github.com/quic-go/qtls-go1-19 v0.3.0 h1:aUBoQdpHzUWtPw5tQZbsD2GnrWCNu7/RIX1PtqGeLYY=
+github.com/quic-go/qtls-go1-19 v0.3.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
+github.com/quic-go/qtls-go1-20 v0.2.0 h1:jUHn+obJ6WI5JudqBO0Iy1ra5Vh5vsitQ1gXQvkmN+E=
+github.com/quic-go/qtls-go1-20 v0.2.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
github.com/radovskyb/watcher v1.0.7 h1:AYePLih6dpmS32vlHfhCeli8127LzkIgwJGcwwe8tUE=
@@ -277,8 +277,8 @@ github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5g
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d h1:lvCTyBbr36+tqMccdGMwuEU+hjux/zL6xSmf5S9ITaA=
github.com/shurcooL/gofontwoff v0.0.0-20181114050219-180f79e6909d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
-github.com/siyuan-note/dejavu v0.0.0-20230315034343-e9513a7e1999 h1:t4FSwNVaa2CJbAIJNyF5egCdgqAeBDbP0WmGXcPBbGs=
-github.com/siyuan-note/dejavu v0.0.0-20230315034343-e9513a7e1999/go.mod h1:KUsHkTYpibU30rUArZOakCCHF1SGHQlxPWUu2LqW72s=
+github.com/siyuan-note/dejavu v0.0.0-20230319084158-c8c1eaadf7bd h1:h46K2Da4gmnDtXniCTX9p0NEP5toLd4qeTJ4teRiyns=
+github.com/siyuan-note/dejavu v0.0.0-20230319084158-c8c1eaadf7bd/go.mod h1:8fvMTYkfHRBn13YyZxbRfk2GCxDFszYlJfyyYFkvvNU=
github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75 h1:Bi7/7f29LW+Fm0cHc0J1NO1cZqyJwljSWVmfOqVZgaE=
github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75/go.mod h1:H8fyqqAbp9XreANjeSbc72zEdFfKTXYN34tc1TjZwtw=
github.com/siyuan-note/eventbus v0.0.0-20230216103454-41885eac6c2b h1:828lTUW2C0uNiolODqoACu7J8sDUzswD4Xo04mUombg=
@@ -351,8 +351,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
-golang.org/x/exp v0.0.0-20230314191032-db074128a8ec h1:pAv+d8BM2JNnNctsLJ6nnZ6NqXT8N4+eauvZSb3P0I0=
-golang.org/x/exp v0.0.0-20230314191032-db074128a8ec/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
+golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 h1:pVgRXcIictcr+lBQIFeiwuwtDIs4eL21OuM9nyAADmo=
+golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
diff --git a/kernel/model/box.go b/kernel/model/box.go
index 2464c06ec..f8c3b0923 100644
--- a/kernel/model/box.go
+++ b/kernel/model/box.go
@@ -527,19 +527,6 @@ func (box *Box) UpdateHistoryGenerated() {
boxLatestHistoryTime[box.ID] = time.Now()
}
-func TryAccessFileByBlockID(id string) (ok bool) {
- bt := treenode.GetBlockTree(id)
- if nil == bt {
- return
- }
- p := filepath.Join(util.DataDir, bt.BoxID, bt.Path)
-
- if !gulu.File.IsExist(p) {
- return false
- }
- return true
-}
-
func getBoxesByPaths(paths []string) (ret map[string]*Box) {
ret = map[string]*Box{}
for _, p := range paths {
diff --git a/kernel/model/flashcard.go b/kernel/model/flashcard.go
index c040bfc42..622ad8d17 100644
--- a/kernel/model/flashcard.go
+++ b/kernel/model/flashcard.go
@@ -29,6 +29,7 @@ import (
"github.com/88250/gulu"
"github.com/88250/lute/ast"
"github.com/88250/lute/parse"
+ "github.com/open-spaced-repetition/go-fsrs"
"github.com/siyuan-note/logging"
"github.com/siyuan-note/riff"
"github.com/siyuan-note/siyuan/kernel/cache"
@@ -634,6 +635,10 @@ func removeFlashcardsByBlockIDs(blockIDs []string, deck *riff.Deck) {
}
cards := deck.GetCardsByBlockIDs(blockIDs)
+ if 1 > len(cards) {
+ return
+ }
+
for _, card := range cards {
deck.RemoveCard(card.ID())
}
@@ -900,11 +905,20 @@ func getDeckDueCards(deck *riff.Deck) (ret []riff.Card) {
ret = []riff.Card{}
dues := deck.Dues()
+ newCount := 0
+ reviewCount := 0
for _, c := range dues {
if nil != skipCardCache[c.ID()] {
continue
}
+ fsrsCard := c.Impl().(*fsrs.Card)
+ if fsrs.New == fsrsCard.State {
+ newCount++
+ } else {
+ reviewCount++
+ }
+
ret = append(ret, c)
}
return
diff --git a/kernel/util/runtime.go b/kernel/util/runtime.go
index d4f0642cb..fd949201d 100644
--- a/kernel/util/runtime.go
+++ b/kernel/util/runtime.go
@@ -130,105 +130,116 @@ func ReportFileSysFatalError(err error) {
os.Exit(logging.ExitCodeFileSysErr)
}
+var checkFileSysStatusLock = sync.Mutex{}
+
func CheckFileSysStatus() {
if ContainerStd != Container {
return
}
- const fileSysStatusCheckFile = ".siyuan/filesys_status_check"
-
for {
<-thirdPartySyncCheckTicker.C
+ checkFileSysStatus()
+ }
+}
- if IsCloudDrivePath(WorkspaceDir) {
- ReportFileSysFatalError(fmt.Errorf("workspace dir [%s] is in third party sync dir", WorkspaceDir))
- return
- }
+func checkFileSysStatus() {
+ if IsMutexLocked(&checkFileSysStatusLock) {
+ logging.LogWarnf("check file system status is locked, skip")
+ return
+ }
- dir := filepath.Join(DataDir, fileSysStatusCheckFile)
- if err := os.RemoveAll(dir); nil != err {
+ checkFileSysStatusLock.Lock()
+ defer checkFileSysStatusLock.Unlock()
+
+ const fileSysStatusCheckFile = ".siyuan/filesys_status_check"
+ if IsCloudDrivePath(WorkspaceDir) {
+ ReportFileSysFatalError(fmt.Errorf("workspace dir [%s] is in third party sync dir", WorkspaceDir))
+ return
+ }
+
+ dir := filepath.Join(DataDir, fileSysStatusCheckFile)
+ if err := os.RemoveAll(dir); nil != err {
+ ReportFileSysFatalError(err)
+ return
+ }
+
+ if err := os.MkdirAll(dir, 0755); nil != err {
+ ReportFileSysFatalError(err)
+ return
+ }
+
+ for i := 0; i < 7; i++ {
+ tmp := filepath.Join(dir, "check_consistency")
+ data := make([]byte, 1024*4)
+ _, err := rand.Read(data)
+ if nil != err {
ReportFileSysFatalError(err)
return
}
- if err := os.MkdirAll(dir, 0755); nil != err {
+ if err = os.WriteFile(tmp, data, 0644); nil != err {
ReportFileSysFatalError(err)
return
}
- for i := 0; i < 7; i++ {
- tmp := filepath.Join(dir, "check_consistency")
- data := make([]byte, 1024*4)
- _, err := rand.Read(data)
+ time.Sleep(5 * time.Second)
+
+ for j := 0; j < 32; j++ {
+ renamed := tmp + "_renamed"
+ if err = os.Rename(tmp, renamed); nil != err {
+ ReportFileSysFatalError(err)
+ break
+ }
+
+ time.Sleep(time.Second)
+
+ f, err := os.Open(renamed)
if nil != err {
ReportFileSysFatalError(err)
return
}
- if err = os.WriteFile(tmp, data, 0644); nil != err {
+ if err = f.Close(); nil != err {
ReportFileSysFatalError(err)
return
}
- time.Sleep(5 * time.Second)
-
- for j := 0; j < 32; j++ {
- renamed := tmp + "_renamed"
- if err = os.Rename(tmp, renamed); nil != err {
- ReportFileSysFatalError(err)
- break
- }
-
- time.Sleep(time.Second)
-
- f, err := os.Open(renamed)
- if nil != err {
- ReportFileSysFatalError(err)
- return
- }
-
- if err = f.Close(); nil != err {
- ReportFileSysFatalError(err)
- return
- }
-
- if err = os.Rename(renamed, tmp); nil != err {
- ReportFileSysFatalError(err)
- return
- }
-
- entries, err := os.ReadDir(dir)
- if nil != err {
- ReportFileSysFatalError(err)
- return
- }
-
- checkFilenames := bytes.Buffer{}
- for _, entry := range entries {
- if !entry.IsDir() && strings.Contains(entry.Name(), "check_") {
- checkFilenames.WriteString(entry.Name())
- checkFilenames.WriteString("\n")
- }
- }
- lines := strings.Split(strings.TrimSpace(checkFilenames.String()), "\n")
- if 1 < len(lines) {
- buf := bytes.Buffer{}
- for _, line := range lines {
- buf.WriteString(" ")
- buf.WriteString(line)
- buf.WriteString("\n")
- }
- output := buf.String()
- ReportFileSysFatalError(fmt.Errorf("dir [%s] has more than 1 file:\n%s", dir, output))
- return
- }
- }
-
- if err = os.RemoveAll(tmp); nil != err {
+ if err = os.Rename(renamed, tmp); nil != err {
ReportFileSysFatalError(err)
return
}
+ entries, err := os.ReadDir(dir)
+ if nil != err {
+ ReportFileSysFatalError(err)
+ return
+ }
+
+ checkFilenames := bytes.Buffer{}
+ for _, entry := range entries {
+ if !entry.IsDir() && strings.Contains(entry.Name(), "check_") {
+ checkFilenames.WriteString(entry.Name())
+ checkFilenames.WriteString("\n")
+ }
+ }
+ lines := strings.Split(strings.TrimSpace(checkFilenames.String()), "\n")
+ if 1 < len(lines) {
+ buf := bytes.Buffer{}
+ for _, line := range lines {
+ buf.WriteString(" ")
+ buf.WriteString(line)
+ buf.WriteString("\n")
+ }
+ output := buf.String()
+ ReportFileSysFatalError(fmt.Errorf("dir [%s] has more than 1 file:\n%s", dir, output))
+ return
+ }
+ }
+
+ if err = os.RemoveAll(tmp); nil != err {
+ ReportFileSysFatalError(err)
+ return
}
}
}
diff --git a/kernel/util/working.go b/kernel/util/working.go
index 5c847efd8..cada3f05b 100644
--- a/kernel/util/working.go
+++ b/kernel/util/working.go
@@ -397,7 +397,7 @@ func initPandoc() {
}
pandocZip := filepath.Join(WorkingDir, "pandoc.zip")
- if "dev" == Mode {
+ if "dev" == Mode || !gulu.File.IsExist(pandocZip) {
if gulu.OS.IsWindows() {
pandocZip = filepath.Join(WorkingDir, "pandoc/pandoc-windows-amd64.zip")
} else if gulu.OS.IsDarwin() {