diff --git a/shell_alias_gen/export_manager.py b/shell_alias_gen/export_manager.py new file mode 100644 index 0000000..af7edab --- /dev/null +++ b/shell_alias_gen/export_manager.py @@ -0,0 +1,173 @@ +"""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())