from typing import List, Dict, Optional
from datetime import datetime
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()
completion = 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(set(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()