"""
Advanced input handler for PR Assistant with editor mode, file inclusion, and image support.
"""
import base64
import mimetypes
import re
import readline
from pathlib import Path
from typing import Optional
class AdvancedInputHandler:
"""Handles advanced input with editor mode, file inclusion, and image support."""
def __init__(self):
self.editor_mode = False
def setup_readline(self):
"""Setup readline with basic completer."""
try:
def completer(text, state):
return None
readline.set_completer(completer)
readline.parse_and_bind("tab: complete")
except:
pass
def toggle_editor_mode(self):
"""Toggle between simple and editor input modes."""
self.editor_mode = not self.editor_mode
mode = "Editor" if self.editor_mode else "Simple"
print(f"\nSwitched to {mode.lower()} input mode.")
def get_input(self, prompt: str = "You> ") -> Optional[str]:
"""Get input from user, handling different modes."""
try:
if self.editor_mode:
return self._get_editor_input(prompt)
else:
return self._get_simple_input(prompt)
except KeyboardInterrupt:
return None
except EOFError:
return None
def _get_simple_input(self, prompt: str) -> Optional[str]:
"""Get simple input with file completion."""
try:
user_input = input(prompt).strip()
if not user_input:
return ""
if user_input.lower() == "/editor":
self.toggle_editor_mode()
return self.get_input(prompt)
processed_input = self._process_input(user_input)
return processed_input
except KeyboardInterrupt:
return None
def _get_editor_input(self, prompt: str) -> Optional[str]:
"""Get multi-line input for editor mode."""
try:
print("Editor mode: Enter your message. Type 'END' on a new line to finish.")
print("Type '/simple' to switch back to simple mode.")
lines = []
while True:
try:
line = input()
if line.strip().lower() == "end":
break
elif line.strip().lower() == "/simple":
self.toggle_editor_mode()
return self.get_input(prompt)
lines.append(line)
except EOFError:
break
content = "\n".join(lines).strip()
if not content:
return ""
processed_content = self._process_input(content)
return processed_content
except KeyboardInterrupt:
return None
def _process_input(self, text: str) -> str:
"""Process input text for file inclusions and images."""
text = self._process_file_inclusions(text)
text = self._process_image_inclusions(text)
return text
def _process_file_inclusions(self, text: str) -> str:
"""Replace @[filename] with file contents."""
def replace_file(match):
filename = match.group(1).strip()
try:
path = Path(filename).expanduser().resolve()
if path.exists() and path.is_file():
mime_type, _ = mimetypes.guess_type(str(path))
if mime_type and (mime_type.startswith("text/") or mime_type in ["application/json", "application/xml"]):
with open(path, encoding="utf-8", errors="replace") as f:
content = f.read()
return f"\n--- File: {filename} ---\n{content}\n--- End of {filename} ---\n"
elif mime_type and not mime_type.startswith("image/"): # Handle other binary files
with open(path, "rb") as f:
binary_data = base64.b64encode(f.read()).decode("utf-8")
return f"\n--- Binary File: {filename} ({mime_type}) ---\ndata:{mime_type};base64,{binary_data}\n--- End of {filename} ---\n"
else:
return f"[File not included (unsupported type or already handled as image): {filename}]"
else:
return f"[File not found: {filename}]"
except Exception as e:
return f"[Error reading file {filename}: {e}]"
pattern = "@\\[([^\\]]+)\\]"
return re.sub(pattern, replace_file, text)
def _process_image_inclusions(self, text: str) -> str:
"""Process image file references and encode them."""
words = text.split()
processed_parts = []
for word in words:
try:
path = Path(word.strip()).expanduser().resolve()
if path.exists() and path.is_file():
mime_type, _ = mimetypes.guess_type(str(path))
if mime_type and mime_type.startswith("image/"):
with open(path, "rb") as f:
image_data = base64.b64encode(f.read()).decode("utf-8")
processed_parts.append(
f"[Image: {path.name}]\ndata:{mime_type};base64,{image_data}\n"
)
continue
except:
pass
processed_parts.append(word)
return " ".join(processed_parts)
input_handler = AdvancedInputHandler()
def get_advanced_input(prompt: str = "You> ") -> Optional[str]:
"""Get advanced input from user."""
return input_handler.get_input(prompt)