"""Interactive REPL mode for exploring regex patterns.""" import sys import os from typing import Optional from .parser import parse_regex from .translator import translate_regex from .test_generator import generate_test_cases from .flavors import get_flavor_manager def format_output(text: str, use_color: bool = True) -> str: """Format output with optional color.""" if not use_color or not sys.stdout.isatty(): return text try: from pygments import highlight from pygments.lexers import RegexLexer from pygments.formatters import TerminalFormatter lexer = RegexLexer() formatter = TerminalFormatter() return highlight(text, lexer, formatter) except ImportError: return text class InteractiveSession: """Interactive session for regex exploration.""" def __init__(self, flavor: str = "pcre", use_color: bool = True): self.flavor = flavor self.use_color = use_color self.history: list[str] = [] self.history_file = os.path.expanduser("~/.regex_humanizer_history") self._load_history() def _load_history(self): """Load command history from file.""" if os.path.exists(self.history_file): try: with open(self.history_file, 'r') as f: self.history = [line.strip() for line in f if line.strip()] except Exception: self.history = [] def _save_history(self): """Save command history to file.""" try: os.makedirs(os.path.dirname(self.history_file), exist_ok=True) with open(self.history_file, 'w') as f: for cmd in self.history[-1000:]: f.write(cmd + '\\n') except Exception: pass def run(self): """Run the interactive session.""" print("\\nRegex Humanizer - Interactive Mode") print("Type 'help' for available commands, 'quit' to exit.\\n") while True: try: import click user_input = click.prompt( "regex> ", type=str, default="", show_default=False ) if not user_input.strip(): continue self.history.append(user_input) self._save_history() self._process_command(user_input.strip()) except (KeyboardInterrupt, EOFError): print("\\nGoodbye!") break def _process_command(self, command: str): """Process a user command.""" parts = command.split(None, 1) cmd = parts[0].lower() args = parts[1] if len(parts) > 1 else "" commands = { "help": self._cmd_help, "quit": self._cmd_quit, "exit": self._cmd_quit, "explain": self._cmd_explain, "test": self._cmd_test, "flavor": self._cmd_flavor, "set": self._cmd_flavor, "load": self._cmd_load, "save": self._cmd_save, "history": self._cmd_history, "clear": self._cmd_clear, "example": self._cmd_example, } handler = commands.get(cmd) if handler: handler(args) else: print(f"Unknown command: {cmd}") print("Type 'help' for available commands.") def _cmd_help(self, args: str): """Show help message.""" help_text = """ Available Commands: explain - Explain a regex pattern in English test - Generate test cases for a pattern flavor - Set the regex flavor (pcre, javascript, python) set - Same as 'flavor' load - Load a pattern from a file save - Save the last pattern to a file history - Show command history example - Show an example pattern clear - Clear the screen quit / exit - Exit the interactive mode Examples: explain ^\\d{3}-\\d{4}$ test [a-z]+ flavor javascript """ print(help_text) def _cmd_quit(self, args: str): """Exit the session.""" print("Goodbye!") sys.exit(0) def _cmd_explain(self, args: str): """Explain a regex pattern.""" if not args: print("Usage: explain ") return try: pattern = self._expand_pattern(args) result = translate_regex(pattern, self.flavor) header = f"Pattern: {pattern}" print("\\n" + "=" * (len(header))) print(header) print("=" * (len(header))) print("\\nEnglish Explanation:") print("-" * (len(header))) print(result) print() except Exception as e: print(f"Error parsing pattern: {e}") def _cmd_test(self, args: str): """Generate test cases for a pattern.""" if not args: print("Usage: test ") return try: pattern = self._expand_pattern(args) result = generate_test_cases(pattern, self.flavor, 3, 3) header = f"Pattern: {pattern}" print("\\n" + "=" * (len(header))) print(header) print("=" * (len(header))) print(f"\\nFlavor: {self.flavor}") print("\\nMatching strings:") print("-" * (len(header))) for i, s in enumerate(result["matching"], 1): print(f" {i}. {s}") print("\\nNon-matching strings:") print("-" * (len(header))) for i, s in enumerate(result["non_matching"], 1): print(f" {i}. {s}") print() except Exception as e: print(f"Error generating tests: {e}") def _cmd_flavor(self, args: str): """Set the current flavor.""" if not args: manager = get_flavor_manager() flavors = manager.list_flavors() print("Available flavors:") for name, desc in flavors: marker = " (current)" if name == self.flavor else "" print(f" {name}{marker}: {desc}") return flavor_name = args.strip().lower() manager = get_flavor_manager() if manager.get_flavor(flavor_name): self.flavor = flavor_name print(f"Flavor set to: {flavor_name}") else: print(f"Unknown flavor: {flavor_name}") print("Available flavors: pcre, javascript, python") def _cmd_load(self, args: str): """Load a pattern from a file.""" if not args: print("Usage: load ") return filename = args.strip() if not os.path.exists(filename): print(f"File not found: {filename}") return try: with open(filename, 'r') as f: pattern = f.read().strip() print(f"Loaded pattern: {pattern}") if hasattr(self, '_last_pattern'): pass self._last_pattern = pattern except Exception as e: print(f"Error reading file: {e}") def _cmd_save(self, args: str): """Save a pattern to a file.""" if not args: print("Usage: save ") return pattern = getattr(self, '_last_pattern', None) if not pattern: print("No pattern to save. Use 'explain' or 'test' first.") return try: with open(args.strip(), 'w') as f: f.write(pattern) print(f"Saved pattern to: {args.strip()}") except Exception as e: print(f"Error writing file: {e}") def _cmd_history(self, args: str): """Show command history.""" print("Command history:") for i, cmd in enumerate(self.history[-50:], 1): print(f" {i:3}. {cmd}") def _cmd_clear(self, args: str): """Clear the screen.""" os.system('cls' if os.name == 'nt' else 'clear') def _cmd_example(self, args: str): """Show an example pattern.""" examples = [ r"^\\d{3}-\\d{4}$", r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", r"^(?:http|https)://[^\\s]+$", r"\\b\\d{4}-\\d{2}-\\d{2}\\b", r"(?i)(hello|hi|greetings)\\s+world!?", ] import random example = random.choice(examples) print(f"\\nExample pattern: {example}") print("\\nType: explain " + example) print("Type: test " + example) print() def _expand_pattern(self, pattern: str) -> str: """Expand a pattern from history or args.""" return pattern def start_interactive_mode(flavor: str = "pcre"): """Start the interactive mode.""" session = InteractiveSession(flavor=flavor) session.run()