diff --git a/gitignore_generator/template_loader.py b/gitignore_generator/template_loader.py new file mode 100644 index 0000000..6ba74d4 --- /dev/null +++ b/gitignore_generator/template_loader.py @@ -0,0 +1,179 @@ +"""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()