# textkit.editor：结构化精确编辑

供文件编辑工具使用的底层引擎，只处理字符串、不读写文件；通过工具编辑文件时不需要直接调用。`literal-only / unique-by-default / atomic / preserve-by-default`。只通过 `process(text,args)` 调用，不为六种操作再制造六个同义函数。

## 按任务选最少字段

| 任务 | `operation` | 必要字段 |
|---|---|---|
| 替换准确旧片段 | `replace` | `oldText,newText` |
| 锚点前/后插入 | `insertBefore` / `insertAfter` | `anchor,newText` |
| 替换标记内部 | `replaceBetween` | `beginAnchor,endAnchor,newText` |
| 删除标记内部 | `deleteBetween` | `beginAnchor,endAnchor` |
| 替换完整行 | `replaceLines` | `startLine,newText`；可选 `endLine,expectedOldText` |

只传所选操作适用的字段。`newText` 必须显式传入；空串表示删除。`deleteBetween` 不接收 `newText`。

```aardio
import textkit;
import textkit.editor;

var text = 'if(ok){\r\n    old();\r\n}\r\n';
var generated = '        step1();\n        step2();';
var result,err,info = textkit.editor.process(text,{
    operation="replace";
    oldText="    old();";
    newText=textkit.indent(textkit.dedent(generated),"    ");
    previewMaxBytes=0;
});
if(result === null) return {error=err;info=info};
print(result);
```

## 匹配与布局

- **Copy old, format new**：`oldText/anchor/expectedOldText` 从当前原文复制。不要 trim、dedent、重新排版或按诊断候选位置直接写入。
- 默认必须恰好一处；`replaceAll=true` 才处理全部非重叠命中。`expectedCount=N` 是准确次数断言，不是上限或第 N 处；零命中始终失败。
- 默认 `preserveEol=true`：只容忍 CRLF/LF/CR 差异；大小写、SPACE/TAB、行尾空格仍然严格。新内容适配局部行尾，未修改部分保留原始字节。
- `preserveEol=false` 禁用换行等价；不会取消 `replaceLines` 的整行行尾衔接规则。
- 不自动给插入内容加换行，也不推测缩进。新文本需要布局时显式调用 `textkit`。
- `between` 保留两端锚点；`includeAnchors=true` 才包含。嵌套/未闭合的区块整单拒绝；`anchor` 可作 `beginAnchor` 的别名，只传一个。
- `replaceLines` 使用 1 起始、含两端的行号，`endLine` 默认等于 `startLine`。空串删除整行；新文本非空且缺行尾时，沿用原区间最后的行尾。`expectedOldText` 可含或不含最后一个行尾；空串表示期望空行。

## 返回与恢复

成功返回 `newText,null,info`；失败返回 `null,err,info`，无部分结果。看 `code/hint` 后重新读取目标区域，不自动做模糊或空白放宽重试。

`info.count` 是命中数，`changedCount` 是实际变化数；`previewMaxBytes` 默认 1024、范围 0..4096，0 关闭文本回显。定位最多 6 处、预览最多 4 处，预算只限制回显。`*Bytes` 是字节统计/诊断，不是字符位置。库只处理字符串；文件 BOM、备份、编译和提交交给文件工具。

[textkit 主库](../index.html)
