2025-11-04 05:17:27 +01:00
|
|
|
from datetime import datetime
|
2025-11-04 08:09:12 +01:00
|
|
|
from typing import Dict, List, Optional
|
|
|
|
|
|
2025-11-04 05:17:27 +01:00
|
|
|
from .colors import Colors
|
|
|
|
|
from .progress import ProgressBar
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EditOperation:
|
2025-11-04 08:09:12 +01:00
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
op_type: str,
|
|
|
|
|
filepath: str,
|
|
|
|
|
start_pos: int = 0,
|
|
|
|
|
end_pos: int = 0,
|
|
|
|
|
content: str = "",
|
|
|
|
|
old_content: str = "",
|
|
|
|
|
):
|
2025-11-04 05:17:27 +01:00
|
|
|
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 = {
|
2025-11-04 08:09:12 +01:00
|
|
|
"INSERT": Colors.GREEN,
|
|
|
|
|
"REPLACE": Colors.YELLOW,
|
|
|
|
|
"DELETE": Colors.RED,
|
|
|
|
|
"WRITE": Colors.BLUE,
|
2025-11-04 05:17:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
color = op_colors.get(self.op_type, Colors.RESET)
|
|
|
|
|
status_icon = {
|
2025-11-04 08:09:12 +01:00
|
|
|
"pending": "○",
|
|
|
|
|
"in_progress": "◐",
|
|
|
|
|
"completed": "●",
|
|
|
|
|
"failed": "✗",
|
|
|
|
|
}.get(self.status, "○")
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
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()]
|
|
|
|
|
|
2025-11-04 08:09:12 +01:00
|
|
|
if self.op_type in ("INSERT", "REPLACE"):
|
|
|
|
|
output.append(
|
|
|
|
|
f" {Colors.GRAY}Position: {self.start_pos}-{self.end_pos}{Colors.RESET}"
|
|
|
|
|
)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
if show_content:
|
|
|
|
|
if self.old_content:
|
2025-11-04 08:09:12 +01:00
|
|
|
lines = self.old_content.split("\n")
|
|
|
|
|
preview = lines[0][:60] + (
|
|
|
|
|
"..." if len(lines[0]) > 60 or len(lines) > 1 else ""
|
|
|
|
|
)
|
2025-11-04 05:17:27 +01:00
|
|
|
output.append(f" {Colors.RED}- {preview}{Colors.RESET}")
|
|
|
|
|
|
|
|
|
|
if self.content:
|
2025-11-04 08:09:12 +01:00
|
|
|
lines = self.content.split("\n")
|
|
|
|
|
preview = lines[0][:60] + (
|
|
|
|
|
"..." if len(lines[0]) > 60 or len(lines) > 1 else ""
|
|
|
|
|
)
|
2025-11-04 05:17:27 +01:00
|
|
|
output.append(f" {Colors.GREEN}+ {preview}{Colors.RESET}")
|
|
|
|
|
|
2025-11-04 08:09:12 +01:00
|
|
|
return "\n".join(output)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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 = {
|
2025-11-04 08:09:12 +01:00
|
|
|
"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"),
|
2025-11-04 05:17:27 +01:00
|
|
|
}
|
|
|
|
|
return stats
|
|
|
|
|
|
|
|
|
|
def get_completion_percentage(self) -> float:
|
|
|
|
|
if not self.operations:
|
|
|
|
|
return 0.0
|
|
|
|
|
stats = self.get_stats()
|
2025-11-04 08:09:12 +01:00
|
|
|
return (stats["completed"] / stats["total"]) * 100
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
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}")
|
2025-11-04 08:09:12 +01:00
|
|
|
output.append(
|
|
|
|
|
f"{Colors.BOLD}{Colors.BLUE}EDIT OPERATIONS PROGRESS{Colors.RESET}"
|
|
|
|
|
)
|
2025-11-04 05:17:27 +01:00
|
|
|
output.append(f"{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}\n")
|
|
|
|
|
|
|
|
|
|
stats = self.get_stats()
|
2025-11-04 08:09:12 +01:00
|
|
|
self.get_completion_percentage()
|
2025-11-04 05:17:27 +01:00
|
|
|
|
2025-11-04 08:09:12 +01:00
|
|
|
progress_bar = ProgressBar(total=stats["total"], width=40)
|
|
|
|
|
progress_bar.current = stats["completed"]
|
2025-11-04 05:17:27 +01:00
|
|
|
bar_display = progress_bar._get_bar_display()
|
|
|
|
|
|
|
|
|
|
output.append(f"Progress: {bar_display}")
|
2025-11-04 08:09:12 +01:00
|
|
|
output.append(
|
|
|
|
|
f"{Colors.BLUE}Total: {stats['total']}, Completed: {stats['completed']}, "
|
|
|
|
|
f"Pending: {stats['pending']}, Failed: {stats['failed']}{Colors.RESET}\n"
|
|
|
|
|
)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
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")
|
2025-11-04 08:09:12 +01:00
|
|
|
return "\n".join(output)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
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}")
|
2025-11-04 08:09:12 +01:00
|
|
|
output.append(
|
|
|
|
|
f"{Colors.BLUE}Total operations: {stats['total']}, "
|
|
|
|
|
f"Completed: {stats['completed']}, Failed: {stats['failed']}{Colors.RESET}"
|
|
|
|
|
)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
output.append(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.RESET}\n")
|
2025-11-04 08:09:12 +01:00
|
|
|
return "\n".join(output)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
def display_summary(self) -> str:
|
|
|
|
|
if not self.operations:
|
|
|
|
|
return f"{Colors.GRAY}No edits to summarize{Colors.RESET}"
|
|
|
|
|
|
|
|
|
|
stats = self.get_stats()
|
2025-11-04 08:09:12 +01:00
|
|
|
files_modified = len({op.filepath for op in self.operations})
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
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}")
|
|
|
|
|
|
2025-11-04 08:09:12 +01:00
|
|
|
if stats["failed"] > 0:
|
2025-11-04 05:17:27 +01:00
|
|
|
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")
|
2025-11-04 08:09:12 +01:00
|
|
|
return "\n".join(output)
|
2025-11-04 05:17:27 +01:00
|
|
|
|
|
|
|
|
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()
|