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.lockFile0} v${Constants.SIYUAN_VERSION}
-
-

${window.siyuan.languages.lockFile1}

-

${window.siyuan.languages.lockFile2}

-
-
- -
- -
-
`; - 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() {