mirror of
https://github.com/Aider-AI/aider.git
synced 2025-06-02 10:45:00 +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,
|
||||
handle_tool_error,
|
||||
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):
|
||||
|
@ -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)"
|
||||
|
||||
# 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_occurrences = len(start_pattern_indices)
|
||||
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
||||
|
@ -86,4 +87,4 @@ def _execute_delete_block(coder, file_path, start_pattern, end_pattern=None, lin
|
|||
return handle_tool_error(coder, tool_name, e, add_traceback=False)
|
||||
except Exception as e:
|
||||
# Handle unexpected errors
|
||||
return handle_tool_error(coder, tool_name, e)
|
||||
return handle_tool_error(coder, tool_name, e)
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
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):
|
||||
"""
|
||||
|
@ -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)"
|
||||
|
||||
# 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
|
||||
if dry_run:
|
||||
|
@ -97,4 +98,4 @@ def _execute_delete_line(coder, file_path, line_number, change_id=None, dry_run=
|
|||
|
||||
except Exception as e:
|
||||
coder.io.tool_error(f"Error in DeleteLine: {str(e)}\n{traceback.format_exc()}")
|
||||
return f"Error: {str(e)}"
|
||||
return f"Error: {str(e)}"
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
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):
|
||||
"""
|
||||
|
@ -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)"
|
||||
|
||||
# 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
|
||||
if dry_run:
|
||||
|
@ -108,4 +109,4 @@ def _execute_delete_lines(coder, file_path, start_line, end_line, change_id=None
|
|||
|
||||
except Exception as e:
|
||||
coder.io.tool_error(f"Error in DeleteLines: {str(e)}\n{traceback.format_exc()}")
|
||||
return f"Error: {str(e)}"
|
||||
return f"Error: {str(e)}"
|
|
@ -1,5 +1,6 @@
|
|||
import os
|
||||
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):
|
||||
"""
|
||||
|
@ -145,9 +146,9 @@ def _execute_extract_lines(coder, source_file_path, target_file_path, start_patt
|
|||
new_target_content = target_content + extracted_block
|
||||
|
||||
# --- 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_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 ---
|
||||
if dry_run:
|
||||
|
@ -217,4 +218,4 @@ def _execute_extract_lines(coder, source_file_path, target_file_path, start_patt
|
|||
|
||||
except Exception as e:
|
||||
coder.io.tool_error(f"Error in ExtractLines: {str(e)}\n{traceback.format_exc()}")
|
||||
return f"Error: {str(e)}"
|
||||
return f"Error: {str(e)}"
|
|
@ -9,6 +9,7 @@ from .tool_utils import (
|
|||
apply_change,
|
||||
handle_tool_error,
|
||||
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):
|
||||
|
@ -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)"
|
||||
|
||||
# 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)
|
||||
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
||||
action = "indent" if indent_levels > 0 else "unindent"
|
||||
|
|
|
@ -8,6 +8,7 @@ from .tool_utils import (
|
|||
apply_change,
|
||||
handle_tool_error,
|
||||
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):
|
||||
|
@ -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)"
|
||||
|
||||
# 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)
|
||||
occurrence_str = f"occurrence {occurrence} of " if num_occurrences > 1 else ""
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import os
|
||||
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):
|
||||
"""
|
||||
|
@ -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.
|
||||
|
||||
Parameters:
|
||||
- coder: The Coder instance
|
||||
- file_path: Path to the file to modify
|
||||
- start_line: The first 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:
|
||||
coder.io.tool_warning("No changes made: new content is 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
|
||||
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
|
||||
if dry_run:
|
||||
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) ---
|
||||
coder.io.write_text(abs_path, new_content_full)
|
||||
|
@ -136,4 +138,4 @@ def _execute_replace_lines(coder, file_path, start_line, end_line, new_content,
|
|||
|
||||
except Exception as e:
|
||||
coder.io.tool_error(f"Error in ReplaceLines: {str(e)}\n{traceback.format_exc()}")
|
||||
return f"Error: {str(e)}"
|
||||
return f"Error: {str(e)}"
|
|
@ -5,6 +5,7 @@ from .tool_utils import (
|
|||
apply_change,
|
||||
handle_tool_error,
|
||||
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):
|
||||
|
@ -57,7 +58,7 @@ def _execute_replace_text(coder, file_path, find_text, replace_text, near_contex
|
|||
|
||||
# 5. Generate diff for feedback
|
||||
# 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"
|
||||
|
||||
# 6. Handle dry run
|
||||
|
@ -88,4 +89,4 @@ def _execute_replace_text(coder, file_path, find_text, replace_text, near_contex
|
|||
return handle_tool_error(coder, tool_name, e, add_traceback=False)
|
||||
except Exception as e:
|
||||
# Handle unexpected errors
|
||||
return handle_tool_error(coder, tool_name, e)
|
||||
return handle_tool_error(coder, tool_name, e)
|
|
@ -1,3 +1,4 @@
|
|||
import difflib
|
||||
import os
|
||||
import traceback
|
||||
|
||||
|
@ -170,6 +171,42 @@ def determine_line_range(
|
|||
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):
|
||||
"""
|
||||
Writes the new content, tracks the change, and updates coder state.
|
||||
|
@ -237,4 +274,4 @@ def format_tool_result(coder, tool_name, success_message, change_id=None, diff_s
|
|||
# except ToolError as e:
|
||||
# return handle_tool_error(coder, "MyTool", e, add_traceback=False) # Don't need traceback for ToolErrors
|
||||
# except Exception as e:
|
||||
# return handle_tool_error(coder, "MyTool", e)
|
||||
# return handle_tool_error(coder, "MyTool", e)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue