鸿蒙 PC Markdown 编辑器 1.0 候选阶段工程规划
仓库地址:https://gitcode.com/VON-/codex_md_oh
计划提交:75d4060。进入基线:G3 分享缓存收口与设备测试记录49241e2。
为什么没有真机仍然可以继续工程开发
OhMarkdown 的目标是鸿蒙 PC 优先,真机验证当然不能省略。但“没有真机”和“所有开发必须停止”不是同一个结论。即时渲染是否共享同一文本缓冲区、版本历史是否有界、多窗口会话是否相互隔离、撤销是否保留源码,这些核心风险可以先通过代码、Chromium、HarmonyOS 模拟器和自动化测试下降。
真正不能做的是把模拟器写成真机,把打印预览写成 PDF 文件,把系统分享面板写成接收应用成功。G4 采用条件阶段流转:研发工作继续,发布资格不提前。G3 没有获得的外部证据全部保留到 RC 硬门槛,竞争优势记分卡也不会因为阶段名称改变而自动加分。
这种处理比无限期冻结更务实,也比虚假完成更严格。工程可以继续积累可测试能力;一旦获得真机,优先执行积压矩阵,任何数据丢失、权限、输入法或系统服务问题都暂停新功能。
G4 的产品目标不是堆功能
1.0 候选阶段包含即时渲染、结构化编辑、版本历史、多窗口、无障碍、性能、安全和发布准备。它们看起来像七八个独立模块,实际围绕同一个目标:让用户在鸿蒙 PC 上长期处理真实 Markdown,而不是只完成一次演示。
即时渲染提升专注写作,版本历史降低误操作成本,多窗口适合对照资料与多个工作区,无障碍与键盘效率决定高频使用,兼容性和安全决定文档能否长期迁移。任何一项若破坏原始 Markdown、换行或外部修改保护,都会抵消表面功能带来的价值。
因此 G4 的排序不是先做最显眼的动画,而是先锁定文本事实来源,再扩展显示与操作;先定义历史边界,再保存快照;先建立窗口状态隔离,再打开第二个窗口。
当前应用基线
下图来自 OhMarkdown 在 HarmonyOS MateBook Pro 2in1 模拟器中的真实主窗口。当前已经具备活动栏、工作区侧栏、多标签、源码/分栏/预览、命令入口和状态栏,G4 不需要重新设计一套工作台。
这张图证明 G4 有稳定承载面,不证明真机性能或多窗口完成。即时渲染会成为现有视图模式的新成员;版本历史适合进入侧栏或独立工具面;多窗口复用同一工作台组件,但每个窗口必须拥有独立会话。
保持界面连续性也有产品价值。用户不需要因为进入 1.0 候选重新学习文件树、标签和保存流程,研发则可以用现有 Playwright 与模拟器证据做回归对照。
同一文本事实来源是第一原则
OhMarkdown 当前 Web 编辑器把 CodeMirrorEditorState作为编辑期事实来源。源码、分栏和预览不会分别维护正文。G4 的即时渲染必须继续遵守这一点:视觉隐藏 Markdown 标记可以由 Decoration 完成,但不能把预览 DOM 变成另一个可编辑模型,再反向序列化 Markdown。
typeViewMode='source'|'split'|'preview';interfaceEditorSessionSnapshot{state:EditorState;dirty:boolean;revision:number;}functiongetDocument():string{returneditor.state.sliceDoc();}G4-02 会把live加入模式协议,但正文仍来自editor.state.doc。切换前后getDocument()必须完全相等,撤销历史不重建,保存基线不改变,原生 Bridge 也不能收到一份由 DOM 推导的文本。
这条原则是 OhMarkdown 相对传统富文本 Markdown 编辑器的重要优势:显示效果可以演进,文件语义始终可审计。
即时渲染为何使用 Decoration
CodeMirror 6 的 Decoration 与 ViewPlugin 能在不修改文档内容的前提下隐藏标记、替换视觉节点或增加部件。标题的#、强调的**、链接目标和图片语法都可以按光标位置决定显示方式。用户进入结构时恢复必要标记,离开后只隐藏可安全推导的部分。
constliveRenderingCompartment=newCompartment();functioncreateEditorState(content:string):EditorState{returnEditorState.create({doc:content,extensions:[basicSetup,markdown({base:markdownLanguage}),liveRenderingCompartment.of([])]});}functionsetLiveRendering(enabled:boolean):void{editor.dispatch({effects:liveRenderingCompartment.reconfigure(enabled?createLiveRenderingExtension():[])});}这段代码表示目标结构,不代表首个提交已经完成。实现时仍需处理组合输入、选择范围、语法树更新、屏幕阅读、复制和超长文档预算。文章把计划与现状分开,避免将设计代码误写成已落地能力。
首个纵切为什么只覆盖标题和强调
Markdown 即时渲染的复杂度会快速扩散。链接包含标签与目标,图片涉及异步资源,代码块有语言高亮和围栏,列表会改变 Enter 与缩进,表格需要列布局。如果一次覆盖全部语法,任何输入问题都难以定位。
G4-02 只建立模式、命令、状态同步和 Decoration 框架,首批覆盖 ATX 标题与成对强调标记。两类结构足以验证光标进入后恢复标记、光标离开后视觉简化、中文输入不跳动、撤销不变、保存不变和模式切换不重建文档。
未覆盖语法继续显示源码。即时渲染不是非黑即白:局部保守回退比错误隐藏更安全。后续 G4-03 再逐项加入链接、图片、引用、列表、代码块与任务列表,每一类都有独立语料和文章。
大文档必须继续降级
当前编辑器在五兆代码单元以上启用minimalSetup,关闭 Markdown 解析、自动换行、预览和导出增强。即时渲染依赖语法树与 Decoration,更不能绕过保护模式。
constLARGE_DOCUMENT_CHARACTER_THRESHOLD=5*1024*1024;functioncreateEditorState(content:string):EditorState{constuseLargeDocumentSetup=content.length>=LARGE_DOCUMENT_CHARACTER_THRESHOLD;returnEditorState.create({doc:content,extensions:[useLargeDocumentSetup?minimalSetup:basicSetup,useLargeDocumentSetup?[]:markdown({base:markdownLanguage}),useLargeDocumentSetup?[]:EditorView.lineWrapping]});}G4 会把即时渲染命令也接入!largeDocumentMode条件。大文档仍优先保住源码编辑与保存,不为了展示效果重新引入语法树、DOM 或全量历史快照。产品优势来自可预测,不来自在极限文件上偶尔成功。
结构化编辑必须是一笔事务
列表延续、缩进、自动配对和表格命令会直接修改源码,与纯显示 Decoration 不同。每个命令必须计算明确的changes与selection,作为一次 CodeMirror transaction 提交,用户按一次撤销就能恢复操作前状态。
例如表格增加一列不能先改表头、再改分隔线、最后逐行改正文,让撤销分成几十次;也不能格式化整张表而破坏用户有意保留的空格。G4-04 采用局部、最小修改,无法可靠解析时拒绝命令并保持正文不变。
中文输入法组合期间不运行自动配对或列表命令。快捷键与 Enter/Tab 处理必须识别 composition 状态,避免候选尚未提交时插入 Markdown 标记。现有中文剪贴板和快捷键设备回归会继续作为基础门禁。
版本历史不是第二份文档数据库
版本历史的事实来源仍是用户 Markdown 文件和当前 CodeMirror 缓冲区。历史记录是可丢弃、可重建的辅助副本,损坏不能阻止用户打开原文。首版不引入数据库、Git 或云同步,而是使用应用沙箱中的有界快照、内容哈希和元数据。
interfaceVersionHistoryRecord{version:number;documentIdentity:string;sourceFingerprint:string;contentHash:string;content:string;createdAt:number;}这只是数据需求草图,正式实现前还要形成独立 ADR,确定文档身份、上限、原子替换、隐私和迁移。恢复历史时不会直接静默覆盖磁盘;它会把历史正文载入当前会话并标记未保存,用户明确保存后才进入现有冲突保护链。
版本历史如果让外部修改保护失效,就不是安全功能。G4-05 必须复用文件指纹和保存前重读,而不是另建绕过 DocumentService 的写入路径。
历史清理要有容量预算
每次按键保存完整快照会快速膨胀,尤其是图片链接多、正文长的技术文档。首版需要组合时间间隔、内容哈希去重、单文档数量、单文档字节和全局字节预算。超过预算时按明确顺序清理,当前打开版本和最近恢复点优先保留。
清理失败不应删除用户原文,也不能让普通保存失败;但历史写入失败必须反馈,不能显示一个实际不存在的版本。敏感正文仍只在本地沙箱,日志不记录文件名、路径与内容。
具体数字要根据模拟器压力和未来真机结果确定,不在规划文章中伪造。设计阶段先定义可测试接口和失败语义,再决定默认 20、50 或 100 个版本。
多窗口首先是状态隔离
在 PC 上打开第二个窗口不难,困难的是两个窗口是否意外共享活动标签、当前工作区、侧栏宽度、搜索任务、自动保存计时器和 Web Controller。G4-06 要求每个窗口拥有独立会话,不能把当前正文放进进程级全局变量。
现有DocumentSession已经为标签隔离提供基础:
exportinterfaceDocumentSession{id:string;name:string;uri:string;content:string;dirty:boolean;revision:number;fingerprint:DocumentFingerprint|undefined;}exportconstMAX_OPEN_DOCUMENT_SESSIONS:number=12;多窗口会在窗口范围持有会话集合。若同一文件在两个窗口打开,磁盘写入仍由文件指纹和保存前重读保护,不能用进程内消息假设另一个窗口一定同步。模拟器先验证状态模型,物理窗口管理、触控板和系统文件关联留到真机 RC 闸门。
会话恢复不能恢复错误权限
重启后可以恢复标签名称、URI、工作区和视图模式,但系统授予的文件能力可能已失效。应用必须重新验证 URI,可读才加载;失效时显示可恢复提示,让用户重新选择文件,不能绕过系统授权去猜测绝对路径。
未保存正文继续使用 RecoveryService 的原子记录,已保存标签则从磁盘读取。会话布局与正文恢复是不同数据:布局损坏可以回到默认窗口,正文恢复损坏必须保护当前文件并给出明确失败。
G4 不会为“看起来恢复完整”而把用户所有打开文件复制进永久数据库。会话恢复只保存完成任务所需的最小元数据。
无障碍不是阶段末补标签
即时渲染隐藏标记后,屏幕阅读器是否还能理解标题、链接与代码块;多窗口打开后焦点落在哪里;版本历史差异是否能用键盘选择,这些问题会影响组件设计。G4-07 虽然是独立步骤,但规则从 G4-02 就开始执行。
图标按钮继续有可访问名称和 Tooltip,核心工作流全键盘完成,焦点返回编辑器。系统字体放大时工具栏、搜索选项和状态栏不能截断。RTL、Emoji、组合字符和超长中文文件名进入兼容语料,Decoration 不能按 UTF-8 字节计算 CodeMirror 的 UTF-16 偏移。
没有真机时可以完成 DOM/ArkUI 语义检查、键盘回归和字体布局截图;系统屏幕阅读器与物理输入仍保留待验,不能写成全部通过。
质量工程必须绑定每个小阶段
G4 不会等所有功能完成才统一测试。每个纵切至少运行相关定向用例、Playwright 全量、Debug HAP、ArkTS UnitTestBuild、ohosTest HAP 构建、模拟器可执行用例和 diff check。涉及系统能力时增加外部应用或系统界面证据。
即时渲染的关键断言不是“看起来漂亮”,而是切换前后源码相等、撤销历史保留、保存基线不变、组合输入稳定、未覆盖语法回退。版本历史要做损坏、空间不足和外部冲突;多窗口要做状态串扰与同文件保存竞争。
性能数字按环境分组。Chromium 可以做算法回归,模拟器可以做 ArkTS/ArkWeb 整链,真机才能形成 Release P95。三类结果不会互相冒充。
G4 的架构边界
初始保持 Level 2、D2:继续使用 ArkUI、ArkWeb、CodeMirror 和当前 entry 模块,在现有服务边界增加真实需要的历史或窗口能力。不拆 HAR,不引入通用事件总线、全局状态框架或仓储层。
出现以下情况必须暂停并记录新 ADR:即时渲染需要第二文本模型;版本历史必须引入数据库;多窗口需要重构应用模块;跨窗口同步需要新持久化协议;任何方案要求开放 ArkWeb 文件或网络能力。
边界的目的不是拒绝合理架构升级,而是避免在功能压力下悄悄改变文件安全模型。真正需要升级时,应先把收益、迁移、失败和回退写清楚。
外部债务如何并行保留
G4 开发期间,G3 的 PDF、Markdown 分享接收方、鸿蒙 PC 真机、竞品统一任务、50-100 人封闭测试、规模化强杀、远程 CI 和内部连续试用继续保留。它们不会阻止每一行代码,却会阻止 RC 退出和公开发布。
状态表必须同时显示“G4 已启动”和“发布硬门槛未满足”。如果只写前者,会让团队误判产品成熟度;如果只写后者,又会让可执行工程停滞。条件流转的价值就在于把两个事实同时保存。
第四阶段文章怎样同步
第四阶段不预设固定 20 篇,也不等阶段结束再集中写。每完成一个可独立验收的小阶段,立即增加一篇独立技术文章。标题包含鸿蒙与 PC,正文不少于 5000 字符,包含公开仓库、真实代码、提交哈希、测试结果和至少一张应用内部图片。
文章不能用设计稿冒充实现。本文是 G4-01 计划与条件闸门的完成记录,代码示例中凡属目标结构均明确标注;G4-02 完成后会另写即时渲染基础文章,使用最终代码和模拟器截图。文章仍仅保存在本地忽略目录,不推送公开仓库。
下一步工程动作
G4-02 首先增加live视图模式、命令路由与可动态重配置的 Decoration 容器,再实现标题与强调的最小视觉规则。测试会先锁定模式切换不改正文、光标进入恢复标记、中文输入与撤销稳定、大文档禁用。
该纵切通过后才扩大链接、图片、引用、列表和代码块。每扩大一种结构,都需要语法边界、选择行为、复制、无障碍和错误回退证据。这样即时渲染不会变成一次高风险重写,而是一系列可验证增量。
结论
鸿蒙 PC 真机缺失改变了验证排期,不改变产品标准。OhMarkdown 通过 ADR-0003 将 G3 标记为研发条件通过,保留所有外部债务为 RC 硬门槛,并以提交75d4060启动 G4-01。
G4 的核心路线已经明确:同一 CodeMirror 文本事实来源上的即时渲染,有界且不覆盖外部修改的版本历史,窗口范围隔离的多窗口,以及贯穿每个纵切的无障碍、性能、安全和文章记录。下一步进入即时渲染基础,而公开发布仍必须等待真实系统、真实设备和真实用户证据。