- Implement Markdown parsing for ghost text using Milkdown parser - Add support for both block and inline content in ghost text - Refactor prompt system with comprehensive rules and examples - Adjust LLM parameters: increase temperature to 0.7, add repeat_penalty - Add CSS styles for formatted ghost text (bold, italic, code, links) - Add documentation for Copilot prompt system and ghost text rendering
4.0 KiB
4.0 KiB
虚拟文本 Markdown 渲染解决方案
问题分析
当前虚拟文本(灰色字)无法正确渲染 Markdown 和换行符,根本原因是:
- 纯文本插入:
insertGhostText使用tr.insertText()直接插入纯文本 - 绕过解析器:文本未经过 Milkdown 的 Markdown 解析流程
- 节点结构错误:
\n字符被当作普通字符,而非创建新段落节点
解决方案架构
flowchart TB
subgraph 当前流程
A1[LLM 返回 Markdown] --> B1[insertText 直接插入]
B1 --> C1[添加 copilot_ghost mark]
C1 --> D1[显示为灰色纯文本]
end
subgraph 新流程
A2[LLM 返回 Markdown] --> B2[调用 parserCtx 解析]
B2 --> C2[生成 ProseMirror 节点]
C2 --> D2[为所有节点添加 ghost 属性]
D2 --> E2[插入到文档]
E2 --> F2[显示为格式化灰色文本]
end
style D1 fill:#f99
style F2 fill:#9f9
技术方案
方案一:使用 Milkdown Parser 解析(推荐)
优点:
- 完整支持 Markdown 语法
- 与编辑器行为一致
- 自动处理换行
实现步骤:
- 获取
parserCtx从 Milkdown 上下文 - 使用 parser 将 Markdown 解析为 ProseMirror Fragment
- 遍历所有节点,添加
copilot_ghostmark - 使用
tr.replaceWith()插入节点
方案二:使用 Decoration API(备选)
优点:
- 不修改实际文档内容
- 更轻量级
缺点:
- 实现复杂
- 可能与某些功能冲突
详细实现计划
步骤 1:修改 copilotPlugin.ts
需要修改以下部分:
// 新增导入
import { parserCtx } from '@milkdown/kit/core'
// 修改 insertGhostText 函数
async function insertGhostText(view: EditorView, suggestion: string, from: number) {
if (!currentCtx || !suggestion) return
const schema = view.state.schema
const markType = schema.marks.copilot_ghost
if (!markType) return
// 使用 parser 解析 Markdown
const parser = currentCtx.get(parserCtx)
const doc = await parser(suggestion)
if (!doc) return
// 为所有文本节点添加 ghost mark
const ghostDoc = doc.descendants((node, pos) => {
if (node.isText) {
// 添加 mark
}
})
// 插入节点
const tr = view.state.tr
tr.replaceWith(from, from, ghostDoc.content)
tr.setMeta(COPILOT_PLUGIN_KEY, { from, to: from + doc.content.size, suggestion })
view.dispatch(tr)
}
步骤 2:处理换行符
换行符处理策略:
| 换行类型 | 处理方式 |
|---|---|
单个 \n |
创建 hard_break 节点 |
双个 \n\n |
创建新段落节点 |
| 列表项换行 | 创建新列表项节点 |
步骤 3:样式处理
需要修改 CSS 以支持格式化的虚拟文本:
.copilot-ghost-text {
color: #999;
opacity: 0.6;
pointer-events: none;
}
/* 虚拟文本内的格式化元素 */
.copilot-ghost-text strong,
.copilot-ghost-text em,
.copilot-ghost-text code {
opacity: inherit;
}
步骤 4:状态管理
需要跟踪虚拟节点的范围,以便:
- Tab 键接受时正确移除 mark
- 用户输入时正确清除虚拟内容
- 导出时正确处理虚拟文本
文件修改清单
| 文件 | 修改内容 |
|---|---|
src/plugins/copilotPlugin.ts |
重构 insertGhostText,添加解析逻辑 |
src/components/MilkdownEditor.vue |
更新 CSS 样式 |
src/plugins/types.ts |
可能需要更新类型定义 |
风险与注意事项
- 性能考虑:解析 Markdown 可能有延迟,需要考虑用户体验
- 嵌套处理:复杂的 Markdown 结构(如嵌套列表)需要特殊处理
- 撤销/重做:确保虚拟文本的接受/拒绝正确处理 undo stack
- 光标位置:插入多段落内容后光标位置需要正确设置
验收标准
- Markdown 语法正确渲染(粗体、斜体、代码等)
- 换行符正确转换为段落
- Tab 键接受功能正常
- Escape 键拒绝功能正常
- 导出时虚拟文本正确处理
- 性能无明显下降