apply_diff
掌握 `apply_diff` 工具,使用模糊匹配和行提示在 Roo Code 中进行精确的代码更改,并支持多文件。
apply_diff 工具通过精确指定要替换的内容,对文件进行精确、细致的更改。它采用一种复杂的策略来查找和应用更改,同时保持适当的代码格式和结构。
参数
该工具接受以下参数:
- path (必需):要修改的文件的路径,相对于当前工作目录。
- diff (必需):定义更改的搜索/替换块,使用特定于活动 diff 策略的格式。
- start_line (可选):搜索内容开始位置的提示。注意:此顶级参数未被当前主要策略使用,该策略依赖于 diff 内容中的
:start_line:。 - end_line (可选):搜索内容结束位置的提示。注意:此顶级参数未被当前主要策略使用。
功能
此工具使用模糊匹配,通过行号提示来精确查找和替换内容,从而对现有文件应用有针对性的更改。与简单的搜索和替换不同,它根据提供的内容和位置提示来识别要替换的精确块。
使用时机
- 当 Roo 需要对现有代码进行精确更改而无需重写整个文件时。
- 在重构特定代码部分时保持周围上下文。
- 在以细致的精度修复现有代码中的错误时。
- 在实施仅修改文件某些部分的特性增强时。
主要功能
- 使用由
:start_line:提示引导的模糊匹配(归一化字符串的 Levenshtein 距离),具有可配置的置信度阈值(通常为 0.8-1.0)。 - 使用
BUFFER_LINES(默认 40)提供匹配周围的上下文。 - 在提示的起始行周围的可配置上下文窗口(
bufferLines)内执行由内而外的搜索。 - 通过替换精确块来被动地保留代码格式和缩进。
- 在应用前以 diff 视图显示更改供用户审查和编辑。
- 跟踪每个文件的连续错误(
consecutiveMistakeCountForApplyDiff)以防止重复失败。 - 根据
.rooignore规则验证文件访问。 - 有效处理多行编辑。
局限性
- 最适合使用独特、有特色的代码部分以进行可靠识别。
- 对于非常大的文件或高度重复的代码模式,性能可能会有所不同。
- 如果内容含糊不清,模糊匹配有时可能会选择不正确的位置。
- 每个 diff 策略都有特定的格式要求。
- 复杂的编辑可能需要仔细选择策略或手动审查。
工作原理
调用 apply_diff 工具时,它遵循此过程:
- 参数验证:验证必需的
path和diff参数。 - RooIgnore 检查:验证目标文件路径是否被
.rooignore规则允许。 - 文件分析:加载目标文件内容。
- 匹配查找:使用模糊匹配算法(归一化字符串的 Levenshtein 距离),由上下文窗口(
BUFFER_LINES)内的:start_line:提示引导,由内而外搜索以根据置信度阈值定位目标内容。 - 变更准备:通过替换已识别的块来生成建议的更改。
- 用户交互:
- 在 diff 视图中显示更改。
- 允许用户审查并可能编辑建议的更改。
- 等待用户批准或拒绝。
- 变更应用:如果获得批准,则将更改(可能包括用户编辑)应用到文件。
- 错误处理:如果发生错误(例如,匹配失败、部分应用),则增加该文件的
consecutiveMistakeCountForApplyDiff并报告失败类型。 - 反馈:返回结果,包括任何用户反馈或错误详细信息。
Diff 格式要求
<diff> 参数需要一种特定格式,支持在单个请求中进行一个或多个更改。每个更改块都需要一个原始内容的行号提示。
- 要求:
SEARCH块内容需要精确匹配(在模糊阈值内),包括空格和缩进。每个块内的:start_line:行号提示是强制性的。:end_line:提示是可选的(但解析器支持)。文件内容中像<<<<<<<这样的标记必须在SEARCH块中进行转义(\\)。
<diff> 块的示例格式:
<<<<<<< SEARCH
:start_line:10
:end_line:12
-------
// Old calculation logic
const result = value * 0.9;
return result;
=======
// Updated calculation logic with logging
console.log(`Calculating for value: ${value}`);
const result = value * 0.95; // Adjusted factor
return result;
>>>>>>> REPLACE
<<<<<<< SEARCH
:start_line:25
:end_line:25
-------
const defaultTimeout = 5000;
=======
const defaultTimeout = 10000; // Increased timeout
>>>>>>> REPLACE
实验性:多文件编辑 (MULTI_FILE_APPLY_DIFF)
apply_diff 的一个实验性版本允许在单个工具调用中对多个文件应用更改。此功能通过 MULTI_FILE_APPLY_DIFF 实验标志激活。
实验模式的主要功能
- 多文件操作:在一个请求中编辑多个文件,简化复杂的重构任务。
- 批量审批 UI:当目标为多个文件时,会出现一个单一的 UI,供用户一次性批准或拒绝所有更改,或单独管理每个文件的权限。
- 新的 XML 格式:引入了一种使用
<args>和<file>标签的新、更结构化的 XML 格式来处理多个操作。 - 向后兼容性:实验性工具仍与旧版单文件
path和diff参数格式兼容。
工作原理(实验性)
- 实验检查:工具首先检查是否启用了
MULTI_FILE_APPLY_DIFF实验。如果未启用,则回退到旧版的apply_diff实现。 - 参数解析:它解析新的
<args>XML 格式以识别所有目标文件及其相应的 diff 操作。它还可以处理旧版的path/diff参数。 - 验证和审批:
- 验证所有目标文件是否存在且可访问(未被
.rooignore阻止)。 - 如果正在修改多个文件,则向用户显示一个批量审批对话框。
- Diff 应用:对于每个已批准的文件,它使用
MultiFileSearchReplaceDiffStrategy应用指定的 diff。此策略可以对单个文件应用多个、不重叠的更改。 - 结果:它返回一个整合的结果消息,总结所有尝试的操作的结果。
新的 Diff 格式(实验性)
实验模式在 <apply_diff> 工具调用中使用新的 XML 结构。
<args>:所有文件操作的容器。<file>:每个要修改的文件的块。包含<path>和一个或多个<diff>标签。<path>:文件的相对路径。<diff>:包含更改的块。<content>:SEARCH/REPLACE块。<start_line>:(可选) 行号提示。
示例:在一个调用中修改两个文件
<apply_diff>
<args>
<file>
<path>src/services/auth.service.ts</path>
<diff>
<content>
<<<<<<< SEARCH
:start_line:50
-------
const token_expiration = '15m';
>>>>>>> REPLACE
</content>
</diff>
</file>
<file>
<path>src/config/auth.config.ts</path>
<diff>
<content>
<<<<<<< SEARCH
:start_line:12
-------
rateLimit: 5,
=======
rateLimit: 10,
>>>>>>> REPLACE
</content>
</diff>
</file>
</args>
</apply_diff>