from datetime import datetime from typing import Dict, List, Optional from .colors import Colors from .progress import ProgressBar class EditOperation: def __init__( self, op_type: str, filepath: str, start_pos: int = 0, end_pos: int = 0, content: str = "", old_content: str = "", ): self.op_type = op_type self.filepath = filepath self.start_pos = start_pos self.end_pos = end_pos self.content = content self.old_content = old_content self.timestamp = datetime.now() self.status = "pending" def format_operation(self) -> str: op_colors = { "INSERT": Colors.GREEN, "REPLACE": Colors.YELLOW, "DELETE": Colors.RED, "WRITE": Colors.BLUE, } color = op_colors.get(self.op_type, Colors.RESET) status_icon = { "pending": "○", "in_progress": "◐", "completed": "●", "failed": "✗", }.get(self.status, "○") return f"{color}{status_icon} [{self.op_type}]{Colors.RESET} {self.filepath}" def format_details(self, show_content: bool = True) -> str: output = [self.format_operation()] if self.op_type in ("INSERT", "REPLACE"): output.append( f" {Colors.GRAY}Position: {self.start_pos}-{self.end_pos}{Colors.RESET}" ) if show_content: if self.old_content: lines = self.old_content.split("\n") preview = lines[0][:60] + ( "..." if len(lines[0]) > 60 or len(lines) > 1 else "" ) output.append(f" {Colors.RED}- {preview}{Colors.RESET}") if self.content: lines = self.content.split("\n") preview = lines[0][:60] + ( "..." if len(lines[0]) > 60 or len(lines) > 1 else "" ) output.append(f" {Colors.GREEN}+ {preview}{Colors.RESET}") return "\n".join(output) class EditTracker: def __init__(self): self.operations: List[EditOperation] = [] self.current_file: Optional[str] = None def add_operation(self, op_type: str, filepath: str, **kwargs) -> EditOperation: op = EditOperation(op_type, filepath, **kwargs) self.operations.append(op) self.current_file = filepath return op def mark_in_progress(self, operation: EditOperation): operation.status = "in_progress" def mark_completed(self, operation: EditOperation): operation.status = "completed" def mark_failed(self, operation: EditOperation): operation.status = "failed" def get_stats(self) -> Dict[str, int]: stats = { "total": len(self.operations), "completed": sum(1 for op in self.operations if op.status == "completed"), "pending": sum(1 for op in self.operations if op.status == "pending"), "in_progress": sum( 1 for op in self.operations if op.status == "in_progress" ), "failed": sum(1 for op in self.operations if op.status == "failed"), } return stats def get_completion_percentage(self) -> float: if not self.operations: return 0.0 stats = self.get_stats() return (stats["completed"] / stats["total"]) * 100 def display_progress(self) -> str: if not self.operations: return f"{Colors.GRAY}No edit operations tracked{Colors.RESET}" output = [] output.append(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}") output.append( f"{Colors.BOLD}{Colors.BLUE}EDIT OPERATIONS PROGRESS{Colors.RESET}" ) output.append(f"{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}\n") stats = self.get_stats() self.get_completion_percentage() progress_bar = ProgressBar(total=stats["total"], width=40) progress_bar.current = stats["completed"] bar_display = progress_bar._get_bar_display() output.append(f"Progress: {bar_display}") output.append( f"{Colors.BLUE}Total: {stats['total']}, Completed: {stats['completed']}, " f"Pending: {stats['pending']}, Failed: {stats['failed']}{Colors.RESET}\n" ) output.append(f"{Colors.BOLD}Recent Operations:{Colors.RESET}") for i, op in enumerate(self.operations[-5:], 1): output.append(f"{i}. {op.format_operation()}") output.append(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}\n") return "\n".join(output) def display_timeline(self, show_content: bool = False) -> str: if not self.operations: return f"{Colors.GRAY}No edit operations tracked{Colors.RESET}" output = [] output.append(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}") output.append(f"{Colors.BOLD}{Colors.BLUE}EDIT TIMELINE{Colors.RESET}") output.append(f"{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}\n") for i, op in enumerate(self.operations, 1): timestamp = op.timestamp.strftime("%H:%M:%S") output.append(f"{Colors.GRAY}[{timestamp}]{Colors.RESET} {i}.") output.append(op.format_details(show_content)) output.append("") stats = self.get_stats() output.append(f"{Colors.BOLD}Summary:{Colors.RESET}") output.append( f"{Colors.BLUE}Total operations: {stats['total']}, " f"Completed: {stats['completed']}, Failed: {stats['failed']}{Colors.RESET}" ) output.append(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}\n") return "\n".join(output) def display_summary(self) -> str: if not self.operations: return f"{Colors.GRAY}No edits to summarize{Colors.RESET}" stats = self.get_stats() files_modified = len({op.filepath for op in self.operations}) output = [] output.append(f"\n{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}") output.append(f"{Colors.BOLD}{Colors.GREEN}EDIT SUMMARY{Colors.RESET}") output.append(f"{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}\n") output.append(f"{Colors.GREEN}Files Modified: {files_modified}{Colors.RESET}") output.append(f"{Colors.GREEN}Total Operations: {stats['total']}{Colors.RESET}") output.append(f"{Colors.GREEN}Successful: {stats['completed']}{Colors.RESET}") if stats["failed"] > 0: output.append(f"{Colors.RED}Failed: {stats['failed']}{Colors.RESET}") output.append(f"\n{Colors.BOLD}Operations by Type:{Colors.RESET}") op_types = {} for op in self.operations: op_types[op.op_type] = op_types.get(op.op_type, 0) + 1 for op_type, count in sorted(op_types.items()): output.append(f" {op_type}: {count}") output.append(f"\n{Colors.BOLD}{Colors.GREEN}{'=' * 60}{Colors.RESET}\n") return "\n".join(output) def clear(self): self.operations.clear() self.current_file = None tracker = EditTracker() def track_edit(op_type: str, filepath: str, **kwargs) -> EditOperation: return tracker.add_operation(op_type, filepath, **kwargs) def display_edit_progress() -> str: return tracker.display_progress() def display_edit_timeline(show_content: bool = False) -> str: return tracker.display_timeline(show_content) def display_edit_summary() -> str: return tracker.display_summary() def clear_tracker(): tracker.clear()