From 638f5e39540109c1cf4a1f5eee01400adb769593 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 6 Jul 2025 02:59:59 +0000 Subject: [PATCH 1/2] feat: Revamp installer and introduce nvpak CLI - Reworked install.sh and install.ps1 to be lightweight and delegate to a central Lua installer. - Created a Lua installer module (nvpak.core.installer) to handle: - Secondary dependency checks (ripgrep, fd, pynvim, clipboard tools). - Nerd Fonts guidance. - Plugin installation/synchronization via lazy.nvim. - Introduced 'nvpak' CLI tool (nvpak.sh, nvpak.ps1) for external management: - Commands: install, uninstall, update, upgrade, refresh, fetch, help. - Supports aliases via a configuration file. - 'install' and 'uninstall' currently provide guidance due to complexity of programmatic config modification; 'refresh' is used after manual changes. - Updated README.md with new installation instructions and CLI documentation. --- README.md | 163 +++++++---- install.ps1 | 266 ++++++++--------- install.sh | 408 ++++++++++++-------------- lua/nvpak/core/installer.lua | 455 +++++++++++++++++++++++++++++ scripts/nvpak.ps1 | 179 ++++++++++++ scripts/nvpak.sh | 169 +++++++++++ scripts/nvpak_aliases.conf.example | 26 ++ 7 files changed, 1251 insertions(+), 415 deletions(-) create mode 100644 lua/nvpak/core/installer.lua create mode 100644 scripts/nvpak.ps1 create mode 100644 scripts/nvpak.sh create mode 100644 scripts/nvpak_aliases.conf.example diff --git a/README.md b/README.md index 9260d7b..820900c 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,89 @@ 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 installer scripts (`install.sh`/`install.ps1`) do not automatically add the `nvpak` CLI scripts to your system's PATH. You'll need to do this manually for now, or you can run them directly by specifying their path. The CLI scripts are located in the `scripts/` directory of your NvPak installation (`$NVIM_CONFIG_DIR/scripts/`). + +**Recommended: Add to PATH** +1. Choose one of the following methods: + * **Symlink:** Create symbolic links to `nvpak.sh` (and `nvpak.ps1` for Windows PowerShell users) in a directory that is already in your PATH (e.g., `~/.local/bin` on Linux/macOS). + ```bash + # For Linux/macOS (assuming ~/.local/bin is in your PATH) + mkdir -p ~/.local/bin + ln -sfn "$HOME/.config/nvim/scripts/nvpak.sh" "$HOME/.local/bin/nvpak" + ``` + For PowerShell, you might add the `scripts` directory to your `$env:Path` or create an alias. + * **Copy:** Copy `nvpak.sh` and `nvpak.ps1` to a directory in your PATH. + * **Add NvPak's `scripts` directory to PATH:** Add `$HOME/.config/nvim/scripts` (or equivalent) to your shell's configuration file (e.g., `.bashrc`, `.zshrc`, PowerShell Profile). + +**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..5442aee 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,179 @@ 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 - } - else { - Error-Exit "Neovim command (nvim) not found even after installation attempt. Please check your PATH." + # 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)." } - 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, a new PowerShell session might be needed for PATH changes to fully apply." } # --- Entry Point --- diff --git a/install.sh b/install.sh index d7a5a73..2124c4f 100644 --- a/install.sh +++ b/install.sh @@ -1,282 +1,232 @@ #!/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" - else - error "Homebrew not found. Please install Homebrew first: https://brew.sh/" - 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 Git..." + if ! command_exists git; then + info "Git not found." + missing_deps+=("git") else - error "Unsupported operating system: $(uname). This script supports Linux, macOS, and Unix-like shells on Windows." + info "Git is installed." fi -fi - -info "Detected OS: $OS" - -# --- Dependency Installation Placeholder --- -# Will be filled in subsequent steps - -# --- Clone NvPak --- -NVIM_CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/nvim" -NVPAK_REPO_URL="https://github.com/Pakrohk-DotFiles/NvPak.git" -# --- 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." + 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 + info "Neovim is installed." fi - # Install core dependencies - info "Installing core dependencies (git, curl, unzip, neovim)..." - CORE_DEPS=("git" "curl" "unzip" "nvim") # nvim might be named differently (neovim) + 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 - 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 + info "Installing $actual_pkg_name..." + if eval "$pm_cmd $actual_pkg_name"; then + success "$actual_pkg_name installed successfully." 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." + 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 - # 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." + # 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 for Unix-like systems..." + + local os="" + local pm="" + local pm_update="" + + # 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 "ripgrep is already installed." + error_exit "Unsupported Linux distribution or package manager not found. Please install Git and Neovim manually and re-run." 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." + elif [[ "$(uname)" == "Darwin" ]]; then + os="Mac" + if command_exists brew; then + pm="brew install" + pm_update="brew update" else - info "fd is already installed." + error_exit "Homebrew not found on macOS. Please install Homebrew (https://brew.sh/) 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 - else - info "Clipboard tool (xclip, xsel, or wl-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" == "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." - 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 - - # 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; 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 + # 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 + ) + + 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 "Neovim command (nvim) not found even after installation attempt. Please check your PATH." + error_exit "NvPak Lua installer failed. Check Neovim output for errors." fi - 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'." + # The old messages about Nerd Fonts and running Neovim for plugins are now handled by the Lua installer. + 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)." } # --- 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 From aa70d79a5e5f3ca3e9c8c5193bb9c32429857449 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 6 Jul 2025 03:09:32 +0000 Subject: [PATCH 2/2] fix: Deploy nvpak CLI scripts and update documentation - Modified `install.sh` to attempt copying `nvpak.sh` to `~/.local/bin` or `/usr/local/bin` (with user prompt for sudo if needed). - Modified `install.ps1` to copy `nvpak.ps1` to `$env:LOCALAPPDATA\NvPak\bin` and provide instructions for adding the directory to PATH. - Updated `README.md` to reflect these new CLI deployment methods and provide clear setup instructions for the `nvpak` command. --- README.md | 30 +++++++++++++++------- install.ps1 | 45 ++++++++++++++++++++++++++++++++- install.sh | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 820900c..f483f66 100755 --- a/README.md +++ b/README.md @@ -145,19 +145,31 @@ NvPak now includes a command-line interface (CLI) tool named `nvpak` to help you **Setup for `nvpak` CLI:** -The installer scripts (`install.sh`/`install.ps1`) do not automatically add the `nvpak` CLI scripts to your system's PATH. You'll need to do this manually for now, or you can run them directly by specifying their path. The CLI scripts are located in the `scripts/` directory of your NvPak installation (`$NVIM_CONFIG_DIR/scripts/`). - -**Recommended: Add to PATH** -1. Choose one of the following methods: - * **Symlink:** Create symbolic links to `nvpak.sh` (and `nvpak.ps1` for Windows PowerShell users) in a directory that is already in your PATH (e.g., `~/.local/bin` on Linux/macOS). +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 - # For Linux/macOS (assuming ~/.local/bin is in your PATH) mkdir -p ~/.local/bin ln -sfn "$HOME/.config/nvim/scripts/nvpak.sh" "$HOME/.local/bin/nvpak" ``` - For PowerShell, you might add the `scripts` directory to your `$env:Path` or create an alias. - * **Copy:** Copy `nvpak.sh` and `nvpak.ps1` to a directory in your PATH. - * **Add NvPak's `scripts` directory to PATH:** Add `$HOME/.config/nvim/scripts` (or equivalent) to your shell's configuration file (e.g., `.bashrc`, `.zshrc`, PowerShell Profile). + Ensure the script is executable (`chmod +x ~/.local/bin/nvpak`). **CLI Commands:** diff --git a/install.ps1 b/install.ps1 index 5442aee..a0cdecc 100644 --- a/install.ps1 +++ b/install.ps1 @@ -205,8 +205,51 @@ function Main { 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 { + 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 PowerShell script part finished!" - Info "If Scoop installed or updated tools, a new PowerShell session might be needed for PATH changes to fully apply." + 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 2124c4f..f4fbee4 100644 --- a/install.sh +++ b/install.sh @@ -225,8 +225,78 @@ main() { fi # The old messages about Nerd Fonts and running Neovim for plugins are now handled by the Lua installer. + + # --- 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 + 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 shell script part finished!" - info "Please restart your terminal if new tools were installed by your package manager earlier (e.g., Neovim itself)." + 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 ---