#!/bin/bash # Neovim Configuration Dependencies Installer # Compatible with: Ubuntu/Debian, Fedora/RHEL, Arch/Manjaro, openSUSE, Alpine # Version: 1.0 set -e # Colors and styling RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' WHITE='\033[1;37m' BOLD='\033[1m' DIM='\033[2m' NC='\033[0m' # No Color # Unicode characters CHECKMARK="✓" CROSS="✗" ARROW="→" STAR="★" GEAR="⚙" ROCKET="🚀" PACKAGE="📦" # Global variables DISTRO="" PACKAGE_MANAGER="" INSTALL_CMD="" UPDATE_CMD="" LOG_FILE="/tmp/nvim_installer.log" TEMP_DIR="/tmp/nvim_deps_build" # Detect distribution detect_distro() { if [ -f /etc/os-release ]; then . /etc/os-release case "$ID" in ubuntu | debian | pop | elementary | linuxmint) DISTRO="debian" PACKAGE_MANAGER="apt" INSTALL_CMD="apt install -y" UPDATE_CMD="apt update" ;; fedora | rhel | centos | rocky | almalinux) DISTRO="fedora" PACKAGE_MANAGER="dnf" INSTALL_CMD="dnf install -y" UPDATE_CMD="dnf check-update || true" ;; arch | manjaro | endeavouros | garuda) DISTRO="arch" PACKAGE_MANAGER="pacman" INSTALL_CMD="pacman -S --noconfirm" UPDATE_CMD="pacman -Sy" ;; opensuse* | sles) DISTRO="opensuse" PACKAGE_MANAGER="zypper" INSTALL_CMD="zypper install -y" UPDATE_CMD="zypper refresh" ;; alpine) DISTRO="alpine" PACKAGE_MANAGER="apk" INSTALL_CMD="apk add" UPDATE_CMD="apk update" ;; *) echo -e "${RED}${CROSS} Unsupported distribution: $ID${NC}" exit 1 ;; esac else echo -e "${RED}${CROSS} Cannot detect distribution${NC}" exit 1 fi } # Print styled header print_header() { clear echo -e "${PURPLE}╔════════════════════════════════════════════════════════════════════╗${NC}" echo -e "${PURPLE}║${NC}${BOLD}${WHITE} ${ROCKET} NEOVIM DEPENDENCY INSTALLER ${ROCKET} ${NC}${PURPLE}║${NC}" echo -e "${PURPLE}║${NC}${DIM} Ultimate Setup for Modern Neovim ${NC}${PURPLE}║${NC}" echo -e "${PURPLE}╚════════════════════════════════════════════════════════════════════╝${NC}" echo echo -e "${CYAN}${BOLD}Detected System:${NC} ${GREEN}$DISTRO${NC} (${PACKAGE_MANAGER})" echo -e "${CYAN}${BOLD}Install Location:${NC} ${GREEN}$(which nvim 2>/dev/null || echo "Will be installed")${NC}" echo } # Print section header print_section() { local title="$1" local icon="$2" echo -e "\n${PURPLE}${BOLD}┌─${NC} ${icon} ${BOLD}${WHITE}$title${NC}" echo -e "${PURPLE}${BOLD}└─${NC}${DIM}────────────────────────────────────────────────────${NC}" } # Print step with status print_step() { local step="$1" local status="$2" case "$status" in "start") echo -ne "${YELLOW} ${GEAR} ${step}...${NC}" ;; "ok") echo -e "\r${GREEN} ${CHECKMARK} ${step}${NC}" ;; "fail") echo -e "\r${RED} ${CROSS} ${step}${NC}" ;; "skip") echo -e "${BLUE} ${ARROW} ${step} (already installed)${NC}" ;; esac } # Log function log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >>"$LOG_FILE" } # Check if command exists command_exists() { command -v "$1" >/dev/null 2>&1 } # Check if package is installed package_installed() { case "$PACKAGE_MANAGER" in apt) dpkg -l "$1" 2>/dev/null | grep -q "^ii" ;; dnf) dnf list installed "$1" >/dev/null 2>&1 ;; pacman) pacman -Q "$1" >/dev/null 2>&1 ;; zypper) zypper search -i "$1" | grep -q "^i" ;; apk) apk info -e "$1" >/dev/null 2>&1 ;; esac } # Install package with error handling install_package() { local package="$1" local description="$2" print_step "Installing $description" "start" if package_installed "$package" 2>/dev/null; then print_step "Installing $description" "skip" return 0 fi if sudo $INSTALL_CMD "$package" >>"$LOG_FILE" 2>&1; then print_step "Installing $description" "ok" log "Successfully installed $package" else print_step "Installing $description" "fail" log "Failed to install $package" return 1 fi } # Update package manager update_packages() { print_step "Updating package database" "start" if sudo $UPDATE_CMD >>"$LOG_FILE" 2>&1; then print_step "Updating package database" "ok" else print_step "Updating package database" "fail" echo -e "${YELLOW}Warning: Package update failed, continuing anyway...${NC}" fi } # Install system dependencies install_system_deps() { print_section "System Dependencies" "${PACKAGE}" case "$DISTRO" in debian) local packages=( "curl:HTTP client" "wget:Download utility" "git:Version control" "build-essential:Build tools" "cmake:Build system" "gettext:Internationalization" "ninja-build:Build system" "unzip:Archive utility" "tar:Archive utility" "gzip:Compression utility" "file:File type detection" "pkg-config:Package configuration" "libtool:Library tools" "autoconf:Configure script generator" "automake:Makefile generator" "libreadline-dev:Readline library" "libncurses5-dev:Terminal handling" "libssl-dev:SSL/TLS library" "zlib1g-dev:Compression library" "lua5.1:Lua interpreter" "liblua5.1-dev:Lua development files" ) ;; fedora) local packages=( "curl:HTTP client" "wget:Download utility" "git:Version control" "gcc:C compiler" "gcc-c++:C++ compiler" "make:Build utility" "cmake:Build system" "ninja-build:Build system" "gettext:Internationalization" "unzip:Archive utility" "tar:Archive utility" "gzip:Compression utility" "file:File type detection" "pkgconfig:Package configuration" "libtool:Library tools" "autoconf:Configure script generator" "automake:Makefile generator" "readline-devel:Readline library" "ncurses-devel:Terminal handling" "openssl-devel:SSL/TLS library" "zlib-devel:Compression library" "lua:Lua interpreter" "lua-devel:Lua development files" ) ;; arch) local packages=( "curl:HTTP client" "wget:Download utility" "git:Version control" "base-devel:Development tools" "cmake:Build system" "ninja:Build system" "gettext:Internationalization" "unzip:Archive utility" "tar:Archive utility" "gzip:Compression utility" "file:File type detection" "pkgconf:Package configuration" "libtool:Library tools" "autoconf:Configure script generator" "automake:Makefile generator" "readline:Readline library" "ncurses:Terminal handling" "openssl:SSL/TLS library" "zlib:Compression library" "lua51:Lua interpreter" ) ;; opensuse) local packages=( "curl:HTTP client" "wget:Download utility" "git:Version control" "gcc:C compiler" "gcc-c++:C++ compiler" "make:Build utility" "cmake:Build system" "ninja:Build system" "gettext-tools:Internationalization" "unzip:Archive utility" "tar:Archive utility" "gzip:Compression utility" "file:File type detection" "pkg-config:Package configuration" "libtool:Library tools" "autoconf:Configure script generator" "automake:Makefile generator" "readline-devel:Readline library" "ncurses-devel:Terminal handling" "libopenssl-devel:SSL/TLS library" "zlib-devel:Compression library" "lua51:Lua interpreter" "lua51-devel:Lua development files" ) ;; alpine) local packages=( "curl:HTTP client" "wget:Download utility" "git:Version control" "build-base:Build tools" "cmake:Build system" "samurai:Build system" "gettext:Internationalization" "unzip:Archive utility" "tar:Archive utility" "gzip:Compression utility" "file:File type detection" "pkgconfig:Package configuration" "libtool:Library tools" "autoconf:Configure script generator" "automake:Makefile generator" "readline-dev:Readline library" "ncurses-dev:Terminal handling" "openssl-dev:SSL/TLS library" "zlib-dev:Compression library" "lua5.1:Lua interpreter" "lua5.1-dev:Lua development files" ) ;; esac for package_info in "${packages[@]}"; do IFS=':' read -r package description <<<"$package_info" install_package "$package" "$description" || true done } # Install development tools install_dev_tools() { print_section "Development Tools" "🛠️" # Node.js and npm if ! command_exists node; then case "$DISTRO" in debian) print_step "Installing Node.js via NodeSource" "start" curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - >>"$LOG_FILE" 2>&1 install_package "nodejs" "Node.js runtime" ;; fedora) install_package "nodejs" "Node.js runtime" install_package "npm" "Node package manager" ;; arch) install_package "nodejs" "Node.js runtime" install_package "npm" "Node package manager" ;; opensuse) install_package "nodejs18" "Node.js runtime" install_package "npm18" "Node package manager" ;; alpine) install_package "nodejs" "Node.js runtime" install_package "npm" "Node package manager" ;; esac else print_step "Installing Node.js runtime" "skip" fi # Python and pip if ! command_exists python3; then install_package "python3" "Python interpreter" else print_step "Installing Python interpreter" "skip" fi if ! command_exists pip3; then case "$DISTRO" in debian) install_package "python3-pip" "Python package manager" ;; fedora | opensuse) install_package "python3-pip" "Python package manager" ;; arch) install_package "python-pip" "Python package manager" ;; alpine) install_package "py3-pip" "Python package manager" ;; esac else print_step "Installing Python package manager" "skip" fi # Ripgrep for telescope if ! command_exists rg; then case "$DISTRO" in debian) install_package "ripgrep" "Fast grep alternative" ;; fedora | arch | opensuse) install_package "ripgrep" "Fast grep alternative" ;; alpine) install_package "ripgrep" "Fast grep alternative" ;; esac else print_step "Installing fast grep alternative" "skip" fi # fd-find for telescope if ! command_exists fd; then case "$DISTRO" in debian) install_package "fd-find" "Fast find alternative" ;; fedora | arch | opensuse | alpine) install_package "fd" "Fast find alternative" ;; esac else print_step "Installing fast find alternative" "skip" fi } # Build and install LuaJIT install_luajit() { print_section "LuaJIT Installation" "⚡" if command_exists luajit; then print_step "Installing LuaJIT" "skip" return 0 fi print_step "Downloading LuaJIT source" "start" mkdir -p "$TEMP_DIR" cd "$TEMP_DIR" if git clone https://github.com/LuaJIT/LuaJIT.git >>"$LOG_FILE" 2>&1; then print_step "Downloading LuaJIT source" "ok" else print_step "Downloading LuaJIT source" "fail" return 1 fi cd LuaJIT print_step "Compiling LuaJIT" "start" if make >>"$LOG_FILE" 2>&1; then print_step "Compiling LuaJIT" "ok" else print_step "Compiling LuaJIT" "fail" return 1 fi print_step "Installing LuaJIT" "start" if sudo make install >>"$LOG_FILE" 2>&1; then print_step "Installing LuaJIT" "ok" # Update library path echo "/usr/local/lib" | sudo tee /etc/ld.so.conf.d/luajit.conf >/dev/null sudo ldconfig else print_step "Installing LuaJIT" "fail" return 1 fi } # Build and install LuaRocks install_luarocks() { print_section "LuaRocks Installation" "💎" if command_exists luarocks; then print_step "Installing LuaRocks" "skip" return 0 fi print_step "Downloading LuaRocks source" "start" cd "$TEMP_DIR" if wget -q https://luarocks.org/releases/luarocks-3.9.2.tar.gz >>"$LOG_FILE" 2>&1; then print_step "Downloading LuaRocks source" "ok" else print_step "Downloading LuaRocks source" "fail" return 1 fi tar -zxf luarocks-3.9.2.tar.gz cd luarocks-3.9.2 print_step "Configuring LuaRocks build" "start" if ./configure --with-lua-include=/usr/local/include/luajit-2.1 >>"$LOG_FILE" 2>&1; then print_step "Configuring LuaRocks build" "ok" else print_step "Configuring LuaRocks build" "fail" return 1 fi print_step "Compiling LuaRocks" "start" if make >>"$LOG_FILE" 2>&1; then print_step "Compiling LuaRocks" "ok" else print_step "Compiling LuaRocks" "fail" return 1 fi print_step "Installing LuaRocks" "start" if sudo make install >>"$LOG_FILE" 2>&1; then print_step "Installing LuaRocks" "ok" else print_step "Installing LuaRocks" "fail" return 1 fi } # Install Neovim install_neovim() { print_section "Neovim Installation" "${ROCKET}" if command_exists nvim; then local current_version=$(nvim --version | head -n1 | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+') print_step "Installing Neovim ($current_version installed)" "skip" return 0 fi print_step "Downloading latest Neovim" "start" cd "$TEMP_DIR" if wget -q https://github.com/neovim/neovim/releases/latest/download/nvim-linux64.tar.gz >>"$LOG_FILE" 2>&1; then print_step "Downloading latest Neovim" "ok" else print_step "Downloading latest Neovim" "fail" return 1 fi print_step "Installing Neovim" "start" tar -zxf nvim-linux64.tar.gz sudo cp -r nvim-linux64/* /usr/local/ >>"$LOG_FILE" 2>&1 if command -v nvim >/dev/null 2>&1; then print_step "Installing Neovim" "ok" else print_step "Installing Neovim" "fail" return 1 fi } # Install LSP servers and tools install_lsp_tools() { print_section "LSP Servers & Tools" "🔧" # Install language servers via npm local npm_packages=( "typescript-language-server:TypeScript LSP" "bash-language-server:Bash LSP" "vscode-langservers-extracted:HTML/CSS/JSON LSP" "@tailwindcss/language-server:Tailwind CSS LSP" "yaml-language-server:YAML LSP" "dockerfile-language-server-nodejs:Docker LSP" ) for package_info in "${npm_packages[@]}"; do IFS=':' read -r package description <<<"$package_info" print_step "Installing $description" "start" if sudo npm install -g "$package" >>"$LOG_FILE" 2>&1; then print_step "Installing $description" "ok" else print_step "Installing $description" "fail" fi done # Install Python tools print_step "Installing Python language server" "start" if pip3 install --user pyright >>"$LOG_FILE" 2>&1; then print_step "Installing Python language server" "ok" else print_step "Installing Python language server" "fail" fi print_step "Installing Python linter/formatter" "start" if pip3 install --user ruff >>"$LOG_FILE" 2>&1; then print_step "Installing Python linter/formatter" "ok" else print_step "Installing Python linter/formatter" "fail" fi } # Install additional utilities install_utilities() { print_section "Additional Utilities" "🎯" # LazyGit if ! command_exists lazygit; then print_step "Installing LazyGit" "start" case "$DISTRO" in debian) local lazygit_version=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep -Po '"tag_name": "v\K[^"]*') curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${lazygit_version}_Linux_x86_64.tar.gz" >>"$LOG_FILE" 2>&1 tar xf lazygit.tar.gz lazygit sudo install lazygit /usr/local/bin ;; arch) install_package "lazygit" "Git TUI" ;; fedora) sudo dnf copr enable atim/lazygit -y >>"$LOG_FILE" 2>&1 install_package "lazygit" "Git TUI" ;; *) # Fallback to binary installation local lazygit_version=$(curl -s "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | grep -Po '"tag_name": "v\K[^"]*') curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_${lazygit_version}_Linux_x86_64.tar.gz" >>"$LOG_FILE" 2>&1 tar xf lazygit.tar.gz lazygit sudo install lazygit /usr/local/bin ;; esac print_step "Installing LazyGit" "ok" else print_step "Installing LazyGit" "skip" fi # Tree-sitter CLI print_step "Installing Tree-sitter CLI" "start" if sudo npm install -g tree-sitter-cli >>"$LOG_FILE" 2>&1; then print_step "Installing Tree-sitter CLI" "ok" else print_step "Installing Tree-sitter CLI" "fail" fi } # Copy Neovim configuration setup_neovim_config() { print_section "Neovim Configuration Setup" "⚙️" # Create Neovim config directory print_step "Creating Neovim config directory" "start" mkdir -p ~/.config/nvim print_step "Creating Neovim config directory" "ok" # Look for init.lua in common locations local config_found=false local config_source="" # Check if init.lua exists in current directory if [ -f "./init.lua" ]; then config_source="./init.lua" config_found=true # Check if there's a paste.txt file (from your upload) elif [ -f "./paste.txt" ]; then config_source="./paste.txt" config_found=true # Check in nvim subdirectory elif [ -f "./nvim/init.lua" ]; then config_source="./nvim/init.lua" config_found=true # Check in .config/nvim subdirectory elif [ -f "./.config/nvim/init.lua" ]; then config_source="./.config/nvim/init.lua" config_found=true # Check in lua subdirectory elif [ -f "./lua/init.lua" ]; then config_source="./lua/init.lua" config_found=true fi if [ "$config_found" = true ]; then print_step "Found Neovim configuration" "ok" # Backup existing config if it exists if [ -f ~/.config/nvim/init.lua ]; then print_step "Backing up existing configuration" "start" cp ~/.config/nvim/init.lua ~/.config/nvim/init.lua.backup.$(date +%Y%m%d_%H%M%S) print_step "Backing up existing configuration" "ok" fi print_step "Installing Neovim configuration" "start" cp "$config_source" ~/.config/nvim/init.lua chmod 644 ~/.config/nvim/init.lua print_step "Installing Neovim configuration" "ok" # If there are additional lua files, copy them too if [ -d "./lua" ]; then print_step "Copying additional Lua modules" "start" cp -r ./lua ~/.config/nvim/ 2>/dev/null || true print_step "Copying additional Lua modules" "ok" fi return 0 else print_step "Searching for Neovim configuration" "fail" echo -e "${YELLOW} ${ARROW} No init.lua found in current directory${NC}" echo -e "${YELLOW} ${ARROW} Place your init.lua in the same folder as this script${NC}" echo -e "${YELLOW} ${ARROW} Or run this script from your config repository${NC}" return 1 fi } # Final setup and verification final_setup() { print_section "Final Setup & Verification" "🎉" # Set up environment print_step "Setting up environment" "start" if ! grep -q "/usr/local/bin" ~/.bashrc 2>/dev/null; then echo 'export PATH="/usr/local/bin:$PATH"' >>~/.bashrc fi # Also add to .profile for other shells if ! grep -q "/usr/local/bin" ~/.profile 2>/dev/null; then echo 'export PATH="/usr/local/bin:$PATH"' >>~/.profile fi print_step "Setting up environment" "ok" # Verify installations print_step "Verifying Neovim installation" "start" if command -v nvim >/dev/null 2>&1; then print_step "Verifying Neovim installation" "ok" else print_step "Verifying Neovim installation" "fail" fi # Test configuration if [ -f ~/.config/nvim/init.lua ]; then print_step "Validating Neovim configuration" "start" if nvim --headless -c "lua vim.print('Config OK')" -c "qa" >>"$LOG_FILE" 2>&1; then print_step "Validating Neovim configuration" "ok" else print_step "Validating Neovim configuration" "fail" echo -e "${YELLOW} ${ARROW} Configuration may have syntax errors${NC}" fi fi # Clean up print_step "Cleaning up temporary files" "start" rm -rf "$TEMP_DIR" print_step "Cleaning up temporary files" "ok" } # Print final message print_completion() { echo echo -e "${PURPLE}╔════════════════════════════════════════════════════════════════════╗${NC}" echo -e "${PURPLE}║${NC}${BOLD}${GREEN} ${CHECKMARK} INSTALLATION COMPLETE ${CHECKMARK} ${NC}${PURPLE}║${NC}" echo -e "${PURPLE}╚════════════════════════════════════════════════════════════════════╝${NC}" echo echo -e "${GREEN}${BOLD}What's been installed:${NC}" echo -e "${WHITE} ${CHECKMARK} Neovim (latest stable)${NC}" echo -e "${WHITE} ${CHECKMARK} LuaJIT (compiled from source)${NC}" echo -e "${WHITE} ${CHECKMARK} LuaRocks (package manager)${NC}" echo -e "${WHITE} ${CHECKMARK} All system dependencies${NC}" echo -e "${WHITE} ${CHECKMARK} LSP servers (TypeScript, Python, Bash, etc.)${NC}" echo -e "${WHITE} ${CHECKMARK} Development tools (Node.js, Python, ripgrep, fd)${NC}" echo -e "${WHITE} ${CHECKMARK} LazyGit (Git TUI)${NC}" echo -e "${WHITE} ${CHECKMARK} Tree-sitter CLI${NC}" if [ -f ~/.config/nvim/init.lua ]; then echo -e "${WHITE} ${CHECKMARK} Your Neovim configuration${NC}" fi echo echo -e "${CYAN}${BOLD}Next steps:${NC}" if [ -f ~/.config/nvim/init.lua ]; then echo -e "${WHITE} 1. Restart your terminal or run: source ~/.bashrc${NC}" echo -e "${WHITE} 2. Launch Neovim: nvim${NC}" echo -e "${WHITE} 3. Wait for Lazy.nvim to install plugins automatically${NC}" echo -e "${WHITE} 4. Run :checkhealth to verify everything works${NC}" else echo -e "${WHITE} 1. Copy your Neovim configuration to ~/.config/nvim/init.lua${NC}" echo -e "${WHITE} 2. Restart your terminal or run: source ~/.bashrc${NC}" echo -e "${WHITE} 3. Launch Neovim: nvim${NC}" echo -e "${WHITE} 4. Let Lazy.nvim install the plugins automatically${NC}" fi echo echo -e "${BLUE}${BOLD}Useful commands:${NC}" echo -e "${WHITE} • nvim --version ${DIM}# Check Neovim version${NC}" echo -e "${WHITE} • :checkhealth ${DIM}# Verify setup in Neovim${NC}" echo -e "${WHITE} • :Lazy ${DIM}# Manage plugins${NC}" echo -e "${WHITE} • :Mason ${DIM}# Manage LSP servers${NC}" echo echo -e "${YELLOW}Log file: $LOG_FILE${NC}" echo -e "${GREEN}Happy coding! ${ROCKET}${NC}" } # Error handler handle_error() { echo -e "\n${RED}${CROSS} Installation failed!${NC}" echo -e "${YELLOW}Check the log file for details: $LOG_FILE${NC}" exit 1 } # Main installation function main() { # Set up error handling trap handle_error ERR # Initialize log echo "Neovim Dependencies Installation - $(date)" >"$LOG_FILE" # Check if running as root if [[ $EUID -eq 0 ]]; then echo -e "${RED}${CROSS} Please don't run this script as root!${NC}" exit 1 fi # Detect distribution detect_distro # Print header print_header # Confirm installation echo -e "${YELLOW}${BOLD}This script will install:${NC}" echo -e "${WHITE} • System dependencies and build tools${NC}" echo -e "${WHITE} • LuaJIT (compiled from source)${NC}" echo -e "${WHITE} • LuaRocks package manager${NC}" echo -e "${WHITE} • Latest Neovim${NC}" echo -e "${WHITE} • LSP servers and development tools${NC}" echo -e "${WHITE} • Additional utilities (LazyGit, Tree-sitter, etc.)${NC}" # Check if config file exists local config_preview="" if [ -f "./init.lua" ]; then config_preview=" (init.lua found - will be installed)" elif [ -f "./paste.txt" ]; then config_preview=" (paste.txt found - will be installed as init.lua)" elif [ -f "./nvim/init.lua" ] || [ -f "./.config/nvim/init.lua" ] || [ -f "./lua/init.lua" ]; then config_preview=" (configuration found - will be installed)" fi if [ -n "$config_preview" ]; then echo -e "${WHITE} • Your Neovim configuration${GREEN}${config_preview}${NC}" fi echo echo -ne "${CYAN}Continue with installation? [Y/n]: ${NC}" read -r response if [[ "$response" =~ ^[Nn]$ ]]; then echo -e "${YELLOW}Installation cancelled.${NC}" exit 0 fi echo -e "\n${BLUE}${BOLD}Starting installation...${NC}" # Run installation steps update_packages install_system_deps install_dev_tools install_luajit install_luarocks install_neovim install_lsp_tools install_utilities setup_neovim_config # Add config setup final_setup # Show completion message print_completion } # Run main function main "$@"