zh CN Incremental Sugar - chiba233/yume-dsl-token-walker GitHub Wiki
增量语法糖
基于 SourceSpan 的辅助函数,衔接 yume-dsl-rich-text 的增量 session API。parseSlice 从头重解析一个区域,而增量 session 复用之前的解析状态、只更新变化部分。
什么时候用:
- 用户逐键输入——session 延续上次的解析状态
- 需要知道每次编辑是真正增量的还是回退到了全量重解析
- 需要一个有状态的 session,反复
applyEdit,而非一次性切片
什么时候用 parseSlice:
- 一次性区域提取(比如渲染单个节点)
- 不需要追踪 incremental vs. full-fallback
- 无状态——不需要管理 session
Demo:逐键编辑
import {createSimpleInlineHandlers} from "yume-dsl-rich-text";
import {createSliceSession, applyIncrementalEditBySpan, toSliceEdit, replaceSliceText} from "yume-dsl-token-walker";
import type {SourceSpan} from "yume-dsl-rich-text";
const handlers = createSimpleInlineHandlers(["bold", "italic"]);
const source = "head $$bold(world)$$ tail";
// 1. 创建 session——解析初始源码
const session = createSliceSession(source, {handlers});
// 2. 定位要编辑的区域(比如来自 nodeAtOffset 或编辑器选区)
const start = source.indexOf("world");
const span: SourceSpan = {
start: {offset: start, line: 1, column: start + 1},
end: {offset: start + 5, line: 1, column: start + 6},
};
// 3. 应用编辑——session 内部更新文档
const result = applyIncrementalEditBySpan(session, span, "DSL", {handlers});
console.log(result.doc.source); // "head $$bold(DSL)$$ tail"
console.log(result.mode); // "incremental" 或 "full-fallback"
console.log(session.getDocument().source); // 同上——session 是有状态的
独立辅助函数
可以脱离 session 单独使用底层辅助函数:
import {toSliceEdit, replaceSliceText} from "yume-dsl-token-walker";
const span: SourceSpan = {
start: {offset: 3, line: 1, column: 4},
end: {offset: 7, line: 1, column: 8},
};
// 将 span 转为 IncrementalEdit 载荷
const edit = toSliceEdit(span, "XYZ");
// { startOffset: 3, oldEndOffset: 7, newText: "XYZ" }
// 按 span 偏移量做纯字符串替换
const next = replaceSliceText("abcdefgh", span, "XYZ");
// "abcXYZgh"
API 参考
toSliceEdit(span, newText)
const toSliceEdit: (span: SourceSpan, newText: string) => IncrementalEdit;
将 SourceSpan + 替换文本转为 IncrementalEdit 载荷。把 span.start.offset 映射到 startOffset,span.end.offset 映射到 oldEndOffset。
replaceSliceText(source, span, newText)
const replaceSliceText: (source: string, span: SourceSpan, newText: string) => string;
纯字符串工具。按 span 偏移量切分 source 并插入 newText。不涉及解析。
createSliceSession(source, options?, sessionOptions?)
const createSliceSession: (
source: string,
options?: IncrementalParseOptions,
sessionOptions?: IncrementalSessionOptions,
) => SliceSession;
创建增量 session。是 yume-dsl-rich-text 的 createIncrementalSession 的语义别名,命名上和 parseSlice 工作流对齐。
| 参数 | 说明 |
|---|---|
source |
初始源码文本 |
options |
解析选项——handlers、allowForms 等 |
sessionOptions |
透传给 createIncrementalSession 的 session 选项 |
applyIncrementalEditBySpan(session, span, newText, options?)
const applyIncrementalEditBySpan: (
session: SliceSession,
span: SourceSpan,
newText: string,
options?: IncrementalParseOptions,
) => SliceSessionApplyResult;
高层便捷函数:从 session.getDocument() 读取当前源码,用 replaceSliceText 构建新源码,用 toSliceEdit 转换 span,然后委托给 session.applyEdit(...)。
| 参数 | 说明 |
|---|---|
session |
来自 createSliceSession 的 session |
span |
要替换的区域 |
newText |
替换文本 |
options |
重解析时的解析选项 |
类型
SliceSession
interface SliceSession {
getDocument: () => IncrementalDocument;
applyEdit: (
edit: IncrementalEdit,
newSource: string,
options?: IncrementalParseOptions,
) => SliceSessionApplyResult;
rebuild: (newSource: string, options?: IncrementalParseOptions) => IncrementalDocument;
}
SliceSessionApplyResult
interface SliceSessionApplyResult {
doc: IncrementalDocument;
mode: "incremental" | "full-fallback";
fallbackReason?: string;
}
| 字段 | 说明 |
|---|---|
doc |
编辑后的文档 |
mode |
"incremental" 复用了之前的状态;"full-fallback" 走了全量重解析 |
fallbackReason |
当 mode 为 "full-fallback" 时,说明增量失败的原因 |