"""Template loader for gitignore-generator.""" import json import os from pathlib import Path from typing import Dict, List, Optional, Set from gitignore_generator.config import config class TemplateLoader: """Load and manage gitignore templates.""" def __init__(self): """Initialize template loader.""" self._templates_index: Optional[Dict] = None self._custom_templates: Dict[str, str] = {} def _load_templates_index(self) -> Dict: """Load the templates index file.""" if self._templates_index is None: index_path = config.template_dir / "templates.json" if index_path.exists(): with open(index_path, "r") as f: self._templates_index = json.load(f) else: self._templates_index = {"languages": [], "ides": [], "custom": []} return self._templates_index def _save_templates_index(self) -> None: """Save the templates index file.""" index_path = config.template_dir / "templates.json" with open(index_path, "w") as f: json.dump(self._templates_index, f, indent=2) def get_available_templates(self, category: Optional[str] = None) -> List[str]: """Get list of available templates.""" index = self._load_templates_index() self._load_custom_templates() if category: templates = index.get(category, []) if category == "languages": templates = templates + list(self._custom_templates.keys()) return sorted(set(templates)) else: all_templates = [] for cat in ["languages", "ides"]: all_templates.extend(index.get(cat, [])) all_templates = all_templates + list(self._custom_templates.keys()) return sorted(set(all_templates)) def get_templates_by_category(self) -> Dict[str, List[str]]: """Get all templates organized by category.""" index = self._load_templates_index() self._load_custom_templates() result = { "languages": index.get("languages", []), "ides": index.get("ides", []), "custom": list(self._custom_templates.keys()) } return result def _load_custom_templates(self) -> None: """Load custom templates from user config directory.""" if self._custom_templates: return custom_dir = config.custom_templates_dir if custom_dir.exists(): for template_file in custom_dir.glob("*.gitignore"): self._custom_templates[template_file.stem] = str(template_file) def load_template(self, template_name: str, category: Optional[str] = None) -> Optional[str]: """Load a template by name.""" self._load_custom_templates() if template_name in self._custom_templates: custom_path = Path(self._custom_templates[template_name]) if custom_path.exists(): with open(custom_path, "r") as f: return f.read() del self._custom_templates[template_name] if category: categories = [category] else: index = self._load_templates_index() categories = ["languages", "ides"] for cat in categories: template_path = config.template_dir / cat / f"{template_name}.gitignore" if template_path.exists(): with open(template_path, "r") as f: return f.read() return None def get_template_content(self, template_name: str) -> Optional[str]: """Get template content by name (searches all categories).""" return self.load_template(template_name) def save_custom_template(self, name: str, content: str) -> bool: """Save a custom template.""" custom_dir = config.custom_templates_dir try: custom_dir.mkdir(parents=True, exist_ok=True) except OSError: return False template_path = custom_dir / f"{name}.gitignore" try: with open(template_path, "w") as f: f.write(content) self._custom_templates[name] = str(template_path) return True except OSError: return False def delete_custom_template(self, name: str) -> bool: """Delete a custom template.""" if name not in self._custom_templates: return False template_path = Path(self._custom_templates[name]) try: if template_path.exists(): template_path.unlink() del self._custom_templates[name] return True except OSError: return False def template_exists(self, template_name: str) -> bool: """Check if a template exists.""" self._load_custom_templates() if template_name in self._custom_templates: return True for cat in ["languages", "ides"]: template_path = config.template_dir / cat / f"{template_name}.gitignore" if template_path.exists(): return True return False def search_templates(self, query: str) -> List[str]: """Search for templates matching query.""" query = query.lower() results = [] for template_name in self.get_available_templates(): if query in template_name.lower(): results.append(template_name) return results def merge_templates(self, template_names: List[str]) -> str: """Merge multiple templates into one.""" lines_seen: Set[str] = set() merged_lines = [] for template_name in template_names: content = self.get_template_content(template_name) if content: for line in content.splitlines(): line = line.strip() if line and not line.startswith("#"): normalized = line.rstrip("/") if normalized not in lines_seen: lines_seen.add(normalized) merged_lines.append(line) return "\n".join(sorted(set(merged_lines))) template_loader = TemplateLoader()