Files
LinuxInstalls/nvim/setup_neovim.sh
T
2026-09-30 16:29:04 -03:00

322 lines
15 KiB
Bash
Executable File

#!/bin/bash
# Resolve this script's own directory so config/ can sit right next to
# it and be found regardless of where/how this is invoked (./setup_neovim.sh,
# bash /some/path/setup_neovim.sh, a symlink, etc.) -- config and other
# files are real, standalone files under config/, not embedded in this
# script, so this script's only job is installing dependencies and
# copying them into place.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_DIR="$SCRIPT_DIR/config"
if [ ! -d "$CONFIG_DIR" ]; then
echo "ERROR: $CONFIG_DIR not found."
echo "This script expects a config/ directory next to it (keep the two together"
echo "however you copy/clone this -- e.g. don't move setup_neovim.sh on its own)."
exit 1
fi
echo
echo "========================================="
echo " Starting Neovim Setup"
echo "========================================="
# 1. Detect distro and install system dependencies
echo "[1/4] Detecting distro and installing system dependencies..."
if [ ! -f /etc/os-release ]; then
echo "ERROR: Cannot detect your Linux distribution (/etc/os-release not found)."
echo "This script supports Fedora, Ubuntu, Debian, and Arch Linux."
exit 1
fi
. /etc/os-release
DISTRO_ID="$ID"
DISTRO_ID_LIKE="${ID_LIKE:-}"
# Normalize into one of: fedora, debian, arch. Checking ID_LIKE too so
# common derivatives (Pop!_OS, Linux Mint, Manjaro, EndeavourOS, etc.)
# land in the right family even though only the four distros above
# were specifically asked for.
case "$DISTRO_ID $DISTRO_ID_LIKE" in
*fedora*|*rhel*)
DISTRO_FAMILY="fedora"
;;
*arch*)
DISTRO_FAMILY="arch"
;;
*debian*|*ubuntu*)
DISTRO_FAMILY="debian"
;;
*)
echo "ERROR: Unsupported or undetected distro (ID=$DISTRO_ID, ID_LIKE=$DISTRO_ID_LIKE)."
echo "This script supports Fedora, Ubuntu, Debian, and Arch Linux."
exit 1
;;
esac
echo "Detected: $DISTRO_ID (family: $DISTRO_FAMILY)"
# Which Neovim frontend(s) to set up. Neovide (a separate GUI
# application) always runs the real `nvim` binary as its backend --
# the terminal-based install right below happens either way and is
# what Neovide itself depends on -- this choice only controls whether
# Neovide is ALSO installed on top of it. Both frontends share the
# exact same config (see config/nvim/init.lua's `if vim.g.neovide`
# block), so there's nothing else to pick between; this is purely an
# installation question.
NVIM_FRONTEND="terminal"
if [ -t 0 ]; then
echo
echo "Which Neovim frontend(s) do you want installed?"
echo " 1) Terminal-based only (nvim in your terminal)"
echo " 2) Desktop application only (Neovide GUI -- still needs the nvim"
echo " binary below as its backend, so that's installed either way)"
echo " 3) Both"
read -rp "Enter 1, 2, or 3 [1]: " FRONTEND_CHOICE
case "$FRONTEND_CHOICE" in
2) NVIM_FRONTEND="desktop" ;;
3) NVIM_FRONTEND="both" ;;
*) NVIM_FRONTEND="terminal" ;;
esac
else
echo "Non-interactive shell detected -- defaulting to terminal-based Neovim only."
echo "Run this script directly (not piped) and choose option 2 or 3 to also install Neovide."
fi
# The MariaDB *client* (not the server) is installed too: vim-dadbod runs
# queries by shelling out to the `mariadb` binary. The package name differs
# per distro -- Fedora: mariadb, Debian/Ubuntu: mariadb-client, Arch:
# mariadb-clients. To actually query something you also need a server
# running somewhere; this script neither installs nor starts one.
case "$DISTRO_FAMILY" in
fedora)
sudo dnf install -y neovim git curl wget gcc gcc-c++ make cmake \
nodejs npm python3-pip ripgrep fd-find \
golang clang-tools-extra dotnet-sdk-8.0 unzip fontconfig \
lldb gdb fish mariadb
;;
debian)
export DEBIAN_FRONTEND=noninteractive
sudo apt-get update
# Package name differences from Fedora: g++ (not gcc-c++),
# golang-go (not golang), clang-tools (not clang-tools-extra --
# Debian/Ubuntu split clang-format/clang-tidy differently, this
# is the closest equivalent bundle).
sudo apt-get install -y neovim git curl wget gcc g++ make cmake \
nodejs npm python3-pip ripgrep fd-find \
golang-go clang-tools unzip fontconfig \
lldb gdb fish mariadb-client
# fd-find installs its binary as `fdfind` on Debian/Ubuntu (a
# name clash with an unrelated existing package called `fd`),
# unlike Fedora/Arch where it's just `fd`. Symlink it so tools
# that look for a plain `fd` on PATH (e.g. Telescope's
# find_files) work the same way here as everywhere else.
if command -v fdfind >/dev/null 2>&1 && ! command -v fd >/dev/null 2>&1; then
mkdir -p "$HOME/.local/bin"
ln -sf "$(command -v fdfind)" "$HOME/.local/bin/fd"
echo "Symlinked fdfind -> ~/.local/bin/fd (make sure ~/.local/bin is on your PATH)."
fi
# .NET SDK: Ubuntu ships dotnet-sdk-8.0 directly in its own
# repos. Debian does not (long-standing packaging/licensing
# reasons) and needs Microsoft's own apt feed added first.
# Best-effort either way -- a failure here doesn't stop the
# rest of the script, since this only matters for C#/omnisharp.
if [ "$DISTRO_ID" = "ubuntu" ] || echo "$DISTRO_ID_LIKE" | grep -qi ubuntu; then
sudo apt-get install -y dotnet-sdk-8.0 || \
echo "WARNING: dotnet-sdk-8.0 install failed -- see https://learn.microsoft.com/en-us/dotnet/core/install/linux-ubuntu-install"
else
(
set -e
DEBIAN_MAJOR="${VERSION_ID%%.*}"
wget -q "https://packages.microsoft.com/config/debian/${DEBIAN_MAJOR}/packages-microsoft-prod.deb" -O /tmp/packages-microsoft-prod.deb
sudo dpkg -i /tmp/packages-microsoft-prod.deb
rm -f /tmp/packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-sdk-8.0
) || echo "WARNING: dotnet-sdk-8.0 install failed -- see https://learn.microsoft.com/en-us/dotnet/core/install/linux-debian for manual steps"
fi
;;
arch)
# Arch's own wiki explicitly warns against `pacman -Sy
# <package>` (sync without upgrading first) -- it risks
# partial-upgrade dependency issues. -Syu first is the
# recommended safe order; this does mean the script also
# upgrades your existing packages, not just installs new ones,
# which is expected/intentional here, not a side effect to
# work around.
sudo pacman -Syu --noconfirm
# Package name differences from Fedora: gcc includes g++
# already (no separate gcc-c++ package), python-pip (not
# python3-pip -- Arch's default python already is python3),
# fd (not fd-find), go (not golang), clang bundles clang-format/
# clang-tidy directly (no separate clang-tools-extra).
sudo pacman -S --noconfirm neovim git curl wget gcc make cmake \
nodejs npm python-pip ripgrep fd \
go clang dotnet-sdk-8.0 unzip fontconfig \
lldb gdb fish mariadb-clients
;;
esac
# Neovide install, if chosen above. Best-effort, same philosophy as
# the .NET SDK install below: a failure here is a WARNING, not a
# reason to stop the rest of the setup.
if [ "$NVIM_FRONTEND" = "desktop" ] || [ "$NVIM_FRONTEND" = "both" ]; then
echo "Installing Neovide (desktop Neovim GUI)..."
case "$DISTRO_FAMILY" in
arch)
# Packaged directly upstream -- see
# https://neovide.dev/installation.html#arch-linux
sudo pacman -S --noconfirm neovide libxkbcommon-x11 || \
echo "WARNING: Neovide install failed -- see https://neovide.dev/installation.html"
;;
fedora|debian)
# Neither Fedora nor Debian/Ubuntu package Neovide --
# upstream's own install docs point at building it from
# source via cargo instead. This pulls in a Rust
# toolchain (via rustup, only if cargo isn't already on
# PATH) and compiles Neovide and its dependency tree,
# which can take several minutes.
echo "Neovide has no Fedora/Debian/Ubuntu package -- building it from source"
echo "(via cargo -- this can take several minutes)..."
(
set -e
case "$DISTRO_FAMILY" in
fedora)
sudo dnf install -y clang ninja-build fontconfig-devel freetype-devel \
@development-tools libstdc++-static libstdc++-devel
;;
debian)
sudo apt-get install -y curl gnupg ca-certificates git clang ninja-build \
gcc-multilib g++-multilib cmake libssl-dev pkg-config libfreetype6-dev \
libasound2-dev libexpat1-dev libxcb-composite0-dev libbz2-dev libsndio-dev \
freeglut3-dev libxmu-dev libxi-dev libfontconfig1-dev libxcursor-dev
;;
esac
if ! command -v cargo >/dev/null 2>&1; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
# shellcheck disable=SC1091
. "$HOME/.cargo/env"
cargo install --git https://github.com/neovide/neovide --locked
) || echo "WARNING: Neovide build failed -- see https://neovide.dev/installation.html#linux-source for manual steps"
;;
esac
fi
# This config relies on fairly recent Neovim APIs (vim.lsp.config/
# enable, virtual_lines diagnostics, vim.o.winborder -- all 0.11+).
# Distro-packaged Neovim can lag well behind that, especially on
# Debian stable and older Ubuntu LTS releases. Warn (don't fail) if
# what actually got installed is too old.
NVIM_VER_LINE=$(nvim --version 2>/dev/null | head -n1)
NVIM_MAJOR=$(echo "$NVIM_VER_LINE" | sed -n 's/.*v\([0-9]*\)\.\([0-9]*\).*/\1/p')
NVIM_MINOR=$(echo "$NVIM_VER_LINE" | sed -n 's/.*v\([0-9]*\)\.\([0-9]*\).*/\2/p')
if [ -n "$NVIM_MAJOR" ] && [ -n "$NVIM_MINOR" ] && [ "$NVIM_MAJOR" -eq 0 ] && [ "$NVIM_MINOR" -lt 11 ]; then
echo "WARNING: Installed Neovim is v${NVIM_MAJOR}.${NVIM_MINOR}, but this config needs 0.11+."
echo " Debian stable and older Ubuntu LTS releases often ship an older"
echo " version. See https://github.com/neovim/neovim/blob/master/INSTALL.md"
echo " for official AppImage/PPA/prebuilt options if so."
fi
# Install global NPM packages for JS/TS, HTML, and CSS LSPs
echo "Installing NPM-based LSPs..."
sudo npm install -g typescript typescript-language-server vscode-langservers-extracted
# 2. Install Nerd Fonts (JetBrainsMono and Cascadia Code)
echo "[2/4] Installing JetBrainsMono and Cascadia Code Nerd Fonts..."
FONT_DIR="$HOME/.local/share/fonts"
mkdir -p "$FONT_DIR"
# JetBrainsMono
if [ ! -f "$FONT_DIR/JetBrainsMonoNerdFont-Regular.ttf" ]; then
wget -q --show-progress https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.zip -O /tmp/JetBrainsMono.zip
unzip -q -o /tmp/JetBrainsMono.zip -d "$FONT_DIR"
rm /tmp/JetBrainsMono.zip
echo "JetBrainsMono Nerd Font downloaded."
else
echo "JetBrainsMono Nerd Font already installed."
fi
# Cascadia Code (CaskaydiaCove)
if [ ! -f "$FONT_DIR/CaskaydiaCoveNerdFont-Regular.ttf" ]; then
wget -q --show-progress https://github.com/ryanoasis/nerd-fonts/releases/latest/download/CascadiaCode.zip -O /tmp/CascadiaCode.zip
unzip -q -o /tmp/CascadiaCode.zip -d "$FONT_DIR"
rm /tmp/CascadiaCode.zip
echo "Cascadia Code Nerd Font downloaded."
else
echo "Cascadia Code Nerd Font already installed."
fi
# Update font cache
fc-cache -fv
echo "Fonts installed and cache updated successfully!"
# 3. Delete existing Neovim config
echo "[3/4] Deleting existing Neovim configurations..."
if [ -d "$HOME/.config/nvim" ]; then
rm -fr "$HOME/.config/nvim"
fi
if [ -d "$HOME/.local/share/nvim" ]; then
rm -fr "$HOME/.local/share/nvim"
fi
# 4. Install Neovim configuration (copied from config/nvim, not
# embedded in this script -- edit those files directly to customize).
echo "[4/4] Installing new Neovim configuration..."
NVIM_DIR="$HOME/.config/nvim"
mkdir -p "$NVIM_DIR"
# Copy the whole config/nvim tree (the trailing "/." copies the directory's
# contents, dotfiles included, into the existing target) rather than naming
# files one by one. The config is split into many small modules -- one file
# per plugin in lua/plugins/, helpers in lua/config/ -- and a new module
# dropped anywhere under config/nvim/ gets installed without touching this
# script. The target was wiped just above, so nothing stale can linger from
# an older layout (such as the old monolithic lua/plugins/init.lua).
cp -r "$CONFIG_DIR/nvim/." "$NVIM_DIR/"
# --- ~/.clang-format, ~/.clang-tidy, and ~/cpp-style-guide.md ---
# Personal fallback style, implementing a specific C/C++ coding style
# guide (naming conventions, brace style, include ordering, etc. --
# see the comments in each file for exactly which guide section a
# given setting maps to, and cpp-style-guide.md itself for the guide
# those comments point into). Both tools walk UP from the file being
# checked/formatted looking for their respective config file; $HOME
# sits above every project you'll open, so these become your default
# for any project that doesn't ship its own .clang-format/.clang-tidy
# (a project's own file, being closer to the file, always takes
# precedence over these).
#
# <leader>lf (LSP format) and <leader>lt (clang-tidy --fix) each only
# consume .clang-format / .clang-tidy respectively. clangd's live
# diagnostics pick up .clang-tidy automatically too (clang-tidy
# integration is on by default in clangd).
#
# Copied unconditionally (not "if missing") every run, same as the
# rest of this config -- so a stray pre-existing file from some other
# tool can't silently block these from taking effect.
cp "$CONFIG_DIR/clang-format" "$HOME/.clang-format"
cp "$CONFIG_DIR/clang-tidy" "$HOME/.clang-tidy"
cp "$CONFIG_DIR/cpp-style-guide.md" "$HOME/cpp-style-guide.md"
echo "Wrote ~/.clang-format and ~/.clang-tidy (Allman braces, real tabs), and ~/cpp-style-guide.md."
echo "========================================="
echo " Setup Complete!"
echo " Run 'nvim'. p and P are restored, use <leader>p to force inline paste!"
echo " Debugger: <leader>db to set a breakpoint, F5 / <leader>dc to start/continue,"
echo " <leader>du to toggle the debug UI. First debug session will auto-install codelldb via Mason."
echo " Project-specific CMake debug targets loaded from ~/.config/nvim/lua/dap/configurations/cmake.lua"
echo " Database (MariaDB): <leader>Du opens the DB UI; press A there to add a connection"
echo " (URL form: mariadb://user:password@127.0.0.1:3306/dbname). The sqls language server is"
echo " installed on first launch; see README.md ('Database (MariaDB)') for its optional config."
if [ "$NVIM_FRONTEND" = "desktop" ] || [ "$NVIM_FRONTEND" = "both" ]; then
echo " Neovide: run 'neovide' to launch the desktop app (same config, same keymaps)."
echo " If the command isn't found yet, open a new shell first (rustup updates PATH"
echo " in shell startup files, which this script's own shell won't have re-read)."
fi
echo "========================================="