152 lines
4.9 KiB
Python
152 lines
4.9 KiB
Python
"""
|
|
Edit Manager - Track and apply pending edits for RoadPad accept modes.
|
|
|
|
Handles three modes:
|
|
- manual: Show diff, user accepts/rejects
|
|
- on save: Queue edits, apply on save
|
|
- always: Apply immediately
|
|
"""
|
|
|
|
from typing import List, Tuple, Optional
|
|
from datetime import datetime
|
|
|
|
|
|
class Edit:
|
|
"""Represents a single pending edit."""
|
|
|
|
def __init__(self, query: str, response: str, timestamp: str = None):
|
|
self.query = query
|
|
self.response = response
|
|
self.timestamp = timestamp or datetime.now().isoformat()
|
|
self.applied = False
|
|
self.rejected = False
|
|
|
|
def __repr__(self):
|
|
status = "applied" if self.applied else ("rejected" if self.rejected else "pending")
|
|
return f"Edit({self.query[:30]}..., {status})"
|
|
|
|
|
|
class EditManager:
|
|
"""Manage pending edits and apply them based on accept mode."""
|
|
|
|
def __init__(self):
|
|
self.pending_edits: List[Edit] = []
|
|
self.applied_edits: List[Edit] = []
|
|
self.rejected_edits: List[Edit] = []
|
|
|
|
def add_edit(self, query: str, response: str) -> Edit:
|
|
"""Add a new edit to the pending queue."""
|
|
edit = Edit(query, response)
|
|
self.pending_edits.append(edit)
|
|
return edit
|
|
|
|
def accept_edit(self, edit: Edit) -> bool:
|
|
"""Accept and apply a specific edit."""
|
|
if edit in self.pending_edits:
|
|
edit.applied = True
|
|
self.pending_edits.remove(edit)
|
|
self.applied_edits.append(edit)
|
|
return True
|
|
return False
|
|
|
|
def reject_edit(self, edit: Edit) -> bool:
|
|
"""Reject a specific edit."""
|
|
if edit in self.pending_edits:
|
|
edit.rejected = True
|
|
self.pending_edits.remove(edit)
|
|
self.rejected_edits.append(edit)
|
|
return True
|
|
return False
|
|
|
|
def accept_all(self) -> int:
|
|
"""Accept all pending edits. Returns count applied."""
|
|
count = len(self.pending_edits)
|
|
for edit in list(self.pending_edits):
|
|
self.accept_edit(edit)
|
|
return count
|
|
|
|
def reject_all(self) -> int:
|
|
"""Reject all pending edits. Returns count rejected."""
|
|
count = len(self.pending_edits)
|
|
for edit in list(self.pending_edits):
|
|
self.reject_edit(edit)
|
|
return count
|
|
|
|
def clear_pending(self) -> None:
|
|
"""Clear all pending edits without applying."""
|
|
self.pending_edits.clear()
|
|
|
|
def get_pending_count(self) -> int:
|
|
"""Get count of pending edits."""
|
|
return len(self.pending_edits)
|
|
|
|
def get_next_edit(self) -> Optional[Edit]:
|
|
"""Get the next pending edit for review."""
|
|
return self.pending_edits[0] if self.pending_edits else None
|
|
|
|
def get_diff_preview(self, edit: Edit) -> str:
|
|
"""Generate a diff-style preview of the edit."""
|
|
lines = []
|
|
lines.append("=" * 80)
|
|
lines.append("[EDIT PREVIEW]")
|
|
lines.append("")
|
|
lines.append(f"Query: {edit.query}")
|
|
lines.append("")
|
|
lines.append("Proposed changes:")
|
|
lines.append("-" * 80)
|
|
|
|
# Show response as additions
|
|
for line in edit.response.split('\n'):
|
|
lines.append(f"+ {line}")
|
|
|
|
lines.append("-" * 80)
|
|
lines.append("")
|
|
lines.append("Commands:")
|
|
lines.append(" Ctrl+Y - Accept this edit")
|
|
lines.append(" Ctrl+N - Reject this edit")
|
|
lines.append(" Ctrl+A - Accept all pending")
|
|
lines.append(" Ctrl+R - Reject all pending")
|
|
lines.append("=" * 80)
|
|
|
|
return '\n'.join(lines)
|
|
|
|
def apply_edits_to_buffer(self, buffer, edits: List[Edit]) -> int:
|
|
"""
|
|
Apply accepted edits to the buffer.
|
|
Returns count of edits applied.
|
|
"""
|
|
count = 0
|
|
for edit in edits:
|
|
if edit.applied and not edit.rejected:
|
|
# Append response to buffer
|
|
separator = "─" * 80
|
|
|
|
buffer.lines.append("")
|
|
buffer.lines.append(separator)
|
|
buffer.lines.append("[Applied Edit]")
|
|
buffer.lines.append(f" Query: {edit.query}")
|
|
buffer.lines.append("")
|
|
|
|
for line in edit.response.split('\n'):
|
|
buffer.lines.append(f" {line}")
|
|
|
|
buffer.lines.append("")
|
|
buffer.lines.append(separator)
|
|
buffer.lines.append("")
|
|
|
|
count += 1
|
|
|
|
return count
|
|
|
|
def get_status_text(self, mode: int) -> str:
|
|
"""Get status text for the status bar."""
|
|
mode_names = ["manual", "on save", "always"]
|
|
mode_name = mode_names[mode]
|
|
|
|
pending = self.get_pending_count()
|
|
|
|
if pending > 0:
|
|
return f"{mode_name} ({pending} pending)"
|
|
else:
|
|
return mode_name
|