"""Export aliases to various shell configuration formats.""" from abc import ABC, abstractmethod from dataclasses import dataclass from typing import List, Optional, Protocol from .command_analyzer import AliasSuggestion class ExportFormatter(ABC): """Abstract base class for export formatters.""" @abstractmethod def format_alias(self, suggestion: AliasSuggestion) -> str: """Format a single alias for export.""" pass @abstractmethod def format_header(self) -> str: """Format the file header.""" pass @abstractmethod def get_file_extension(self) -> str: """Return the file extension for this format.""" pass class BashFormatter(ExportFormatter): """Formatter for Bash alias syntax.""" def format_alias(self, suggestion: AliasSuggestion) -> str: escaped = suggestion.original_command.replace("'", "'\\''") return f"alias {suggestion.alias_name}='{escaped}'" def format_header(self) -> str: return "# Shell Aliases - Auto-generated by shell-alias-gen\n" \ "# Generated on: {date}\n\n".format( date=self._get_timestamp() ) def get_file_extension(self) -> str: return ".bash" def _get_timestamp(self) -> str: from datetime import datetime return datetime.now().strftime("%Y-%m-%d %H:%M:%S") class ZshFormatter(ExportFormatter): """Formatter for Zsh alias syntax.""" def format_alias(self, suggestion: AliasSuggestion) -> str: escaped = suggestion.original_command.replace("'", "'\\''") return f"alias {suggestion.alias_name}='{escaped}'" def format_header(self) -> str: return "# Shell Aliases - Auto-generated by shell-alias-gen\n" \ "# Generated on: {date}\n" \ "# Mode: extended_glob\n\n".format( date=self._get_timestamp() ) def get_file_extension(self) -> str: return ".zsh" def _get_timestamp(self) -> str: from datetime import datetime return datetime.now().strftime("%Y-%m-%d %H:%M:%S") class FishFormatter(ExportFormatter): """Formatter for Fish shell alias syntax.""" def format_alias(self, suggestion: AliasSuggestion) -> str: escaped = suggestion.original_command.replace("'", "'\\''") return f"alias {suggestion.alias_name}='{escaped}'" def format_header(self) -> str: return "# Shell Aliases - Auto-generated by shell-alias-gen\n" \ "# Generated on: {date}\n\n".format( date=self._get_timestamp() ) def get_file_extension(self) -> str: return ".fish" def _get_timestamp(self) -> str: from datetime import datetime return datetime.now().strftime("%Y-%m-%d %H:%M:%S") class GenericFormatter(ExportFormatter): """Generic formatter that can be used for any shell.""" def format_alias(self, suggestion: AliasSuggestion) -> str: return f"alias {suggestion.alias_name}='{suggestion.original_command}'" def format_header(self) -> str: return f"# Shell Aliases\n# Generated by shell-alias-gen\n\n" def get_file_extension(self) -> str: return ".sh" class ExportManager: """Manages exporting aliases to various formats.""" FORMATTERS = { 'bash': BashFormatter, 'zsh': ZshFormatter, 'fish': FishFormatter, 'generic': GenericFormatter, } def __init__(self): self._formatters: dict = {} def get_formatter(self, shell_type: str) -> ExportFormatter: """Get a formatter for the specified shell type.""" shell = shell_type.lower() if shell not in self.FORMATTERS: shell = 'generic' if shell not in self._formatters: self._formatters[shell] = self.FORMATTERS[shell]() return self._formatters[shell] def export( self, suggestions: List[AliasSuggestion], shell_type: str, output_path: Optional[str] = None ) -> str: """Export aliases to a string or file.""" formatter = self.get_formatter(shell_type) lines = [formatter.format_header()] for suggestion in suggestions: lines.append(formatter.format_alias(suggestion)) result = '\n'.join(lines) + '\n' if output_path: with open(output_path, 'w') as f: f.write(result) return result def export_to_rcfile( self, suggestions: List[AliasSuggestion], shell_type: str, rcfile_path: str ) -> bool: """Append aliases to an existing rc file.""" formatter = self.get_formatter(shell_type) section_header = f"\n# === Shell Aliases (shell-alias-gen) ===\n" aliases = [formatter.format_alias(s) for s in suggestions] content = section_header + '\n'.join(aliases) + '\n' try: with open(rcfile_path, 'a') as f: f.write(content) return True except Exception: return False def get_supported_formats(self) -> List[str]: """Return list of supported export formats.""" return list(self.FORMATTERS.keys())