# Plugins 插件层指引

本文件适用于 src/plugins/ 下的插件代码。

## 插件层职责

- 承接 Milkdown/ProseMirror 与业务逻辑之间的粘合层。
- 负责 AI 补全 ghost text、文档块节点、Mermaid 预览等编辑器级行为。
- 这里的代码状态性很强，误改后通常会出现“看起来还能编译，但交互细节坏掉”的问题。

## 文件分工

- copilotPlugin.ts：AI 补全主逻辑，包含 ghost text、请求调度、取消、语言识别、隐藏上下文注入和大小限制。
- docBlockPlugin.ts：文档块节点、remark 适配和视图逻辑。
- mermaidPlugin.ts：Mermaid 代码块预览和渲染。
- index.ts：导出入口。
- types.ts：公共类型。

## copilotPlugin 的真实职责

- 维护 ghost suggestion 的 plugin state。
- 用 mark + decoration 表示 ghost text，而不是简单的纯字符串缓存。
- 为每个 EditorView 维护 runtime：
	- enabled
	- debounceTimer
	- abortController
	- ctx
	- requestSeq
	- docVersion
- 推断当前光标语言，处理 fenced code、latex、mermaid 等上下文。
- 提取 OCR 缓存和文档块内容，拼到隐藏上下文里。
- 控制请求失效和中止，避免旧请求把新文档状态覆盖掉。
- 在结果插入后恢复合理的光标位置和选择状态。

## 先看哪些函数

- getCursorLanguageId：判断当前上下文语言
- extractDocBlocksFromMarkdown：从文档块生成隐藏上下文
- doFetchSuggestion：真正发起补全请求
- clearRuntimeRequests：中止定时器和请求
- insertGhostText / insertPlainText：把建议插回编辑器

## 编辑规则

- 不要把隐藏 OCR 上下文或文档块上下文直接变成最终可见文本，除非需求明确要求。
- 不要破坏 requestSeq 和 AbortController 这套旧请求失效机制。
- 不要随意改 ghost text 的 mark/decorations 表示方式；这会影响显示、接受、拒绝和同步。
- parserCtx 和 serializerCtx 是和 Milkdown 集成的关键上下文，改解析插入逻辑时要一起考虑。
- 插件行为并不完全自洽，很多配置和启停逻辑是在 components/MilkdownEditor.vue 里接上的；不要只在插件内部脑补整体行为。

## 容易踩坑的点

- 大小限制既有插件常量，也有编辑器 UI 层联动。
- 图片节点类型不止一种名字，代码已经兼容 image、image-block、imageBlock。
- 上下文语言识别会影响 Prompt 行为，改错以后通常不是“报错”，而是补全质量或补全边界变差。
- Mermaid、LaTeX、文档块这几类上下文都和“是否允许补全、是否允许上传”相关。
- 这是状态机式代码；局部改动后要优先验证交互，而不是只看类型通过。

## 调试顺序

- 如果是“为什么没有发请求”，先查 enabled、size limit、cursor context、debounce 和 abort。
- 如果是“为什么结果插错位置”，先查 ghost range、mapping、selection 恢复。
- 如果是“为什么上下文不对”，先查 OCR 缓存、文档块摘录和语言识别。
- 如果是“为什么改了插件没生效”，再回看 MilkdownEditor.vue 里的 use/config/watch 是否也要一起改。

## 改动建议

- 先做最小改动。
- 先验证单个交互问题，不要一口气同时改 ghost 插入、语言识别和请求时机。
- 当改动影响请求 payload 时，再考虑是否需要同步后端 Prompt 测试。
- 只有在确认插件本身是控制点时，才在这里改；很多行为实际上是在上层组件里决定的。
