收口本地工作区清理与资源投影
清理历史 Electron、Graphify、沙箱和截图等仓库跟踪残留,补充 CodeGraph 与 Convex active deploy source 协作说明。 新增 tree-first 下一阶段设计稿和 2026-05-20 清理总结,记录本地工作区、路径身份和 Zed/Lapce/VSCode 参考收口方向。 扩展 Rust Web 本地文件夹、DocumentBuffer、mindmap 资源、tree runtime 和页面聚合链路,并补充 task455 local-folder mindmap clean smoke。 验证:git diff --check 通过;pnpm store status --store-dir .pnpm-store 通过;npm ls --depth=0 --json 通过;find -L node_modules 未发现断链。cargo test -p mnote-web 当前 418 passed / 35 failed。
This commit is contained in:
+547
@@ -0,0 +1,547 @@
|
||||
# 5-14 [process] Zed / Lapce / VS Code 参考采用矩阵 v1
|
||||
|
||||
> 更新时间:2026-05-19
|
||||
>
|
||||
> 关联背景:
|
||||
> - `/mnt/Data1T/mnote/CURRENT_ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/process/7-14-online-local-ai-markdown-editing-convergence-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-24-resource-tree-filetree-pagetree-source-contract-checklist-v1.md`
|
||||
>
|
||||
> 本地参考源码:
|
||||
> - VS Code:`/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/vscode`
|
||||
> - Zed:`/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/zed`
|
||||
> - Lapce:`/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/lapce`
|
||||
> - SideX:`/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/sidex-main`
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
这份文档回答一个工程路线问题:
|
||||
|
||||
> **MNote 当前 Rust 主线应继续从 VS Code 源码里参考什么,又应该从哪些 Rust 编辑器项目里借鉴现成结构,避免把 VS Code TypeScript / Electron 代码大量转译到 Rust。**
|
||||
|
||||
当前结论是:
|
||||
|
||||
> **Zed 作为主架构参考,Lapce 作为辅助实现参考,SideX 作为 VS Code 行为迁移到 Rust 后端的桥接参考,VS Code 官方源码作为行为规格参考。**
|
||||
|
||||
这不是说 MNote 要改造成通用 IDE,也不是要复制 Zed / Lapce 的桌面产品形态。MNote 的主线仍然是:
|
||||
|
||||
- `tree-first graph kernel`
|
||||
- local-first Markdown workspace
|
||||
- Rust `mnote-web` Web shell
|
||||
- `Page Aggregate` / `File Tree` / `Resource Tree` 投影
|
||||
- Hermes / Reasonix agent 在授权目录内进行文件编辑
|
||||
|
||||
Zed、Lapce、SideX、VS Code 只用于补齐“编辑器工作区基础设施”的成熟参考,尤其是文件树、打开态 buffer、dirty/save、搜索、外部文件变更、agent 文件编辑权限这些层。
|
||||
|
||||
---
|
||||
|
||||
## 2. 总体判断
|
||||
|
||||
### 2.1 不建议把 VS Code 源码作为转译目标
|
||||
|
||||
VS Code 官方源码仍然是 TypeScript / Electron 架构。它对 MNote 有很强的产品行为参考价值,但不适合作为 Rust 代码转译目标。
|
||||
|
||||
主要风险:
|
||||
|
||||
- VS Code 的 workbench、service、contribution、lifecycle 与 Electron / DOM / Node 绑定很深。
|
||||
- 大量接口依赖 TypeScript DI、事件模型、extension host 和 workbench contribution 体系,转到 Rust 后会变成重建一套框架。
|
||||
- 文件服务、保存冲突、watcher、context key 等模块很有价值,但它们的价值在行为合同和边界划分,不在逐行代码。
|
||||
- MNote 当前不是通用 IDE,而是 local-first Markdown workspace + agent 编辑器,直接转译会把产品边界拉宽。
|
||||
|
||||
因此,VS Code 的定位应固定为:
|
||||
|
||||
> **行为规格参考,不作为 Rust 实现蓝本。**
|
||||
|
||||
### 2.2 Zed 是当前最接近 MNote 长期主线的 Rust 参考
|
||||
|
||||
Zed 的价值不在 UI 壳,而在这条 Rust 原生编辑器链路:
|
||||
|
||||
> `Worktree / Snapshot -> WorktreeStore -> Project / ProjectPath -> BufferStore / MultiBuffer / Editor -> Search / FileFinder -> AgentTool / ToolPermission`
|
||||
|
||||
这与 MNote 的长期方向高度重合:
|
||||
|
||||
- 多 workspace root / local folder。
|
||||
- 稳定的 `{root + relative path}` 文件身份。
|
||||
- 文件树扫描、ignore、watch 增量更新。
|
||||
- 打开态 buffer、dirty/save、路径到 buffer 的索引。
|
||||
- 全文搜索、快速打开。
|
||||
- agent 文件读写、patch、权限与 allowed roots。
|
||||
|
||||
Zed 应作为:
|
||||
|
||||
> **workspace / project / buffer / search / agent 文件编辑权限的主参考。**
|
||||
|
||||
### 2.3 Lapce 是轻量实现与边界拆分的辅助参考
|
||||
|
||||
Lapce 的价值不在“产品完整度超过 Zed”,而在它更轻、更容易抽取工程模式:
|
||||
|
||||
> `UI -> typed RPC -> proxy -> watcher / search / plugin / terminal -> doc / buffer delta / save`
|
||||
|
||||
这对 MNote 有两类价值:
|
||||
|
||||
- typed command / request / response 如何拆到 proxy / backend 执行层。
|
||||
- 文档 `rev / delta / dirty / save` 生命周期如何保持简单。
|
||||
|
||||
Lapce 应作为:
|
||||
|
||||
> **typed RPC、proxy 边界、doc delta/save、file explorer state machine、配置和 keymap 的辅助参考。**
|
||||
|
||||
### 2.4 SideX 不替代 Zed,但应加入参考矩阵
|
||||
|
||||
SideX 的 README 明确写的是:
|
||||
|
||||
> **VSCode's workbench, without Electron.**
|
||||
|
||||
也就是说,SideX 不是 Rust 原生重写 VS Code。它更接近:
|
||||
|
||||
> **保留 VS Code TypeScript workbench / Monaco / service 模型,把 Electron main process、Node fs、node-pty、sqlite、watcher、search 等系统能力替换为 Tauri + Rust command / crate。**
|
||||
|
||||
因此 SideX 不能替代 Zed 成为 MNote 的主架构参考,原因是:
|
||||
|
||||
- 它仍保留 VS Code 的 TypeScript workbench、DI、service、contrib 体系。
|
||||
- 它的目标是“移植 VS Code”,不是建立 projection-first 的 local-first Markdown workspace。
|
||||
- 它会把 MNote 拉回通用 IDE / extension host / desktop shell 的复杂度。
|
||||
|
||||
但 SideX 很适合作为一类新参考:
|
||||
|
||||
> **VS Code 行为如何落到 Rust 后端的迁移样本。**
|
||||
|
||||
它比官方 VS Code 更接近 MNote 的地方在于:
|
||||
|
||||
- Rust `sidex-workspace` 已经抽出 file tree、watcher、search、path util、dirty diff、multi-root 等 workspace crate。
|
||||
- Rust `sidex-keymap` 已经实现接近 VS Code `when` clause 的 context key evaluator。
|
||||
- Rust `sidex-settings` 已经实现 default / user / workspace 的分层 settings。
|
||||
- Tauri command 层把 `fs`、terminal、git、search、storage 等 Node/Electron 能力转换成 Rust command 边界。
|
||||
|
||||
所以本矩阵应把 SideX 放在:
|
||||
|
||||
> **“VS Code 行为规格”和“MNote Rust 实现”之间的桥接参考。**
|
||||
|
||||
### 2.5 Helix 不作为主参考
|
||||
|
||||
Helix 是优秀的 Rust 终端编辑器,适合参考 LSP、Tree-sitter、文本核心和配置理念,但它不是 workbench / Web shell / local-first workspace 主参考。
|
||||
|
||||
---
|
||||
|
||||
## 3. 参考源职责划分
|
||||
|
||||
### 3.1 Zed:主架构参考
|
||||
|
||||
重点参考:
|
||||
|
||||
- `crates/worktree/src/worktree.rs`
|
||||
- `crates/project/src/worktree_store.rs`
|
||||
- `crates/project/src/project.rs`
|
||||
- `crates/project/src/buffer_store.rs`
|
||||
- `crates/project/src/project_search.rs`
|
||||
- `crates/file_finder/src/file_finder.rs`
|
||||
- `crates/agent/src/tools/edit_file_tool.rs`
|
||||
- `crates/agent/src/tools/read_file_tool.rs`
|
||||
- `crates/agent/src/tools/write_file_tool.rs`
|
||||
- `crates/agent/src/tools/edit_session.rs`
|
||||
- `crates/agent/src/tool_permissions.rs`
|
||||
|
||||
不重点采用:
|
||||
|
||||
- GPUI / Entity / App / Window 渲染壳。
|
||||
- pane / dock / desktop lifecycle。
|
||||
- collab / remote / diagnostics 的完整产品线。
|
||||
- 与 MNote local-first Markdown 主线无关的通用 IDE 复杂度。
|
||||
|
||||
### 3.2 Lapce:辅助实现参考
|
||||
|
||||
重点参考:
|
||||
|
||||
- `lapce-app/src/doc.rs`
|
||||
- `lapce-rpc/src/proxy.rs`
|
||||
- `lapce-proxy/src/dispatch.rs`
|
||||
- `lapce-proxy/src/watcher.rs`
|
||||
- `lapce-app/src/file_explorer/data.rs`
|
||||
- `lapce-app/src/global_search.rs`
|
||||
- `lapce-app/src/command.rs`
|
||||
- `lapce-app/src/main_split.rs`
|
||||
- `lapce-core/src/syntax/mod.rs`
|
||||
- `lapce-core/src/language.rs`
|
||||
- `lapce-core/src/encoding.rs`
|
||||
- `lapce-app/src/config.rs`
|
||||
- `defaults/settings.toml`
|
||||
- `lapce-app/src/keypress/loader.rs`
|
||||
- `defaults/keymaps-common.toml`
|
||||
- `lapce-proxy/src/plugin/mod.rs`
|
||||
|
||||
不重点采用:
|
||||
|
||||
- Lapce 自身 UI 框架选择。
|
||||
- 完整插件生态重建。
|
||||
- 终端、调试器等 MNote 当前阶段不需要的 IDE 面。
|
||||
|
||||
### 3.3 VS Code:行为规格参考
|
||||
|
||||
继续参考:
|
||||
|
||||
- `src/vs/platform/files`
|
||||
- `src/vs/platform/commands`
|
||||
- `src/vs/platform/contextkey`
|
||||
- `src/vs/workbench/contrib/files`
|
||||
- `src/vs/workbench/services/filesConfiguration`
|
||||
- `src/vs/base/browser/ui/list`
|
||||
- `src/vs/base/browser/ui/tree`
|
||||
|
||||
重点看行为:
|
||||
|
||||
- file service 的能力边界。
|
||||
- save / save as / revert / conflict 的用户体验。
|
||||
- workspace watcher 与外部文件变更处理。
|
||||
- context key / command enablement。
|
||||
- file import / export / open editors。
|
||||
- tree/list 的选择、焦点、键盘导航和 DnD 行为。
|
||||
|
||||
不采用:
|
||||
|
||||
- TypeScript service 体系逐行转译。
|
||||
- Electron workbench lifecycle。
|
||||
- VS Code extension host 作为 MNote 当前插件模型。
|
||||
|
||||
### 3.4 SideX:VS Code 行为到 Rust 后端的桥接参考
|
||||
|
||||
重点参考:
|
||||
|
||||
- `ARCHITECTURE.md`
|
||||
- `src-tauri/src/lib.rs`
|
||||
- `src-tauri/src/commands/fs.rs`
|
||||
- `src-tauri/src/commands/validation.rs`
|
||||
- `crates/sidex-workspace/src/lib.rs`
|
||||
- `crates/sidex-workspace/src/file_tree.rs`
|
||||
- `crates/sidex-workspace/src/watcher.rs`
|
||||
- `crates/sidex-workspace/src/search.rs`
|
||||
- `crates/sidex-workspace/src/path_util.rs`
|
||||
- `crates/sidex-keymap/src/context.rs`
|
||||
- `crates/sidex-keymap/src/resolver.rs`
|
||||
- `crates/sidex-settings/src/settings.rs`
|
||||
- `crates/sidex-settings/src/jsonc.rs`
|
||||
- `crates/sidex-terminal/src/pty.rs`
|
||||
- `crates/sidex-terminal/src/manager.rs`
|
||||
|
||||
重点看边界:
|
||||
|
||||
- Electron / Node 能力如何映射为 Rust command。
|
||||
- 文件系统 command 如何先做 path validation,再进入 workspace crate。
|
||||
- Rust watcher / search / file tree 如何对外输出可序列化事件和结果。
|
||||
- VS Code `when` clause / context key 如何在 Rust 侧建模。
|
||||
- default / user / workspace settings 如何分层合并。
|
||||
- PTY / terminal manager 如何从 Node native 模块迁移到 Rust。
|
||||
|
||||
不采用:
|
||||
|
||||
- VS Code TypeScript workbench 的整体移植路线。
|
||||
- Tauri desktop shell 作为 MNote 当前 Web 主壳。
|
||||
- extension host / debugger / terminal / git 的完整 IDE 产品面。
|
||||
- SideX 当前对绝对路径 command 的简单安全模型;MNote 必须继续使用 allowed roots、workspace root、symlink escape 和文件版本仲裁。
|
||||
|
||||
---
|
||||
|
||||
## 4. 采用矩阵
|
||||
|
||||
| 主题 | 主参考 | MNote 当前缺口 | 采用方式 | 优先级 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `ProjectPath` / 文件身份 | Zed `ProjectPath` | local folder、page `.md`、resource asset 需要稳定 `{workspace/root + rel path}` 身份 | 借鉴模式,映射到 `KernelObjectIdentity` / File Tree row | P0 |
|
||||
| Worktree / root 管理 | Zed `worktree` + `worktree_store`,SideX `sidex-workspace` | local-first workspace 需要扫描、ignore、watch、root id、路径归一 | Zed 做主模型,SideX 补充 Rust workspace crate 拆分参考 | P0 |
|
||||
| BufferStore / 打开态文件 | Zed `buffer_store`,Lapce `doc.rs` | tiptap、AI、外部编辑器会同时触碰同一 `.md`,需要统一 dirty/save/version | Zed 做架构,Lapce 做简化实现参考 | P0 |
|
||||
| dirty / save / external change | VS Code file save 行为,Zed buffer,Lapce doc,SideX dirty diff / watcher | `/api/documents/save` 兼容面仍未完全退出,文件版本冲突模型待收口 | VS Code 校准行为,Zed/Lapce 定模型,SideX 看 Rust watcher / dirty diff 落点 | P0 |
|
||||
| agent 文件编辑权限 | Zed `edit_file_tool` / `tool_permissions` | Hermes / Reasonix 需要 allowed roots、symlink escape、防脏 buffer 覆盖 | 直接作为权限模型主参考 | P0 |
|
||||
| workspace search | Zed `project_search`,Lapce `global_search`,SideX `sidex-workspace/search.rs` | MNote 需要本地全文搜索与 Page Aggregate / File Tree 对齐 | Zed 做主搜索模型,Lapce 做结果投影,SideX 补充 Rust 并行搜索实现参考 | P1 |
|
||||
| file finder / quick open | Zed `file_finder` | 工作区文件快速打开与 object tab host 尚未成体系 | 借鉴候选生成与排序,不复制 UI | P1 |
|
||||
| file explorer 状态机 | Lapce `file_explorer/data.rs`,SideX `file_tree.rs`,VS Code tree 行为 | File Tree / Page Tree / Resource Tree 需要选择、展开、刷新、右键命令一致性 | Lapce 状态机 + SideX Rust file tree 能力 + VS Code 行为规格 | P1 |
|
||||
| command / context key | VS Code `commands` / `contextkey`,SideX `sidex-keymap/context.rs`,Lapce `command.rs` | tree/page/object tab 命令 enablement 仍容易散落到 UI | VS Code 给语义,SideX 给 Rust when-clause evaluator 参考 | P1 |
|
||||
| typed RPC / backend proxy | Lapce `lapce-rpc` + `lapce-proxy`,SideX Tauri commands | Rust Web、worker、local FS executor、agent runtime 需要 typed request 边界 | Lapce 参考协议拆分,SideX 参考 Node/Electron 能力迁移到 Rust command | P2 |
|
||||
| config / settings | SideX `sidex-settings`,Lapce `config.rs` + `settings.toml`,VS Code settings 行为 | workspace / user / page options / AI policy 需要层级合并规则 | SideX 分层 settings 更接近 Rust 落地,Lapce/VS Code 校准行为 | P2 |
|
||||
| keymap | SideX `sidex-keymap`,Lapce keypress loader,VS Code keybinding 行为 | editor shell、file tree、command palette 后续需要统一快捷键 | SideX 参考 Rust context/when 解析,Lapce 参考 loader,VS Code 校准行为 | P2 |
|
||||
| terminal / PTY 边界 | SideX `sidex-terminal`,VS Code terminal 行为 | MNote 当前不是 IDE 终端优先,但 agent/local workspace 后续可能需要受控命令执行面 | 只参考 Rust PTY manager 和安全边界,不进入当前主线 | P3 |
|
||||
| MultiBuffer / excerpts | Zed `MultiBuffer` | AI review、搜索结果、跨文件上下文需要多片段视图 | Phase C 之后采用,当前不前置 | P3 |
|
||||
| review diff / streaming apply | Zed agent edit session,VS Code diff 行为 | AI suggest/review 仍设计冻结 | 只保留为后续参考,不当前实施 | P3 |
|
||||
| 插件运行时 | Lapce plugin,SideX WASM extension,VS Code extension host | MNote 当前插件是 simplemindmap / office / local tool,不需要通用扩展平台 | 暂不采用,只保留观察 | P3 |
|
||||
|
||||
---
|
||||
|
||||
## 5. P0 实施建议
|
||||
|
||||
P0 不应从 UI 开始,而应先把文件身份、打开态 buffer 和 agent 文件权限三个底座定住。
|
||||
|
||||
### 5.1 固定 MNote 的 `WorkspacePath`
|
||||
|
||||
目标:
|
||||
|
||||
> **用一个 Rust 侧稳定结构表达“哪个 workspace root 下的哪个相对路径”。**
|
||||
|
||||
参考:
|
||||
|
||||
- Zed `ProjectPath`
|
||||
- Zed `WorktreeStore`
|
||||
|
||||
建议语义:
|
||||
|
||||
- `workspace_id`
|
||||
- `root_id`
|
||||
- `source_kind`
|
||||
- `relative_path`
|
||||
- `object_identity`
|
||||
- `resource_kind`
|
||||
|
||||
约束:
|
||||
|
||||
- 不允许 UI 只拿绝对路径当对象身份。
|
||||
- 不允许 Page Tree / File Tree / AI 工具各自生成不同 path key。
|
||||
- symlink、`..`、case sensitivity、ignore 规则必须由 Rust workspace 层处理。
|
||||
|
||||
### 5.2 建立 `BufferStore` / `DocumentBuffer` 最小模型
|
||||
|
||||
目标:
|
||||
|
||||
> **让 tiptap autosave、AI 文件写入、外部编辑器修改都围绕同一份文件版本和 dirty 状态仲裁。**
|
||||
|
||||
参考:
|
||||
|
||||
- Zed `buffer_store.rs`
|
||||
- Lapce `doc.rs`
|
||||
- VS Code save conflict 行为
|
||||
|
||||
建议最小字段:
|
||||
|
||||
- `workspace_path`
|
||||
- `file_version`
|
||||
- `base_content_hash`
|
||||
- `current_content_hash`
|
||||
- `dirty_state`
|
||||
- `last_loaded_at`
|
||||
- `last_saved_at`
|
||||
- `external_change_state`
|
||||
|
||||
当前必须避免:
|
||||
|
||||
- 继续把 `/api/documents/save` 当长期正文写入主入口。
|
||||
- tiptap 和 AI 分别维护互不知情的 revision。
|
||||
- 外部文件变更直接覆盖前台 dirty buffer。
|
||||
|
||||
### 5.3 收口 agent 文件编辑权限
|
||||
|
||||
目标:
|
||||
|
||||
> **MNote 只负责计算授权范围和同步投影,Hermes / Reasonix 在 allowed roots 内用自身 patch/diff 能力编辑文件。**
|
||||
|
||||
参考:
|
||||
|
||||
- Zed `edit_file_tool.rs`
|
||||
- Zed `edit_session.rs`
|
||||
- Zed `tool_permissions.rs`
|
||||
|
||||
必须具备:
|
||||
|
||||
- allowed roots。
|
||||
- 当前文件引用。
|
||||
- selection / range。
|
||||
- symlink escape 防护。
|
||||
- dirty buffer 写入前检查。
|
||||
- 写后 watcher / projection refresh。
|
||||
|
||||
这条线与当前 `7-14 online/local AI Markdown editing convergence` 一致:普通 local-first Markdown 编辑优先走 agent 原生文件编辑能力,`mnote.doc.markdown_edit` 只作为 cloud / remote agent / compat fallback。
|
||||
|
||||
---
|
||||
|
||||
## 6. P1 / P2 / P3 实施建议
|
||||
|
||||
### 6.1 P1:搜索、文件树、命令上下文
|
||||
|
||||
P1 解决的是 workspace 产品体验闭环:
|
||||
|
||||
- 本地全文搜索。
|
||||
- 快速打开。
|
||||
- File Tree / Resource Tree / Page Tree 展开、选择、刷新、右键命令。
|
||||
- command enablement / context key。
|
||||
|
||||
参考组合:
|
||||
|
||||
- Zed `project_search` + `file_finder`
|
||||
- Lapce `global_search` + `file_explorer/data.rs`
|
||||
- VS Code tree/list/contextkey 行为
|
||||
|
||||
验收口径:
|
||||
|
||||
- 搜索结果能回到稳定 `WorkspacePath` / `ObjectIdentity`。
|
||||
- 文件树操作只发 command,不直接改真实对象。
|
||||
- 右键菜单和快捷键基于统一 command context,不在 UI 分支里临时判断。
|
||||
|
||||
### 6.2 P2:typed RPC、配置、keymap
|
||||
|
||||
P2 解决的是边界清晰和长期可维护:
|
||||
|
||||
- UI 到 Rust executor 的 typed request / response。
|
||||
- user / workspace / page / runtime policy 的配置合并。
|
||||
- 编辑器、树、command palette 的 keymap 加载和冲突处理。
|
||||
|
||||
参考组合:
|
||||
|
||||
- Lapce `lapce-rpc/src/proxy.rs`
|
||||
- Lapce `lapce-proxy/src/dispatch.rs`
|
||||
- Lapce `config.rs`
|
||||
- Lapce `keypress/loader.rs`
|
||||
- VS Code settings / keybinding 行为
|
||||
|
||||
验收口径:
|
||||
|
||||
- route / compat / worker 不再各自定义一套命令 payload。
|
||||
- 配置合并顺序可解释、可测试。
|
||||
- 快捷键归属到 command,不直接绑定到某个 DOM 事件分支。
|
||||
|
||||
### 6.3 P3:MultiBuffer、review diff、插件运行时
|
||||
|
||||
P3 只作为后续能力,不进入当前最前排。
|
||||
|
||||
可参考:
|
||||
|
||||
- Zed `MultiBuffer`:搜索结果、AI 上下文、多文件 excerpt。
|
||||
- Zed agent edit session:review / apply / reject。
|
||||
- VS Code diff:冲突、review、保存体验。
|
||||
- Lapce plugin:轻量插件隔离。
|
||||
|
||||
当前边界:
|
||||
|
||||
- 不实施流式 apply + suggest/review。
|
||||
- 不重建 VS Code extension host。
|
||||
- 不把 MNote 拉成通用 IDE。
|
||||
|
||||
### 6.4 SideX 专项采用边界
|
||||
|
||||
SideX 可以补强 P1 / P2,但不改变 P0 主线。
|
||||
|
||||
可以参考的部分:
|
||||
|
||||
- `sidex-workspace` 的 crate 拆分:`file_tree / watcher / search / path_util / dirty_diff / multi_root`。
|
||||
- `src-tauri/src/commands/fs.rs` 的 command facade:前端请求先进入窄 command,再进入 Rust workspace 能力。
|
||||
- `src-tauri/src/commands/validation.rs` 的输入校验意识,但 MNote 需要更强的 workspace root / allowed roots / symlink escape 校验。
|
||||
- `sidex-keymap/context.rs` 的 `when` clause AST 和 evaluator,可作为 MNote command context 的 Rust 参考。
|
||||
- `sidex-settings/settings.rs` 的 default / user / workspace settings 分层,可作为 MNote user / workspace / page / AI policy 合并规则的早期参考。
|
||||
- `sidex-workspace/search.rs` 的 ignore-aware、rayon 并行全文搜索,可作为本地 Markdown workspace 搜索实现参考。
|
||||
|
||||
不应采用的部分:
|
||||
|
||||
- 不采用“把 VS Code TypeScript workbench 原样移植到 Tauri”的产品路线。
|
||||
- 不把 MNote `3000` Rust Web 主壳替换成 Tauri desktop shell。
|
||||
- 不把 extension host / debugger / terminal / git 做成当前默认产品能力。
|
||||
- 不直接沿用 SideX 的绝对路径 command 安全模型;MNote 必须以 workspace identity、allowed roots、file version 和 agent permission 为准。
|
||||
|
||||
对 MNote 的实际帮助是:
|
||||
|
||||
> **当我们从 VS Code 学到一个行为时,可以先看 SideX 是否已有 Rust crate / Tauri command 级别的落地方式;如果有,就用 SideX 校准“这个行为如何从 Node/Electron 能力迁移到 Rust 后端”,再按 MNote 的 kernel / projection / command contract 重写。**
|
||||
|
||||
---
|
||||
|
||||
## 7. VS Code 仍应继续看的源码
|
||||
|
||||
虽然不建议转译 VS Code,但下面这些仍值得继续深读,因为它们定义了成熟编辑器的行为边界。
|
||||
|
||||
### 7.1 文件服务与保存冲突
|
||||
|
||||
重点:
|
||||
|
||||
- `src/vs/platform/files`
|
||||
- `src/vs/workbench/services/filesConfiguration`
|
||||
- `textFileSaveErrorHandler`
|
||||
|
||||
关注问题:
|
||||
|
||||
- 文件不存在、权限失败、外部修改、编码变化、只读文件如何呈现。
|
||||
- dirty buffer 与磁盘版本冲突时如何让用户选择。
|
||||
- save / save as / revert 的命令边界。
|
||||
|
||||
### 7.2 Watcher 与外部变更
|
||||
|
||||
重点:
|
||||
|
||||
- `workspaceWatcher`
|
||||
- file service event。
|
||||
|
||||
关注问题:
|
||||
|
||||
- 外部编辑器修改 `.md` 后如何刷新投影。
|
||||
- 当前 buffer dirty 时如何避免静默覆盖。
|
||||
- rename / delete / move 对打开 tab 和 file tree 的影响。
|
||||
|
||||
### 7.3 Context Key 与 Command Enablement
|
||||
|
||||
重点:
|
||||
|
||||
- `src/vs/platform/contextkey`
|
||||
- `src/vs/platform/commands`
|
||||
|
||||
关注问题:
|
||||
|
||||
- 命令是否可用不应散落在 UI 条件判断里。
|
||||
- File Tree / Page Tree / Object Tab / Editor selection 应贡献统一 context。
|
||||
- 右键菜单、快捷键、command palette 应消费同一套 command context。
|
||||
|
||||
### 7.4 Tree / List 行为
|
||||
|
||||
重点:
|
||||
|
||||
- `src/vs/base/browser/ui/list`
|
||||
- `src/vs/base/browser/ui/tree`
|
||||
- `src/vs/workbench/contrib/files`
|
||||
|
||||
关注问题:
|
||||
|
||||
- 展开、收起、选择、焦点、键盘导航。
|
||||
- DnD 和 rename 的边界。
|
||||
- open editors / file explorer 如何处理打开态与磁盘态。
|
||||
|
||||
---
|
||||
|
||||
## 8. 风险与边界
|
||||
|
||||
### 8.1 许可与代码来源边界
|
||||
|
||||
Zed、Lapce、VS Code 都只能作为参考来源。后续实现应遵循:
|
||||
|
||||
- 不直接复制大段源码。
|
||||
- 不把第三方项目的 UI 壳、生命周期和产品概念搬进 MNote。
|
||||
- 引用具体设计时在设计稿或实现注释中标明“参考模式”,避免伪装成原创推导。
|
||||
|
||||
### 8.2 产品边界风险
|
||||
|
||||
MNote 不应因为参考 Zed / Lapce / VS Code 而变成通用 IDE。
|
||||
|
||||
必须保持:
|
||||
|
||||
- 页面正文真相仍是 local-first `.md`。
|
||||
- Rust kernel 持有树、资源、投影、命令语义。
|
||||
- Page Aggregate 是页面主投影。
|
||||
- File Tree 是 local workspace 的组织投影。
|
||||
- Hermes / Reasonix agent 文件编辑必须受 allowed roots 和文件版本模型约束。
|
||||
|
||||
### 8.3 技术路线风险
|
||||
|
||||
最大风险不是“参考不够”,而是参考源混用后边界变模糊。
|
||||
|
||||
固定规则:
|
||||
|
||||
- Zed 负责主架构参考。
|
||||
- Lapce 负责轻量实现参考。
|
||||
- SideX 负责 VS Code 行为到 Rust 后端的迁移参考。
|
||||
- VS Code 负责行为规格参考。
|
||||
- MNote 自己的 Rust kernel / projection / command contract 负责最终真相。
|
||||
|
||||
---
|
||||
|
||||
## 9. 当前建议结论
|
||||
|
||||
后续推进顺序建议固定为:
|
||||
|
||||
1. **P0:`WorkspacePath / ProjectPath`、`WorktreeStore`、`BufferStore`、agent file edit permission。**
|
||||
2. **P1:workspace search、file finder、file explorer state machine、command context。**
|
||||
3. **P2:typed RPC / proxy、SideX-style Rust command facade、config、keymap。**
|
||||
4. **P3:terminal / PTY 边界、MultiBuffer excerpt、review diff、插件运行时。**
|
||||
|
||||
一句话结论:
|
||||
|
||||
> **不要把 VS Code TypeScript 源码转译成 Rust;应以 Zed 的 Rust workspace / buffer / agent 架构为主参考,以 Lapce 的 typed RPC / proxy / doc delta 为辅助参考,以 SideX 校准 VS Code 行为迁移到 Rust 后端的落地方式,再用官方 VS Code 校准成熟编辑器行为。**
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
# 5-15 本地 Markdown 路径身份统一 Checklist v1
|
||||
|
||||
## 背景
|
||||
|
||||
当前本地 Markdown 主链正在对齐 VS Code 文件模型:普通 `.md` 文件的运行时身份应来自文件资源地址,而不是 frontmatter 或 MNote 内部稳定 ID。
|
||||
|
||||
VS Code 参考:
|
||||
|
||||
- `design/05-editor-mainline/reference-code/vscode/src/vs/platform/files/common/fileService.ts`
|
||||
- `createFile(resource)` 以 `URI` 创建文件。
|
||||
- `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/fileCommands.ts`
|
||||
- 新建文件后 `openEditor({ resource: saveUri })`。
|
||||
- `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/editors/fileEditorInput.ts`
|
||||
- `matches()` 使用 `isEqual(otherInput.resource, this.resource)`。
|
||||
- `design/05-editor-mainline/reference-code/vscode/src/vs/workbench/contrib/files/browser/editors/fileEditorHandler.ts`
|
||||
- working copy 与 editor 是否同一打开项,比较 `workingCopy.resource` 与 `editor.resource`。
|
||||
|
||||
本阶段目标不是引入新的稳定语义 ID,而是先消除普通本地 Markdown runtime 中的多 ID 竞争。
|
||||
|
||||
## 身份原则
|
||||
|
||||
- 普通本地 Markdown 的真实身份是 `sourceKind + rootUri + relativePath`。
|
||||
- 对外 `documentId` 继续使用路径型短句柄:`local-md:<encoded relative_path>`。
|
||||
- `mnote_id` 只作为已有 frontmatter 元数据保留,不参与普通本地 Markdown 的 `documentId` 决策。
|
||||
- `.mnote/page-ids.json` 只允许作为历史兼容/迁移辅助,不参与普通本地 Markdown 的主身份生成。
|
||||
- 不主动修改、删除或重写用户 Markdown frontmatter。
|
||||
|
||||
## 允许修改范围
|
||||
|
||||
- `rust/crates/mnote-web/src/routes/local_search_index.rs`
|
||||
- `rust/crates/mnote-web/src/routes/local_folder_source.rs`
|
||||
- 必要时更新直接相关测试:
|
||||
- `rust/crates/mnote-web/src/routes/search.rs`
|
||||
- `rust/crates/mnote-web/src/routes/tree.rs`
|
||||
- `rust/crates/mnote-web/src/routes/documents.rs`
|
||||
|
||||
不要修改用户数据目录,不要清理仓库中无关脏文件,不要做 git commit。
|
||||
|
||||
## P0 Checklist
|
||||
|
||||
### 1. 搜索索引 documentId 与树形列表统一
|
||||
|
||||
- [ ] `local_search_index.rs` 中 `index_markdown_file()` 永远按 `relative_path` 生成 `local-md:<encoded relative_path>`。
|
||||
- [ ] frontmatter `mnote_id` 不再生成 `local-mdid:*`。
|
||||
- [ ] 搜索结果、最近修改、反链接口返回的 Markdown `documentId` 与文件树一致。
|
||||
- [ ] 含 `mnote_id` 的 Markdown 搜索测试必须断言仍返回路径型 ID,例如 `local-md:docs~2Fchild.md`。
|
||||
|
||||
验收:
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_local_index -- --nocapture
|
||||
```
|
||||
|
||||
### 2. 清理本地 Markdown 身份生成的误导参数
|
||||
|
||||
- [ ] `local_markdown_page_id(relative_path, _mnote_id, _metadata)` 不再保留无用参数签名。
|
||||
- [ ] 普通调用点直接使用 `local_markdown_path_page_id(relative_path)` 或新的清晰命名函数。
|
||||
- [ ] 如果必须保留 legacy resolver,函数名必须包含 `legacy` / `compat`,并且不能参与普通本地 Markdown 主链。
|
||||
|
||||
验收:
|
||||
|
||||
```bash
|
||||
rg -n "local_markdown_page_id\\(|local-mdid|mnote_id|page-ids" rust/crates/mnote-web/src/routes/local_folder_source.rs rust/crates/mnote-web/src/routes/local_search_index.rs
|
||||
```
|
||||
|
||||
期望:
|
||||
|
||||
- `local_markdown_page_id(` 不应再出现在普通主链调用中。
|
||||
- `local_search_index.rs` 不应再出现 `local-mdid` 生成逻辑。
|
||||
- `mnote_id` 可以继续出现在解析、兼容测试或“保留 frontmatter”测试中,但不能参与普通 `documentId` 生成。
|
||||
|
||||
### 3. 不污染用户文件
|
||||
|
||||
- [ ] 新建本地 Markdown 不写 `mnote_id` frontmatter。
|
||||
- [ ] 复制本地 Markdown 不改写 `mnote_id`。
|
||||
- [ ] 保存已有 Markdown 时保留原 frontmatter,但不新增身份字段。
|
||||
|
||||
验收:
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_tree_command_local_folder_lifecycle -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_save -- --nocapture
|
||||
```
|
||||
|
||||
## P1 Checklist
|
||||
|
||||
### 4. 路径型身份覆盖打开/保存/搜索一致性
|
||||
|
||||
- [ ] 同一个含 `mnote_id` 的 `.md` 文件,在文件树、页面 aggregate、搜索索引中返回同一个 `local-md:<encoded relative_path>`。
|
||||
- [ ] `documents.content.get` / 页面打开不再需要 `local-mdid:*` 才能命中文件。
|
||||
- [ ] rename/move 后新路径返回新的路径型 `documentId`,旧路径型 ID 不作为稳定页面 ID 保留。
|
||||
|
||||
验收:
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_identity_uses_path_even_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_local_folder_lifecycle -- --nocapture
|
||||
```
|
||||
|
||||
## 最终验收
|
||||
|
||||
```bash
|
||||
cargo fmt --check --all --manifest-path rust/Cargo.toml
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_local_index -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_identity_uses_path_even_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_local_folder_lifecycle -- --nocapture
|
||||
```
|
||||
|
||||
若涉及浏览器可见行为,Codex 复核阶段必须使用真实浏览器验证并将截图放在 `tmp/` 下。
|
||||
|
||||
## 执行状态(2026-05-19)
|
||||
|
||||
- [x] P0-1 搜索索引 `documentId` 已统一为 `local-md:<encoded relative_path>`,不再由 frontmatter `mnote_id` 生成 `local-mdid:*`。
|
||||
- [x] P0-2 普通本地 Markdown 主链已移除 `local_markdown_page_id(relative_path, _mnote_id, _metadata)` 误导签名,文件树、page aggregate、find-by-id 改用路径型 ID。
|
||||
- [x] P0-3 新建、复制、rename/move/restore/purge 普通本地 Markdown 不再写 `.mnote/page-ids.json`,也不再写入或改写 `mnote_id`。
|
||||
- [x] P1-4 rename/move 后返回新路径型 `documentId`,旧 ID 不再作为稳定页面 ID 保留。
|
||||
- [x] 追加清理:删除 `ParsedLocalMarkdownPage.mnote_id` 字段,避免后续代码重新把 frontmatter `mnote_id` 当身份入口。
|
||||
|
||||
已通过验收:
|
||||
|
||||
```bash
|
||||
cargo fmt --check --all --manifest-path rust/Cargo.toml
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_search_index -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web search_local_index -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_markdown_identity_uses_path_even_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_aggregate_accepts_path_id_when_frontmatter_has_mnote_id -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web local_page_id_initialization_returns_path_id_without_writing_page_ids -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web tree_command_local_folder -- --nocapture
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user