|
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()
|