桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载导读DIFF-375 是 MooTool 桌面端Compose for Desktop 实现JSON Vault 模块的一次精确行为修正当用户在目录树上点击目录条目、而编辑器当前正打开着一段脏dirtyJSON 片段时prepareJsonVaultContext会先尝试 flush保存该片段若保存失败必须回滚树选中到 flush 前的状态避免状态栏/高亮指向新目录、编辑器仍绑定旧文件的错位。本文从 DIFF-375 出发串联 DIFF-374、DIFF-376、DIFF-377、DIFF-380 等相邻变更结合JsonVaultSession.kt的完整实现、JsonVaultPrepareContextTest的 5 个测试用例与VaultConflictEngine的冲突判定逻辑讲清楚这条先 flush、成功后选中、失败即回滚的状态机规则及其在树单击、右键菜单、底栏操作中的统一落地方式。一、DIFF-375 要解决的问题1.1 问题背景三个语义不一致来源prepareJsonVaultContext是 Compose 端 JSON Vault 在上下文操作右键菜单、底栏按钮、树单击前的统一准备入口。在 DIFF-374 中目录条目在prepareJsonVaultContext前直接写vaultSelectedPath导致 flush 失败时选中仍然落在目录上。这带来三处不一致与树单击目录的语义冲突树单击目录时先jsonVaultFlushDirtyOrNoticeflush 失败不改选中而右键/底栏路径却先把选中切到目录行为不一致与随手记QuickNote语义冲突随手记 DIFF-360 已规定单击目录先保存再切换选中JSON 路径落后于这一已确立的交互规范Electron 参照系Compose 重构以 Electron 版为行为参照如 DIFF-360 中对照next/src/features/quickNote/QuickNoteTool.tsx的selectNodeElectron 在保存失败时不改selectedPathCompose 需对齐。1.2 DIFF-375 的修复目标目录条目仅在 flush 成功或无需 flush后更新vaultSelectedPath失败恢复为 flush 前的vaultSelectedPath空则回退currentFile。即目录条目被处理时若已打开片段且脏先尝试保存保存成功或本就不脏/未打开才把选中切到目录保存失败则把选中回滚到 flush 前的位置——若之前没有选中路径则回退到currentFile当前打开的文件保证高亮永远能落在一个真实可感知的条目上。二、源码级实现prepareJsonVaultContext的完整状态机实现位于 JsonVaultSession.kt是 DIFF-375 修复的直接载体internal fun prepareJsonVaultContext( container: AppContainer, session: JsonSession, monitor: VaultRevisionMonitor?, entry: VaultEntry, onConflict: (VaultConflictState) - Unit, ): Boolean { if (entry.directory) { // —— 目录分支DIFF-375 核心—— if (session.currentFile.isBlank() || session.editor.text session.savedText) { session.vaultSelectedPath entry.relativePath return true // 无需 flush直接选中目录 } val previousSelected session.currentFile.ifBlank { session.vaultSelectedPath } val result saveJsonVault(container, session, monitor, showToast false, onConflict onConflict) if (result.isSuccess) { session.vaultSelectedPath entry.relativePath } else { session.notice result.exceptionOrNull()?.message ?: container.t(json.notice.failed) session.vaultSelectedPath previousSelected // 失败回滚 } return result.isSuccess } // —— 文件分支DIFF-376 补齐—— if (entry.relativePath session.currentFile) { session.vaultSelectedPath entry.relativePath return true } if (session.currentFile.isBlank() || session.editor.text session.savedText) { session.vaultSelectedPath entry.relativePath return true } val previousSelected session.currentFile.ifBlank { session.vaultSelectedPath } val result saveJsonVault(container, session, monitor, showToast false, onConflict onConflict) if (result.isSuccess) { session.vaultSelectedPath entry.relativePath } else { session.notice result.exceptionOrNull()?.message ?: container.t(json.notice.failed) session.vaultSelectedPath previousSelected } return result.isSuccess }2.1 关键字段说明函数围绕JsonSession定义于 SessionManager.kt的三个状态字段运转字段含义初值currentFile编辑器当前打开片段的相对路径空串表示未打开vaultSelectedPathVault 树当前高亮/底栏显示的路径savedText最近一次成功保存或加载后的快照文本SAMPLE_JSON脏判定不依赖额外布尔位直接比较editor.text ! savedText而isVaultEditorDirty()进一步要求currentFile.isNotBlank()才成立。entry为VaultEntry定义于 VaultFiles.kt其中directory字段区分目录与文件条目。2.2 目录分支的四种情形场景currentFile脏状态行为返回值未打开任何文件空无关直接选中目录true打开且干净非空不脏直接选中目录无需 flushtrue打开且脏、保存成功非空脏flush 后选中目录true打开且脏、保存失败非空脏写notice、选中回滚false2.3 回滚的精确语义previousSelected回滚值取session.currentFile.ifBlank { session.vaultSelectedPath }正常情况下currentFile非空有打开的文件回滚目标就是仍打开的currentFile——这与 JsonVaultSession.kt 中openJsonVaultTreeFile的previousSelected语义完全一致若currentFile为空但存在一个已被单击高亮的 pending 路径则回退到该vaultSelectedPath避免把选中清零。三、flush 失败如何被判定冲突引擎与 notice 反馈3.1saveJsonVault的失败来源prepareJsonVaultContext中的保存走saveJsonVaultJsonVaultSession.kt失败只有两类无选中文件currentFile为空返回IllegalStateException(json.vault.saveNoSelection)并发写冲突VaultConflictEngine.canOverwrite(session.savedText, disk, session.editor.text)返回false即磁盘内容既不是savedText也不是editorText说明文件已被外部修改此时触发onConflict回调并返回失败。canOverwrite与decide定义于 VaultConflictEngine.ktfun canOverwrite(savedText: String, diskText: String?, editorText: String): Boolean { if (diskText null) return false return diskText savedText || diskText editorText }3.2 统一的 notice 反馈DIFF-363 / DIFF-368失败信息统一写入session.notice优先用异常message为空时回退到json.notice.failed。这一行为由两条变更确立DIFF-363规定prepareJsonVaultContext在saveJsonVault失败时写入session.notice与树onOpen/onMove的 flush 失败处理一致DIFF-368将散落的flushJsonVaultEditorIfDirty notice模式收敛为jsonVaultFlushDirtyOrNoticeJsonVaultSession.ktinternal fun jsonVaultFlushDirtyOrNotice( container: AppContainer, session: JsonSession, monitor: VaultRevisionMonitor?, onConflict: (VaultConflictState) - Unit, ): Boolean flushJsonVaultEditorIfDirty(container, session, monitor, onConflict) .onFailure { session.notice it.message ?: container.t(json.notice.failed) } .isSuccessflushJsonVaultEditorIfDirtyJsonVaultSession.kt本身就是 DIFF-374 引入的干净跳过封装仅当currentFile非空且editor.text ! savedText时才真正写盘干净时直接返回成功这也正是目录分支里无需 flush 直接选中的前提保证。四、测试验证JsonVaultPrepareContextTest五连测DIFF-375 的验收测试是JsonVaultPrepareContextTest.prepareContextDirectoryFlushConflictKeepsTreeSelectionJsonVaultPrepareContextTest.kt。该文件共 5 个用例恰好覆盖目录与文件分支的冲突保选中/回滚矩阵测试方法覆盖点断言要点prepareContextSaveConflictWritesNoticeAndReturnsFalse文件分支冲突notice非空、冲突回调触发、vaultSelectedPath保持open.jsonprepareContextSaveConflictRevertsTreeToOpenFileNotPendingHighlight冲突时回滚到打开文件而非 pending 高亮vaultSelectedPath currentFile open.jsonprepareContextDirectoryEntryFlushesDirtyOpenFileDIFF-374 引入目录分支脏文件被静默 flushflush 后savedText变为{dirty:true}、选中到folder、返回trueprepareContextDirectoryFlushConflictKeepsTreeSelectionDIFF-375 指定目录分支flush 冲突保持树选中返回false、vaultSelectedPath仍为open.json、notice非空prepareContextDirectoryFlushConflictRevertsHighlightToOpenFileDIFF-380 引入目录分支回滚 pending 高亮到打开文件vaultSelectedPath currentFile open.json测试用createTempDirectory构造隔离产品根目录配合AppPaths.resolve、SettingsRepository、AppDatabase、HistoryRepository、LegacyMigrationRowRepository、SessionStore组装出真实的AppContainer再通过container.jsonVault.createFile/createDirectory/write预置磁盘状态、手工把editor置脏来制造冲突是 Compose 端典型的真仓库 假 UI集成式单元测试。4.1 冲突场景的精妙之处以 DIFF-375 指定的测试为例它的磁盘状态特意制造出三方分歧savedText {saved:true}编辑器加载时的快照编辑器文本{dirty:true}用户改动磁盘{disk:true}外部修改模拟 Git 拉取/磁盘监听期间的并发写入。此时canOverwrite({saved:true}, {disk:true}, {dirty:true})为false保存必然失败从而精确验证目录条目 flush 失败 → 选中回滚的路径而不是偶然地命中磁盘快照的忽略分支。五、在 UI 中的落地树单击与右键/底栏的统一5.1 树单击目录DIFF-380 收口JsonScreen.kt 的VaultTreeList在 DIFF-380 之后把目录onSelect统一改为调用prepareJsonVaultContextonSelect { entry - if (entry.directory) { if (!prepareJsonVaultContext(container, session, monitor, entry, onConflict)) { onChanged() returnVaultTreeList } } else { session.vaultSelectedPath entry.relativePath // 文件单击仍只更新高亮 } onChanged() }也就是说DIFF-375 之后目录单击单击目录是选中双击目录才走onOpen加载与右键/底栏共享同一个prepareJsonVaultContext此前右键先切选中、单击不切选中的语义裂痕被抹平。文件单击依旧只更新vaultSelectedPath由onOpen/openJsonVaultTreeFile先 flush、失败回滚previousSelected负责真正的加载。5.2 右键菜单与底栏动作JsonScreen.kt 的onContextAction重命名/移动/复制/删除/导出等与 More 菜单、底栏重命名/移动入口在动作执行前都先调用prepareJsonVaultContext失败即return不再执行目标动作——这正是flush 失败不打断目标操作、只提示并保留现场的设计意图。底栏路径显示则统一由JsonVaultFooterPresentation.effectivePath(vaultSelectedPath, currentFile)JsonScreen.kt推导vaultSelectedPath回滚后底栏自然跟随回滚不会出现底栏指向新目录而编辑器仍是旧文件的错位。六、横向扩展随手记同源修复DIFF-377DIFF-375/376 的模式并非 JSON 独有。DIFF-377 用同一套先saveIfNeeded、成功后更新选中、失败回滚规则修复了随手记prepareQuickNoteVaultContextQuickNoteVaultContext.kt目录分支保存失败时session.vaultSelectedPath previousSelected并返回false不清空编辑器成功后才清空编辑区/metadata。两侧差异仅在于通知渠道——JSON 写session.notice随手记写session.error并可选择 toastnotifyQuickNoteSaveGuardFailure但脏文件保存失败时选中必须回滚这一不变量完全一致可视为 Vault 系列工具F01 随手记 / F04 JSON的共享交互规范。七、验收方式与回归保障DIFF-375 文档给出的验收口径为F04 VaultdesktopTest --offline。在 next-compose 工程中执行./gradlew :composeApp:desktopTest --offline # macOS 若 daemon 下 exit 134追加 --no-daemon ./gradlew :composeApp:desktopTest --offline --no-daemon根据 acceptance.mdCompose 桌面端累计数千条测试以--offline离线模式为统一验收基准公网 smoke 用例被跳过但仍计入总数。JsonVaultPrepareContextTest是其中与 DIFF-375 直接绑定的回归防线今后任何改动只要破坏了目录 flush 失败保持树选中 / 回滚高亮的不变量该测试就会立刻失败。结语DIFF-375 看似只是一个目录条目的选中时机调整实则确立了 Compose 端 Vault 系列的一条核心交互不变量任何需要先落盘才能继续的路径操作在 flush 失败时都必须完整回滚选择状态并给出明确反馈绝不留下编辑器绑定旧文件、界面指向新条目的割裂现场。这条规则从 JSON 目录条目出发依次扩展到 JSON 文件条目DIFF-376、随手记DIFF-377、树目录单击DIFF-380最终统一收敛到prepareJsonVaultContext这一个函数与JsonVaultPrepareContextTest的五个用例成为 Compose 重构对齐 Electron 行为的一条可回归、可验证的准则。赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐MooTool Compose 版 Vault 树「选中即展开祖先目录」DIFF-205 的设计实现与源码剖析MooTool Compose 版 Vault 树「选中即展开祖先目录」DIFF 205 的设计实现与源码剖析 导读本文聚焦 MooTool 新一代 Com桌面应用开发工具MooToolCompose 桌面版DIFF-368 源码解析JSON Vault flush 失败 notice 统一辅助函数MooToolCompose 桌面版DIFF 368 源码解析JSON Vault flush 失败 notice 统一辅助函数 本文以 MooTool桌面应用开发工具MooToolCompose 桌面版JSON Vault 目录选中前强制 flush 脏片段prepareJsonVaultContext 语义、实现与测试MooToolCompose 桌面版JSON Vault 目录选中前强制 flush 脏片段prepareJsonVaultContext 语义、实现与测桌面应用开发工具上一篇kill-doc一键免费下载百度文库等30文档平台的终极自动化工具下一篇oh-my-piOMPMCP 配置完全指南多源发现、OAuth 托管认证与实战排障创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考