diff --git a/app/appearance/langs/en_US.json b/app/appearance/langs/en_US.json index 6508158b0..690b38706 100644 --- a/app/appearance/langs/en_US.json +++ b/app/appearance/langs/en_US.json @@ -1120,6 +1120,7 @@ "193": "Please refer to the [Artificial Intelligence] chapter of the User Guide for configuration", "194": "There are restrictions on the Nutstore interface, please use other WebDAV services", "195": "The system time is incorrect, please calibrate the system time and try again", - "196": "Do not set the workspace under the path of a third-party sync disk, otherwise the data will be damaged (OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)" + "196": "Do not set the workspace under the path of a third-party sync disk, otherwise the data will be damaged (iCloud/OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)", + "197": "Currently the editor is in read-only mode. If you need to edit content, please switch to edit mode" } } diff --git a/app/appearance/langs/es_ES.json b/app/appearance/langs/es_ES.json index 7d1973111..935778a23 100644 --- a/app/appearance/langs/es_ES.json +++ b/app/appearance/langs/es_ES.json @@ -1120,6 +1120,7 @@ "193": "Consulte el capítulo [Inteligencia artificial] de la guía del usuario para la configuración", "194": "Existen restricciones en la interfaz de Nutstore, utilice otros servicios WebDAV", "195": "La hora del sistema es incorrecta, calibre la hora del sistema y vuelva a intentarlo", - "196": "No configure el espacio de trabajo bajo la ruta de un disco de sincronización de terceros, de lo contrario, los datos se dañarán (OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)" + "196": "No configure el espacio de trabajo bajo la ruta de un disco de sincronización de terceros, de lo contrario, los datos se dañarán (iCloud/OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)", + "197": "Actualmente, el editor se encuentra en modo de solo lectura. Si necesita editar contenido, cambie al modo de edición" } } diff --git a/app/appearance/langs/fr_FR.json b/app/appearance/langs/fr_FR.json index b5abc7131..7f074082b 100644 --- a/app/appearance/langs/fr_FR.json +++ b/app/appearance/langs/fr_FR.json @@ -1120,6 +1120,7 @@ "193": "Veuillez vous référer au chapitre [Intelligence Artificielle] du guide de l'utilisateur pour la configuration", "194": "Il existe des restrictions sur l'interface Nutstore, veuillez utiliser d'autres services WebDAV", "195": "L'heure du système est incorrecte, veuillez calibrer l'heure du système et réessayer", - "196": "Ne définissez pas l'espace de travail sous le chemin d'un disque de synchronisation tiers, sinon les données seront endommagées (OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)" + "196": "Ne définissez pas l'espace de travail sous le chemin d'un disque de synchronisation tiers, sinon les données seront endommagées (iCloud/OneDrive/Dropbox/Google Drive/Nutstore/Baidu Netdisk/Tencent Weiyun, etc.)", + "197": "Actuellement, l'éditeur est en mode lecture seule. Si vous devez modifier le contenu, veuillez passer en mode édition" } } diff --git a/app/appearance/langs/zh_CHT.json b/app/appearance/langs/zh_CHT.json index 5ba5564f8..f4b02a424 100644 --- a/app/appearance/langs/zh_CHT.json +++ b/app/appearance/langs/zh_CHT.json @@ -1120,6 +1120,7 @@ "193": "請先參考用戶指南 [人工智能] 章節進行配置", "194": "堅果雲接口存在限制,請使用其他 WebDAV 服務", "195": "系統時間不正確,請校準系統時間後再試", - "196": "請勿將工作空間設置在第三方同步盤路徑下,否則數據會被損壞(OneDrive/Dropbox/Google Drive/堅果雲/百度網盤/騰訊微雲等)" + "196": "請勿將工作空間設置在第三方同步盤路徑下,否則數據會被損壞(iCloud/OneDrive/Dropbox/Google Drive/堅果雲/百度網盤/騰訊微雲等)", + "197": "目前編輯器正處於只讀模式狀態,如果需要編輯內容,請切換到編輯模式" } } diff --git a/app/appearance/langs/zh_CN.json b/app/appearance/langs/zh_CN.json index 08aa9b205..3a6618d9a 100644 --- a/app/appearance/langs/zh_CN.json +++ b/app/appearance/langs/zh_CN.json @@ -1120,6 +1120,7 @@ "193": "请先参考用户指南 [人工智能] 章节进行配置", "194": "坚果云接口存在限制,请使用其他 WebDAV 服务", "195": "系统时间不正确,请校准系统时间后再试", - "196": "请勿将工作空间设置在第三方同步盘路径下,否则数据会被损坏(OneDrive/Dropbox/Google Drive/坚果云/百度网盘/腾讯微云等)" + "196": "请勿将工作空间设置在第三方同步盘路径下,否则数据会被损坏(iCloud/OneDrive/Dropbox/Google Drive/坚果云/百度网盘/腾讯微云等)", + "197": "目前编辑器正处于只读模式状态,如果需要编辑内容,请切换到编辑模式" } } diff --git a/app/electron/init.html b/app/electron/init.html index ea02837a4..46b7dca65 100644 --- a/app/electron/init.html +++ b/app/electron/init.html @@ -285,98 +285,112 @@
diff --git a/app/electron/main.js b/app/electron/main.js index 92b91590b..463d7f432 100644 --- a/app/electron/main.js +++ b/app/electron/main.js @@ -540,7 +540,7 @@ const initKernel = (workspace, port, lang) => { case 26: showErrorWindow( "⚠️ 文件系统不一致 File system inconsistent", - "
请勿使用第三方同步盘进行数据同步,否则数据会被损坏(OneDrive/Dropbox/Google Drive/坚果云/百度网盘/腾讯微云等)
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.)
"); + "
请勿使用第三方同步盘进行数据同步,否则数据会被损坏(iCloud/OneDrive/Dropbox/Google Drive/坚果云/百度网盘/腾讯微云等)
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.)
"); break; case 0: case 1: // Fatal error diff --git a/app/src/protyle/scroll/index.ts b/app/src/protyle/scroll/index.ts index c6b5c1444..4b0788c7b 100644 --- a/app/src/protyle/scroll/index.ts +++ b/app/src/protyle/scroll/index.ts @@ -82,7 +82,7 @@ export class Scroll { if (protyle.block.showAll) { this.element.classList.add("fn__none"); } else { - if (protyle.block.childBlockCount > window.siyuan.config.editor.dynamicLoadBlocks) { + if (protyle.block.scroll) { this.element.classList.remove("fn__none"); } else { this.element.classList.add("fn__none"); diff --git a/app/src/protyle/util/onGet.ts b/app/src/protyle/util/onGet.ts index 683617de9..20da2f73f 100644 --- a/app/src/protyle/util/onGet.ts +++ b/app/src/protyle/util/onGet.ts @@ -72,7 +72,7 @@ export const onGet = (data: IWebSocketData, protyle: IProtyle, action: string[] protyle.block.showAll = false; protyle.block.mode = data.data.mode; protyle.block.blockCount = data.data.blockCount; - protyle.block.childBlockCount = data.data.childBlockCount; + protyle.block.scroll = data.data.scroll; protyle.block.action = action; if (!action.includes(Constants.CB_GET_UNCHANGEID)) { protyle.block.id = data.data.id; diff --git a/app/src/types/protyle.d.ts b/app/src/types/protyle.d.ts index 1fc19c451..0c1dd906d 100644 --- a/app/src/types/protyle.d.ts +++ b/app/src/types/protyle.d.ts @@ -409,7 +409,7 @@ interface IProtyle { id: string, block: { id?: string, - childBlockCount?: number, + scroll?: boolean parentID?: string, parent2ID?: string, rootID?: string, diff --git a/kernel/api/filetree.go b/kernel/api/filetree.go index 45f9cfd2c..d35d9462e 100644 --- a/kernel/api/filetree.go +++ b/kernel/api/filetree.go @@ -690,7 +690,7 @@ func getDoc(c *gin.Context) { isBacklink = isBacklinkArg.(bool) } - blockCount, childBlockCount, content, parentID, parent2ID, rootID, typ, eof, boxID, docPath, isBacklinkExpand, err := model.GetDoc(startID, endID, id, index, keyword, mode, size, isBacklink) + 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 @@ -719,8 +719,8 @@ func getDoc(c *gin.Context) { "type": typ, "content": content, "blockCount": blockCount, - "childBlockCount": childBlockCount, "eof": eof, + "scroll": scroll, "box": boxID, "path": docPath, "isSyncing": isSyncing, diff --git a/kernel/api/riff.go b/kernel/api/riff.go index dde4c45f6..0ccc67358 100644 --- a/kernel/api/riff.go +++ b/kernel/api/riff.go @@ -104,6 +104,25 @@ func reviewRiffCard(c *gin.Context) { } } +func skipReviewRiffCard(c *gin.Context) { + ret := gulu.Ret.NewResult() + defer c.JSON(http.StatusOK, ret) + + arg, ok := util.JsonArg(c, ret) + if !ok { + return + } + + deckID := arg["deckID"].(string) + cardID := arg["cardID"].(string) + err := model.SkipReviewFlashcard(deckID, cardID) + if nil != err { + ret.Code = -1 + ret.Msg = err.Error() + return + } +} + func getNotebookRiffDueCards(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) diff --git a/kernel/api/router.go b/kernel/api/router.go index 8431c5a5a..b0f20efb3 100644 --- a/kernel/api/router.go +++ b/kernel/api/router.go @@ -314,6 +314,7 @@ func ServeAPI(ginServer *gin.Engine) { ginServer.Handle("POST", "/api/riff/getTreeRiffDueCards", model.CheckAuth, getTreeRiffDueCards) ginServer.Handle("POST", "/api/riff/getNotebookRiffDueCards", model.CheckAuth, getNotebookRiffDueCards) ginServer.Handle("POST", "/api/riff/reviewRiffCard", model.CheckAuth, model.CheckReadonly, reviewRiffCard) + ginServer.Handle("POST", "/api/riff/skipReviewRiffCard", model.CheckAuth, model.CheckReadonly, skipReviewRiffCard) ginServer.Handle("POST", "/api/riff/getRiffCards", model.CheckAuth, getRiffCards) ginServer.Handle("POST", "/api/riff/getTreeRiffCards", model.CheckAuth, getTreeRiffCards) ginServer.Handle("POST", "/api/riff/getNotebookRiffCards", model.CheckAuth, getNotebookRiffCards) diff --git a/kernel/api/system.go b/kernel/api/system.go index 41c8def7b..f5808f7fc 100644 --- a/kernel/api/system.go +++ b/kernel/api/system.go @@ -164,6 +164,16 @@ func getConf(c *gin.Context) { if start { start = false + + if model.Conf.Editor.ReadOnly { + // 编辑器启用只读模式时启动后提示用户 https://github.com/siyuan-note/siyuan/issues/7700 + go func() { + time.Sleep(time.Second * 7) + if model.Conf.Editor.ReadOnly { + util.PushMsg(model.Conf.Language(197), 7000) + } + }() + } } } diff --git a/kernel/api/workspace.go b/kernel/api/workspace.go index 7ae5aaa52..9fbca2632 100644 --- a/kernel/api/workspace.go +++ b/kernel/api/workspace.go @@ -108,7 +108,7 @@ func removeWorkspaceDir(c *gin.Context) { } if util.WorkspaceDir == path && (util.ContainerIOS == util.Container || util.ContainerAndroid == util.Container) { - os.Exit(util.ExitCodeOk) + os.Exit(logging.ExitCodeOk) } } diff --git a/kernel/filesys/tree.go b/kernel/filesys/tree.go index 2b1178b65..6a859e16c 100644 --- a/kernel/filesys/tree.go +++ b/kernel/filesys/tree.go @@ -42,7 +42,7 @@ func LoadTree(boxID, p string, luteEngine *lute.Lute) (ret *parse.Tree, err erro if nil != err { logging.LogErrorf("load tree [%s] failed: %s", p, err) if errors.Is(err, filelock.ErrUnableAccessFile) { - os.Exit(util.ExitCodeFileSysInconsistent) + os.Exit(logging.ExitCodeFileSysInconsistent) return } return @@ -97,7 +97,7 @@ func LoadTreeByData(data []byte, boxID, p string, luteEngine *lute.Lute) (ret *p } else { logging.LogWarnf("read parent tree data [%s] failed: %s", parentAbsPath, readErr) if errors.Is(readErr, filelock.ErrUnableAccessFile) { - os.Exit(util.ExitCodeFileSysInconsistent) + os.Exit(logging.ExitCodeFileSysInconsistent) return } } diff --git a/kernel/go.mod b/kernel/go.mod index 0fb47cadc..975c739b0 100644 --- a/kernel/go.mod +++ b/kernel/go.mod @@ -45,9 +45,9 @@ require ( github.com/siyuan-note/dejavu v0.0.0-20230315034343-e9513a7e1999 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-20230223100551-200cbe1cf84e + github.com/siyuan-note/filelock v0.0.0-20230318101209-f0e353df8b5b github.com/siyuan-note/httpclient v0.0.0-20230309131049-f703795de6bc - github.com/siyuan-note/logging v0.0.0-20230223101545-ec2cbf198ffb + github.com/siyuan-note/logging v0.0.0-20230318100514-8ece27db458d github.com/siyuan-note/riff v0.0.0-20230224144841-cfbe0748ddb7 github.com/steambap/captcha v1.4.1 github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2 diff --git a/kernel/go.sum b/kernel/go.sum index bfefefca8..cb546de65 100644 --- a/kernel/go.sum +++ b/kernel/go.sum @@ -283,12 +283,12 @@ github.com/siyuan-note/encryption v0.0.0-20220713091850-5ecd92177b75 h1:Bi7/7f29 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= github.com/siyuan-note/eventbus v0.0.0-20230216103454-41885eac6c2b/go.mod h1:Sqo4FYX5lAXu7gWkbEdJF0e6P57tNNVV4WDKYDctokI= -github.com/siyuan-note/filelock v0.0.0-20230223100551-200cbe1cf84e h1:SjId8gvjrN/dWa/I+FrRFQtNR3QoU1Vkm/DP0Oos6Rw= -github.com/siyuan-note/filelock v0.0.0-20230223100551-200cbe1cf84e/go.mod h1:9uEHHzT1PNXHKTP1PPIB+Q353kMK4RPHPnqjzPEGCUI= +github.com/siyuan-note/filelock v0.0.0-20230318101209-f0e353df8b5b h1:NtC1PhGKtOvjQNf95UUW3K5OW/0OIu3ny8sLq9YYqOQ= +github.com/siyuan-note/filelock v0.0.0-20230318101209-f0e353df8b5b/go.mod h1:kL4KLZ3/SJxQFQ/lUxkbOyQiqVh/MJyo1CGy6sAUqM8= github.com/siyuan-note/httpclient v0.0.0-20230309131049-f703795de6bc h1:MX2cPWpn7Hfd3FmpwLjGdPIjF84AFUS9f/mcPJc/4w4= github.com/siyuan-note/httpclient v0.0.0-20230309131049-f703795de6bc/go.mod h1:WDO42mUVRnkk8M4AhZ4oakZ5jnghulP0c8NFCrrFWG4= -github.com/siyuan-note/logging v0.0.0-20230223101545-ec2cbf198ffb h1:qzz7ZQw7/tHJd1IST+8UymXFF8RacokMLD7VZgyS+ww= -github.com/siyuan-note/logging v0.0.0-20230223101545-ec2cbf198ffb/go.mod h1:6mRFtAAvYPn3cDzqvyv+t8BVPGqpONDMMb5ywOhY1D4= +github.com/siyuan-note/logging v0.0.0-20230318100514-8ece27db458d h1:K7y9mEvoQ2PZkM0f+bHvnyDi/gnKfY5OJjYUe2GFnpc= +github.com/siyuan-note/logging v0.0.0-20230318100514-8ece27db458d/go.mod h1:6mRFtAAvYPn3cDzqvyv+t8BVPGqpONDMMb5ywOhY1D4= github.com/siyuan-note/riff v0.0.0-20230224144841-cfbe0748ddb7 h1:Kr8hhMhr6v+U24TMDCP5WdP4dWrXm5maar+TycTZs9I= github.com/siyuan-note/riff v0.0.0-20230224144841-cfbe0748ddb7/go.mod h1:XJtLlKCr8cZE+lzykM4edHHih92M9M50UNw/nDLYRN8= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= diff --git a/kernel/model/box.go b/kernel/model/box.go index 8f943f549..2a9054417 100644 --- a/kernel/model/box.go +++ b/kernel/model/box.go @@ -491,7 +491,7 @@ func fullReindex() { WaitForWritingFiles() if err := sql.InitDatabase(true); nil != err { - os.Exit(util.ExitCodeReadOnlyDatabase) + os.Exit(logging.ExitCodeReadOnlyDatabase) return } treenode.InitBlockTree(true) diff --git a/kernel/model/conf.go b/kernel/model/conf.go index 0c9d8586c..39db70a8b 100644 --- a/kernel/model/conf.go +++ b/kernel/model/conf.go @@ -463,7 +463,7 @@ func Close(force bool, execInstallPkg int) (exitCode int) { } logging.LogInfof("exited kernel") util.WebSocketServer.Close() - os.Exit(util.ExitCodeOk) + os.Exit(logging.ExitCodeOk) }() return } diff --git a/kernel/model/file.go b/kernel/model/file.go index 5833b3c2c..301e1bbc8 100644 --- a/kernel/model/file.go +++ b/kernel/model/file.go @@ -414,7 +414,7 @@ func StatTree(id string) (ret *util.BlockStatResult) { } } -func GetDoc(startID, endID, id string, index int, keyword string, mode int, size int, isBacklink bool) (blockCount, childBlockCount int, dom, parentID, parent2ID, rootID, typ string, eof bool, boxID, docPath string, isBacklinkExpand bool, err error) { +func GetDoc(startID, endID, id string, index int, keyword string, mode int, size int, isBacklink bool) (blockCount int, dom, parentID, parent2ID, rootID, typ string, eof, scroll bool, boxID, docPath string, isBacklinkExpand bool, err error) { //os.MkdirAll("pprof", 0755) //cpuProfile, _ := os.Create("pprof/GetDoc") //pprof.StartCPUProfile(cpuProfile) @@ -540,7 +540,6 @@ func GetDoc(startID, endID, id string, index int, keyword string, mode int, size } blockCount = tree.DocBlockCount() - childBlockCount = treenode.CountBlockNodes(tree.Root) if ast.NodeDocument == node.Type { parentID = node.ID parent2ID = parentID @@ -561,6 +560,26 @@ func GetDoc(startID, endID, id string, index int, keyword string, mode int, size typ = node.Type.String() } + // 判断是否需要显示动态加载滚动条 https://github.com/siyuan-note/siyuan/issues/7693 + childCount := 0 + ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus { + if !entering { + return ast.WalkContinue + } + + if 1 > childCount { + childCount = 1 + } else { + childCount += treenode.CountBlockNodes(n) + } + + if childCount > Conf.Editor.DynamicLoadBlocks { + scroll = true + return ast.WalkStop + } + return ast.WalkContinue + }) + var nodes []*ast.Node if isBacklink { // 引用计数浮窗请求,需要按照反链逻辑组装 https://github.com/siyuan-note/siyuan/issues/6853 diff --git a/kernel/model/flashcard.go b/kernel/model/flashcard.go index be50ee4f5..c040bfc42 100644 --- a/kernel/model/flashcard.go +++ b/kernel/model/flashcard.go @@ -181,8 +181,13 @@ func getCardsBlocks(cards []riff.Card, page int) (blocks []*Block, total, pageCo return } -// reviewCardCache 用于复习时缓存卡片,以便支持撤销。 -var reviewCardCache = map[string]riff.Card{} +var ( + // reviewCardCache 用于复习时缓存卡片,以便支持撤销。 + reviewCardCache = map[string]riff.Card{} + + // skipCardCache 用于复习时缓存跳过的卡片,以便支持跳过过滤。 + skipCardCache = map[string]riff.Card{} +) func ReviewFlashcard(deckID, cardID string, rating riff.Rating) (err error) { deckLock.Lock() @@ -203,6 +208,9 @@ func ReviewFlashcard(deckID, cardID string, rating riff.Rating) (err error) { // 命中缓存说明这张卡片已经复习过了,这次调用复习是撤销后再次复习 // 将缓存的卡片重新覆盖回卡包中,以恢复最开始复习前的状态 deck.SetCard(cachedCard) + + // 从跳过缓存中移除(如果上一次点的是跳过的话),如果不在跳过缓存中,说明上一次点的是复习,这里移除一下也没有副作用 + delete(skipCardCache, cardID) } else { // 首次复习该卡片,将卡片缓存以便后续支持撤销后再次复习 reviewCardCache[cardID] = card @@ -217,12 +225,32 @@ func ReviewFlashcard(deckID, cardID string, rating riff.Rating) (err error) { dueCards := getDueFlashcards(deckID) if 1 > len(dueCards) { - // 该卡包中没有待复习的卡片了,说明最后一张卡片已经复习完了,清空撤销缓存 + // 该卡包中没有待复习的卡片了,说明最后一张卡片已经复习完了,清空撤销缓存和跳过缓存 reviewCardCache = map[string]riff.Card{} + skipCardCache = map[string]riff.Card{} } return } +func SkipReviewFlashcard(deckID, cardID string) (err error) { + deckLock.Lock() + defer deckLock.Unlock() + + if syncingStorages { + err = errors.New(Conf.Language(81)) + return + } + + deck := Decks[deckID] + card := deck.GetCard(cardID) + if nil == card { + return + } + + skipCardCache[cardID] = card + return +} + type Flashcard struct { DeckID string `json:"deckID"` CardID string `json:"cardID"` @@ -286,7 +314,7 @@ func GetNotebookDueFlashcards(boxID string) (ret []*Flashcard, err error) { return } - cards := deck.Dues() + cards := getDeckDueCards(deck) now := time.Now() for _, card := range cards { blockID := card.BlockID() @@ -317,7 +345,7 @@ func GetTreeDueFlashcards(rootID string) (ret []*Flashcard, err error) { } treeBlockIDs := getTreeSubTreeChildBlocks(rootID) - cards := deck.Dues() + cards := getDeckDueCards(deck) now := time.Now() for _, card := range cards { blockID := card.BlockID() @@ -396,7 +424,7 @@ func getDueFlashcards(deckID string) (ret []*Flashcard) { return } - cards := deck.Dues() + cards := getDeckDueCards(deck) now := time.Now() for _, card := range cards { blockID := card.BlockID() @@ -416,7 +444,7 @@ func getDueFlashcards(deckID string) (ret []*Flashcard) { func getAllDueFlashcards() (ret []*Flashcard) { now := time.Now() for _, deck := range Decks { - cards := deck.Dues() + cards := getDeckDueCards(deck) for _, card := range cards { blockID := card.BlockID() if nil == treenode.GetBlockTree(blockID) { @@ -867,3 +895,17 @@ func getDeckIDs() (deckIDs []string) { } return } + +func getDeckDueCards(deck *riff.Deck) (ret []riff.Card) { + ret = []riff.Card{} + dues := deck.Dues() + + for _, c := range dues { + if nil != skipCardCache[c.ID()] { + continue + } + + ret = append(ret, c) + } + return +} diff --git a/kernel/model/storage.go b/kernel/model/storage.go index 8b91f4c50..960374762 100644 --- a/kernel/model/storage.go +++ b/kernel/model/storage.go @@ -259,6 +259,10 @@ func setCriteria(criteria []*Criterion) (err error) { err = filelock.WriteFile(lsPath, data) if nil != err { logging.LogErrorf("write storage [criteria] failed: %s", err) + if errors.Is(err, filelock.ErrUnableAccessFile) { + os.Exit(logging.ExitCodeFileSysInconsistent) + return + } return } return @@ -274,6 +278,10 @@ func getCriteria() (ret []*Criterion, err error) { data, err := filelock.ReadFile(dataPath) if nil != err { logging.LogErrorf("read storage [criteria] failed: %s", err) + if errors.Is(err, filelock.ErrUnableAccessFile) { + os.Exit(logging.ExitCodeFileSysInconsistent) + return + } return } @@ -345,6 +353,10 @@ func setLocalStorage(val interface{}) (err error) { err = filelock.WriteFile(lsPath, data) if nil != err { logging.LogErrorf("write storage [local] failed: %s", err) + if errors.Is(err, filelock.ErrUnableAccessFile) { + os.Exit(logging.ExitCodeFileSysInconsistent) + return + } return } return @@ -360,6 +372,10 @@ func getLocalStorage() (ret map[string]interface{}, err error) { data, err := filelock.ReadFile(lsPath) if nil != err { logging.LogErrorf("read storage [local] failed: %s", err) + if errors.Is(err, filelock.ErrUnableAccessFile) { + os.Exit(logging.ExitCodeFileSysInconsistent) + return + } return } diff --git a/kernel/server/serve.go b/kernel/server/serve.go index d49e485c0..3dede84be 100644 --- a/kernel/server/serve.go +++ b/kernel/server/serve.go @@ -84,7 +84,7 @@ func Serve(fastMode bool) { if nil != err { if !fastMode { logging.LogErrorf("boot kernel failed: %s", err) - os.Exit(util.ExitCodeUnavailablePort) + os.Exit(logging.ExitCodeUnavailablePort) } // fast 模式下启动失败则直接返回 @@ -95,7 +95,7 @@ func Serve(fastMode bool) { if nil != err { if !fastMode { logging.LogErrorf("boot kernel failed: %s", err) - os.Exit(util.ExitCodeUnavailablePort) + os.Exit(logging.ExitCodeUnavailablePort) } } util.ServerPort = port @@ -129,7 +129,7 @@ func Serve(fastMode bool) { if err = http.Serve(ln, ginServer); nil != err { if !fastMode { logging.LogErrorf("boot kernel failed: %s", err) - os.Exit(util.ExitCodeUnavailablePort) + os.Exit(logging.ExitCodeUnavailablePort) } } } diff --git a/kernel/sql/database.go b/kernel/sql/database.go index e9e592f9c..6f4cebe50 100644 --- a/kernel/sql/database.go +++ b/kernel/sql/database.go @@ -1148,7 +1148,7 @@ func beginTx() (tx *sql.Tx, err error) { if tx, err = db.Begin(); nil != err { logging.LogErrorf("begin tx failed: %s\n %s", err, logging.ShortStack()) if strings.Contains(err.Error(), "database is locked") { - os.Exit(util.ExitCodeReadOnlyDatabase) + os.Exit(logging.ExitCodeReadOnlyDatabase) } } return @@ -1158,7 +1158,7 @@ func beginHistoryTx() (tx *sql.Tx, err error) { if tx, err = historyDB.Begin(); nil != err { logging.LogErrorf("begin history tx failed: %s\n %s", err, logging.ShortStack()) if strings.Contains(err.Error(), "database is locked") { - os.Exit(util.ExitCodeReadOnlyDatabase) + os.Exit(logging.ExitCodeReadOnlyDatabase) } } return diff --git a/kernel/treenode/blocktree.go b/kernel/treenode/blocktree.go index 2e936f840..ec3c562da 100644 --- a/kernel/treenode/blocktree.go +++ b/kernel/treenode/blocktree.go @@ -325,7 +325,7 @@ func InitBlockTree(force bool) { entries, err := os.ReadDir(util.BlockTreePath) if nil != err { logging.LogErrorf("read block tree dir failed: %s", err) - os.Exit(util.ExitCodeBlockTreeErr) + os.Exit(logging.ExitCodeBlockTreeErr) return } @@ -342,7 +342,7 @@ func InitBlockTree(force bool) { fh, err = os.OpenFile(p, os.O_RDWR, 0644) if nil != err { logging.LogErrorf("open block tree file failed: %s", err) - os.Exit(util.ExitCodeBlockTreeErr) + os.Exit(logging.ExitCodeBlockTreeErr) return } @@ -351,7 +351,7 @@ func InitBlockTree(force bool) { fh.Close() if nil != err { logging.LogErrorf("read block tree failed: %s", err) - os.Exit(util.ExitCodeBlockTreeErr) + os.Exit(logging.ExitCodeBlockTreeErr) return } @@ -361,7 +361,7 @@ func InitBlockTree(force bool) { if err = os.RemoveAll(util.BlockTreePath); nil != err { logging.LogErrorf("removed corrupted block tree failed: %s", err) } - os.Exit(util.ExitCodeBlockTreeErr) + os.Exit(logging.ExitCodeBlockTreeErr) return } @@ -410,7 +410,7 @@ func SaveBlockTree(force bool) { data, err := msgpack.Marshal(slice.data) if nil != err { logging.LogErrorf("marshal block tree failed: %s", err) - os.Exit(util.ExitCodeBlockTreeErr) + os.Exit(logging.ExitCodeBlockTreeErr) return false } slice.m.Unlock() @@ -418,7 +418,7 @@ func SaveBlockTree(force bool) { p := filepath.Join(util.BlockTreePath, key.(string)) + ".msgpack" if err = gulu.File.WriteFileSafer(p, data, 0644); nil != err { logging.LogErrorf("write block tree failed: %s", err) - os.Exit(util.ExitCodeBlockTreeErr) + os.Exit(logging.ExitCodeBlockTreeErr) return false } diff --git a/kernel/util/runtime.go b/kernel/util/runtime.go index 175d7cd89..be75d08ef 100644 --- a/kernel/util/runtime.go +++ b/kernel/util/runtime.go @@ -37,18 +37,6 @@ import ( const DatabaseVer = "20220501" // 修改表结构的话需要修改这里 -const ( - ExitCodeReadOnlyDatabase = 20 // 数据库文件被锁 - ExitCodeUnavailablePort = 21 // 端口不可用 - ExitCodeCreateConfDirErr = 22 // 创建配置目录失败 - ExitCodeBlockTreeErr = 23 // 无法读写 blocktree.msgpack 文件 - ExitCodeWorkspaceLocked = 24 // 工作空间已被锁定 - ExitCodeCreateWorkspaceDirErr = 25 // 创建工作空间失败 - ExitCodeFileSysInconsistent = 26 // 文件系统不一致 - ExitCodeOk = 0 // 正常退出 - ExitCodeFatal = 1 // 致命错误 -) - // IsExiting 是否正在退出程序。 var IsExiting = false @@ -139,7 +127,7 @@ func ReportFileSysFatalError(err error) { output = strings.Join(lines[5:], "\n") } logging.LogErrorf("check file system status failed: %s, %s", err, output) - os.Exit(ExitCodeFileSysInconsistent) + os.Exit(logging.ExitCodeFileSysInconsistent) } func CheckFileSysStatus() { diff --git a/kernel/util/working.go b/kernel/util/working.go index 892d9151f..5c847efd8 100644 --- a/kernel/util/working.go +++ b/kernel/util/working.go @@ -190,7 +190,7 @@ func initWorkspaceDir(workspaceArg string) { if !gulu.File.IsExist(workspaceConf) { if err := os.MkdirAll(userHomeConfDir, 0755); nil != err && !os.IsExist(err) { log.Printf("create user home conf folder [%s] failed: %s", userHomeConfDir, err) - os.Exit(ExitCodeCreateConfDirErr) + os.Exit(logging.ExitCodeCreateConfDirErr) } } @@ -203,7 +203,7 @@ func initWorkspaceDir(workspaceArg string) { } if err := os.MkdirAll(defaultWorkspaceDir, 0755); nil != err && !os.IsExist(err) { log.Printf("create default workspace folder [%s] failed: %s", defaultWorkspaceDir, err) - os.Exit(ExitCodeCreateWorkspaceDirErr) + os.Exit(logging.ExitCodeCreateWorkspaceDirErr) } var workspacePaths []string @@ -481,7 +481,7 @@ func tryLockWorkspace() { } else { logging.LogErrorf("lock workspace [%s] failed", WorkspaceDir) } - os.Exit(ExitCodeWorkspaceLocked) + os.Exit(logging.ExitCodeWorkspaceLocked) } func IsWorkspaceLocked(workspacePath string) bool { diff --git a/kernel/util/working_mobile.go b/kernel/util/working_mobile.go index abbcadaff..cb94ba823 100644 --- a/kernel/util/working_mobile.go +++ b/kernel/util/working_mobile.go @@ -46,7 +46,7 @@ func BootMobile(container, appDir, workspaceBaseDir, lang string) { if !gulu.File.IsExist(userHomeConfDir) { if err := os.MkdirAll(userHomeConfDir, 0755); nil != err && !os.IsExist(err) { log.Printf("create user home conf folder [%s] failed: %s", userHomeConfDir, err) - os.Exit(ExitCodeCreateConfDirErr) + os.Exit(logging.ExitCodeCreateConfDirErr) } } @@ -54,7 +54,7 @@ func BootMobile(container, appDir, workspaceBaseDir, lang string) { defaultWorkspaceDir := filepath.Join(workspaceBaseDir, "siyuan") if err := os.MkdirAll(defaultWorkspaceDir, 0755); nil != err && !os.IsExist(err) { log.Printf("create default workspace folder [%s] failed: %s", defaultWorkspaceDir, err) - os.Exit(ExitCodeCreateWorkspaceDirErr) + os.Exit(logging.ExitCodeCreateWorkspaceDirErr) } initWorkspaceDirMobile(workspaceBaseDir)