Skip to content

Commit 911b782

Browse files
committed
Add documentation for the apply_diff tool and its functionality
1 parent 8a6e93d commit 911b782

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

docs/features/tools/apply-diff.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# apply_diff
2+
3+
The `apply_diff` tool makes precise, surgical changes to files by specifying exactly what content to replace. It uses multiple sophisticated strategies for finding and applying changes while maintaining proper code formatting and structure.
4+
5+
## Parameters
6+
7+
The tool accepts these parameters:
8+
9+
- `path` (required): The path of the file to modify relative to the current working directory
10+
- `diff` (required): The search/replace block defining the changes using a format specific to the active diff strategy
11+
- `start_line` (optional): A hint for where the search content begins, used by some strategies
12+
- `end_line` (optional): A hint for where the search content ends, used by some strategies
13+
14+
## What It Does
15+
16+
This tool applies targeted changes to existing files using multiple sophisticated strategies to locate and replace content. Unlike simple search and replace, it implements intelligent matching algorithms that can adapt to different content types and file sizes, with fallback mechanisms for complex changes.
17+
18+
## When is it used?
19+
20+
- When Roo needs to make precise changes to existing code without rewriting entire files
21+
- When refactoring specific sections of code while maintaining surrounding context
22+
- When fixing bugs in existing code with surgical precision
23+
- When implementing feature enhancements that modify only certain parts of a file
24+
25+
## Key Features
26+
27+
- Implements multiple diff strategies optimized for different use cases
28+
- Uses intelligent fuzzy matching with adaptive confidence thresholds
29+
- Supports both exact matching and similarity-based matching
30+
- Preserves code formatting, indentation, and structure
31+
- Includes git-based fallback mechanism for complex changes
32+
- Shows changes in a diff view for user approval before applying
33+
- Adapts matching algorithms based on file size and content uniqueness
34+
- Provides comprehensive error reporting with context and debugging information
35+
36+
## Limitations
37+
38+
- Works best with unique, distinctive code sections that can be reliably identified
39+
- Performance may vary with very large files or repetitive code patterns
40+
- When using fuzzy matching, may occasionally select incorrect matching locations
41+
- Each diff strategy has different requirements and syntax for specifying changes
42+
- Some complex edits may require trying multiple strategies or formats
43+
44+
## How It Works
45+
46+
When the `apply_diff` tool is invoked, it follows this process:
47+
48+
1. **Parameter Validation**: Validates the required `path` and `diff` parameters
49+
2. **Strategy Selection**: Determines which diff strategy to use based on the diff format and configuration
50+
3. **File Analysis**: Loads the target file's content and analyzes code structure and patterns
51+
4. **Match Finding**:
52+
- Uses multiple matching algorithms ranging from exact matches to fuzzy similarity
53+
- Adapts confidence thresholds based on file size and content uniqueness
54+
- Uses line numbers as hints but can find matches without them
55+
5. **Change Preparation**:
56+
- Shows changes in a diff view before applying them
57+
- Maintains proper indentation and formatting
58+
6. **User Approval**: Waits for user approval before applying changes
59+
7. **Change Application**: Applies approved changes to the file
60+
8. **Validation**: Confirms the changes were applied correctly
61+
62+
## Diff Strategies
63+
64+
The tool implements several different strategies for applying changes:
65+
66+
### UnifiedDiffStrategy
67+
Uses standard unified diff format similar to `git diff` output. This is the most traditional diff format used by many tools.
68+
69+
Example format:
70+
```
71+
--- src/utils.ts
72+
+++ src/utils.ts
73+
@@ -1,9 +1,10 @@
74+
import { Logger } from '../logger';
75+
76+
function calculateTotal(items: number[]): number {
77+
- return items.reduce((sum, item) => {
78+
- return sum + item;
79+
+ const total = items.reduce((sum, item) => {
80+
+ return sum + item * 1.1; // Add 10% markup
81+
}, 0);
82+
+ return Math.round(total * 100) / 100; // Round to 2 decimal places
83+
}
84+
```
85+
86+
### SearchReplaceDiffStrategy
87+
A simpler strategy that uses a search/replace block format without line numbers. Useful for direct replacements where you know the exact content to change.
88+
89+
Example format:
90+
```
91+
<<<<<<< SEARCH
92+
def calculate_total(items):
93+
total = 0
94+
for item in items:
95+
total += item
96+
return total
97+
=======
98+
def calculate_total(items):
99+
"""Calculate total with 10% markup"""
100+
return sum(item * 1.1 for item in items)
101+
>>>>>>> REPLACE
102+
```
103+
104+
### MultiSearchReplaceDiffStrategy
105+
An enhanced version of the search/replace strategy that supports multiple search/replace blocks and includes line number hints to help with locating the content.
106+
107+
Example format:
108+
```
109+
<<<<<<< SEARCH
110+
:start_line:1
111+
:end_line:5
112+
-------
113+
def calculate_total(items):
114+
total = 0
115+
for item in items:
116+
total += item
117+
return total
118+
=======
119+
def calculate_total(items):
120+
"""Calculate total with 10% markup"""
121+
return sum(item * 1.1 for item in items)
122+
>>>>>>> REPLACE
123+
```
124+
125+
### NewUnifiedDiffStrategy
126+
The most sophisticated strategy that implements multiple matching algorithms, fuzzy matching with confidence scoring, and even a git-based fallback mechanism for complex changes.
127+
128+
## Matching Algorithms
129+
130+
The system uses several techniques to find the right location for changes:
131+
132+
### Exact Matching
133+
When possible, the system tries to find exact matches of the search content in the file. This is the most reliable method when the content hasn't changed.
134+
135+
### Fuzzy Matching
136+
For cases where the content might have changed slightly, the system uses:
137+
- Levenshtein distance calculations
138+
- String similarity comparisons
139+
- Configurable similarity thresholds
140+
- Context evaluation for surrounding lines
141+
142+
### Adaptive Thresholds
143+
The system adjusts matching thresholds based on:
144+
- File size: Larger files use more relaxed thresholds
145+
- Content uniqueness: More unique content can use stricter thresholds
146+
- Pattern complexity: More complex patterns can use more relaxed thresholds
147+
148+
### Content Uniqueness Detection
149+
The system evaluates how unique the search pattern is within the file to boost confidence in matches:
150+
```javascript
151+
// Conceptual example (actual implementation may vary)
152+
function evaluateContentUniqueness(searchStr: string, content: string[]): number {
153+
const searchLines = searchStr.split("\n")
154+
const uniqueLines = new Set(searchLines)
155+
156+
// Calculate how many search lines are relatively unique in the content
157+
let uniqueCount = 0
158+
for (const line of uniqueLines) {
159+
const matches = contentStr.match(regex)
160+
if (matches && matches.length <= 2) {
161+
// Line appears at most twice
162+
uniqueCount++
163+
}
164+
}
165+
166+
return uniqueCount / uniqueLines.size
167+
}
168+
```
169+
170+
### Git Fallback
171+
For especially complex changes, the system can create a temporary git repository and use git's own merge algorithms as a last resort:
172+
```javascript
173+
// Conceptual example (actual implementation may vary)
174+
async function applyGitFallback(hunk: Hunk, content: string[]) {
175+
// Creates temporary git repository
176+
// Commits original content
177+
// Commits desired changes
178+
// Uses git cherry-pick to apply changes
179+
// Returns result
180+
}
181+
```
182+
183+
## Examples When Used
184+
185+
- When fixing a bug, Roo identifies the specific function containing the bug and uses `apply_diff` to modify only that function, using fuzzy matching if the function has been slightly modified.
186+
- When refactoring code, Roo uses `apply_diff` with the appropriate strategy based on how extensive the changes are.
187+
- When implementing a feature enhancement, Roo adds new capabilities to existing functions using targeted edits, with git fallback for complex changes.
188+
- When updating API usage across a codebase, Roo identifies all instances of deprecated calls and replaces them with updated versions, adapting confidence thresholds based on pattern uniqueness.
189+
190+
## Usage Examples
191+
192+
Using the MultiSearchReplaceDiffStrategy:
193+
```
194+
<apply_diff>
195+
<path>src/calculation.py</path>
196+
<diff>
197+
<<<<<<< SEARCH
198+
:start_line:1
199+
:end_line:5
200+
-------
201+
def calculate_total(items):
202+
total = 0
203+
for item in items:
204+
total += item
205+
return total
206+
=======
207+
def calculate_total(items):
208+
"""Calculate total with 10% markup"""
209+
return sum(item * 1.1 for item in items)
210+
>>>>>>> REPLACE
211+
</diff>
212+
</apply_diff>
213+
```
214+
215+
Using the UnifiedDiffStrategy:
216+
```
217+
<apply_diff>
218+
<path>src/utils.ts</path>
219+
<diff>
220+
--- src/utils.ts
221+
+++ src/utils.ts
222+
@@ -24,7 +24,7 @@
223+
function formatUsername(name: string): string {
224+
return name
225+
.toLowerCase()
226+
- .replace(/[^a-z0-9]/g, '');
227+
+ .replace(/[^a-z0-9_-]/g, '');
228+
}
229+
</diff>
230+
</apply_diff>
231+
```
232+
233+
Using the SearchReplaceDiffStrategy for simple replacements:
234+
```
235+
<apply_diff>
236+
<path>src/cart.js</path>
237+
<diff>
238+
<<<<<<< SEARCH
239+
function calculateDiscount(price, quantity) {
240+
let discount = 0;
241+
if (quantity > 10) {
242+
discount = price * 0.1;
243+
}
244+
return discount;
245+
}
246+
=======
247+
function calculateDiscount(price, quantity) {
248+
let discount = 0;
249+
if (quantity > 10) {
250+
discount = price * quantity * 0.1;
251+
}
252+
return discount;
253+
}
254+
>>>>>>> REPLACE
255+
</diff>
256+
</apply_diff>
257+
```

0 commit comments

Comments
 (0)