桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载导读本文以 MooTool 下一代 Compose Desktop 客户端next-compose中 F01「随手记QuickNote工具栏与文件树」的实证文档为核心深入剖析三项与 Electron 旧版对齐的编辑能力笔记颜色写入 frontmatter 并驱动文件树着色、行距倍数作用于 RSyntaxTextArea 行高、无序/有序列表前缀覆盖选区整行。读者将理解这三项功能从设计决策DIFF-036、核心领域模型NoteListEngine、NoteColors、NoteFrontmatter到存储层NoteVault.list()与渲染层EditorBuffer.applyTheme、VaultTreeList的完整调用链以及 196/196 桌面测试如何印证其与 Electron 行为的一致性最后还会看到当前仍未覆盖的测试盲区与已知限制。一、背景功能对齐feature-parity驱动的 DIFF-036next-compose是 MooTool 基于 JetBrains Compose Multiplatform / Swing 桥接SwingPanel RSyntaxTextArea重写的桌面客户端。它并非简单照搬旧 Electron 实现而是逐项比对功能差异并形成 DIFF 文档。设计文档DIFF-036影响范围 F01 随手记工具栏与文件树明确说明原行为Electron工具栏有笔记颜色、行距倍数、无序/有序列表。颜色写入 frontmatter 并给文件树图标着色。行距按1.65 * lineSpacing作用到编辑器。列表前缀覆盖选区所在整行编号从 1 起。也就是说对齐的不只是字体和语法高亮还包括列表动作与文档元数据颜色、行距。这类功能必须同时改变编辑器正文、文件树节点或文档 frontmatter无法用简单开关实现因此 DIFF-036 独立立项并沉淀出配套证据目录docs/evidence/2026-09-15-note-toolbar/。本产品Compose Desktop在 results.md 中给出的对齐结论是NoteListEngine与 Electron 的「选区整行前缀」规则一致NoteColors七色与文件树着色条件一致EditorBuffer.applyTheme(lineSpacing2)使行高至少约加倍NoteVault.list()会带回 frontmatter 中的 color 字段。二、笔记颜色从 frontmatter 到文件树的完整链路2.1 七色定义与归一化颜色模型由 NoteColors.kt 实现swatches定义了七档色板标识符ARGB 色值用途default0xFF8A8A8A默认灰不参与树着色coral0xFFD97868珊瑚色yellow0xFFC99535黄色green0xFF4E9275绿色blue0xFF4F83CC蓝色purple0xFF8A72B5紫色red0xFFC96761红色三个核心 API 承担了「写入、读取、着色」三个职责normalize(id)将任意输入如Coral、UNKNOWN归一化为合法的色板键未知值一律回落为defaultargb(id)由归一化键取 ARGB 色值供 ComposeColor(...)渲染tintsTree(id)仅当normalize(id) ! default时才对文件树进行着色。2.2 颜色写入 frontmatter 并持久化工具栏的颜色选择由 QuickNoteScreen.kt 驱动。色板按钮点击后执行session.metadata session.metadata.copy(color id)随后随笔记保存写入 YAML frontmatter。序列化由 NoteFrontmatter.kt 完成典型产物形如--- title: API ideas style: syntax: text/plain font_name: font_size: 14 line_spacing: 1.0 color: coral line_wrap: 1 created_at: 2026-09-15T00:00:00Z modified_at: 2026-09-15T00:00:00Z --- # Hello 正文内容...serialize()对color使用yamlScalar安全转义保证任意合法色板键都可往返读写解析侧parse()通过stringValue(values[color], default)缺省回落健壮性有保障。2.3 文件树着色条件文件树渲染位于 VaultTreeList.kt当节点为文件且NoteColors.tintsTree(entry.color)为真时行首渲染一个 6dp 圆形色点Box(Modifier.size(6.dp).clip(CircleShape).background(Color(NoteColors.argb(...))))同时文件名文本本身也使用该颜色否则按colors.textBody显示。default色不触发着色与 Electron 行为对齐。2.4 「未保存仍按会话色显示」的实现细节QuickNoteScreen.kt 在向VaultTreeList传递条目时做了就地覆盖items vaultItems.map { item - if (item.relativePath session.currentFile) item.copy(color session.metadata.color) else item }即当前打开文件即使尚未落盘其会话元数据session.metadata.color也会立即反映到文件树节点上。2.5 Vaultlist()带回 frontmatter color证据文档特别强调Vault list()带回 color。NoteVault.kt 的snapshot()对每个非目录条目执行NoteFrontmatter.parse(...)将parsed?.metadata?.color写入VaultEntry.colorlist()再经VaultSearchIndex.filter返回。测试 NoteVaultTest.kt 明确验证vault.saveNote(note.relativePath, # Hello\nneedle, note.metadata.copy(color coral)) ... assertEquals(coral, vault.list().first { it.relativePath saved.relativePath }.color)同时该测试还验证了created_at、modified_at随 frontmatter 往返、font_size: 15与line_spacing: 1.0的序列化格式注意font_size/line_spacing以字符串形式写入。三、行距倍数1.0–2.0 如何抬高 RSTA 行高3.1 参数范围与归一化NoteMetadata.lineSpacing默认1.0。UI 层QuickNoteScreen.kt提供档位1.0、1.2、1.4、1.6、1.8、2.0主工具栏直接展示溢出菜单moreOpen中重复提供同样的档位。存储层通过NoteFrontmatter.clampLineSpacing做双重约束fun clampLineSpacing(value: Double): Double { val normalized if (value.isFinite()) value else 1.0 return (normalized.coerceIn(1.0, 2.0) * 10).roundToInt() / 10.0 }任何非有限值回落为1.0区间限定[1.0, 2.0]并按 0.1 步长取整防止恶意或脏数据破坏编辑器布局。3.2 行距如何作用到编辑器行距不是 Compose 侧属性而是经由 EditorHost.kt 的lineSpacing参数下传至 EditorBuffer.kt 的applyTheme(...)。其内部applyLineSpacing的实现值得注意private fun applyLineSpacing(spacing: Double) { val multiplier NoteFrontmatter.clampLineSpacing(spacing) if (multiplier 1.0) return // 1.0 保持默认行高 runCatching { val field RSyntaxTextArea::class.java.getDeclaredField(lineHeight) field.isAccessible true val base area.lineHeight val next round(base * multiplier).toInt().coerceAtLeast(base) field.setInt(area, next) area.revalidate() scrollPane.revalidate() area.repaint() } }关键点1.0 语义multiplier 1.0直接返回不改动 RSTA 默认行高反射写私有字段RSTA 的lineHeight是私有字段这里通过反射在RSTextArea计算行高之后按倍数抬高异常防护runCatching包裹反射与重绘升级 RSTA 后若私有字段改名/失效功能静默回退到默认行高不会崩溃。3.3 测试断言「至少约加倍」证据文档中的「EditorBuffer.applyTheme(lineSpacing2)行高至少约加倍」由 EditorThemeTest.kt 的用例直接背书buffer.applyTheme(false, Monospaced, 14, true, lineSpacing 1.0) val compact buffer.area.lineHeight buffer.applyTheme(false, Monospaced, 14, true, lineSpacing 2.0) assertTrue(buffer.area.lineHeight compact * 2 - 1) assertTrue(compact 0)同一文件还验证了主题色、语法 tokenLITERAL_STRING_DOUBLE_QUOTE、LITERAL_NUMBER_DECIMAL_INT随applyTheme生效。3.4 与 Electron 的倍数差异已知限制设计文档明确记录了两端行高基数的差异Electron 采用1.65 * lineSpacing的直接换算Compose Desktop 以 RSTA 默认行高为基数lineSpacing1.0不改默认值倍数关系与 Electron一致但绝对行高基数不同。因此 UI 观感在绝对值上可能与 Electron 存在细微差异属于有意的「倍数对齐而非绝对值对齐」。同时由于依赖 RSTA 私有字段升级 RSTA 版本必须回归复测此用例。四、列表前缀NoteListEngine 的整行语义4.1 核心算法NoteListEngine.kt 是一个无状态的object提供prefixSelectedLines(text, start, end, prefix)纯函数。其选区扩展逻辑空文档直接插入-无序或1.有序选区选中新插入内容非空从caretStart向前找到上一个\n得到行首从caretEnd向后找到下一个\n得到行尾即把选区扩展覆盖到其所在的完整首行与末行对整段选区按行切分无序行加-前缀有序行按index 1生成1.、2.、3.…编号从 1 起返回新文本与扩展后的选区区间供 UI 重设选区。enum class Prefix { Bullet, Numbered } val transformed selected.split(\n).mapIndexed { index, line - when (prefix) { Prefix.Bullet - - $line Prefix.Numbered - ${index 1}. $line } }.joinToString(\n)4.2 进入撤销栈工具栏按钮QuickNoteScreen.kt 的quickNote.bulletList/quickNote.numberedList调用私有函数applyListPrefixval result NoteListEngine.prefixSelectedLines( session.editor.text, area.selectionStart, area.selectionEnd, prefix) quickNoteOnEdt { session.editor.setText(result.text, recordUndo true) // 关键进入撤销栈 session.editor.select(result.selectionStart, result.selectionEnd) }setText(recordUndo true)走atomicDocumentCompoundEditUndoManager上限 400 步保证「添加列表前缀」这一操作可被一次撤销/重做随后select()将选区恢复到扩展后的整行范围方便用户连续加前缀。4.3 与 Electron 的逐行一致性测试NoteListEngineTest.kt 用三个用例锚定「选区所在整行」语义输入操作期望输出alpha\nbeta\ngamma选区(6,10)恰为beta行Bulletalpha\n- beta\ngammaone\ntwo选区(0,7)覆盖两行Numbered1. one\n2. two空文本Bullet- 其中第二个用例证明多行选区会被逐行编号1. one\n2. two而不是只给首行编号。这印证了「覆盖选区所在整行、编号从 1 起」的设计语义。五、测试证据与未测盲区5.1 desktopTest 196/196证据文档给出的结论是desktopTest196/1960 skipped。与之直接相关的测试文件包括NoteListEngineTest.kt列表前缀整行语义、NoteColors七色与着色条件NoteColorsTestEditorThemeTest.kt行距倍数抬高 RSTAlineHeightNoteVaultTest.ktfrontmatter 中color/line_spacing的写入、读取与list()回传NoteFrontmatterTest.ktfrontmatter 解析与clampLineSpacing归一化。5.2 明确未测项复现 / 验收时重点关注证据文档诚实列出的未测项可作为后续验收清单IME/列编辑手工窗口中文输入法与列编辑EditorColumnEditPresentation在真实窗口下的人工验证真实窗口截图当前证据目录仅含results.md尚无窗口级截图佐证托盘权限对话框macOS 屏幕录制/辅助功能权限弹窗链路六套 CSS 逐选择器皮肤Compose 主题与旧版六套皮肤按选择器逐一比对的皮肤层验证三平台安装/升级/卸载Windows/macOS/Linux 三端安装包生命周期尚未覆盖。六、受影响范围与已知限制设计文档「受影响范围」一节还记录了两个必须向用户说明的边界JSON Vault 树无 color 字段JsonVault的VaultEntry与NoteVault不同JSON 工具树不读取 frontmatter colorNoteVault.snapshot()中解析 color 的逻辑仅作用于随手记文件txt/md/json/java/js/ts/py/xml/yaml/yml/sql等NoteFrontmatter.noteExtensions白名单JSON Vault 节点保持默认样式行距基数差异如前文 3.4 所述Compose 端以 RSTA 默认行高为基数、1.0 不改默认值与 Electron 的1.65em基数不同但倍数关系一致。七、结论DIFF-036 与配套证据文档展示了 MooToolnext-compose一项典型的「领域逻辑可测、渲染层桥接 Swing」功能对齐模式颜色、行距、列表前缀三种能力都被抽取为无 UI 依赖的领域模块NoteColors、NoteFrontmatter、NoteListEngine通过 196/196 的desktopTest在无窗口环境下验证与 Electron 的语义一致再由EditorBuffer/VaultTreeList等薄渲染层落地。对于开发者而言若要在升级 RSyntaxTextArea 后回归此功能请优先重跑 EditorThemeTest.kt 的行距用例并按 5.2 节的未测清单补齐手工验收。赞分享桌面应用开发工具【免费下载链接】MooToolHandy tool set for developers项目地址https://gitcode.com/gh_mirrors/mo/MooTool点击查看免费下载相关推荐MooTool Next Compose 随手记工具栏对齐笔记颜色、行距与列表前缀的实现解析DIFF-036MooTool Next Compose 随手记工具栏对齐笔记颜色、行距与列表前缀的实现解析DIFF 036 本篇文章以 MooTool 下一代桌面端桌面应用开发工具MooTool Next Compose 随手记文档库树选中同步、行级脏标记与状态栏路径对齐实战MooTool Next Compose 随手记文档库树选中同步、行级脏标记与状态栏路径对齐实战 导读 在 MooTool 的 Electron 版与 Com桌面应用开发工具MooTool Compose 随手记历史恢复行为对齐移除 restored notice 的设计与实现解析MooTool Compose 随手记历史恢复行为对齐移除 restored notice 的设计与实现解析 MooTool 是面向开发者的工具集项目其 n桌面应用开发工具上一篇Lux AltairChart 源码解读Lux 自动可视化背后的 Vega-Lite 图表基类与渲染管线下一篇Apache Maka Runtime Resume 恢复权威拆分账本从 1346 实验到 PR A/B 不变量驱动的平铺落地创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考