#!/usr/bin/env python3 """ Claude Filter Vim Plugin - Automatic Installation Script Detects Vim/Neovim installation and installs the plugin with proper handling for existing installations (updates/overrides). Features: - Auto-detects Vim vs Neovim - Auto-detects config directory - Installs both Lua (Neovim) and VimScript (Vim) versions - Handles existing installations (updates) - Cross-platform (Linux, macOS, Windows) """ import os import sys import shutil import argparse from pathlib import Path class PluginInstaller: def __init__(self, verbose=False, override=False): self.verbose = verbose self.override = override self.installed = [] self.errors = [] def log(self, message, level="INFO"): """Log messages if verbose mode is enabled""" if self.verbose or level in ["ERROR", "SUCCESS"]: prefix = "✅" if level == "SUCCESS" else "❌" if level == "ERROR" else "ℹ️" print(f"{prefix} [{level}] {message}") def check_editor_installed(self): """Check which editors are installed""" editors = {} # Check Neovim if shutil.which("nvim"): editors["neovim"] = True self.log("Neovim detected") else: editors["neovim"] = False self.log("Neovim not found", "WARN") # Check Vim if shutil.which("vim"): editors["vim"] = True self.log("Vim detected") else: editors["vim"] = False self.log("Vim not found", "WARN") return editors def get_neovim_config_dir(self): """Get Neovim config directory (works on all platforms)""" # Check XDG_CONFIG_HOME first (Linux/macOS) xdg_config = os.environ.get("XDG_CONFIG_HOME") if xdg_config: nvim_dir = Path(xdg_config) / "nvim" if nvim_dir.exists(): return nvim_dir # Check standard locations home = Path.home() # macOS if sys.platform == "darwin": nvim_dir = home / ".config" / "nvim" if nvim_dir.exists(): return nvim_dir # Linux if sys.platform.startswith("linux"): nvim_dir = home / ".config" / "nvim" if nvim_dir.exists(): return nvim_dir # Windows if sys.platform == "win32": # Try AppData first appdata = os.environ.get("APPDATA") if appdata: nvim_dir = Path(appdata) / "nvim" if nvim_dir.exists(): return nvim_dir # Try local AppData local_appdata = os.environ.get("LOCALAPPDATA") if local_appdata: nvim_dir = Path(local_appdata) / "nvim" if nvim_dir.exists(): return nvim_dir # Fallback: Create in ~/.config/nvim return home / ".config" / "nvim" def get_vim_config_dir(self): """Get Vim config directory""" home = Path.home() # Check for .vim directory vim_dir = home / ".vim" if vim_dir.exists(): return vim_dir # Windows: check vimfiles if sys.platform == "win32": vimfiles = home / "vimfiles" if vimfiles.exists(): return vimfiles # Default to .vim return vim_dir def install_neovim_plugin(self): """Install Lua version for Neovim""" self.log("Installing Neovim plugin...") nvim_dir = self.get_neovim_config_dir() plugin_dir = nvim_dir / "plugin" # Create directory if it doesn't exist plugin_dir.mkdir(parents=True, exist_ok=True) # Source and destination source = Path(__file__).parent / "plugin" / "claude_filter.lua" destination = plugin_dir / "claude_filter.lua" if not source.exists(): self.log(f"Source file not found: {source}", "ERROR") self.errors.append(f"Neovim: Source file not found") return False # Check if already installed if destination.exists(): if not self.override: self.log(f"Already installed at {destination}") self.log("Use --override to update") return True else: self.log(f"Removing existing: {destination}") destination.unlink() # Copy file try: shutil.copy2(source, destination) self.log(f"✅ Installed to {destination}", "SUCCESS") self.installed.append(("Neovim", destination)) return True except Exception as e: self.log(f"Failed to copy: {e}", "ERROR") self.errors.append(f"Neovim: {str(e)}") return False def install_vim_plugin(self): """Install VimScript version for Vim""" self.log("Installing Vim plugin...") vim_dir = self.get_vim_config_dir() plugin_dir = vim_dir / "plugin" # Create directory if it doesn't exist plugin_dir.mkdir(parents=True, exist_ok=True) # Source and destination source = Path(__file__).parent / "plugin" / "claude_filter.vim" destination = plugin_dir / "claude_filter.vim" if not source.exists(): self.log(f"Source file not found: {source}", "ERROR") self.errors.append(f"Vim: Source file not found") return False # Check if already installed if destination.exists(): if not self.override: self.log(f"Already installed at {destination}") self.log("Use --override to update") return True else: self.log(f"Removing existing: {destination}") destination.unlink() # Copy file try: shutil.copy2(source, destination) self.log(f"✅ Installed to {destination}", "SUCCESS") self.installed.append(("Vim", destination)) return True except Exception as e: self.log(f"Failed to copy: {e}", "ERROR") self.errors.append(f"Vim: {str(e)}") return False def install(self): """Main installation logic""" self.log("=" * 60) self.log("Claude Filter Vim Plugin - Installer", "SUCCESS") self.log("=" * 60) # Check what's installed editors = self.check_editor_installed() if not any(editors.values()): self.log("Neither Vim nor Neovim found on this system", "ERROR") self.log("Install one of them first:") self.log(" - Neovim: https://neovim.io") self.log(" - Vim: https://www.vim.org") return False success = True # Install for Neovim if editors["neovim"]: if not self.install_neovim_plugin(): success = False # Install for Vim if editors["vim"]: if not self.install_vim_plugin(): success = False # Summary self.log("=" * 60) if self.installed: self.log("Installation Summary:", "SUCCESS") for editor, path in self.installed: self.log(f" {editor}: {path}") if self.errors: self.log("Errors encountered:", "ERROR") for error in self.errors: self.log(f" - {error}") self.log("=" * 60) # Usage instructions if self.installed: self.log("\n✅ Installation successful!\n", "SUCCESS") self.log("Usage:") self.log(" 1. Select text in visual mode (V + arrows)") self.log(" 2. Press a (usually comma+a)") self.log(" 3. Enter your instruction") self.log(" 4. Text is transformed instantly") self.log("\nDocumentation:") self.log(" - Quick start: QUICK_START.md") self.log(" - Detailed setup: SETUP.md") self.log(" - Test cases: TEST_CASES.md") self.log(" - Technical details: TECHNICAL.md") return True else: self.log("Installation failed", "ERROR") return False def verify_installation(self): """Verify that plugin files exist and are readable""" self.log("\nVerifying installation...") all_good = True for editor, path in self.installed: if path.exists() and path.is_file(): size = path.stat().st_size self.log(f"✓ {editor} plugin verified ({size} bytes)") else: self.log(f"✗ {editor} plugin not found at {path}", "ERROR") all_good = False return all_good def main(): parser = argparse.ArgumentParser( description="Install Claude Filter Vim plugin", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: python3 install.py # Install with auto-detection python3 install.py --verbose # Show detailed output python3 install.py --override # Update existing installation python3 install.py -v -o # Both verbose and override """ ) parser.add_argument( "-v", "--verbose", action="store_true", help="Show detailed installation messages" ) parser.add_argument( "-o", "--override", action="store_true", help="Override existing installation (update)" ) parser.add_argument( "--verify", action="store_true", help="Only verify existing installation" ) args = parser.parse_args() installer = PluginInstaller(verbose=args.verbose, override=args.override) if args.verify: installer.install() installer.verify_installation() else: success = installer.install() if success: installer.verify_installation() sys.exit(0) else: sys.exit(1) if __name__ == "__main__": main()