mirror of
https://github.com/Aider-AI/aider.git
synced 2025-06-05 20:25:01 +00:00
Add more real Git-style diffs in command feedback
This commit is contained in:
parent
b717384420
commit
a4bcf4f938
9 changed files with 63 additions and 17 deletions
|
@ -8,6 +8,7 @@ from .tool_utils import (
|
||||||
apply_change,
|
apply_change,
|
||||||
handle_tool_error,
|
handle_tool_error,
|
||||||
format_tool_result,
|
format_tool_result,
|
||||||
|
generate_unified_diff_snippet,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _execute_delete_block(coder, file_path, start_pattern, end_pattern=None, line_count=None, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
def _execute_delete_block(coder, file_path, start_pattern, end_pattern=None, line_count=None, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
||||||
|
@ -50,7 +51,7 @@ def _execute_delete_block(coder, file_path, start_pattern, end_pattern=None, lin
|
||||||
return f"Warning: No changes made (deletion would not change file)"
|
return f"Warning: No changes made (deletion would not change file)"
|
||||||
|
|
||||||
# 5. Generate diff for feedback
|
# 5. Generate diff for feedback
|
||||||
diff_snippet = coder._generate_diff_snippet_delete(original_content, start_line, end_line)
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content, rel_path)
|
||||||
num_deleted = end_line - start_line + 1
|
num_deleted = end_line - start_line + 1
|
||||||
num_occurrences = len(start_pattern_indices)
|
num_occurrences = len(start_pattern_indices)
|
||||||
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
from .tool_utils import generate_unified_diff_snippet
|
||||||
|
|
||||||
def _execute_delete_line(coder, file_path, line_number, change_id=None, dry_run=False):
|
def _execute_delete_line(coder, file_path, line_number, change_id=None, dry_run=False):
|
||||||
"""
|
"""
|
||||||
|
@ -62,7 +63,7 @@ def _execute_delete_line(coder, file_path, line_number, change_id=None, dry_run=
|
||||||
return f"Warning: No changes made (deleting line {line_num_int} would not change file)"
|
return f"Warning: No changes made (deleting line {line_num_int} would not change file)"
|
||||||
|
|
||||||
# Generate diff snippet (using the existing delete block helper for simplicity)
|
# Generate diff snippet (using the existing delete block helper for simplicity)
|
||||||
diff_snippet = coder._generate_diff_snippet_delete(original_content, line_idx, line_idx)
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content, rel_path)
|
||||||
|
|
||||||
# Handle dry run
|
# Handle dry run
|
||||||
if dry_run:
|
if dry_run:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
from .tool_utils import generate_unified_diff_snippet
|
||||||
|
|
||||||
def _execute_delete_lines(coder, file_path, start_line, end_line, change_id=None, dry_run=False):
|
def _execute_delete_lines(coder, file_path, start_line, end_line, change_id=None, dry_run=False):
|
||||||
"""
|
"""
|
||||||
|
@ -71,7 +72,7 @@ def _execute_delete_lines(coder, file_path, start_line, end_line, change_id=None
|
||||||
return f"Warning: No changes made (deleting lines {start_line_int}-{end_line_int} would not change file)"
|
return f"Warning: No changes made (deleting lines {start_line_int}-{end_line_int} would not change file)"
|
||||||
|
|
||||||
# Generate diff snippet
|
# Generate diff snippet
|
||||||
diff_snippet = coder._generate_diff_snippet_delete(original_content, start_idx, end_idx)
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content, rel_path)
|
||||||
|
|
||||||
# Handle dry run
|
# Handle dry run
|
||||||
if dry_run:
|
if dry_run:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
from .tool_utils import generate_unified_diff_snippet
|
||||||
|
|
||||||
def _execute_extract_lines(coder, source_file_path, target_file_path, start_pattern, end_pattern=None, line_count=None, near_context=None, occurrence=1, dry_run=False):
|
def _execute_extract_lines(coder, source_file_path, target_file_path, start_pattern, end_pattern=None, line_count=None, near_context=None, occurrence=1, dry_run=False):
|
||||||
"""
|
"""
|
||||||
|
@ -145,9 +146,9 @@ def _execute_extract_lines(coder, source_file_path, target_file_path, start_patt
|
||||||
new_target_content = target_content + extracted_block
|
new_target_content = target_content + extracted_block
|
||||||
|
|
||||||
# --- Generate Diffs ---
|
# --- Generate Diffs ---
|
||||||
source_diff_snippet = coder._generate_diff_snippet_delete(original_source_content, start_line, end_line)
|
source_diff_snippet = generate_unified_diff_snippet(original_source_content, new_source_content, rel_source_path)
|
||||||
target_insertion_line = len(target_content.splitlines()) if target_content else 0
|
target_insertion_line = len(target_content.splitlines()) if target_content else 0
|
||||||
target_diff_snippet = coder._generate_diff_snippet_insert(original_target_content, target_insertion_line, extracted_lines)
|
target_diff_snippet = generate_unified_diff_snippet(original_target_content, new_target_content, rel_target_path)
|
||||||
|
|
||||||
# --- Handle Dry Run ---
|
# --- Handle Dry Run ---
|
||||||
if dry_run:
|
if dry_run:
|
||||||
|
|
|
@ -9,6 +9,7 @@ from .tool_utils import (
|
||||||
apply_change,
|
apply_change,
|
||||||
handle_tool_error,
|
handle_tool_error,
|
||||||
format_tool_result,
|
format_tool_result,
|
||||||
|
generate_unified_diff_snippet,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _execute_indent_lines(coder, file_path, start_pattern, end_pattern=None, line_count=None, indent_levels=1, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
def _execute_indent_lines(coder, file_path, start_pattern, end_pattern=None, line_count=None, indent_levels=1, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
||||||
|
@ -81,7 +82,7 @@ def _execute_indent_lines(coder, file_path, start_pattern, end_pattern=None, lin
|
||||||
return f"Warning: No changes made (indentation would not change file)"
|
return f"Warning: No changes made (indentation would not change file)"
|
||||||
|
|
||||||
# 5. Generate diff for feedback
|
# 5. Generate diff for feedback
|
||||||
diff_snippet = coder._generate_diff_snippet_indent(original_content, new_content, start_line, end_line)
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content, rel_path)
|
||||||
num_occurrences = len(start_pattern_indices)
|
num_occurrences = len(start_pattern_indices)
|
||||||
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
||||||
action = "indent" if indent_levels > 0 else "unindent"
|
action = "indent" if indent_levels > 0 else "unindent"
|
||||||
|
|
|
@ -8,6 +8,7 @@ from .tool_utils import (
|
||||||
apply_change,
|
apply_change,
|
||||||
handle_tool_error,
|
handle_tool_error,
|
||||||
format_tool_result,
|
format_tool_result,
|
||||||
|
generate_unified_diff_snippet,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _execute_insert_block(coder, file_path, content, after_pattern=None, before_pattern=None, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
def _execute_insert_block(coder, file_path, content, after_pattern=None, before_pattern=None, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
||||||
|
@ -51,7 +52,7 @@ def _execute_insert_block(coder, file_path, content, after_pattern=None, before_
|
||||||
return f"Warning: No changes made (insertion would not change file)"
|
return f"Warning: No changes made (insertion would not change file)"
|
||||||
|
|
||||||
# 5. Generate diff for feedback
|
# 5. Generate diff for feedback
|
||||||
diff_snippet = coder._generate_diff_snippet_insert(original_content, insertion_line_idx, content_lines)
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content, rel_path)
|
||||||
num_occurrences = len(pattern_line_indices)
|
num_occurrences = len(pattern_line_indices)
|
||||||
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
from .tool_utils import generate_unified_diff_snippet
|
||||||
|
from .tool_utils import generate_unified_diff_snippet
|
||||||
|
|
||||||
def _execute_replace_lines(coder, file_path, start_line, end_line, new_content, change_id=None, dry_run=False):
|
def _execute_replace_lines(coder, file_path, start_line, end_line, new_content, change_id=None, dry_run=False):
|
||||||
"""
|
"""
|
||||||
|
@ -7,7 +9,6 @@ def _execute_replace_lines(coder, file_path, start_line, end_line, new_content,
|
||||||
Useful for fixing errors identified by error messages or linters.
|
Useful for fixing errors identified by error messages or linters.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- coder: The Coder instance
|
|
||||||
- file_path: Path to the file to modify
|
- file_path: Path to the file to modify
|
||||||
- start_line: The first line number to replace (1-based)
|
- start_line: The first line number to replace (1-based)
|
||||||
- end_line: The last line number to replace (1-based)
|
- end_line: The last line number to replace (1-based)
|
||||||
|
@ -86,6 +87,7 @@ def _execute_replace_lines(coder, file_path, start_line, end_line, new_content,
|
||||||
if original_content == new_content_full:
|
if original_content == new_content_full:
|
||||||
coder.io.tool_warning("No changes made: new content is identical to original")
|
coder.io.tool_warning("No changes made: new content is identical to original")
|
||||||
return f"Warning: No changes made (new content identical to original)"
|
return f"Warning: No changes made (new content identical to original)"
|
||||||
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content_full, rel_path)
|
||||||
|
|
||||||
# Create a readable diff for the lines replacement
|
# Create a readable diff for the lines replacement
|
||||||
diff = f"Lines {start_line}-{end_line}:\n"
|
diff = f"Lines {start_line}-{end_line}:\n"
|
||||||
|
@ -101,7 +103,7 @@ def _execute_replace_lines(coder, file_path, start_line, end_line, new_content,
|
||||||
# Handle dry run
|
# Handle dry run
|
||||||
if dry_run:
|
if dry_run:
|
||||||
coder.io.tool_output(f"Dry run: Would replace lines {start_line}-{end_line} in {file_path}")
|
coder.io.tool_output(f"Dry run: Would replace lines {start_line}-{end_line} in {file_path}")
|
||||||
return f"Dry run: Would replace lines {start_line}-{end_line}. Diff:\n{diff}"
|
return f"Dry run: Would replace lines {start_line}-{end_line}. Diff snippet:\n{diff_snippet}"
|
||||||
|
|
||||||
# --- Apply Change (Not dry run) ---
|
# --- Apply Change (Not dry run) ---
|
||||||
coder.io.write_text(abs_path, new_content_full)
|
coder.io.write_text(abs_path, new_content_full)
|
||||||
|
|
|
@ -5,6 +5,7 @@ from .tool_utils import (
|
||||||
apply_change,
|
apply_change,
|
||||||
handle_tool_error,
|
handle_tool_error,
|
||||||
format_tool_result,
|
format_tool_result,
|
||||||
|
generate_unified_diff_snippet,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _execute_replace_text(coder, file_path, find_text, replace_text, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
def _execute_replace_text(coder, file_path, find_text, replace_text, near_context=None, occurrence=1, change_id=None, dry_run=False):
|
||||||
|
@ -57,7 +58,7 @@ def _execute_replace_text(coder, file_path, find_text, replace_text, near_contex
|
||||||
|
|
||||||
# 5. Generate diff for feedback
|
# 5. Generate diff for feedback
|
||||||
# Note: _generate_diff_snippet is currently on the Coder class
|
# Note: _generate_diff_snippet is currently on the Coder class
|
||||||
diff_snippet = coder._generate_diff_snippet(original_content, start_index, len(find_text), replace_text)
|
diff_snippet = generate_unified_diff_snippet(original_content, new_content, rel_path)
|
||||||
occurrence_str = f"occurrence {occurrence}" if num_occurrences > 1 else "text"
|
occurrence_str = f"occurrence {occurrence}" if num_occurrences > 1 else "text"
|
||||||
|
|
||||||
# 6. Handle dry run
|
# 6. Handle dry run
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import difflib
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
@ -170,6 +171,42 @@ def determine_line_range(
|
||||||
return start_line, end_line
|
return start_line, end_line
|
||||||
|
|
||||||
|
|
||||||
|
def generate_unified_diff_snippet(original_content, new_content, file_path, context_lines=3):
|
||||||
|
"""
|
||||||
|
Generates a unified diff snippet between original and new content.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
original_content (str): The original file content.
|
||||||
|
new_content (str): The modified file content.
|
||||||
|
file_path (str): The relative path to the file (for display in diff header).
|
||||||
|
context_lines (int): Number of context lines to show around changes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A formatted unified diff snippet, or an empty string if no changes.
|
||||||
|
"""
|
||||||
|
if original_content == new_content:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
original_lines = original_content.splitlines(keepends=True)
|
||||||
|
new_lines = new_content.splitlines(keepends=True)
|
||||||
|
|
||||||
|
diff = difflib.unified_diff(
|
||||||
|
original_lines,
|
||||||
|
new_lines,
|
||||||
|
fromfile=f"a/{file_path}",
|
||||||
|
tofile=f"b/{file_path}",
|
||||||
|
n=context_lines, # Number of context lines
|
||||||
|
)
|
||||||
|
|
||||||
|
# Join the diff lines, potentially skipping the header if desired,
|
||||||
|
# but let's keep it for standard format.
|
||||||
|
diff_snippet = "".join(diff)
|
||||||
|
|
||||||
|
# Ensure snippet ends with a newline for cleaner formatting in results
|
||||||
|
if diff_snippet and not diff_snippet.endswith('\n'):
|
||||||
|
diff_snippet += '\n'
|
||||||
|
|
||||||
|
return diff_snippet
|
||||||
def apply_change(coder, abs_path, rel_path, original_content, new_content, change_type, metadata, change_id=None):
|
def apply_change(coder, abs_path, rel_path, original_content, new_content, change_type, metadata, change_id=None):
|
||||||
"""
|
"""
|
||||||
Writes the new content, tracks the change, and updates coder state.
|
Writes the new content, tracks the change, and updates coder state.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue