资讯详情

MooTool Compose 客户端 JSON 检查器结果区与文档库树方向键的实现解析(DIFF-039)

📅 2026/10/14 2:25:28 | 华诺云谱 👁 阅读
MooTool Compose 客户端 JSON 检查器结果区与文档库树方向键的实现解析(DIFF-039)
桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载导读本文以 MooTool 的 ComposeKotlin Multiplatform / Desktop重构分支中 DIFF-039 设计文档 为核心解析三项关键改造JSON 检查器新增的缩进标签与结果区展示操作notice与校验status错误态使用危险色、随手记树与 JSON 树独立的展开模式设置smart/expandAll/collapseAll三档以及文档库树面向键盘的方向键导航↑↓ 移动、← 折叠/回父级、→ 展开/进子项、Enter 打开文件。读者读完可掌握这套实现的 UI 行为、配置字段、按键映射细节与底层纯函数实现并知道如何在仓库源码与测试中找到对应的验证依据。背景原 Electron 行为与本产品差异按照 DIFF-039 原行为描述Electron 版本中JSON 检查器Inspector包含格式Format、转换Transform、JSONPath 三块功能并在面板底部保留一个「结果」Result状态区Vault 文档库工具栏提供「展开全部 / 折叠全部」按钮随手记Quick Note与 JSON 分别写入quickNoteTreeExpandMode/jsonTreeExpandMode两个设置字段交互规格要求复杂树应当支持用方向键展开 / 折叠。而本产品Compose 桌面端在改造前存在三个缺口随手记此前误用了 JSON 的展开设置两者共用一份切换任一都会互相污染检查器缺少结果区JSONPath 查询结果、格式化提示没有稳定落点树只能通过鼠标点击操作导航与设置相关的目标清单未实现。这正是 DIFF-039 立项的理由。一、JSON 检查器缩进标签与结果区1.1 缩进标签2 / 4 空格在 JsonScreen.kt 的检查器「格式」卡片中新增了缩进Indent选择标签使用MooSegmented提供2与4两档与 ElectronJsonInspector的 indentselect对齐MooSegmented( options listOf(2 to 2, 4 to 4), value session.formatOptions.normalizeInspectorIndent().spaces.toString(), onChange { session.formatOptions session.formatOptions.copy(spaces it.toInt()).normalizeInspectorIndent() } )底层取值在 JsonModels.kt 的JsonFormatOptions.normalizeInspectorIndent()中做了归一化只允许 2 或 4其余任何值都回退为 2。这保证了后续格式化输出与 Electron 行为完全一致。1.2 结果区notice与校验status的展示规则检查器最下方新增了「结果」卡片mooJsonInspectorSectionResult()其文案由纯函数 jsonInspectorResultDisplay 统一计算val pathPinned pathResult.isNotBlank() (notice.isBlank() || notice pathAppliedNotice || notice jsonPathPanelTitle) val text when { pathPinned - pathResult // JSONPath 查询/路径预览优先 notice.isNotBlank() - notice // Vault、格式化等操作提示次之 pathResult.isNotBlank() - pathResult else - status.message // 兜底展示校验状态 } val isError pathResult.isBlank() status.kind JsonStatus.Kind.Error优先级设计的意图源码注释中已说明是JSONPath 查询 / 路径预览的结果pathResult优先展示当用户进行 Vault 操作、格式化等动作产生notice提示时如果当前并不是常规 JSONPath 场景则notice覆盖旧查询结果避免旧结果盖住新提示规避 DIFF-225 之后出现的残留问题。结果区渲染在 JsonScreen.ktText( resultDisplay.text, color if (resultDisplay.isError) colors.danger else colors.textPrimary, fontSize 11.sp )即校验失败 / 查询异常时结果区文字使用危险色colors.danger正常状态使用主文字色。卡片右上角提供「复制」按钮其可用性由JsonInspectorPresentation.resultCopyActionEnabled(resultDisplay.text)控制——空结果不可复制。1.3 状态模型JsonStatus校验状态的来源在 JsonModels.ktdata class JsonStatus( val kind: Kind, val message: String, val line: Int? null, val column: Int? null ) { enum class Kind { Idle, Valid, Error } }status由JsonWiringPresentation.runValidate(session.editor.text, translator)在编辑器 revision 变化时重新计算JsonScreen.kt L209-L211包含Idle/Valid/Error三态并可附带行列位置。底部状态栏同样复用该statusError用危险色、Valid用成功色、其余用弱化色。二、树展开模式独立设置与三档语义2.1 两个独立设置字段DIFF-039 的关键修复之一是把「随手记误用 JSON 展开设置」的问题解决掉在 Settings.kt 的VaultSettings中保留两个相互独立的字段Serializable data class VaultSettings( ... val jsonTreeExpandMode: String smart, val quickNoteTreeExpandMode: String smart )两个字段默认值均为smart互不影响。2.2 设置页与侧栏按钮的联动设置页在 SettingsScreen.kt 中「Vault 设置」区拆出两行独立的设置项「JSON 树展开」与「随手记树展开」均使用MooSegmented提供smart/expandAll/collapseAll三档选择改动实时写入对应字段。侧栏工具栏按钮JSON 检查器侧栏JsonScreen.kt L945-L951与随手记侧栏QuickNoteScreen.kt L690-L696各自提供「展开全部 / 折叠全部」按钮按钮文案随当前设置切换点击后在expandAll与collapseAll之间切换并持久化写入各自的*TreeExpandMode设置MooButton( if (settings.vault.jsonTreeExpandMode expandAll) container.t(json.vault.collapseAll) else container.t(json.vault.expandAll), onClick { val next if (settings.vault.jsonTreeExpandMode expandAll) collapseAll else expandAll container.updateSettings { it.copy(vault it.vault.copy(jsonTreeExpandMode next)) } } )树的实际渲染通过expandMode settings.vault.jsonTreeExpandMode传入分别见 JsonScreen.kt L1131 与 QuickNoteScreen.kt L806。2.3 三种展开模式的语义与归一化展开模式的核心计算集中在 VaultTreeExpand.ktfun vaultTreeExpandForMode(expandMode: String, items: ListVaultEntry, selectedPath: String ): MapString, Boolean { return when (expandMode) { collapseAll - { // 仅保留选中项祖先目录展开 val keep vaultAncestorDirectoryPaths(selectedPath).toSet() directories.associateWith { it in keep } } expandAll - directories.associateWith { true } // 全部展开 else - directories.associateWith { path - !path.contains(/) } // smart只展开根目录层 } }smart默认只展开第一层目录相对路径中不含/的目录是兼顾浏览效率与信息密度的默认档位expandAll所有目录全部展开collapseAll仅保留当前选中项的祖先目录展开——这是刻意设计的防迷失机制避免选中深层文件后点「全部折叠」把自己当前所在位置藏进折叠树里。同时normalizeVaultTreeExpandMode负责数据卫生合法值只有smart/expandAll/collapseAll其余含空串一律回退为expandAll行为与 Electronsettings.test.ts中的mergeSettings对齐VaultTreeExpand.kt L5-L12。2.4 设置加载与历史迁移路径该设置字段沿多条链路流通均有归一化保护磁盘加载SettingsRepository.kt 在 load 时对两个字段调用normalizeVaultTreeExpandMode非法值不会原样保留对应测试SettingsVaultPathSanitizeTest中unknown/bogus均被修正为expandAll。Electron 设置导入ElectronNextSettingsImport.kt 导入时同样做归一化。Java 旧版配置迁移LegacyJavaSettings.kt 中legacyVaultTreeExpandMode将旧版func.quickNote/func.jsonBeauty下的COLLAPSE_ALL/EXPAND_ALL映射到新字段Java 只有两档故映射为collapseAll/expandAll再由applyPatch写入对应VaultSettingsL484-L495。三、文档库树方向键导航3.1 焦点模型仅在树获得焦点时拦截按键方向键处理挂在树的Box容器上VaultTreeList.kt L289-L319Box( modifier .fillMaxSize() .focusRequester(focusRequester) .focusable() .onPreviewKeyEvent { event - if (event.type ! KeyEventType.KeyDown || event.blockedByIme()) returnonPreviewKeyEvent false val key when (event.key) { Key.DirectionUp - up Key.DirectionDown - down Key.DirectionLeft - left Key.DirectionRight - right Key.MoveHome - home Key.MoveEnd - end Key.Enter, Key.NumPadEnter - enter else - returnonPreviewKeyEvent false } val result applyVaultTreeKey(key, focusedPath, nodes, treeExpanded) ... true } )这里有三个关键边界设计正是原文档「受影响范围」中**「方向键在树未获焦点时不拦截编辑器」**的直接实现事件处理挂在focusable()的树容器上只有当树持有焦点时onPreviewKeyEvent才会收到方向键事件编辑器中的方向键行为不受影响KeyEventType.KeyDown之外的事件如 IME 组合过程中的按键直接放行显式调用blockedByIme()做 IME 保护——输入法合成期间的按键不会被树拦截避免中文输入法候选选择与方向键导航互相冲突。3.2 按键 → 行为的映射核心逻辑是纯函数 applyVaultTreeKey输入当前焦点路径与展开状态输出新的焦点、展开补丁、打开路径等全部在可见行上运算按键行为实现要点↑ / ↓在可见行之间向上/向下移动基于visibleVaultEntries计算出的可见列表取上/下一项边界处停留Home / End跳到第一个 / 最后一个可见行visible.first()/visible.last()←目录已展开 → 折叠该目录否则 → 焦点回到父级目录折叠补丁写入expanded (path to false)→目录已折叠 → 展开该目录否则 → 进入第一个子项下一个以path/开头的可见行无子项时停留原地Enter目录 → 切换展开状态并选中该目录文件 → 打开文件目录的openPath保持null打开文件不打开目录其中「可见行」的计算在 visibleVaultEntries递归遍历buildVaultTree构建的树折叠目录的子项不出现在可见行中因此 ↑↓ 的移动天然跳过折叠内容。VaultTreeKeyResult携带四个输出字段data class VaultTreeKeyResult( val focusedPath: String, val expanded: MapString, Boolean? null, // 展开/折叠补丁 val openPath: String? null, // 要打开的文件 val selectPath: String? null, // Enter 在目录上时选中目录 )UI 侧接到结果后按字段分发VaultTreeList.kt L306-L318展开补丁仅在变化时回调onTreeExpandedChangeselectPath触发onSelect与鼠标点击选目录的行为一致openPath同时触发onSelect与onOpen。3.3 选中项可见性保障expandVaultPathForSelectionVaultTreeList.kt L99-L111负责在选中路径变化时展开所有祖先目录确保新选中的节点不会被折叠树遮挡for (path in vaultAncestorDirectoryPaths(selectedPath)) { if (path in directories) expanded[path] true } if (selectedPath in directories) expanded[selectedPath] truevaultAncestorDirectoryPaths(work/nested/note.txt)返回[work, work/nested]行为与 ElectronvaultTreeExpand.ts的ancestorDirectoryPaths对齐VaultTreeExpand.kt L14-L19。四、测试验证与证据链4.1 单元测试VaultTreeKeyTest方向键逻辑由 VaultTreeKeyTest.kt 覆盖包含三个测试方法arrowsMoveAmongVisibleRowsAndEnterOpensFiles在{Work/, Work/api.md, readme.md}树上验证 ↓ 从Work移到Work/api.md、Enter 打开文件、← 折叠目录、→ 展开目录、Enter 落在目录上时openPath为 null 且仅选中目录visibleListHidesCollapsedChildren验证折叠目录的可见行会被隐藏Work折叠时可见行为[Work, readme.md]展开后为[Work, Work/api.md, readme.md]expandSelectionOpensAncestorsAndSelectedDirectory验证深层选择时祖先目录逐级展开。4.2 工程级证据206/206 全绿DIFF-039 证据目录 记录了当时的验证结果命令JAVA_HOME$(/usr/libexec/java_home -v 21) ./gradlew :composeApp:desktopTest --offline 结果desktopTest 206/2060 skipped / 0 failed 本机macOS Darwin 25.6.0 x86_64Zulu 21同时如实标注了覆盖边界检查器结果区与独立quickNoteTreeExpandMode为代码落地无窗口截图验证而真实窗口内的方向键手势、IME / 列编辑手工验证、托盘权限对话框、三平台安装包验证仍未覆盖。4.3 后续演进该功能在后续 DIFF 中持续增强可沿文档库追踪expandSelectionOpensAncestorsAndSelectedDirectory的回归保障见 DIFF-205方向键目录选择、Enter 打开文件的进一步验收见 DIFF-381 与 DIFF-386展开模式的 Electron 对齐归一化见 DIFF-480。五、受影响范围与设计边界按原文档的「受影响范围」声明本次改造刻意守住两条边界方向键不拦截编辑器树的方向键处理完全以焦点为前提编辑器含列编辑、普通文本导航不受影响IME 合成期间按键一律放行。不做 CSS 逐选择器移植Compose 版仍非Electron 六套 CSS六套主题样式的逐选择器移植实现视觉细节以组件级近似为主。此外展开模式字段在 Electron、Java 旧配置、磁盘设置三条来源上均做了归一化非法值统一回退expandAll保证设置 UI、侧栏按钮与实际树渲染三者语义一致。总结DIFF-039 是本产品Compose补齐 JSON 检查器与文档库树交互的重要里程碑检查器缩进标签与结果区让 JSONPath 查询、操作提示与校验状态有了统一且带错误着色的落点独立的quickNoteTreeExpandMode/jsonTreeExpandMode三档设置终结了随手记与 JSON 共用展开状态的串扰问题纯函数化的方向键导航把树从只能鼠标点升级为完整的键盘可操作控件并通过VaultTreeKeyTest与 206/206 的desktopTest全量验证锁定行为。文中所有行为均可在上文列出的源码路径与测试文件中直接复现核验。赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐MooTool Vault 全文检索内存索引随手记与 JSON 文档库的输入级实时过滤实现解析MooTool Vault 全文检索内存索引随手记与 JSON 文档库的输入级实时过滤实现解析 本文基于 MooTool 项目基于 Compose Mult桌面应用开发工具Parsr Python 客户端实战指南通过 parsr-client 完成文档上传、结果拉取与 JSON 结构化解析Parsr Python 客户端实战指南通过 parsr client 完成文档上传、结果拉取与 JSON 结构化解析 Parsr 是一个把 PDF、Word后端数据工程MooTool Next Compose 随手记 frontmatter、Vault 树 CRUD、Git 定时器与跨产品导入DIFF-029 差异工程解析MooTool Next Compose 随手记 frontmatter、Vault 树 CRUD、Git 定时器与跨产品导入DIFF 029 差异工程解析桌面应用开发工具上一篇LaTeX预印本模板终极指南打造专业学术论文格式的简单方法下一篇Symfony Polyfill Ctype 的整数参数处理机制详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑