diff --git a/README.md b/README.md index 9260d7b..f483f66 100755 --- a/README.md +++ b/README.md @@ -24,34 +24,31 @@ Now you can configure only what you need by forking nvpak without any add-ons. P ## Requirements 📋 -To ensure the installation scripts and NvPak work correctly, please have the following: +To ensure NvPak installs and works correctly, please have the following: - **Operating System:** - Linux (most distributions) - macOS - - Windows 10/11 (with PowerShell 5.1+) - - Android (via Termux) -- **Core Tools (the scripts will attempt to install these if missing):** - - `git` - - `curl` - - `unzip` - - `neovim v0.8.0` or later (the script aims for the latest stable version) + - Windows 10/11 (with PowerShell 5.1+ for the installer) + - Android (via Termux, using the Linux installer) +- **Core Prerequisites (the main `install.sh` or `install.ps1` scripts will attempt to install these):** + - `git` (version 2.19.0+ recommended for some plugin manager features) + - `neovim v0.8.0` or later (LuaJIT build required) - **Shell:** - - `bash` or `dash` for Unix-like systems (Linux, macOS, Termux, Git Bash on Windows). - - `PowerShell v5.1` or later for the native Windows installation script. -- **Recommended for full functionality (the scripts will attempt to install these):** - - `ripgrep` (for Telescope live grep) - - `fd` (alternative for Telescope) + - `bash` (or a compatible shell like `zsh`, `dash`) for Unix-like systems. + - `PowerShell v5.1` or later for the native Windows installation script (`install.ps1`). +- **Recommended for full functionality (the NvPak Lua installer will guide you or check for these):** + - `ripgrep` (for Telescope live grep and other search functionalities) + - `fd` (a fast alternative to `find`, used by Telescope) - Clipboard tools: - - Linux: `xclip` or `xsel` (Xorg), `wl-clipboard` (Wayland) - - macOS: `pbcopy`/`pbpaste` (built-in) - - Windows: Handled by Neovim/win32yank (often auto-installed or installable via `scoop install win32yank`) - - Termux: `termux-api` (for `termux-clipboard-get`/`set`) - - `pynvim` (if you are a Python developer) -- **For Windows Native Installation:** - - `Scoop.sh` package manager. The script can help you install it. -- **Important for UI:** - - **Nerd Fonts:** Install a [Nerd Font](https://www.nerdfonts.com/) and set it as your terminal's font for proper icon display. + - Linux: `xclip` or `xsel` (for X11), `wl-clipboard` (for Wayland) + - macOS: `pbcopy`/`pbpaste` (usually built-in) + - Windows: `win32yank` (installable via `scoop install win32yank`; Neovim might have fallbacks) + - `pynvim` (Python 3 bindings for Neovim, if you are a Python developer) +- **For Windows Native Installation (`install.ps1`):** + - `Scoop.sh` package manager is highly recommended. The script will offer to install it if not found. +- **Crucial for UI:** + - **Nerd Fonts:** To display icons and symbols correctly, you **must** install a [Nerd Font](https://www.nerdfonts.com/font-downloads) and configure your terminal emulator to use it. Popular choices include FiraCode Nerd Font, JetBrainsMono Nerd Font, and Hack Nerd Font. The Lua installer will remind you about this. ### Screenshots 📷 @@ -79,13 +76,11 @@ Show # Installation 💻 -NvPak provides automated installation scripts for various operating systems. +NvPak provides streamlined installation scripts that handle core dependencies and then delegate to an internal Lua-based installer for further setup. -## Prerequisites - -Before running the installation scripts, ensure you have: -- **Internet connection:** To download dependencies and the NvPak repository. -- **Permissions:** You might need administrative/sudo rights to install some packages. +**General Prerequisites for Installation Scripts:** +- **Internet connection:** Required to download dependencies and the NvPak repository. +- **Permissions:** You might need administrative/sudo rights to install system-level packages like Git or Neovim if they are not already present. ## Linux / macOS / Android (Termux) / Unix-like shells on Windows (Git Bash, WSL) @@ -102,13 +97,20 @@ Before running the installation scripts, ensure you have: ```bash ./install.sh ``` - The script will attempt to detect your OS and package manager to install all necessary dependencies, clone/update NvPak to `~/.config/nvim` (or `$XDG_CONFIG_HOME/nvim`), and guide you through the final steps. + This script will: + - Attempt to detect your OS and package manager. + - Ensure `git` and `neovim` are installed, prompting for installation if missing. + - Clone or update NvPak to `~/.config/nvim` (or `$XDG_CONFIG_HOME/nvim`). + - Launch Neovim headlessly to run the NvPak Lua installer, which will: + - Check for recommended secondary dependencies (like `ripgrep`, `fd`, `pynvim`, clipboard tools) and guide you if any are missing. + - Guide you on installing Nerd Fonts. + - Synchronize and install all configured plugins using `lazy.nvim` (via `rocks.nvim`). ## Windows (Native PowerShell) -1. **Open PowerShell as Administrator.** This is highly recommended to ensure Scoop and other dependencies can be installed or configured correctly. +1. **Open PowerShell.** Running as Administrator is recommended if you anticipate needing to install Scoop or other system-level tools. 2. **Set Execution Policy (if needed):** - If you haven't run PowerShell scripts from the internet before, you might need to allow script execution for the current user: + If you haven't run PowerShell scripts from the internet before, you might need to allow script execution: ```powershell Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force ``` @@ -117,34 +119,101 @@ Before running the installation scripts, ensure you have: Invoke-WebRequest -Uri "https://raw.githubusercontent.com/Pakrohk-DotFiles/NvPak/main/install.ps1" -OutFile "install.ps1" .\install.ps1 ``` - The script will use Scoop to install dependencies (it will offer to install Scoop itself if not found), clone/update NvPak to `~\AppData\Local\nvim`, and prepare Neovim for first use. - *Note: If Scoop is installed for the first time by the script, you will be prompted to open a new PowerShell window and re-run `.\install.ps1` for the PATH changes (especially for Scoop itself) to take effect.* + This script will: + - Offer to install `Scoop.sh` if it's not found (Scoop is used to install `git` and `neovim`). + - Ensure `git` and `neovim` are installed. + - Clone or update NvPak to `~\AppData\Local\nvim`. + - Launch Neovim headlessly to run the NvPak Lua installer (with the same responsibilities as mentioned in the Linux section). + *Note: If Scoop is installed for the first time by the script, you will be prompted to open a new PowerShell window and re-run `.\install.ps1` for the PATH changes to take effect.* -## Post-Installation Steps +## Post-Installation Essentials -After the script finishes: -1. **Nerd Fonts:** Crucial for UI icons. Ensure you have a [Nerd Font](https://www.nerdfonts.com/) installed and **set as your terminal's font**. The installation script will remind you, but the font configuration is manual. -2. **First Neovim Run:** The installation script will attempt to run Neovim once (often headlessly) to finalize plugin installations via `rocks.nvim`. You might see messages from `rocks.nvim` about installing plugins. Please wait for this process to complete. If you open Neovim manually for the first time, this process will also occur. -3. **Restart Terminal (Recommended):** After new tools are installed (especially by Scoop or system package managers), it's a good idea to restart your terminal or source your shell's configuration file (e.g., `.bashrc`, `.zshrc`) for all PATH changes to apply. +1. **Nerd Fonts:** This is crucial for a proper UI experience with icons. If you haven't already, install a [Nerd Font](https://www.nerdfonts.com/font-downloads) and **set it as your terminal's display font**. The Lua installer will remind you, but the font configuration in your terminal is a manual step. +2. **Restart Terminal (Recommended):** Especially if new tools like Neovim, Git, or Scoop were installed, restarting your terminal ensures all PATH changes are correctly applied. # Usage 🚀 -Once NvPak is installed: - -1. **Open Neovim:** - ```bash - nvim +Once NvPak is installed, simply open Neovim: +```bash +nvim +``` +All configured plugins should be installed and ready to use. + +## Managing NvPak with the `nvpak` CLI + +NvPak now includes a command-line interface (CLI) tool named `nvpak` to help you manage your NvPak installation and plugins from outside Neovim. + +**Setup for `nvpak` CLI:** + +The `nvpak` CLI scripts (`nvpak.sh` for Linux/macOS, `nvpak.ps1` for Windows) are located in the `scripts/` directory within your NvPak configuration folder (e.g., `~/.config/nvim/scripts`). The main installation scripts attempt to make these CLI tools easily accessible: + +* **Linux/macOS (`install.sh`):** + The `install.sh` script will try to copy `nvpak.sh` to: + 1. `~/.local/bin/nvpak` (if `~/.local/bin` exists and is in your PATH). + 2. Or, `/usr/local/bin/nvpak` (it may ask for `sudo` permission if needed and not already running as root). + If successful, the `nvpak` command should be available after opening a new terminal session. If automatic installation fails, the script will provide manual instructions (e.g., creating a symlink or copying the script to a directory in your PATH). + +* **Windows (`install.ps1`):** + The `install.ps1` script will: + 1. Copy `nvpak.ps1` to `$env:LOCALAPPDATA\NvPak\bin\nvpak.ps1`. + 2. Provide you with PowerShell commands to add the `$env:LOCALAPPDATA\NvPak\bin` directory to your User PATH environment variable. + You **must** run these provided commands and then **open a new PowerShell window** for the `nvpak` command to be recognized. + +**Manual Setup (If Needed):** + +If the automatic setup by the installers doesn't work for your environment, or if you prefer a manual setup: +1. Ensure the NvPak `scripts` directory (e.g., `~/.config/nvim/scripts` or `~\AppData\Local\nvim\scripts`) is added to your system's PATH environment variable. +2. Alternatively, you can copy or create symbolic links for `nvpak.sh` (or `nvpak.ps1`) into a directory that is already in your PATH (e.g., `~/.local/bin` for Linux/macOS). + * Example for Linux/macOS symlink: + ```bash + mkdir -p ~/.local/bin + ln -sfn "$HOME/.config/nvim/scripts/nvpak.sh" "$HOME/.local/bin/nvpak" + ``` + Ensure the script is executable (`chmod +x ~/.local/bin/nvpak`). + +**CLI Commands:** + +* `nvpak help`: Displays the help message with all available commands. +* `nvpak install `: + * **Note:** Fully automated installation by modifying configuration files is complex and **not yet implemented**. + * This command will currently guide you to manually add the plugin to your NvPak plugin configuration (e.g., `rocks.toml` or relevant Lua files). + * After manual addition, run `nvpak refresh` to synchronize. +* `nvpak uninstall `: + * **Note:** Similar to `install`, fully automated uninstallation is **not yet implemented**. + * This command will guide you to manually remove the plugin from your configuration. + * After manual removal, run `nvpak refresh` to synchronize and clean. +* `nvpak update [plugin-name]`: Updates a specific plugin if `plugin-name` is provided, or all installed plugins if no name is given. +* `nvpak upgrade`: A convenient alias to update all installed plugins. +* `nvpak refresh`: Synchronizes your plugin state with `lazy.nvim` based on your current configuration. Use this after manually adding or removing plugins from your config files. +* `nvpak fetch`: Fetches the latest updates for NvPak itself from its Git repository (i.e., runs `git pull` in the NvPak directory). + +**CLI Aliases:** + +You can define short aliases for `nvpak` commands. +1. Create the alias configuration file: + * Linux/macOS: `~/.config/nvpak/aliases.conf` (or `$XDG_CONFIG_HOME/nvpak/aliases.conf`) + * Windows: `~\AppData\Local\nvpak\aliases.conf` +2. Add aliases in the format `alias_name=command_name`. Example: + ```ini + # Example aliases.conf + in=install + rm=uninstall + up=update + ug=upgrade + sy=refresh # sy for sync + fp=fetch # fp for fetch pak ``` -2. **Plugin Management (with rocks.nvim):** - NvPak uses [rocks.nvim](https://github.com/nvim-neorocks/rocks.nvim) for plugin management, defined in the `rocks.toml` file. - - Plugins are automatically installed or updated by `rocks.nvim` when Neovim starts if there are changes to `rocks.toml` or if new plugins are added. - - The installation script already triggers this initial plugin setup. - - You generally don't need to manually sync plugins. However, if you modify `rocks.toml` or want to force a sync/update, you can use commands within Neovim: - - `:Rocks sync` - Installs any missing plugins, updates plugins marked as `scm` or those with newer version constraints. - - `:Rocks update []` - Updates a specific plugin or all plugins to their latest allowed versions. - - `:Rocks clean` - Removes any installed plugins that are no longer listed in `rocks.toml`. - - `:Rocks build []` - To rebuild a specific plugin if needed. - - Refer to the `rocks.nvim` documentation for more commands and details. + An example file `scripts/nvpak_aliases.conf.example` is provided in the NvPak repository. + +## Plugin Management within Neovim (via rocks.nvim & lazy.nvim) + +NvPak uses [rocks.nvim](https://github.com/nvim-neorocks/rocks.nvim) which in turn utilizes [lazy.nvim](https://github.com/folke/lazy.nvim) for plugin management. Plugins are primarily defined in `rocks.toml`. +- `lazy.nvim` automatically installs missing plugins and updates them based on the lockfile (`lazy-lock.json`) or plugin specifications during startup. +- You can also manage plugins from within Neovim using `lazy.nvim` commands: + - `:Lazy` or `:Lazyui`: Opens the `lazy.nvim` user interface. + - `:Lazy sync`: Synchronizes plugins (installs missing, cleans unused). + - `:Lazy update [plugin_name]`: Updates plugins. + - Refer to the `lazy.nvim` documentation for more commands. Enjoy your clean and powerful Neovim setup! diff --git a/install.ps1 b/install.ps1 index defdfc7..a0cdecc 100644 --- a/install.ps1 +++ b/install.ps1 @@ -2,37 +2,29 @@ <# .SYNOPSIS - Installs NvPak, a Neovim configuration, and its dependencies on Windows. + Installs NvPak, a Neovim configuration, on Windows. .DESCRIPTION - This script automates the installation of Neovim, Git, Curl, Unzip, Ripgrep, Fd, - and other necessary tools using Scoop package manager. It then clones or updates - the NvPak configuration from GitHub. + This script ensures Git and Neovim are installed (using Scoop if available), + clones or updates the NvPak configuration from GitHub, and then triggers + the Lua-based NvPak installer. .NOTES - Author: Jules (AI Assistant) + Author: Jules (AI Assistant) & Pakrohk License: Apache 2.0 (Same as NvPak) #> # --- Configuration --- $NvPakRepoUrl = "https://github.com/Pakrohk-DotFiles/NvPak.git" -$NvimConfigDir = "$env:LOCALAPPDATA\nvim" +$NvimConfigDir = "$env:LOCALAPPDATA\nvim" # Standard Neovim config directory on Windows +$NvPakInstallerLuaModule = "nvpak.core.installer" # Lua module to run, e.g., require('nvpak.core.installer').init() # --- Helper Functions --- function Print-Message($message, $color) { Write-Host $message -ForegroundColor $color } -function Info($message) { - Print-Message "INFO: $message" "Cyan" -} - -function Success($message) { - Print-Message "SUCCESS: $message" "Green" -} - -function Warning($message) { - Print-Message "WARNING: $message" "Yellow" -} - +function Info($message) { Print-Message "INFO: $message" "Cyan" } +function Success($message) { Print-Message "SUCCESS: $message" "Green" } +function Warning($message) { Print-Message "WARNING: $message" "Yellow" } function Error-Exit($message) { Print-Message "ERROR: $message" "Red" exit 1 @@ -42,171 +34,222 @@ function Command-Exists($command) { return (Get-Command $command -ErrorAction SilentlyContinue) -ne $null } +# --- Prerequisite Installation --- function Install-Scoop { Info "Scoop package manager not found." - $confirmation = Read-Host "Do you want to install Scoop? (Required for automatic dependency installation) (y/N)" + $confirmation = Read-Host "Do you want to install Scoop? (Recommended for automatic Git/Neovim installation) (y/N)" if ($confirmation -eq 'y') { Info "Installing Scoop..." try { Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force Invoke-RestMethod -Uri get.scoop.sh | Invoke-Expression Success "Scoop installed successfully." - Info "Please open a new PowerShell terminal and re-run this script to continue with NvPak installation." - Info "Scoop adds itself to your PATH, which requires a new terminal session to take effect." - exit 0 # Exit so user can restart + Info "IMPORTANT: Scoop has been installed and added to your PATH." + Info "Please OPEN A NEW PowerShell terminal and RE-RUN this script to continue." + exit 0 # Exit so user can restart in a new shell where scoop is in PATH } catch { - Error-Exit "Failed to install Scoop. Please install it manually from https://scoop.sh/ and re-run this script." + Error-Exit "Failed to install Scoop. Please install it manually from https://scoop.sh/ and ensure Git and Neovim are also installed, then re-run this script." } } else { - Error-Exit "Scoop installation declined. Cannot proceed with automatic dependency installation." + Warning "Scoop installation declined. Proceeding with checks for existing Git/Neovim." + Warning "If Git or Neovim are not found, you will need to install them manually." } } -function Install-Package($packageName, [switch]$NoUpdate) { - Info "Checking for $packageName..." - if (-not (Command-Exists $packageName.Split(' ')[0])) { # Check for the command itself, not the scoop package name if different - Info "Installing $packageName via Scoop..." - try { - if (-not $NoUpdate) { - Info "Updating Scoop before installing $packageName..." - scoop update $packageName -ErrorAction Stop - } - scoop install $packageName -ErrorAction Stop - Success "$packageName installed successfully." - } - catch { - Warning "Failed to install $packageName via Scoop. Please try installing it manually: 'scoop install $packageName'" - # Optionally, make this an Error-Exit if the package is critical - } +function Install-Prerequisites { + $scoopAvailable = Command-Exists "scoop" + if (-not $scoopAvailable) { + Install-Scoop # This might exit if user installs scoop + $scoopAvailable = Command-Exists "scoop" # Re-check in case user declined but scoop was already there somehow } - else { - Info "$packageName is already installed." + + if ($scoopAvailable) { + Info "Scoop is available. Updating Scoop buckets..." + scoop update # Update all buckets + } else { + Info "Scoop not found or installation declined. Will check for manual installations of Git and Neovim." } -} -# --- Main Logic --- -function Main { - Info "Starting NvPak installation for Windows..." + $packagesToInstall = @() + # Check for Git + Info "Checking for Git..." + if (-not (Command-Exists "git")) { + Info "Git not found." + if ($scoopAvailable) { $packagesToInstall += "git" } + else { Error-Exit "Git not found. Please install Git manually (e.g., from https://git-scm.com/download/win) and re-run this script." } + } else { + Info "Git is installed." + } - # Check for Scoop - if (-not (Command-Exists "scoop")) { - Install-Scoop + # Check for Neovim + Info "Checking for Neovim (nvim)..." + if (-not (Command-Exists "nvim")) { + Info "Neovim (nvim) not found." + if ($scoopAvailable) { $packagesToInstall += "neovim" } + else { Error-Exit "Neovim (nvim) not found. Please install Neovim manually (e.g., from https://neovim.io/) and re-run this script." } } else { - Info "Scoop is installed." - Info "Updating Scoop itself..." - scoop update scoop # Update scoop itself first + Info "Neovim is installed." } - # Install core dependencies using Scoop - Info "Installing core dependencies (Git, Curl, Unzip, Neovim)..." - Install-Package "git" - Install-Package "curl" - Install-Package "unzip" # 7zip provides unzip capabilities and is more common with scoop - Install-Package "neovim" - - # Install additional tools - Info "Installing additional tools (ripgrep, fd)..." - Install-Package "ripgrep" - Install-Package "fd" - # Clipboard on Windows is generally handled by Neovim's integration with win32yank (often bundled or installed by LSP/plugins) - # Or users can install win32yank via scoop: scoop install win32yank - - # Pynvim (optional, for Python devs) - if (Command-Exists "pip3") { - Info "Checking for pynvim (Python 3)..." - $pynvim_check = python3 -m pynvim -c "import sys; sys.exit(0)" 2>&1 - if ($LASTEXITCODE -ne 0) { - Info "pynvim (Python 3) not found. Installing..." - pip3 install --user pynvim - if ($LASTEXITCODE -ne 0) { - Warning "Failed to install pynvim with pip3. Python integration might not work." - } else { - Success "pynvim installed." + if ($packagesToInstall.Count -gt 0 -and $scoopAvailable) { + Info "Attempting to install missing prerequisites via Scoop: $($packagesToInstall -join ', ')" + foreach ($pkg in $packagesToInstall) { + Info "Installing $pkg via Scoop..." + try { + scoop install $pkg -ErrorAction Stop + Success "$pkg installed successfully via Scoop." } - } else { - Info "pynvim (Python 3) is already installed." - } - } - elseif (Command-Exists "pip") { - Info "Checking for pynvim (Python)..." - $pynvim_check = python -m pynvim -c "import sys; sys.exit(0)" 2>&1 - if ($LASTEXITCODE -ne 0) { - Info "pynvim (Python) not found. Installing..." - pip install --user pynvim - if ($LASTEXITCODE -ne 0) { - Warning "Failed to install pynvim with pip. Python integration might not work." - } else { - Success "pynvim installed." + catch { + Error-Exit "Failed to install $pkg via Scoop. Please install it manually and re-run this script. Scoop error: $($_.Exception.Message)" } - } else { - Info "pynvim (Python) is already installed." } + } elseif ($packagesToInstall.Count -gt 0 -and (-not $scoopAvailable)) { + # This case should have been caught by earlier Error-Exits if Scoop was declined and tools were missing. + Error-Exit "Prerequisites missing and Scoop is not available for automatic installation. Please install manually." } else { - Warning "pip/pip3 not found. Cannot install pynvim automatically. If you are a Python developer, please install it manually." + Info "All prerequisites (Git, Neovim) are already installed or were installed." } + # Final check + if (-not (Command-Exists "git")) { Error-Exit "Git is required but could not be installed/found. Please install Git manually." } + if (-not (Command-Exists "nvim")) { Error-Exit "Neovim (nvim) is required but could not be installed/found. Please install Neovim manually." } + Success "Git and Neovim are available." +} + + +# --- Main Logic --- +function Main { + Info "Starting NvPak installation for Windows..." + + Install-Prerequisites + # Clone or update NvPak repository Info "Setting up NvPak configuration directory: $NvimConfigDir" - if (Test-Path $NvimConfigDir) { - Info "NvPak directory already exists. Checking for updates..." + $gitDir = Join-Path $NvimConfigDir ".git" + + if (Test-Path $gitDir) { + Info "NvPak directory already exists and is a git repository. Checking for updates..." Push-Location $NvimConfigDir - if (Test-Path ".git") { + try { $currentRemote = git remote get-url origin - if ($currentRemote -eq $NvPakRepoUrl) { - Info "Pulling latest changes from NvPak repository..." + if ($currentRemote -match [regex]::Escape($NvPakRepoUrl)) { # Use -match for flexibility (http vs https) + Info "Pulling latest changes from NvPak repository ($NvPakRepoUrl)..." git pull if ($LASTEXITCODE -ne 0) { - Warning "Failed to pull latest changes. Your configuration might be outdated." + Warning "Failed to pull latest NvPak changes. Your configuration might be outdated or you have local changes." + Warning "Attempting to continue. If issues arise, consider a fresh clone after backing up." + } else { + Success "NvPak updated successfully." } } else { - Warning "The existing directory $NvimConfigDir is a git repository, but not for NvPak ($currentRemote)." - Warning "Please move or backup your existing Neovim configuration and re-run the script." - Error-Exit "Installation aborted due to existing non-NvPak git repository." + Warning "The existing directory $NvimConfigDir is a git repository, but not for NvPak." + Warning "Current remote: $currentRemote" + Warning "Expected remote: $NvPakRepoUrl" + Error-Exit "Please backup/move your existing Neovim config from $NvimConfigDir and re-run." } } - else { - Warning "$NvimConfigDir exists but is not a git repository. It might be an old NvPak install or a custom config." + catch { + Error-Exit "Error while checking git repository in $NvimConfigDir: $($_.Exception.Message)" + } + finally { + Pop-Location + } + } + elseif (Test-Path $NvimConfigDir -PathType Container) { + # Directory exists but not a .git repo, or .git is not a directory + # Check if it's empty + if ((Get-ChildItem -Path $NvimConfigDir -Force | Measure-Object).Count -eq 0) { + Info "$NvimConfigDir exists but is empty. Cloning NvPak..." + git clone --depth 1 $NvPakRepoUrl $NvimConfigDir + if ($LASTEXITCODE -ne 0) { Error-Exit "Failed to clone NvPak repository to $NvimConfigDir." } + Success "NvPak cloned successfully to $NvimConfigDir." + } else { + Warning "$NvimConfigDir exists, is not empty, and is not a NvPak git repository." Error-Exit "Please backup/move your existing Neovim config from $NvimConfigDir and re-run." } - Pop-Location } - else { + else { # Directory does not exist Info "Cloning NvPak repository to $NvimConfigDir..." git clone --depth 1 $NvPakRepoUrl $NvimConfigDir - if ($LASTEXITCODE -ne 0) { - Error-Exit "Failed to clone NvPak repository." - } + if ($LASTEXITCODE -ne 0) { Error-Exit "Failed to clone NvPak repository to $NvimConfigDir." } + Success "NvPak cloned successfully to $NvimConfigDir." } - # Nerd Fonts Installation (Guidance) - Info "--- Nerd Fonts ---" - Info "For the best visual experience, please install a Nerd Font." - Info "You can find them at: https://www.nerdfonts.com/" - Info "After installation, set it as your terminal font (e.g., in Windows Terminal settings)." - Write-Host "" # Newline - - # Initial Neovim run for plugin installation - Info "Running Neovim for the first time to install plugins via rocks.nvim..." - Info "This might take a few moments. Please wait for Neovim to fully load and install plugins." - Info "If prompted by rocks.nvim, confirm any installations." - - if (Command-Exists "nvim") { - Start-Process nvim -ArgumentList "--headless", "+qa" -Wait - Info "Neovim headless setup attempt complete. Starting Neovim..." - Info "Please close Neovim after plugins are installed (you might see messages from rocks.nvim)." - Start-Process nvim + # Trigger Lua installer + Info "Launching Neovim to run NvPak Lua installer ($NvPakInstallerLuaModule)..." + $nvimPath = Get-Command nvim | Select-Object -ExpandProperty Source + $initLuaPath = Join-Path $NvimConfigDir "init.lua" + + $arguments = @( + "--headless" + "-u", "`"$initLuaPath`"" # Ensure NvPak's init.lua is loaded + "-c", "`"lua require('$NvPakInstallerLuaModule').init()`"" + ) + + Info "Executing: $nvimPath $arguments" + # Start-Process $nvimPath -ArgumentList $arguments -Wait -NoNewWindow # Using -NoNewWindow can be good for seeing output + # However, for scripts that might need interactive prompts from Lua (less likely for pure headless) + # or if Neovim itself has issues with -NoNewWindow in some contexts, running directly might be better. + # Let's try invoking directly, which is more common for CLI tools. + & $nvimPath $arguments + + if ($LASTEXITCODE -eq 0) { + Success "NvPak Lua installer finished successfully." + Info "NvPak setup is complete. You can now start Neovim with 'nvim'." + Info "Further configuration or plugin installations might happen on the first interactive launch." + } else { + Error-Exit "NvPak Lua installer failed. Exit code: $LASTEXITCODE. Check Neovim output for errors (if any was printed)." + } + + # --- Deploy nvpak.ps1 CLI script --- + Info "Attempting to deploy 'nvpak.ps1' CLI script..." + $nvpakCliSource = Join-Path $NvimConfigDir "scripts\nvpak.ps1" # Note backslash for PowerShell + $nvpakCliDestDir = Join-Path $env:LOCALAPPDATA "NvPak\bin" + $nvpakCliDestFile = Join-Path $nvpakCliDestDir "nvpak.ps1" + + if (-not (Test-Path $nvpakCliSource)) { + Warning "'nvpak.ps1' not found in NvPak scripts directory: $nvpakCliSource" + Warning "Cannot deploy 'nvpak' CLI automatically." } else { - Error-Exit "Neovim command (nvim) not found even after installation attempt. Please check your PATH." + try { + if (-not (Test-Path $nvpakCliDestDir)) { + New-Item -ItemType Directory -Path $nvpakCliDestDir -Force -ErrorAction Stop | Out-Null + Info "Created directory: $nvpakCliDestDir" + } + Copy-Item -Path $nvpakCliSource -Destination $nvpakCliDestFile -Force -ErrorAction Stop + Success "'nvpak.ps1' CLI script copied to: $nvpakCliDestFile" + + # Check if the destination directory is in PATH + $currentPath = [Environment]::GetEnvironmentVariable("Path", "User") + if ($currentPath -notlike "*$($nvpakCliDestDir -replace '\\', '\\')*") { # Escape backslashes for regex like comparison + Warning "The directory '$nvpakCliDestDir' is not in your User PATH." + Info "To use the 'nvpak' command directly in PowerShell, you need to add this directory to your PATH." + Info "You can do this by running the following commands in PowerShell (consider running as Administrator if you want to set System PATH):" + Info "---" + Info " `$CurrentUserPath = [Environment]::GetEnvironmentVariable('Path', 'User')`" + Info " `$NewPath = `$CurrentUserPath;$nvpakCliDestDir`" # Or `$NewPath = "$nvpakCliDestDir;$CurrentUserPath"` to prepend + Info " `[Environment]::SetEnvironmentVariable('Path', `$NewPath, 'User')`" + Info " `# For System PATH (requires Admin): [Environment]::SetEnvironmentVariable('Path', `$NewPath, 'Machine')`" + Info "---" + Info "After updating your PATH, you MUST open a new PowerShell window for the changes to take effect." + } else { + Success "'$nvpakCliDestDir' seems to be in your PATH. 'nvpak' command should be available in new PowerShell sessions." + } + } + catch { + Warning "Failed to deploy 'nvpak.ps1' CLI script. Error: $($_.Exception.Message)" + Info "You can manually copy '$nvpakCliSource' to a directory in your PATH." + } } + Write-Host "" # Extra line for readability - Success "NvPak installation script finished!" - Info "Please restart your terminal or source your shell configuration if you installed new tools." - Info "Open Neovim with 'nvim'." + Success "NvPak PowerShell script part finished!" + Info "If Scoop installed or updated tools, or if you modified your PATH for 'nvpak' CLI, a new PowerShell session is likely needed." } # --- Entry Point --- diff --git a/install.sh b/install.sh index d7a5a73..f4fbee4 100644 --- a/install.sh +++ b/install.sh @@ -1,282 +1,302 @@ #!/usr/bin/env bash -# Function to print colored messages +# NvPak Installer Script (Shell version) +# Responsibilities: +# 1. Ensure Git and Neovim are installed. +# 2. Clone/update the NvPak repository. +# 3. Trigger the Lua-based installer within NvPak. + +# --- Configuration --- +NVIM_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvim" +NVPAK_REPO_URL="https://github.com/Pakrohk-DotFiles/NvPak.git" +NVPAK_INSTALLER_LUA_MODULE="nvpak.core.installer" # Lua module to run e.g., require('nvpak.core.installer').init() + +# --- Helper Functions --- print_message() { local color_code="$1" local message="$2" echo -e "\033[${color_code}m${message}\033[0m" } -info() { - print_message "34" "INFO: $1" # Blue -} - -success() { - print_message "32" "SUCCESS: $1" # Green -} - -warning() { - print_message "33" "WARNING: $1" # Yellow -} - -error() { - print_message "31" "ERROR: $1" # Red +info() { print_message "34" "INFO: $1"; } # Blue +success() { print_message "32" "SUCCESS: $1"; } # Green +warning() { print_message "33" "WARNING: $1"; } # Yellow +error_exit() { + print_message "31" "ERROR: $1" >&2 # Red, to stderr exit 1 } -# Function to check if a command exists command_exists() { - command -v "$1" &> /dev/null + command -v "$1" &>/dev/null } -# Detect OS -OS="" -if [[ "$(uname)" == "Linux" ]]; then - OS="Linux" - if command_exists apt-get; then - PM="sudo apt-get install -y" - PM_UPDATE="sudo apt-get update" - elif command_exists yum; then - PM="sudo yum install -y" - PM_UPDATE="sudo yum update" - elif command_exists dnf; then - PM="sudo dnf install -y" - PM_UPDATE="sudo dnf check-update" - elif command_exists pacman; then - PM="sudo pacman -Syu --noconfirm" # Pacman usually updates and installs in one go - PM_UPDATE="" # No separate update needed before install usually - elif grep -q "Android" /proc/version; then - OS="Android" - if command_exists pkg; then - PM="pkg install -y" - PM_UPDATE="pkg update -y && pkg upgrade -y" - else - error "Termux 'pkg' package manager not found. Please install it first." - fi - else - error "Unsupported Linux distribution. Please install dependencies manually." +# --- Prerequisite Installation --- +install_prerequisites() { + local os_type="$1" + local pm_cmd="$2" + local pm_update_cmd="$3" + local missing_deps=() + + # Update package manager if an update command is defined + if [[ -n "$pm_update_cmd" ]]; then + info "Updating package list via $pm_update_cmd..." + eval "$pm_update_cmd" || warning "Failed to update package list. Proceeding with caution." fi -elif [[ "$(uname)" == "Darwin" ]]; then - OS="Mac" - if command_exists brew; then - PM="brew install" - PM_UPDATE="brew update" + + info "Checking for Git..." + if ! command_exists git; then + info "Git not found." + missing_deps+=("git") else - error "Homebrew not found. Please install Homebrew first: https://brew.sh/" + info "Git is installed." fi -else - # Rudimentary check for Windows, assuming Git Bash or WSL - # A dedicated PowerShell script is better for Windows native support - if [[ -n "$WINDIR" ]] || [[ "$(uname -o 2>/dev/null)" == "Msys" ]] || [[ "$(uname -o 2>/dev/null)" == "Cygwin" ]]; then - OS="Windows_Shell" # Indicates a Unix-like shell on Windows - info "Detected Windows with a Unix-like shell (Git Bash, WSL, Cygwin, Msys)." - info "Attempting to use common commands. For best results, use PowerShell or ensure your environment has necessary tools." - # No standard package manager here, dependencies might need manual setup or specific instructions. - # We'll try to check for common tools but installation will be tricky. + + info "Checking for Neovim..." + if ! command_exists nvim; then + info "Neovim (nvim) not found." + missing_deps+=("neovim") # Use 'neovim' as common package name, 'nvim' for command else - error "Unsupported operating system: $(uname). This script supports Linux, macOS, and Unix-like shells on Windows." + info "Neovim is installed." fi -fi -info "Detected OS: $OS" + if [[ ${#missing_deps[@]} -gt 0 ]]; then + info "Attempting to install missing prerequisites: ${missing_deps[*]} using '$pm_cmd'..." + for dep_pkg_name in "${missing_deps[@]}"; do + # Handle common package name variations (e.g., neovim vs nvim) + local actual_pkg_name="$dep_pkg_name" + if [[ "$dep_pkg_name" == "neovim" && "$os_type" == "Linux" ]]; then + # On some systems, the package is 'nvim', on others 'neovim' + # We'll try 'neovim' first as it's more common for explicit install + # If 'neovim' fails and 'nvim' is the command, the Lua installer can handle specific checks. + : # Keep actual_pkg_name as neovim + elif [[ "$dep_pkg_name" == "neovim" && "$os_type" == "Android" ]]; then + actual_pkg_name="neovim" # Termux uses 'neovim' + fi -# --- Dependency Installation Placeholder --- -# Will be filled in subsequent steps + info "Installing $actual_pkg_name..." + if eval "$pm_cmd $actual_pkg_name"; then + success "$actual_pkg_name installed successfully." + else + warning "Failed to install $actual_pkg_name automatically." + warning "Please install it manually and re-run this script." + if [[ "$actual_pkg_name" == "neovim" ]]; then + warning "For Neovim, see: https://github.com/neovim/neovim/wiki/Installing-Neovim" + elif [[ "$actual_pkg_name" == "git" ]]; then + warning "For Git, see: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git" + fi + error_exit "Prerequisite installation failed for $actual_pkg_name." + fi + done + else + info "All prerequisites (Git, Neovim) are already installed." + fi -# --- Clone NvPak --- -NVIM_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvim" -NVPAK_REPO_URL="https://github.com/Pakrohk-DotFiles/NvPak.git" + # Final check after install attempts + if ! command_exists git; then error_exit "Git is required but could not be installed/found. Please install Git manually."; fi + if ! command_exists nvim; then error_exit "Neovim is required but could not be installed/found. Please install Neovim manually."; fi +} # --- Main Logic --- main() { - info "Starting NvPak installation..." - - # Update package manager (if applicable and defined) - if [[ -n "$PM_UPDATE" ]]; then - info "Updating package manager..." - eval "$PM_UPDATE" || warning "Failed to update package manager. Proceeding with caution." - fi - - # Install core dependencies - info "Installing core dependencies (git, curl, unzip, neovim)..." - CORE_DEPS=("git" "curl" "unzip" "nvim") # nvim might be named differently (neovim) + info "Starting NvPak installation for Unix-like systems..." - if [[ "$OS" == "Linux" || "$OS" == "Mac" ]]; then - for dep in "${CORE_DEPS[@]}"; do - if ! command_exists "$dep"; then - # Special handling for nvim package name - if [[ "$dep" == "nvim" ]]; then - if command_exists nvim; then - info "Neovim is already installed." - continue - fi - info "Installing Neovim..." - if [[ "$OS" == "Mac" ]]; then - eval "$PM neovim" || error "Failed to install Neovim." - elif [[ "$PM" == "sudo apt-get install -y" ]]; then # Debian/Ubuntu - # Add Neovim PPA for latest stable or nightly - # For simplicity, let's try installing 'neovim' package directly. - # Users might need to add PPA for newer versions. - eval "$PM neovim" || error "Failed to install Neovim. You might need to add a PPA for the latest version." - else # Other Linux distros - eval "$PM neovim" || eval "$PM nvim" || error "Failed to install Neovim." - fi - else - info "Installing $dep..." - eval "$PM $dep" || error "Failed to install $dep." - fi - else - info "$dep is already installed." - fi - done - elif [[ "$OS" == "Android" ]]; then - # Termux specific - info "Installing core dependencies for Termux (git, curl, unzip, neovim)..." - eval "$PM git curl unzip neovim" || error "Failed to install core dependencies on Termux." - elif [[ "$OS" == "Windows_Shell" ]]; then - info "Please ensure Git, Curl, Unzip, and Neovim are installed and in your PATH." - # Attempt to check, but installation is manual here - for dep in "${CORE_DEPS[@]}"; do - if ! command_exists "$dep"; then - if [[ "$dep" == "nvim" ]] && command_exists "neovim"; then # check for neovim as well - info "Neovim (as neovim) is already installed." - else - warning "$dep not found. Please install it manually." - fi - else - info "$dep is already installed." - fi - done - fi + local os="" + local pm="" + local pm_update="" - # Install additional tools (ripgrep, clipboard tools) - info "Installing additional tools (ripgrep, fd, clipboard tools)..." - if [[ "$OS" == "Linux" ]]; then - # Ripgrep - if ! command_exists rg; then - info "Installing ripgrep..." - eval "$PM ripgrep" || warning "Failed to install ripgrep. Telescope search might be slower." - else - info "ripgrep is already installed." - fi - # fd - if ! command_exists fd; then - info "Installing fd-find (often packaged as fd-find, binary is fd)..." - eval "$PM fd-find" || eval "$PM fd" || warning "Failed to install fd. Telescope might use alternative finders." + # OS and Package Manager Detection + if [[ "$(uname)" == "Linux" ]]; then + os="Linux" + if command_exists apt-get; then + pm="sudo apt-get install -y" + pm_update="sudo apt-get update" + elif command_exists yum; then + pm="sudo yum install -y" + pm_update="sudo yum update -y" # Often -y is good for yum update too + elif command_exists dnf; then + pm="sudo dnf install -y" + pm_update="sudo dnf check-update" # dnf check-update doesn't need -y, it's not modifying + elif command_exists pacman; then + pm="sudo pacman -S --noconfirm" # For install, update is separate or part of -Syu + pm_update="sudo pacman -Syu --noconfirm" # Full system upgrade + elif grep -q "Android" /proc/version && command_exists pkg; then + os="Android" # Termux + pm="pkg install -y" + pm_update="pkg update -y && pkg upgrade -y" else - info "fd is already installed." + error_exit "Unsupported Linux distribution or package manager not found. Please install Git and Neovim manually and re-run." fi - # Clipboard - if ! command_exists xclip && ! command_exists xsel && ! command_exists wl-copy; then - info "Installing clipboard tools (xclip/xsel for Xorg, wl-clipboard for Wayland)..." - if [[ -n "$WAYLAND_DISPLAY" ]]; then - eval "$PM wl-clipboard" || warning "Failed to install wl-clipboard for Wayland." - else - eval "$PM xclip" || eval "$PM xsel" || warning "Failed to install xclip or xsel for Xorg." - fi + elif [[ "$(uname)" == "Darwin" ]]; then + os="Mac" + if command_exists brew; then + pm="brew install" + pm_update="brew update" else - info "Clipboard tool (xclip, xsel, or wl-clipboard) is already installed." + error_exit "Homebrew not found on macOS. Please install Homebrew (https://brew.sh/) and re-run." fi - elif [[ "$OS" == "Mac" ]]; then - if ! command_exists rg; then info "Installing ripgrep..."; eval "$PM ripgrep" || warning "Failed to install ripgrep."; else info "ripgrep is already installed."; fi - if ! command_exists fd; then info "Installing fd..."; eval "$PM fd" || warning "Failed to install fd."; else info "fd is already installed."; fi - # Clipboard on macOS is usually handled by pbcopy/pbpaste, which are built-in. - elif [[ "$OS" == "Android" ]]; then - if ! command_exists rg; then info "Installing ripgrep for Termux..."; eval "$PM ripgrep" || warning "Failed to install ripgrep."; else info "ripgrep is already installed."; fi - if ! command_exists fd; then info "Installing fd for Termux..."; eval "$PM fd" || warning "Failed to install fd."; else info "fd is already installed."; fi - info "For clipboard on Termux, use termux-clipboard-get/set (install with 'pkg install termux-api')." - if ! command_exists termux-clipboard-get; then - info "Installing termux-api for clipboard..." - eval "$PM termux-api" || warning "Failed to install termux-api for clipboard access." - else - info "termux-api (for clipboard) is already installed." + elif [[ -n "$WINDIR" ]] || [[ "$(uname -o 2>/dev/null)" == "Msys" ]] || [[ "$(uname -o 2>/dev/null)" == "Cygwin" ]]; then + info "Detected a Windows-based Unix-like shell (e.g., Git Bash, WSL, Cygwin, Msys)." + info "This script will attempt to check for Git and Neovim." + info "For a native Windows experience, please use the 'install.ps1' script." + if ! command_exists git || ! command_exists nvim; then + warning "Git or Neovim might not be installed or not in PATH." + warning "Please ensure Git and Neovim are installed and accessible in your PATH." + # Do not error_exit here, let user try if they know what they are doing. + # The Lua installer will perform more checks. fi - elif [[ "$OS" == "Windows_Shell" ]]; then - info "Please ensure ripgrep and fd are installed and in your PATH for Telescope." - if ! command_exists rg; then warning "ripgrep (rg) not found. Please install it manually."; else info "ripgrep is already installed."; fi - if ! command_exists fd; then warning "fd not found. Please install it manually."; else info "fd is already installed."; fi - info "Clipboard on Windows is typically handled by Neovim itself or via PowerShell/WSL integrations." + # No standard package manager for these environments, so skip auto-install. + else + error_exit "Unsupported operating system: $(uname). This script supports Linux, macOS, and Unix-like shells on Windows." fi - # Pynvim (optional, for Python devs) - if command_exists pip3; then - if ! python3 -c "import pynvim" &> /dev/null; then - info "pynvim (Python 3) not found. Installing..." - pip3 install --user pynvim || warning "Failed to install pynvim with pip3. Python integration might not work." - else - info "pynvim is already installed." - fi - elif command_exists pip; then - if ! python -c "import pynvim" &> /dev/null; then - info "pynvim (Python 2/default) not found. Installing..." - pip install --user pynvim || warning "Failed to install pynvim with pip. Python integration might not work." - else - info "pynvim is already installed." - fi + info "Detected OS: $os" + if [[ -n "$pm" ]]; then # If a package manager was identified for auto-installation + install_prerequisites "$os" "$pm" "$pm_update" else - warning "pip/pip3 not found. Cannot install pynvim automatically. If you are a Python developer, please install it manually." + info "Skipping automatic prerequisite installation due to OS/environment." + info "Please ensure Git and Neovim are installed and in your PATH." + if ! command_exists git; then error_exit "Git is required. Please install it manually."; fi + if ! command_exists nvim; then error_exit "Neovim (nvim) is required. Please install it manually."; fi + success "Git and Neovim found." fi - # Clone or update NvPak repository info "Setting up NvPak configuration directory: $NVIM_CONFIG_DIR" - if [ -d "$NVIM_CONFIG_DIR" ]; then - info "NvPak directory already exists. Checking for updates..." - cd "$NVIM_CONFIG_DIR" || error "Could not cd into $NVIM_CONFIG_DIR" - if [ -d ".git" ]; then - current_remote=$(git remote get-url origin) + if [ -d "$NVIM_CONFIG_DIR/.git" ]; then + info "NvPak directory already exists and is a git repository. Checking for updates..." + ( # Subshell to avoid cd side effects + cd "$NVIM_CONFIG_DIR" || error_exit "Could not cd into $NVIM_CONFIG_DIR" + current_remote=$(git remote get-url origin 2>/dev/null) if [[ "$current_remote" == "$NVPAK_REPO_URL" ]]; then - info "Pulling latest changes from NvPak repository..." - git pull || warning "Failed to pull latest changes. Your configuration might be outdated." + info "Pulling latest changes from NvPak repository ($NVPAK_REPO_URL)..." + if git pull; then + success "NvPak updated successfully." + else + warning "Failed to pull latest NvPak changes. Your configuration might be outdated or you have local changes." + warning "Attempting to continue. If issues arise, consider a fresh clone after backing up." + fi else - warning "The existing directory $NVIM_CONFIG_DIR is a git repository, but not for NvPak ($current_remote)." - warning "Please move or backup your existing Neovim configuration and re-run the script." - # Potentially offer to backup and clone, but for now, let's be safe. - # read -p "Do you want to backup the existing directory and clone NvPak? (y/N): " backup_confirm - # if [[ "$backup_confirm" =~ ^[Yy]$ ]]; then - # mv "$NVIM_CONFIG_DIR" "${NVIM_CONFIG_DIR}.backup.$(date +%s)" - # info "Backed up existing config to ${NVIM_CONFIG_DIR}.backup.$(date +%s)" - # info "Cloning NvPak repository..." - # git clone --depth 1 "$NVPAK_REPO_URL" "$NVIM_CONFIG_DIR" || error "Failed to clone NvPak repository." - # else - # error "Installation aborted by user." - # fi - error "Please backup/move your existing Neovim config from $NVIM_CONFIG_DIR and re-run." + warning "The existing directory $NVIM_CONFIG_DIR is a git repository, but not for NvPak." + warning "Current remote: $current_remote" + warning "Expected remote: $NVPAK_REPO_URL" + error_exit "Please backup/move your existing Neovim config from $NVIM_CONFIG_DIR and re-run." fi + ) + elif [ -d "$NVIM_CONFIG_DIR" ] && [ -z "$(ls -A "$NVIM_CONFIG_DIR")" ]; then + info "$NVIM_CONFIG_DIR exists but is empty. Cloning NvPak..." + if git clone --depth 1 "$NVPAK_REPO_URL" "$NVIM_CONFIG_DIR"; then + success "NvPak cloned successfully to $NVIM_CONFIG_DIR." else - warning "$NVIM_CONFIG_DIR exists but is not a git repository. It might be an old NvPak install or a custom config." - error "Please backup/move your existing Neovim config from $NVIM_CONFIG_DIR and re-run." + error_exit "Failed to clone NvPak repository to $NVIM_CONFIG_DIR." fi - cd - > /dev/null # Go back to previous directory + elif [ -d "$NVIM_CONFIG_DIR" ]; then + warning "$NVIM_CONFIG_DIR exists and is not empty, nor is it a NvPak git repository." + error_exit "Please backup/move your existing Neovim config from $NVIM_CONFIG_DIR and re-run." else info "Cloning NvPak repository to $NVIM_CONFIG_DIR..." - git clone --depth 1 "$NVPAK_REPO_URL" "$NVIM_CONFIG_DIR" || error "Failed to clone NvPak repository." + if git clone --depth 1 "$NVPAK_REPO_URL" "$NVIM_CONFIG_DIR"; then + success "NvPak cloned successfully to $NVIM_CONFIG_DIR." + else + error_exit "Failed to clone NvPak repository to $NVIM_CONFIG_DIR." + fi fi - # Nerd Fonts Installation (Guidance) - info "--- Nerd Fonts ---" - info "For the best visual experience, please install a Nerd Font." - info "You can find them at: https://www.nerdfonts.com/" - info "After installation, set it as your terminal font." - echo "" # Newline for readability + # Trigger Lua installer + info "Launching Neovim to run NvPak Lua installer ($NVPAK_INSTALLER_LUA_MODULE)..." + # We use -u $NVIM_CONFIG_DIR/init.lua to ensure it loads NvPak's init.lua, + # which should then correctly set up package paths for the installer module. + # The --headless ensures no UI pops up if not needed, but the Lua script can decide. + # The Lua script itself should handle further user interaction. + # The +qa is removed as the Lua script will handle exit or further steps. + local nvim_cmd_args=( + "--headless" + "-u" "$NVIM_CONFIG_DIR/init.lua" # Ensure NvPak's init is loaded + "-c" "lua require('$NVPAK_INSTALLER_LUA_MODULE').init()" + # "+qa" # Lua script will manage quitting or further interaction + ) - # Initial Neovim run for plugin installation - info "Running Neovim for the first time to install plugins via rocks.nvim..." - info "This might take a few moments. Please wait for Neovim to fully load and install plugins." - info "If prompted by rocks.nvim, confirm any installations." + info "Executing: nvim ${nvim_cmd_args[*]}" + if nvim "${nvim_cmd_args[@]}"; then + success "NvPak Lua installer finished successfully." + info "NvPak setup is complete. You can now start Neovim with 'nvim'." + info "Further configuration or plugin installations might happen on the first interactive launch." + else + error_exit "NvPak Lua installer failed. Check Neovim output for errors." + fi + + # The old messages about Nerd Fonts and running Neovim for plugins are now handled by the Lua installer. - if command_exists nvim; then - nvim --headless "+qa" # Attempt a headless quit to trigger initial setup if possible - info "Neovim headless setup attempt complete. Starting Neovim..." - info "Please close Neovim after plugins are installed (you might see messages from rocks.nvim)." - nvim + # --- Deploy nvpak CLI script --- + info "Attempting to deploy 'nvpak' CLI script..." + local nvpak_cli_source="$NVIM_CONFIG_DIR/scripts/nvpak.sh" + if [ ! -f "$nvpak_cli_source" ]; then + warning "'nvpak.sh' not found in NvPak scripts directory: $nvpak_cli_source" + warning "Cannot deploy 'nvpak' CLI automatically." else - error "Neovim command (nvim) not found even after installation attempt. Please check your PATH." + local cli_installed_path="" + # Try ~/.local/bin first + local local_bin_dir="$HOME/.local/bin" + if [ -d "$local_bin_dir" ]; then + if [[ ":$PATH:" == *":$local_bin_dir:"* ]]; then + info "Found '$local_bin_dir' in PATH. Attempting to install 'nvpak' there." + if cp "$nvpak_cli_source" "$local_bin_dir/nvpak" && chmod +x "$local_bin_dir/nvpak"; then + success "'nvpak' CLI script installed to $local_bin_dir/nvpak" + cli_installed_path="$local_bin_dir/nvpak" + else + warning "Failed to copy 'nvpak.sh' to $local_bin_dir. Permissions?" + fi + else + info "'$local_bin_dir' exists but does not seem to be in your PATH." + info "You might need to add it to your PATH: export PATH=\"\$HOME/.local/bin:\$PATH\" (in .bashrc/.zshrc)" + fi + else + info "'$HOME/.local/bin' not found." + fi + + # If not installed in ~/.local/bin, try /usr/local/bin (might need sudo) + if [ -z "$cli_installed_path" ]; then + local usr_local_bin_dir="/usr/local/bin" + if [ -w "$usr_local_bin_dir" ]; then # Check if writable directly + info "Attempting to install 'nvpak' to $usr_local_bin_dir (writable)." + if cp "$nvpak_cli_source" "$usr_local_bin_dir/nvpak" && chmod +x "$usr_local_bin_dir/nvpak"; then + success "'nvpak' CLI script installed to $usr_local_bin_dir/nvpak" + cli_installed_path="$usr_local_bin_dir/nvpak" + else + warning "Failed to copy 'nvpak.sh' to $usr_local_bin_dir even though it seemed writable." + fi + elif command_exists sudo && [ "$EUID" -ne 0 ]; then # Not root, but sudo exists + info "'$usr_local_bin_dir' is not writable by current user." + read -r -p "Do you want to try installing 'nvpak' to $usr_local_bin_dir using sudo? (y/N): " response + if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then + info "Attempting to install 'nvpak' to $usr_local_bin_dir using sudo..." + if sudo cp "$nvpak_cli_source" "$usr_local_bin_dir/nvpak" && sudo chmod +x "$usr_local_bin_dir/nvpak"; then + success "'nvpak' CLI script installed to $usr_local_bin_dir/nvpak using sudo." + cli_installed_path="$usr_local_bin_dir/nvpak" + else + warning "Failed to install 'nvpak.sh' to $usr_local_bin_dir using sudo." + fi + else + info "Skipped installing 'nvpak' to $usr_local_bin_dir via sudo." + fi + fi + fi + + if [ -n "$cli_installed_path" ]; then + info "The 'nvpak' command should now be available in new terminal sessions." + info "If not, ensure '$cli_installed_path' is in a directory included in your PATH." + else + warning "Could not automatically install 'nvpak' CLI to a standard PATH directory." + info "You can manually make it available by:" + info " 1. Creating a symbolic link: sudo ln -s \"$nvpak_cli_source\" /usr/local/bin/nvpak" + info " 2. Or copying it: sudo cp \"$nvpak_cli_source\" /usr/local/bin/nvpak && sudo chmod +x /usr/local/bin/nvpak" + info " 3. Or adding the '$NVIM_CONFIG_DIR/scripts' directory to your PATH." + info " (e.g., export PATH=\"\$PATH:$NVIM_CONFIG_DIR/scripts\" in your .bashrc or .zshrc)" + fi fi + echo "" # Extra line for readability - success "NvPak installation script finished!" - info "Please restart your terminal or source your shell configuration if you installed new tools." - info "Open Neovim with 'nvim'." + success "NvPak shell script part finished!" + info "Please restart your terminal if new tools were installed by your package manager earlier (e.g., Neovim itself), or for 'nvpak' CLI to become available." } # --- Entry Point --- diff --git a/lua/nvpak/core/installer.lua b/lua/nvpak/core/installer.lua new file mode 100644 index 0000000..081a7c6 --- /dev/null +++ b/lua/nvpak/core/installer.lua @@ -0,0 +1,455 @@ +-- NvPak Core Installer Module +-- Handles dependency checks, plugin installation, and initial setup. + +local M = {} + +-- Placeholder for utility functions (OS detection, command execution, etc.) +local utils = {} + +--- Detects the current operating system. +--- @return string "windows", "linux", "macos", or "unknown" +function utils.get_os() + local uname = vim.loop.os_uname() + if not uname then return "unknown" end + if uname.sysname == "Windows_NT" then return "windows" end + if uname.sysname == "Linux" then return "linux" end + if uname.sysname == "Darwin" then return "macos" end + return "unknown" +end + +--- Checks if a command exists. +--- @param cmd string The command to check. +--- @return boolean true if the command exists, false otherwise. +function utils.command_exists(cmd) + return vim.fn.executable(cmd) == 1 +end + +--- Prints an informational message. +--- @param msg string The message to print. +function utils.info(msg) + vim.api.nvim_echo({ { "INFO: ", "Bold" }, { msg, "None" } }, true, {}) +end + +--- Prints a success message. +--- @param msg string The message to print. +function utils.success(msg) + vim.api.nvim_echo({ { "SUCCESS: ", "Bold" }, { msg, "Green" } }, true, {}) +end + +--- Prints a warning message. +--- @param msg string The message to print. +function utils.warning(msg) + vim.api.nvim_echo({ { "WARNING: ", "Bold" }, { msg, "Yellow" } }, true, {}) +end + +--- Prints an error message. +--- @param msg string The message to print. +function utils.error_msg(msg) + vim.api.nvim_echo({ { "ERROR: ", "Bold" }, { msg, "Red" } }, true, {}) +end + + +--- Main function called by the shell installer scripts. +function M.init() + utils.info("NvPak Lua Installer started.") + utils.info("Detected OS: " .. utils.get_os()) + + -- 1. Check and install secondary dependencies + M.check_secondary_dependencies() + + -- 2. Nerd Fonts Guidance + M.guide_nerd_fonts() + + -- 3. Plugin Installation (using rocks.nvim) + -- This will likely involve calling functions from your rocks.nvim setup + M.install_plugins() + + -- 4. Offer initial setup options (plugin profiles) - Future step + -- M.offer_setup_profiles() + + utils.success("NvPak Lua Installer finished basic setup.") + utils.info("You might need to restart Neovim for all changes to take effect.") + utils.info("Run ':checkhealth' to verify your setup after restarting.") + + -- For now, we quit after running. This might change if we want interactive prompts. + -- If running truly headless and no more interaction is needed: + if vim.v.headless == 1 then + vim.cmd("qall!") + end +end + +--- Checks and guides installation of secondary dependencies. +function M.check_secondary_dependencies() + utils.info("Checking secondary dependencies...") + local os = utils.get_os() + + -- Example: ripgrep (rg) + if not utils.command_exists("rg") then + utils.warning("ripgrep (rg) is not installed. This is highly recommended for Telescope search.") + if os == "linux" then + utils.info("On Linux, you can often install it with: sudo apt install ripgrep / sudo yum install ripgrep / sudo dnf install ripgrep / sudo pacman -S ripgrep") + elseif os == "macos" then + utils.info("On macOS, you can install it with: brew install ripgrep") + elseif os == "windows" then + utils.info("On Windows, you can install it with Scoop: scoop install ripgrep") + end + else + utils.success("ripgrep (rg) is installed.") + end + + -- Example: fd + if not utils.command_exists("fd") then + utils.warning("fd is not installed. This is a useful alternative for Telescope.") + if os == "linux" then + utils.info("On Linux, you can often install it with: sudo apt install fd-find / sudo yum install fd-find / sudo dnf install fd-find / sudo pacman -S fd") + utils.info("Note: On some systems, the binary might be 'fdfind'. You may need to create a symlink 'fd' to 'fdfind'.") + elseif os == "macos" then + utils.info("On macOS, you can install it with: brew install fd") + elseif os == "windows" then + utils.info("On Windows, you can install it with Scoop: scoop install fd") + end + else + utils.success("fd is installed.") + end + + -- TODO: Add checks for pynvim, clipboard tools based on OS + -- For pynvim: + M.check_pynvim(os) + + -- For clipboard tools: + M.check_clipboard_tools(os) +end + +--- Checks for pynvim and Python 3. +--- @param os string Current OS ("windows", "linux", "macos") +function M.check_pynvim(os) + utils.info("Checking for pynvim (Python 3 integration)...") + local python_exe = "python3" + if os == "windows" then + -- On Windows, 'python' might be Python 3, or 'py -3' could be more reliable + -- For simplicity, we'll try 'python3' first, then 'python' + if not utils.command_exists("python3") and utils.command_exists("python") then + python_exe = "python" + elseif not utils.command_exists("python3") and utils.command_exists("py") then + -- Check if py -3 works + local py3_check_cmd = { "py", "-3", "-c", "import sys; sys.exit(0)" } + local _, py3_exit_code = vim.fn.system(py3_check_cmd) + if py3_exit_code == 0 then + python_exe = "py -3" -- Found a working Python 3 launcher + else + utils.warning("python3 not found, and 'py -3' does not seem to work.") + end + end + end + + if not utils.command_exists(python_exe:match("^[^%s]+")) then -- Get the base command for existence check + utils.warning(python_exe .. " (Python 3) is not installed or not in PATH.") + utils.info("pynvim requires Python 3. Please install Python 3.") + if os == "linux" then + utils.info("On Linux, install with: sudo apt install python3 python3-pip / sudo yum install python3 python3-pip ...") + elseif os == "macos" then + utils.info("On macOS, install with: brew install python") + elseif os == "windows" then + utils.info("On Windows, download from https://www.python.org/ or install with Scoop: scoop install python") + end + return + end + + local pip_exe = python_exe:gsub("python", "pip"):gsub("py", "pip") -- python3 -> pip3, python -> pip, py -3 -> pip -3 (approx) + if python_exe == "py -3" then pip_exe = "py -3 -m pip" end -- More robust for py launcher + + if not utils.command_exists(pip_exe:match("^[^%s]+")) and not (python_exe == "py -3") then -- pip might not be separate for 'py' + -- Attempt to see if pip module is available via python_exe -m pip + local pip_check_cmd = vim.split(python_exe .. " -m pip --version", " ") + local _, pip_via_module_exit_code = vim.fn.system(pip_check_cmd) + if pip_via_module_exit_code ~= 0 then + utils.warning(pip_exe .. " (pip for Python 3) is not installed or not in PATH.") + utils.info("pynvim is installed using pip. Please ensure pip for Python 3 is installed.") + if os == "windows" and python_exe ~= "py -3" then + utils.info("Often, ensuring Python from python.org is installed and 'Scripts' directory is in PATH fixes this.") + utils.info("Or run: " .. python_exe .. " -m ensurepip --upgrade") + end + return + else + pip_exe = python_exe .. " -m pip" -- Use this form if direct pipX command failed + end + end + + + -- Check if pynvim is importable + -- Using a temp file to avoid issues with quotes in system() command + local check_script_path = vim.fn.stdpath("cache") .. "/check_pynvim.py" + vim.fn.writefile({ "import pynvim" }, check_script_path) + local pynvim_check_cmd = vim.split(python_exe .. " " .. vim.fn.shellescape(check_script_path), " ") + + utils.info("Verifying pynvim installation with: " .. table.concat(pynvim_check_cmd, " ")) + local _, exit_code = vim.fn.system(pynvim_check_cmd) + vim.loop.fs_unlink(check_script_path) -- Clean up temp file + + if exit_code == 0 then + utils.success("pynvim is installed and importable with " .. python_exe) + else + utils.warning("pynvim module is not importable with " .. python_exe) + utils.info("Attempting to install/upgrade pynvim using: " .. pip_exe .. " install --user --upgrade pynvim") + local install_cmd = vim.split(pip_exe .. " install --user --upgrade pynvim", " ") + -- Running pip install. This can take time. + -- Consider if this should be truly headless or provide more feedback. + local _, pip_exit_code = vim.fn.system(install_cmd) + if pip_exit_code == 0 then + utils.success("pynvim installed/upgraded successfully via pip.") + utils.info("Please restart Neovim for Python plugins to work correctly.") + else + utils.error_msg("Failed to install pynvim using pip. Exit code: " .. pip_exit_code) + utils.info("Please try installing it manually: " .. pip_exe .. " install --user --upgrade pynvim") + end + end +end + +--- Checks for clipboard tools. +--- @param os string Current OS ("windows", "linux", "macos") +function M.check_clipboard_tools(os) + utils.info("Checking for clipboard tools...") + if os == "linux" then + local wayland = vim.env.WAYLAND_DISPLAY ~= nil + local needed = "" + if wayland then + if not utils.command_exists("wl-copy") or not utils.command_exists("wl-paste") then + needed = "wl-clipboard" + end + else -- X11 + if not utils.command_exists("xclip") and not utils.command_exists("xsel") then + needed = "xclip or xsel" + end + end + if needed ~= "" then + utils.warning(needed .. " not found. Clipboard integration might not work.") + utils.info("On Linux, install with: sudo apt install " .. needed .. " / sudo yum install " .. needed .. " ...") + else + utils.success("Suitable clipboard tool (wl-clipboard, xclip, or xsel) found for Linux.") + end + elseif os == "macos" then + if utils.command_exists("pbcopy") and utils.command_exists("pbpaste") then + utils.success("pbcopy/pbpaste found for macOS clipboard integration.") + else + utils.warning("pbcopy/pbpaste not found on macOS. This is unusual. Clipboard will not work.") + end + elseif os == "windows" then + -- Neovim often bundles win32yank or it's expected to be handled. + -- We can check for win32yank if user wants to ensure it via Scoop. + if not utils.command_exists("win32yank") then + utils.info("win32yank.exe not found in PATH. Neovim might use an internal version or fallback.") + utils.info("For optimal clipboard on Windows, especially in WSL or terminals, consider installing win32yank:") + utils.info("scoop install win32yank") + else + utils.success("win32yank found. Clipboard should work.") + end + end +end + +--- Guides the user for Nerd Fonts installation. +function M.guide_nerd_fonts() + utils.info("--- Nerd Fonts ---") + utils.info("For the best visual experience with icons and symbols, a Nerd Font is highly recommended.") + utils.info("1. Download a Nerd Font of your choice from: https://www.nerdfonts.com/font-downloads") + utils.info("2. Install the font on your system (instructions vary by OS).") + utils.info("3. Configure your terminal emulator to use the installed Nerd Font.") + utils.info("Popular choices include: FiraCode Nerd Font, JetBrainsMono Nerd Font, Hack Nerd Font.") +end + +--- Handles plugin installation using rocks.nvim. +function M.install_plugins() + utils.info("Starting plugin installation via rocks.nvim...") + -- This assumes rocks.nvim is already set up by your NvPak's init.lua + -- and that it might have an API to trigger installation or synchronization. + + -- Example: If rocks.nvim has a function to sync/install all plugins + -- This is a HYPOTHETICAL example. You need to replace this with actual rocks.nvim API calls. + -- pcall(function() + -- local rocks_api = require("rocks") -- Or however you access rocks + -- if rocks_api and rocks_api.sync then + -- utils.info("Calling rocks.nvim sync...") + -- local ok, result = rocks_api.sync() -- Or install, or bootstrap + -- if ok then + -- utils.success("rocks.nvim sync completed.") + -- if result then vim.print(result) end + -- else + -- utils.error_msg("rocks.nvim sync failed: " .. tostring(result)) + -- end + -- else + -- utils.warning("Could not find rocks.nvim API for plugin installation. Manual setup might be needed.") + -- utils.info("Typically, plugins are installed when Neovim starts with the new configuration.") + -- end + -- end) + + -- This assumes rocks.nvim is already set up by NvPak's init.lua + -- and that it uses lazy.nvim as its backend. + -- NvPak's init.lua (or a file it requires, like lua/plugins/init.lua which calls lua/plugins/rocks.lua) + -- should have already called require("lazy").setup(...). + + local lazy_ok, lazy = pcall(require, "lazy") + + if not lazy_ok or not lazy then + utils.error_msg("Failed to load lazy.nvim. Ensure it is correctly bootstrapped by your NvPak configuration (init.lua).") + utils.info("Plugin installation cannot proceed without lazy.nvim.") + return + end + + utils.info("Attempting to synchronize plugins with lazy.nvim...") + + -- The `lazy.sync()` function checks for missing plugins, installs them, + -- and cleans up removed plugins. It's suitable for this installer script. + -- It can also take options, but default behavior should be fine here. + local sync_ok, result = pcall(lazy.sync, { + -- We might want to ensure it doesn't prompt if running headless, + -- though lazy.nvim is generally good about headless operation. + -- Example options (check lazy.nvim docs for actual available options for sync): + -- notify = false, -- if we want to suppress notifications here and show our own + -- install = { missing = true }, -- ensure missing plugins are installed + -- update = { all = false }, -- don't update all, just sync + -- clean = true, -- clean up removed plugins + }) + + if sync_ok then + utils.success("lazy.nvim sync process completed.") + if type(result) == "table" and result.updated and #result.updated > 0 then + utils.info("Number of plugins updated/installed: " .. #result.updated) + elseif type(result) == "table" and result.installed and #result.installed > 0 then + utils.info("Number of plugins installed: " .. #result.installed) + else + utils.info("No new plugins were installed or updated by lazy.sync, or no detailed result returned.") + end + -- vim.print(result) -- Could be verbose, use with caution or extract specific info + else + utils.error_msg("lazy.nvim sync process failed.") + utils.error_msg("Error details: " .. tostring(result)) + utils.info("Plugins might not be fully installed. Check your configuration and try ':Lazy sync' manually in Neovim.") + end + + -- Optionally, run health check for lazy if available + if lazy.health then + utils.info("Running lazy.nvim health check...") + -- This might be too verbose for an installer, but good for debugging + -- local health_ok, health_result = pcall(lazy.health) + -- if health_ok and health_result then + -- utils.info("Lazy health check results:") + -- vim.print(health_result) + -- end + end + + utils.success("Plugin installation/synchronization step finished.") +end + +-- Placeholder for future CLI-related functions +function M.cli_install_package(plugin_spec) + utils.info("CLI: Request to install plugin: " .. plugin_spec) + utils.warning("Automated installation via CLI by modifying plugin configuration files is complex and not yet fully implemented.") + utils.info("Please manually add the plugin spec to your NvPak plugin configuration (e.g., rocks.toml or Lua files).") + utils.info("After adding, you can try 'nvpak refresh' or run :Lazy sync in Neovim.") + -- As a fallback, we can attempt a sync, which might pick up changes if user manually edited files. + M.try_lazy_sync("Plugin installation requested. Attempting to sync with lazy.nvim.") +end + +function M.try_lazy_sync(reason_message) + utils.info(reason_message) + local lazy_ok, lazy = pcall(require, "lazy") + if not lazy_ok or not lazy then + utils.error_msg("lazy.nvim module not found. Cannot perform sync.") + return false + end + local ok, result = pcall(lazy.sync) + if ok then + utils.success("lazy.nvim sync completed.") + -- utils.info(vim.inspect(result)) -- Can be verbose + return true + else + utils.error_msg("lazy.nvim sync failed: " .. tostring(result)) + return false + end +end + +function M.cli_update_package(packageName) + utils.info("CLI: Request to update plugin: " .. packageName) + local lazy_ok, lazy = pcall(require, "lazy") + if not lazy_ok or not lazy then + utils.error_msg("lazy.nvim module not found. Cannot update plugin.") + return + end + + utils.info("Attempting to update '" .. packageName .. "' with lazy.nvim...") + -- lazy.update() can take a plugin name or nil (for all) + -- It also takes options, like `notify = true/false` + local ok, result = pcall(lazy.update, packageName) + if ok then + utils.success("lazy.nvim update process for '" .. packageName .. "' initiated.") + -- utils.info(vim.inspect(result)) -- Result might indicate if updates were found/applied + utils.info("Check Neovim notifications or :Lazy interface for update details.") + else + utils.error_msg("lazy.nvim update command failed for '" .. packageName .. "': " .. tostring(result)) + end +end + +function M.cli_upgrade_all_packages() + utils.info("CLI: Request to upgrade all installed plugins.") + local lazy_ok, lazy = pcall(require, "lazy") + if not lazy_ok or not lazy then + utils.error_msg("lazy.nvim module not found. Cannot upgrade plugins.") + return + end + + utils.info("Attempting to update all plugins with lazy.nvim...") + local ok, result = pcall(lazy.update) -- No argument means update all + if ok then + utils.success("lazy.nvim update process for all plugins initiated.") + -- utils.info(vim.inspect(result)) + utils.info("Check Neovim notifications or :Lazy interface for update details.") + else + utils.error_msg("lazy.nvim update command for all plugins failed: " .. tostring(result)) + end +end + +function M.cli_uninstall_package(packageName) + utils.info("CLI: Request to uninstall plugin: " .. packageName) + utils.warning("Automated uninstallation via CLI by modifying plugin configuration files is complex and not yet fully implemented.") + utils.info("Please manually remove the plugin spec from your NvPak plugin configuration (e.g., rocks.toml or Lua files).") + utils.info("After removing, you can try 'nvpak refresh' or run :Lazy sync (which also cleans) in Neovim.") + M.try_lazy_sync("Plugin uninstallation requested. Attempting to sync/clean with lazy.nvim.") +end + +function M.cli_refresh_plugins() + utils.info("CLI: Request to refresh plugin list and sync.") + M.try_lazy_sync("Refreshing plugins as requested by CLI.") +end + +function M.cli_fetch_nvpak() + utils.info("CLI: Request to fetch NvPak updates (git pull)") + local config_dir = vim.fn.stdpath("config") + local cmd = { "git", "-C", config_dir, "pull" } + utils.info("Running: " .. table.concat(cmd, " ")) + local job_id = vim.fn.jobstart(cmd, { + stdout_buffered = true, + stderr_buffered = true, + on_exit = function(_, code, _) + if code == 0 then + utils.success("NvPak updated successfully from git.") + vim.cmd("redraw!") -- Redraw to show messages + else + utils.error_msg("Failed to update NvPak from git. Exit code: " .. code) + local stderr = vim.fn.jobgetstderr(job_id) + if stderr and #stderr > 0 then + utils.error_msg("Git stderr:") + for _, line in ipairs(stderr) do + if line ~= "" then utils.error_msg(line) end + end + end + vim.cmd("redraw!") + end + -- If running from CLI, this exit might be too soon or not needed + -- if vim.v.headless == 1 and not M._is_cli_call then vim.cmd("qall!") end + end, + }) + if not job_id or job_id == 0 or job_id == -1 then + utils.error_msg("Failed to start git pull job.") + end +end + +return M diff --git a/scripts/nvpak.ps1 b/scripts/nvpak.ps1 new file mode 100644 index 0000000..73ee4b3 --- /dev/null +++ b/scripts/nvpak.ps1 @@ -0,0 +1,179 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + NvPak CLI - Command Line Interface for managing NvPak and its plugins on Windows. +.DESCRIPTION + Provides commands to install, uninstall, update plugins, and fetch NvPak updates. + Supports aliases defined in a configuration file. +.NOTES + Author: Jules (AI Assistant) & Pakrohk +#> + +# --- Configuration --- +$NvPakConfigDir = Join-Path $env:LOCALAPPDATA "nvpak" # For aliases, etc. +$NvimConfigDir = Join-Path $env:LOCALAPPDATA "nvim" # NvPak's installation directory +$AliasFile = Join-Path $NvPakConfigDir "aliases.conf" +$InstallerModule = "nvpak.core.installer" # The Lua module containing CLI functions + +# --- Helper Functions --- +function Print-Message($message, $color, $WriteError = $false) { + if ($WriteError) { + Write-Error $message # Errors go to stderr stream + } else { + Write-Host $message -ForegroundColor $color + } +} + +function Info($message) { Print-Message $message "Cyan" } +function Success($message) { Print-Message $message "Green" } +function Warning($message) { Print-Message $message "Yellow" } +function Error-Exit($message) { + Print-Message $message "Red" -WriteError $true + exit 1 +} + +function Command-Exists($command) { + return (Get-Command $command -ErrorAction SilentlyContinue) -ne $null +} + +# Ensure Neovim is installed +if (-not (Command-Exists "nvim")) { + Error-Exit "Neovim (nvim.exe) is not installed or not in your PATH. NvPak CLI requires Neovim." +} + +# Ensure NvPak config directory exists +if (-not (Test-Path (Join-Path $NvimConfigDir "init.lua"))) { + Error-Exit "NvPak configuration (init.lua) not found at $NvimConfigDir. Please install NvPak first." +} + +# --- Alias Resolution --- +function Resolve-AliasCmd { + param( + [string]$CommandAlias + ) + if (Test-Path $AliasFile) { + try { + $aliases = Get-Content $AliasFile | Where-Object { $_ -notmatch '^\s*#' -and $_ -match '.=' } | ConvertFrom-StringData -Delimiter '=' + if ($aliases.$CommandAlias) { + return $aliases.$CommandAlias.Trim() + } + } + catch { + Warning "Could not parse alias file at $AliasFile. Error: $($_.Exception.Message)" + } + } + return $CommandAlias # Return original if not found or file doesn't exist/parse +} + +# --- Neovim Command Execution --- +function Run-NvimLuaCommand { + param( + [string]$LuaFunctionName, + [string[]]$Arguments + ) + + $luaArgsString = "" + if ($Arguments) { + $escapedArgs = $Arguments | ForEach-Object { "'" + ($_ -replace "'", "''") + "'" } # Escape single quotes for Lua + $luaArgsString = $escapedArgs -join ", " + } + + $luaCommand = "require('$InstallerModule').$LuaFunctionName($luaArgsString)" + Info "Executing Lua: $luaCommand" + + $nvimPath = (Get-Command nvim).Source + $initLuaPath = Join-Path $NvimConfigDir "init.lua" + + $nvimArgs = @( + "--headless" + "-u", "`"$initLuaPath`"" # Ensure NvPak's init.lua is loaded + "-c", "lua $luaCommand" + # Similar to bash, ensure messages are flushed and nvim exits. + # PowerShell's Start-Process or direct call might behave differently regarding console output. + # Using direct call `&` seems more appropriate for CLI tools. + "-c", "lua vim.cmd('redraw') vim.cmd('sleep 100m') if vim.v.headless == 1 and vim.fn.argc() == 0 then vim.cmd('qall!') end" + ) + + try { + & $nvimPath $nvimArgs + # $LASTEXITCODE should be set by the direct call. + if ($LASTEXITCODE -ne 0) { + Warning "Neovim command execution for '$LuaFunctionName' finished with exit code $LASTEXITCODE." + # Further error details would ideally come from the Lua script's output. + } + } + catch { + Error-Exit "Failed to start Neovim process for '$LuaFunctionName'. Error: $($_.Exception.Message)" + } +} + +# --- Main CLI Logic --- +if ($args.Count -eq 0) { + Info "Usage: nvpak [arguments]" + Info "Available commands (pre-alias resolution): install, uninstall, update, upgrade, fetch, help" + Info "Run 'nvpak help' for more details." + exit 0 +} + +$actionAlias = $args[0] +$remainingArgs = $args[1..($args.Count - 1)] + +$action = Resolve-AliasCmd -CommandAlias $actionAlias + +switch ($action) { + "install" { + if ($remainingArgs.Count -lt 1) { Error-Exit "Usage: nvpak install " } + Info "Action: Install plugin '$($remainingArgs[0])'" + Run-NvimLuaCommand "cli_install_package" $remainingArgs[0] + } + "uninstall" { + if ($remainingArgs.Count -lt 1) { Error-Exit "Usage: nvpak uninstall " } + Info "Action: Uninstall plugin '$($remainingArgs[0])'" + Run-NvimLuaCommand "cli_uninstall_package" $remainingArgs[0] + } + "update" { + if ($remainingArgs.Count -eq 0) { + Info "Action: Update all plugins" + Run-NvimLuaCommand "cli_upgrade_all_packages" @() + } else { + Info "Action: Update plugin '$($remainingArgs[0])'" + Run-NvimLuaCommand "cli_update_package" $remainingArgs[0] + } + } + "upgrade" { + Info "Action: Upgrade all plugins" + Run-NvimLuaCommand "cli_upgrade_all_packages" @() + } + "refresh" { + Info "Action: Refresh plugin list and sync" + Run-NvimLuaCommand "cli_refresh_plugins" @() + } + "fetch" { + Info "Action: Fetch NvPak updates (git pull)" + Run-NvimLuaCommand "cli_fetch_nvpak" @() + } + "help" { + Write-Host "NvPak CLI Help:" + Write-Host "-----------------" + Write-Host "Manages NvPak configuration and plugins from the command line." + Write-Host "" + Write-Host "Usage: nvpak [arguments]" + Write-Host "" + Write-Host "Commands:" + Write-Host " install Install a new plugin (e.g., 'user/repo')." + Write-Host " uninstall Uninstall a plugin." + Write-Host " update [plugin-name] Update a specific plugin or all plugins if no name is given." + Write-Host " upgrade Update all installed plugins." + Write-Host " refresh Synchronize plugins with the configuration (use after manual config changes)." + Write-Host " fetch Fetch the latest updates for NvPak itself from its repository." + Write-Host " help Show this help message." + Write-Host "" + Write-Host "Aliases can be defined in: $AliasFile" + Write-Host "Format: alias_name=command_name (e.g., in=install)" + } + default { + Error-Exit "Unknown command or alias: '$actionAlias' (resolved to '$action'). Run 'nvpak help'." + } +} + +exit 0 diff --git a/scripts/nvpak.sh b/scripts/nvpak.sh new file mode 100644 index 0000000..4103a04 --- /dev/null +++ b/scripts/nvpak.sh @@ -0,0 +1,169 @@ +#!/usr/bin/env bash + +# NvPak CLI - Command Line Interface for managing NvPak and its plugins. + +# --- Configuration --- +# Attempt to use XDG_CONFIG_HOME, fallback to ~/.config +NVPAK_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvpak" +NVIM_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvim" # NvPak's installation directory +ALIAS_FILE="$NVPAK_CONFIG_DIR/aliases.conf" +INSTALLER_MODULE="nvpak.core.installer" # The Lua module containing CLI functions + +# --- Helper Functions --- +print_message() { + local color_code="$1" + local message="$2" + echo -e "\033[${color_code}m${message}\033[0m" +} + +info() { print_message "34" "INFO: $1"; } +success() { print_message "32" "SUCCESS: $1"; } +warning() { print_message "33" "WARNING: $1"; } +error_exit() { + print_message "31" "ERROR: $1" >&2 + exit 1 +} + +command_exists() { + command -v "$1" &>/dev/null +} + +# Ensure Neovim is installed +if ! command_exists nvim; then + error_exit "Neovim (nvim) is not installed or not in your PATH. NvPak CLI requires Neovim." +fi + +# Ensure NvPak config directory exists (implies NvPak might be installed) +if [ ! -d "$NVIM_CONFIG_DIR" ] || [ ! -f "$NVIM_CONFIG_DIR/init.lua" ]; then + error_exit "NvPak configuration directory not found at $NVIM_CONFIG_DIR. Please install NvPak first." +fi + +# --- Alias Resolution --- +resolve_alias() { + local cmd_alias="$1" + if [ -f "$ALIAS_FILE" ]; then + # Read aliases, ignore comments and empty lines + # Format: alias_name=command_name + local resolved_cmd + resolved_cmd=$(grep -E "^\s*${cmd_alias}\s*=" "$ALIAS_FILE" | sed -E 's/^\s*[^=]+=\s*//' | tr -d '[:space:]') + if [ -n "$resolved_cmd" ]; then + echo "$resolved_cmd" + return + fi + fi + echo "$cmd_alias" # Return original if not found or file doesn't exist +} + +# --- Neovim Command Execution --- +# Executes a Lua function within NvPak's Neovim environment. +# $1: The Lua function to call (e.g., "cli_install_package") +# $2+: Arguments for the Lua function, each will be passed as a string. +run_nvim_lua_command() { + local lua_function_name="$1" + shift # Remove function name from arguments list + + local lua_args_string="" + local arg + for arg in "$@"; do + # Escape single quotes for Lua string literal + local escaped_arg=$(echo "$arg" | sed "s/'/'\\\\''/g") + if [ -z "$lua_args_string" ]; then + lua_args_string="'$escaped_arg'" + else + lua_args_string="$lua_args_string, '$escaped_arg'" + fi + done + + local lua_command="require('$INSTALLER_MODULE').$lua_function_name($lua_args_string)" + info "Executing Lua: $lua_command" + + # Using -u to load NvPak's init.lua ensures its environment (package paths etc.) is set up. + # --headless ensures no UI. + # We might not need -c "qall!" if the Lua functions handle exiting or if Neovim exits naturally. + # For interactive CLI commands that print output, Neovim needs to stay open long enough. + # The Lua functions should print to stdout/stderr for the CLI. + if nvim --headless -u "$NVIM_CONFIG_DIR/init.lua" -c "lua $lua_command" -c "lua vim.cmd('redraw') vim.cmd('sleep 100m') if vim.v.headless == 1 and vim.fn.argc() == 0 then vim.cmd('qall!') end"; then + # The sleep and redraw are attempts to ensure messages are flushed before nvim quits. + # The conditional qall! is to make sure it quits if truly headless and no other files were opened. + # This part might need refinement based on how Lua functions signal completion/output. + # For functions like 'fetch' that use jobstart, Neovim must remain running until the job completes. + # The Lua function itself should manage this, potentially by not exiting immediately if a job is running. + : # Success, Lua script might have printed its own success/error. + else + error_exit "Neovim command execution failed for '$lua_function_name'." + fi +} + +# --- Main CLI Logic --- +if [ "$#" -eq 0 ]; then + # TODO: Implement a proper help / usage message + info "Usage: nvpak [arguments]" + info "Available commands (pre-alias resolution): install, uninstall, update, upgrade, fetch, help" + info "Run 'nvpak help' for more details." + exit 0 +fi + +ACTION_ALIAS="$1" +shift # Remove action from arguments + +ACTION=$(resolve_alias "$ACTION_ALIAS") + +case "$ACTION" in + install) + if [ "$#" -lt 1 ]; then error_exit "Usage: nvpak install "; fi + info "Action: Install plugin '$1'" + run_nvim_lua_command "cli_install_package" "$1" + ;; + uninstall) + if [ "$#" -lt 1 ]; then error_exit "Usage: nvpak uninstall "; fi + info "Action: Uninstall plugin '$1'" + run_nvim_lua_command "cli_uninstall_package" "$1" + ;; + update) + # nvpak update (all) or nvpak update + if [ "$#" -eq 0 ]; then + info "Action: Update all plugins" + run_nvim_lua_command "cli_upgrade_all_packages" # Assuming upgrade_all_packages is the function for all + else + info "Action: Update plugin '$1'" + run_nvim_lua_command "cli_update_package" "$1" + fi + ;; + upgrade) + info "Action: Upgrade all plugins" + run_nvim_lua_command "cli_upgrade_all_packages" + ;; + refresh) + info "Action: Refresh plugin list and sync" + run_nvim_lua_command "cli_refresh_plugins" + ;; + fetch) + info "Action: Fetch NvPak updates (git pull)" + run_nvim_lua_command "cli_fetch_nvpak" + ;; + help) + # TODO: More detailed help message + echo "NvPak CLI Help:" + echo "-----------------" + echo "Manages NvPak configuration and plugins from the command line." + echo "" + echo "Usage: nvpak [arguments]" + echo "" + echo "Commands:" + echo " install Install a new plugin (e.g., 'user/repo')." + echo " uninstall Uninstall a plugin." + echo " update [plugin-name] Update a specific plugin or all plugins if no name is given." + echo " upgrade Update all installed plugins." + echo " refresh Synchronize plugins with the configuration (use after manual config changes)." + echo " fetch Fetch the latest updates for NvPak itself from its repository." + echo " help Show this help message." + echo "" + echo "Aliases can be defined in: $ALIAS_FILE" + echo "Format: alias_name=command_name (e.g., in=install)" + ;; + *) + error_exit "Unknown command or alias: '$ACTION_ALIAS' (resolved to '$ACTION'). Run 'nvpak help'." + ;; +esac + +exit 0 diff --git a/scripts/nvpak_aliases.conf.example b/scripts/nvpak_aliases.conf.example new file mode 100644 index 0000000..3f7644d --- /dev/null +++ b/scripts/nvpak_aliases.conf.example @@ -0,0 +1,26 @@ +# Example aliases for NvPak CLI +# Format: alias_name=command_name +# Lines starting with # or empty lines are ignored. + +# Installation +in=install +add=install + +# Uninstallation +un=uninstall +rm=uninstall +remove=uninstall + +# Update/Upgrade +up=update +ud=update +ug=upgrade + +# Fetch NvPak updates +pull=fetch +sync=fetch # Could also be an alias for a plugin sync command if one exists + +# Help +h=help +man=help +? =help