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 映射到 startOffsetspan.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-textcreateIncrementalSession 的语义别名,命名上和 parseSlice 工作流对齐。

参数 说明
source 初始源码文本
options 解析选项——handlersallowForms
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" 时,说明增量失败的原因