"""Interactive mode for gitignore-generator.""" from typing import List, Optional, Tuple import click from gitignore_generator.template_loader import template_loader from gitignore_generator.validator import validator def show_preview(content: str) -> None: """Show preview of gitignore content.""" click.echo("\n--- Preview ---") lines = content.splitlines() for i, line in enumerate(lines[:30], 1): click.echo(f"{i:3} | {line}") if len(lines) > 30: click.echo(f"... and {len(lines) - 30} more lines") click.echo("-------------\n") def prompt_category() -> str: """Prompt user to select template category.""" categories = template_loader.get_templates_by_category() category_options = [] for cat in ["languages", "ides"]: if categories.get(cat): category_options.append(cat.capitalize()) category_options.append("Custom") click.echo("\nSelect category:") for i, cat in enumerate(category_options, 1): click.echo(f" {i}. {cat}") choice = click.prompt("Enter choice", type=int, default=1) if 1 <= choice <= len(category_options): selected = category_options[choice - 1] if selected == "Custom": return "custom" return selected.lower() return "languages" def prompt_templates(category: str) -> List[str]: """Prompt user to select templates.""" templates = template_loader.get_available_templates(category) if not templates: return [] click.echo(f"\n{category.capitalize()} templates (select multiple, comma-separated):") for i, template in enumerate(templates[:20], 1): click.echo(f" {i}. {template}") if len(templates) > 20: click.echo(f" ... and {len(templates) - 20} more") click.echo(" 0. None/Skip") choices = click.prompt("Enter template numbers", type=str, default="") selected = [] if choices.strip(): try: nums = [int(x.strip()) for x in choices.split(",")] for num in nums: if 1 <= num <= len(templates): selected.append(templates[num - 1]) except ValueError: pass return selected def prompt_custom_patterns() -> List[str]: """Prompt user for custom patterns.""" patterns = [] click.echo("\nAdd custom patterns (one per line, empty to finish):") while True: pattern = click.prompt("Pattern", default="", show_default=False).strip() if not pattern: break if pattern.startswith("#"): click.echo(" Skipping comment line") continue issue = validator.validate_pattern(pattern) if issue: click.echo(f" Warning: {issue.message}") if not click.confirm("Add anyway?"): continue patterns.append(pattern) return patterns def prompt_output_file() -> str: """Prompt user for output file name.""" return click.prompt("Output file", default=".gitignore", show_default=True) def run_interactive_wizard() -> Optional[Tuple[str, str]]: """Run the interactive wizard.""" try: click.echo("=== Gitignore Generator - Interactive Mode ===") category = prompt_category() selected_templates = [] if category != "custom": selected_templates = prompt_templates(category) custom_patterns = prompt_custom_patterns() if not selected_templates and not custom_patterns: click.echo("\nNo templates or patterns selected. Aborting.") return None content_parts = [] for template_name in selected_templates: template_content = template_loader.get_template_content(template_name) if template_content: content_parts.append(f"# --- {template_name} ---\n") content_parts.append(template_content) content_parts.append("\n") if custom_patterns: content_parts.append("# --- Custom Patterns ---\n") content_parts.extend(custom_patterns) content_parts.append("\n") final_content = "".join(content_parts).rstrip() + "\n" show_preview(final_content) if click.confirm("Do you want to edit the patterns?"): final_content = edit_content_interactive(final_content) output_file = prompt_output_file() return final_content, output_file except KeyboardInterrupt: click.echo("\n\nAborted by user.") return None except EOFError: click.echo("\n\nInput stream closed. Exiting.") return None def edit_content_interactive(content: str) -> str: """Allow interactive editing of content.""" lines = content.splitlines() click.echo("\nEdit mode (empty line number to finish editing):") click.echo(" Commands: 'add ', 'delete ', 'show', 'save'") while True: cmd = click.prompt("Edit command", default="save", show_default=False).strip().lower() if cmd == "save" or not cmd: break if cmd.startswith("add "): pattern = cmd[4:].strip() if pattern: lines.append(pattern) click.echo(f"Added: {pattern}") elif cmd.startswith("delete "): try: line_num = int(cmd[7:].strip()) if 1 <= line_num <= len(lines): deleted = lines.pop(line_num - 1) click.echo(f"Deleted line {line_num}: {deleted}") else: click.echo("Invalid line number") except ValueError: click.echo("Invalid command") elif cmd == "show": show_preview("\n".join(lines)) else: click.echo("Unknown command. Use: add , delete , show, save") return "\n".join(lines) + "\n" def run_simple_interactive() -> None: """Run a simple interactive session.""" result = run_interactive_wizard() if result: content, output_file = result try: with open(output_file, "w") as f: f.write(content) click.echo(f"\nSuccessfully wrote .gitignore to '{output_file}'") except IOError as e: click.echo(f"\nError writing file: {e}")