#!/usr/bin/env python3
"""
Advanced input handler for PR Assistant with editor mode, file inclusion, and image support.
"""
import os
import re
import base64
import mimetypes
import readline
import glob
from pathlib import Path
from typing import Optional
# from pr.ui.colors import Colors # Avoid import issues
class AdvancedInputHandler:
"""Handles advanced input with editor mode, file inclusion, and image support."""
def __init__(self):
self.editor_mode = False
self.setup_readline()
def setup_readline(self):
"""Setup readline with basic completer."""
try:
# Simple completer that doesn't interfere
def completer(text, state):
return None
readline.set_completer(completer)
readline.parse_and_bind('tab: complete')
except:
pass # Readline not available
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 ""
# Check for special commands
if user_input.lower() == '/editor':
self.toggle_editor_mode()
return self.get_input(prompt) # Recurse to get new input
# Process file inclusions and images
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) # Switch back and get input
lines.append(line)
except EOFError:
break
content = '\n'.join(lines).strip()
if not content:
return ""
# Process file inclusions and images
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."""
# Process @[filename] inclusions
text = self._process_file_inclusions(text)
# Process image inclusions (look for image file paths)
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():
with open(path, 'r', encoding='utf-8', errors='replace') as f:
content = f.read()
return f"\n--- File: {filename} ---\n{content}\n--- End of {filename} ---\n"
else:
return f"[File not found: {filename}]"
except Exception as e:
return f"[Error reading file {filename}: {e}]"
# Replace @[filename] patterns
pattern = r'@\[([^\]]+)\]'
return re.sub(pattern, replace_file, text)
def _process_image_inclusions(self, text: str) -> str:
"""Process image file references and encode them."""
# Find potential image file paths
words = text.split()
processed_parts = []
for word in words:
# Check if it's a file path that exists and is an image
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/'):
# Encode image
with open(path, 'rb') as f:
image_data = base64.b64encode(f.read()).decode('utf-8')
# Replace with data URL
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)
# Global instance
input_handler = AdvancedInputHandler()
def get_advanced_input(prompt: str = "You> ") -> Optional[str]:
"""Get advanced input from user."""
return input_handler.get_input(prompt)