Files
llm-in-text/plans/ghost-text-markdown-rendering.md
“ydy0615” 7cddfaba30 feat(editor): add Markdown rendering for ghost text and optimize prompt system
- 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
2026-02-13 21:17:45 +08:00

158 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 虚拟文本 Markdown 渲染解决方案
## 问题分析
当前虚拟文本(灰色字)无法正确渲染 Markdown 和换行符,根本原因是:
1. **纯文本插入**`insertGhostText` 使用 `tr.insertText()` 直接插入纯文本
2. **绕过解析器**:文本未经过 Milkdown 的 Markdown 解析流程
3. **节点结构错误**`\n` 字符被当作普通字符,而非创建新段落节点
## 解决方案架构
```mermaid
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 语法
- 与编辑器行为一致
- 自动处理换行
**实现步骤**
1. 获取 `parserCtx` 从 Milkdown 上下文
2. 使用 parser 将 Markdown 解析为 ProseMirror Fragment
3. 遍历所有节点,添加 `copilot_ghost` mark
4. 使用 `tr.replaceWith()` 插入节点
### 方案二:使用 Decoration API备选
**优点**
- 不修改实际文档内容
- 更轻量级
**缺点**
- 实现复杂
- 可能与某些功能冲突
## 详细实现计划
### 步骤 1修改 copilotPlugin.ts
需要修改以下部分:
```typescript
// 新增导入
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 以支持格式化的虚拟文本:
```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` | 可能需要更新类型定义 |
## 风险与注意事项
1. **性能考虑**:解析 Markdown 可能有延迟,需要考虑用户体验
2. **嵌套处理**:复杂的 Markdown 结构(如嵌套列表)需要特殊处理
3. **撤销/重做**:确保虚拟文本的接受/拒绝正确处理 undo stack
4. **光标位置**:插入多段落内容后光标位置需要正确设置
## 验收标准
- [ ] Markdown 语法正确渲染(粗体、斜体、代码等)
- [ ] 换行符正确转换为段落
- [ ] Tab 键接受功能正常
- [ ] Escape 键拒绝功能正常
- [ ] 导出时虚拟文本正确处理
- [ ] 性能无明显下降