Initial upload: Shell History Alias Generator with full test suite
Some checks failed
CI / test (push) Has been cancelled
Some checks failed
CI / test (push) Has been cancelled
This commit is contained in:
173
shell_alias_gen/export_manager.py
Normal file
173
shell_alias_gen/export_manager.py
Normal file
@@ -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())
|
||||||
Reference in New Issue
Block a user