From 386b9c8ea5527e726f3db0bcbe6ee6aa4c7b84e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Wed, 8 Apr 2026 21:15:42 +0200 Subject: [PATCH 01/10] fix: fall back to AppImage when tarball neovim requires newer glibc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ubuntu 20.04 ships glibc 2.31; neovim ≥ 0.10 tarballs require ≥ 2.32. The binary installs silently but crashes on first run. Two changes: - _neovim_try_appimage(): downloads the .appimage release asset and extracts it with --appimage-extract (no FUSE required); the resulting squashfs-root/usr/ tree maps cleanly onto both /usr/local and ~/.local. Falls through to apt if the AppImage asset is absent or extraction fails. - install_neovim(): after copying the tarball, verifies the binary actually executes before declaring success; if it does not, calls the AppImage fallback. Also tightens the idempotency skip guard so a version-matching but glibc-broken binary is not silently skipped on subsequent runs. --- modules/neovim.sh | 61 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/modules/neovim.sh b/modules/neovim.sh index 97f4e6e..5567d13 100755 --- a/modules/neovim.sh +++ b/modules/neovim.sh @@ -42,6 +42,55 @@ link_nvim_config() { log_ok "~/.config/nvim → dotfiles/nvim/.config/nvim" } +# Fallback for systems with older glibc: extract the AppImage instead. +# AppImages bundle their own runtime so glibc ≥ 2.32 is not required. +# squashfs-root/usr/{bin,lib,share}/… mirrors a standard /usr/ prefix, so +# copying usr/. → $prefix works for both /usr/local (sudo) and ~/.local. +_neovim_try_appimage() { + local nvim_arch="$1" prefix="$2" raw="$3" + log_info "neovim: binary requires newer glibc — trying AppImage" + + local appimage_url + appimage_url=$(printf '%s\n' "$raw" \ + | grep -o '"browser_download_url": *"[^"]*nvim-'"${nvim_arch}"'\.appimage"' \ + | grep -o 'https://[^"]*' \ + | head -1) + + if [ -z "$appimage_url" ]; then + log_warn "neovim: no AppImage in release — falling back to apt" + _neovim_apt + return + fi + + local tmp + tmp=$(mktemp -d) + # shellcheck disable=SC2064 + trap "rm -rf '$tmp'" RETURN + + if has curl; then + curl -sfL "$appimage_url" -o "$tmp/nvim.appimage" + else + wget -qO "$tmp/nvim.appimage" "$appimage_url" + fi + chmod +x "$tmp/nvim.appimage" + + # --appimage-extract works without FUSE; produces squashfs-root/ + (cd "$tmp" && ./nvim.appimage --appimage-extract >/dev/null 2>&1) + + if [ ! -d "$tmp/squashfs-root/usr" ]; then + log_warn "neovim: AppImage extraction failed — falling back to apt" + _neovim_apt + return + fi + + if $CAN_SUDO; then + [ -n "${SUDO:-}" ] && sudo -v 2>/dev/null || true + $SUDO cp -r "$tmp/squashfs-root/usr/." "$prefix/" + else + cp -r "$tmp/squashfs-root/usr/." "$prefix/" + fi +} + install_neovim() { log_step "neovim (GitHub releases)" # Fetches the API response once and extracts both download URL and tag from @@ -92,11 +141,12 @@ install_neovim() { local prefix if $CAN_SUDO; then prefix="/usr/local"; else prefix="$HOME/.local"; fi - # Skip if already at latest version + # Skip if already at latest version AND binary actually runs. + # A version-matching but glibc-broken binary must not be skipped. if has nvim; then local current current=$(nvim --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) - if [ "$current" = "$latest" ]; then + if [ "$current" = "$latest" ] && "$prefix/bin/nvim" --version >/dev/null 2>&1; then log_ok "neovim $latest_tag already installed — skipping" # Shadow check still needed: `nvim` above may have resolved to a # user-local copy (e.g. ~/.local/bin/nvim) that shadows an existing @@ -143,6 +193,13 @@ install_neovim() { cp -r "$extracted"/. "$prefix/" fi + # Verify the binary actually runs — older glibc systems (e.g. Ubuntu 20.04, + # glibc 2.31) cannot execute the standard tarball which requires glibc ≥ 2.32. + # Fall back to the AppImage which is self-contained and glibc-independent. + if ! "$prefix/bin/nvim" --version >/dev/null 2>&1; then + _neovim_try_appimage "$nvim_arch" "$prefix" "$raw" + fi + # Use the full path so the version shown is always the binary we just # installed, not whatever `nvim` resolves to in the install-time bash PATH. log_ok "neovim installed → $prefix ($($prefix/bin/nvim --version 2>/dev/null | head -1))" From 65a3680571f0300dae8b64322a9cbed30fe0282c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Wed, 8 Apr 2026 22:07:40 +0200 Subject: [PATCH 02/10] fix: test binary before copying; remove wrong AppImage fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AppImages use the same binary compiled against the same glibc ABI — they provide no relief for glibc version incompatibility. The fallback was silently installing a broken binary and reporting success. Rework the glibc-incompatibility path: - Test the extracted binary IN tmpdir BEFORE copying to the install prefix, so an incompatible new binary never overwrites a working older install. - On glibc failure, fall directly to apt (the correct fallback), with a clear message including the detected system glibc version. - Improve _neovim_apt nosudo message to explain options when apt is also unavailable (no sudo + old glibc = must upgrade OS or build from source). - Remove _neovim_try_appimage entirely — the appimage asset shares the same binary and offers no improvement over the tarball for this failure mode. --- modules/neovim.sh | 74 +++++++++++------------------------------------ 1 file changed, 17 insertions(+), 57 deletions(-) diff --git a/modules/neovim.sh b/modules/neovim.sh index 5567d13..062753e 100755 --- a/modules/neovim.sh +++ b/modules/neovim.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Neovim: install latest stable release from GitHub (prebuilt tarball). -# Falls back to apt if GitHub is unreachable or arch is unsupported. +# Falls back to apt if GitHub is unreachable, arch is unsupported, or the +# prebuilt binary is incompatible with the system's glibc. # Idempotent: skips install when the installed version already matches latest. # Probe ~/.local/bin/nvim and ~/bin/nvim for older copies that would shadow @@ -42,55 +43,6 @@ link_nvim_config() { log_ok "~/.config/nvim → dotfiles/nvim/.config/nvim" } -# Fallback for systems with older glibc: extract the AppImage instead. -# AppImages bundle their own runtime so glibc ≥ 2.32 is not required. -# squashfs-root/usr/{bin,lib,share}/… mirrors a standard /usr/ prefix, so -# copying usr/. → $prefix works for both /usr/local (sudo) and ~/.local. -_neovim_try_appimage() { - local nvim_arch="$1" prefix="$2" raw="$3" - log_info "neovim: binary requires newer glibc — trying AppImage" - - local appimage_url - appimage_url=$(printf '%s\n' "$raw" \ - | grep -o '"browser_download_url": *"[^"]*nvim-'"${nvim_arch}"'\.appimage"' \ - | grep -o 'https://[^"]*' \ - | head -1) - - if [ -z "$appimage_url" ]; then - log_warn "neovim: no AppImage in release — falling back to apt" - _neovim_apt - return - fi - - local tmp - tmp=$(mktemp -d) - # shellcheck disable=SC2064 - trap "rm -rf '$tmp'" RETURN - - if has curl; then - curl -sfL "$appimage_url" -o "$tmp/nvim.appimage" - else - wget -qO "$tmp/nvim.appimage" "$appimage_url" - fi - chmod +x "$tmp/nvim.appimage" - - # --appimage-extract works without FUSE; produces squashfs-root/ - (cd "$tmp" && ./nvim.appimage --appimage-extract >/dev/null 2>&1) - - if [ ! -d "$tmp/squashfs-root/usr" ]; then - log_warn "neovim: AppImage extraction failed — falling back to apt" - _neovim_apt - return - fi - - if $CAN_SUDO; then - [ -n "${SUDO:-}" ] && sudo -v 2>/dev/null || true - $SUDO cp -r "$tmp/squashfs-root/usr/." "$prefix/" - else - cp -r "$tmp/squashfs-root/usr/." "$prefix/" - fi -} - install_neovim() { log_step "neovim (GitHub releases)" # Fetches the API response once and extracts both download URL and tag from @@ -181,6 +133,19 @@ install_neovim() { return fi + # Test the binary IN the tmpdir BEFORE overwriting any existing installation. + # Prebuilt GitHub binaries require glibc ≥ 2.32 (Ubuntu 22.04+); systems with + # older glibc (e.g. Ubuntu 20.04, glibc 2.31) must fall back to apt. + # Note: the AppImage asset uses the same compiled binary — it has the same glibc + # requirement — so it is not a viable fallback for this class of failure. + if ! "$extracted/bin/nvim" --version >/dev/null 2>&1; then + local glibc_ver + glibc_ver=$(ldd --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+$' || echo "unknown") + log_warn "neovim: prebuilt binary requires glibc ≥ 2.32 (system has $glibc_ver) — falling back to apt" + _neovim_apt + return + fi + if $CAN_SUDO; then # Refresh credential cache right before use — the download above may have # taken long enough for the 15-minute sudo cache to expire. @@ -193,13 +158,6 @@ install_neovim() { cp -r "$extracted"/. "$prefix/" fi - # Verify the binary actually runs — older glibc systems (e.g. Ubuntu 20.04, - # glibc 2.31) cannot execute the standard tarball which requires glibc ≥ 2.32. - # Fall back to the AppImage which is self-contained and glibc-independent. - if ! "$prefix/bin/nvim" --version >/dev/null 2>&1; then - _neovim_try_appimage "$nvim_arch" "$prefix" "$raw" - fi - # Use the full path so the version shown is always the binary we just # installed, not whatever `nvim` resolves to in the install-time bash PATH. log_ok "neovim installed → $prefix ($($prefix/bin/nvim --version 2>/dev/null | head -1))" @@ -209,6 +167,8 @@ install_neovim() { _neovim_apt() { if ! $CAN_SUDO; then log_warn "neovim: no sudo — cannot install via apt" + log_warn " Prebuilt GitHub binaries require glibc ≥ 2.32 (Ubuntu 22.04+)" + log_warn " Options: upgrade OS, or build neovim from source" return fi apt_install neovim From b099fbf026c822c46f1af12c2ab8744ffd668c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Wed, 8 Apr 2026 22:16:30 +0200 Subject: [PATCH 03/10] fix: remove broken nvim binary when glibc fallback triggers A prior failed install could leave an incompatible binary at $prefix/bin/nvim. Subsequent runs correctly detect and skip the install but leave the crashing binary in place. Remove it during the glibc fallback path so nvim is simply absent rather than crashing on every invocation. --- modules/neovim.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/neovim.sh b/modules/neovim.sh index 062753e..6340313 100755 --- a/modules/neovim.sh +++ b/modules/neovim.sh @@ -142,6 +142,12 @@ install_neovim() { local glibc_ver glibc_ver=$(ldd --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+$' || echo "unknown") log_warn "neovim: prebuilt binary requires glibc ≥ 2.32 (system has $glibc_ver) — falling back to apt" + # Remove any broken binary left by a prior failed install so `nvim` + # is simply absent rather than crashing on every invocation. + if [ -f "$prefix/bin/nvim" ] && ! "$prefix/bin/nvim" --version >/dev/null 2>&1; then + rm -f "$prefix/bin/nvim" + log_info "neovim: removed incompatible binary from $prefix/bin/nvim" + fi _neovim_apt return fi From a51e3bc9b059ba194dfb08faef65d7d1b756aeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Thu, 9 Apr 2026 16:35:05 +0200 Subject: [PATCH 04/10] feat: add build-from-source script for neovim on old-glibc systems For Ubuntu 20.04 (glibc 2.31) where prebuilt GitHub binaries require glibc >= 2.32 and the PPA has dropped focal support, build from source. scripts/install-neovim-src.sh: - Installs build deps (git, ninja, cmake, gettext, build-essential) - Resolves latest stable tag via GitHub API (or accepts NEOVIM_TAG env) - Shallow-clones the tagged commit; CMake FetchContent handles all C deps - Tests binary before logging success; cleans up build dir on EXIT - Env vars: NEOVIM_TAG (pin version), NEOVIM_PREFIX (install prefix) --- scripts/install-neovim-src.sh | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100755 scripts/install-neovim-src.sh diff --git a/scripts/install-neovim-src.sh b/scripts/install-neovim-src.sh new file mode 100755 index 0000000..515f974 --- /dev/null +++ b/scripts/install-neovim-src.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# Build and install the latest stable neovim from source. +# Required on systems where glibc < 2.32 (e.g. Ubuntu 20.04) prevents +# running the prebuilt GitHub release binaries. +# +# Usage: bash scripts/install-neovim-src.sh +# NEOVIM_TAG=v0.12.1 bash scripts/install-neovim-src.sh # pin version +# NEOVIM_PREFIX=~/.local bash scripts/install-neovim-src.sh # nosudo install +set -euo pipefail + +# ── Preflight ───────────────────────────────────────────────────────────────── +if ! sudo -n true 2>/dev/null && ! sudo -v 2>/dev/null; then + echo "ERROR: sudo is required to install build deps and copy files to /usr/local" >&2 + exit 1 +fi +echo "Note: this build downloads ~200 MB of dependencies and takes 5–15 minutes." + +PREFIX="${NEOVIM_PREFIX:-/usr/local}" + +# ── Build dependencies ──────────────────────────────────────────────────────── +echo "── Installing build dependencies ──" +sudo apt-get install -y \ + git ninja-build gettext cmake unzip curl build-essential + +# ── Resolve tag ────────────────────────────────────────────────────────────── +if [ -z "${NEOVIM_TAG:-}" ]; then + NEOVIM_TAG=$(curl -sfL \ + https://api.github.com/repos/neovim/neovim/releases/latest \ + | grep -o '"tag_name": *"[^"]*"' \ + | grep -o 'v[^"]*') +fi +[ -n "$NEOVIM_TAG" ] || { echo "ERROR: could not resolve latest neovim tag" >&2; exit 1; } +echo "── Building neovim $NEOVIM_TAG → $PREFIX ──" + +# ── Clone ───────────────────────────────────────────────────────────────────── +TMP=$(mktemp -d) +# shellcheck disable=SC2064 +trap "rm -rf '$TMP'" EXIT + +git clone --branch "$NEOVIM_TAG" --depth 1 \ + https://github.com/neovim/neovim.git "$TMP/neovim" + +cd "$TMP/neovim" + +# ── Build ───────────────────────────────────────────────────────────────────── +cmake -B build \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" + +cmake --build build -j"$(nproc)" + +# ── Install ─────────────────────────────────────────────────────────────────── +sudo cmake --install build + +VER=$("$PREFIX/bin/nvim" --version 2>/dev/null | head -1) || VER="(unknown)" +echo "✓ $VER installed → $PREFIX" From 6b8b37079837c80591a773dc7c371edc5baa66b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Thu, 9 Apr 2026 16:49:37 +0200 Subject: [PATCH 05/10] fix: v0.9.5 legacy fallback for glibc<2.32 + nvim compat guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit modules/neovim.sh: - Early glibc detection before download: systems with glibc < 2.32 skip the ~100 MB latest tarball entirely and go straight to the legacy path - _neovim_legacy_binary(): downloads v0.9.5 (built on Ubuntu 18.04 CI, glibc 2.17 baseline — runs on glibc 2.31). x86_64 only; ARM64 falls back to apt. Verifies binary in tmpdir before copying to prefix. - Idempotent: keeps any existing working compatible binary on re-runs nvim/.config/nvim/init.lua: - blink.cmp: cond = nvim-0.10 (uses vim.snippet built-in, added in 0.10) - LSP capabilities: blink on nvim≥0.10, protocol default on older - vim.diagnostic.jump(): guarded; falls back to goto_prev/next on nvim<0.10 - Server registration: vim.lsp.config/enable on nvim≥0.11, lspconfig.server.setup() on nvim 0.9–0.10 (automatic_enable only in the 0.11+ path where it is a known option) - servers{} table is single source of truth for ensure_installed, enable(), and the lspconfig loop --- modules/neovim.sh | 79 ++++++++++++++++++++++++-------- nvim/.config/nvim/init.lua | 92 +++++++++++++++++++++++--------------- 2 files changed, 115 insertions(+), 56 deletions(-) diff --git a/modules/neovim.sh b/modules/neovim.sh index 6340313..474652c 100755 --- a/modules/neovim.sh +++ b/modules/neovim.sh @@ -112,6 +112,29 @@ install_neovim() { log_info "neovim: installing $latest_tag → $prefix" fi + # Early glibc check — avoids a needless ~100 MB download on old systems. + # Prebuilt binaries since v0.10.0 require glibc ≥ 2.32 (Ubuntu 22.04+). + # Detect before downloading; if too old, go straight to the legacy binary. + local glibc_ver + glibc_ver=$(ldd --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+$' || echo "0.0") + if _ver_older_than "$glibc_ver" "2.32"; then + log_warn "neovim: system glibc $glibc_ver < 2.32 — latest prebuilt incompatible" + # Remove any broken binary left by a prior failed install. + if [ -f "$prefix/bin/nvim" ] && ! "$prefix/bin/nvim" --version >/dev/null 2>&1; then + rm -f "$prefix/bin/nvim" + log_info "neovim: removed incompatible binary from $prefix/bin/nvim" + fi + # Keep any already-working compatible binary (e.g. v0.9.5 from a prior run). + if "$prefix/bin/nvim" --version >/dev/null 2>&1; then + local legacy_cur + legacy_cur=$("$prefix/bin/nvim" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) + log_ok "neovim $legacy_cur already installed (glibc-compatible) — skipping" + return + fi + [ "$arch" = "x86_64" ] && _neovim_legacy_binary "$prefix" || _neovim_apt + return + fi + if ! $CAN_SUDO; then mkdir -p "$prefix"; fi local tmp @@ -133,25 +156,6 @@ install_neovim() { return fi - # Test the binary IN the tmpdir BEFORE overwriting any existing installation. - # Prebuilt GitHub binaries require glibc ≥ 2.32 (Ubuntu 22.04+); systems with - # older glibc (e.g. Ubuntu 20.04, glibc 2.31) must fall back to apt. - # Note: the AppImage asset uses the same compiled binary — it has the same glibc - # requirement — so it is not a viable fallback for this class of failure. - if ! "$extracted/bin/nvim" --version >/dev/null 2>&1; then - local glibc_ver - glibc_ver=$(ldd --version 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+$' || echo "unknown") - log_warn "neovim: prebuilt binary requires glibc ≥ 2.32 (system has $glibc_ver) — falling back to apt" - # Remove any broken binary left by a prior failed install so `nvim` - # is simply absent rather than crashing on every invocation. - if [ -f "$prefix/bin/nvim" ] && ! "$prefix/bin/nvim" --version >/dev/null 2>&1; then - rm -f "$prefix/bin/nvim" - log_info "neovim: removed incompatible binary from $prefix/bin/nvim" - fi - _neovim_apt - return - fi - if $CAN_SUDO; then # Refresh credential cache right before use — the download above may have # taken long enough for the 15-minute sudo cache to expire. @@ -170,6 +174,43 @@ install_neovim() { if $CAN_SUDO; then _nvim_warn_shadows /usr/local/bin/nvim; fi } +# Download the last neovim release compatible with glibc < 2.32. +# v0.9.5 was built on Ubuntu 18.04 CI (glibc 2.17 baseline) and runs on any +# glibc ≥ 2.17. Asset name changed to nvim-linux-x86_64 at v0.10.0; v0.9.x +# used nvim-linux64. Only x86_64 is handled — ARM64 falls back to apt. +_neovim_legacy_binary() { + local prefix="$1" + local tag="v0.9.5" + local url="https://github.com/neovim/neovim/releases/download/${tag}/nvim-linux64.tar.gz" + log_info "neovim: downloading legacy $tag (glibc 2.17+ compatible)" + + local tmp + tmp=$(mktemp -d) + # shellcheck disable=SC2064 + trap "rm -rf '$tmp'" RETURN + + if has curl; then + curl -sfL "$url" | tar -xz -C "$tmp" || { log_warn "neovim: legacy download failed — falling back to apt"; _neovim_apt; return; } + else + wget -qO- "$url" | tar -xz -C "$tmp" || { log_warn "neovim: legacy download failed — falling back to apt"; _neovim_apt; return; } + fi + + local extracted="$tmp/nvim-linux64" + if [ ! -d "$extracted" ] || ! "$extracted/bin/nvim" --version >/dev/null 2>&1; then + log_warn "neovim: legacy binary not usable — falling back to apt" + _neovim_apt + return + fi + + if $CAN_SUDO; then + [ -n "${SUDO:-}" ] && sudo -v 2>/dev/null || true + $SUDO cp -r "$extracted"/. "$prefix/" + else + cp -r "$extracted"/. "$prefix/" + fi + log_ok "neovim legacy $tag installed → $prefix ($($prefix/bin/nvim --version 2>/dev/null | head -1))" +} + _neovim_apt() { if ! $CAN_SUDO; then log_warn "neovim: no sudo — cannot install via apt" diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index 540cd90..832e401 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -73,7 +73,9 @@ require('lazy').setup({ opts = { style = 'palenight' } }, -- darker/dark/palenight/oceanic -- ── LSP ────────────────────────────────────────────────────────────────── - -- blink.cmp is a dependency so capabilities are available in config + -- blink.cmp (loaded when nvim ≥ 0.10) is listed as a dependency so lazy.nvim + -- ensures it loads first on capable versions; on nvim 0.9 it is disabled + -- (cond below) and the lspconfig config falls back to default capabilities. { 'neovim/nvim-lspconfig', lazy = false, @@ -84,14 +86,13 @@ require('lazy').setup({ }, config = function() require('mason').setup() - require('mason-lspconfig').setup({ - ensure_installed = { 'pyright', 'clangd', 'bashls', 'lua_ls' }, - automatic_enable = false, -- we call vim.lsp.enable() ourselves below - }) - local capabilities = require('blink.cmp').get_lsp_capabilities() + -- blink.cmp requires nvim ≥ 0.10; fall back to plain capabilities on older. + local capabilities = vim.fn.has('nvim-0.10') == 1 + and require('blink.cmp').get_lsp_capabilities() + or vim.lsp.protocol.make_client_capabilities() - -- Single LspAttach autocmd covers all servers — no per-server on_attach needed + -- Single LspAttach autocmd covers all servers — no per-server on_attach needed. vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup('UserLspAttach', { clear = true }), callback = function(event) @@ -101,16 +102,22 @@ require('lazy').setup({ local map = function(key, fn, desc) vim.keymap.set('n', key, fn, vim.tbl_extend('force', opts, { desc = desc })) end - map('gd', vim.lsp.buf.definition, 'Go to definition') - map('gD', vim.lsp.buf.declaration, 'Go to declaration') - map('gr', vim.lsp.buf.references, 'References') - map('gi', vim.lsp.buf.implementation, 'Go to implementation') - map('K', vim.lsp.buf.hover, 'Hover docs') - map('rn', vim.lsp.buf.rename, 'Rename symbol') + map('gd', vim.lsp.buf.definition, 'Go to definition') + map('gD', vim.lsp.buf.declaration, 'Go to declaration') + map('gr', vim.lsp.buf.references, 'References') + map('gi', vim.lsp.buf.implementation, 'Go to implementation') + map('K', vim.lsp.buf.hover, 'Hover docs') + map('rn', vim.lsp.buf.rename, 'Rename symbol') map('ca', vim.lsp.buf.code_action, 'Code action') - map('d', vim.diagnostic.open_float, 'Show diagnostics') - map('[d', function() vim.diagnostic.jump({ count = -1 }) end, 'Prev diagnostic') - map(']d', function() vim.diagnostic.jump({ count = 1 }) end, 'Next diagnostic') + map('d', vim.diagnostic.open_float, 'Show diagnostics') + -- vim.diagnostic.jump() was added in nvim 0.10 + if vim.fn.has('nvim-0.10') == 1 then + map('[d', function() vim.diagnostic.jump({ count = -1 }) end, 'Prev diagnostic') + map(']d', function() vim.diagnostic.jump({ count = 1 }) end, 'Next diagnostic') + else + map('[d', vim.diagnostic.goto_prev, 'Prev diagnostic') + map(']d', vim.diagnostic.goto_next, 'Next diagnostic') + end -- LSP word highlight — replaces vim-illuminate (semantic, not regex) -- Use a buffer-keyed augroup so multiple servers attaching to the same @@ -131,34 +138,44 @@ require('lazy').setup({ end, }) - vim.lsp.config('pyright', { - capabilities = capabilities, - settings = { - python = { - analysis = { - useLibraryCodeForTypes = true, -- infer types from lib source when stubs absent + -- Server configs defined once; registration method differs by nvim version. + -- nvim 0.11+: vim.lsp.config/enable (new built-in API, no lspconfig on_attach) + -- nvim 0.9–0.10: lspconfig.server.setup() (classic API) + local servers = { + pyright = { + capabilities = capabilities, + settings = { python = { analysis = { useLibraryCodeForTypes = true } } }, + }, + clangd = { capabilities = capabilities }, + bashls = { capabilities = capabilities }, + lua_ls = { + capabilities = capabilities, + settings = { + Lua = { + runtime = { version = 'LuaJIT' }, + workspace = { library = { vim.env.VIMRUNTIME }, checkThirdParty = false }, + diagnostics = { globals = { 'vim' } }, }, }, }, - }) - for _, server in ipairs({ 'clangd', 'bashls' }) do - vim.lsp.config(server, { capabilities = capabilities }) + } + + if vim.fn.has('nvim-0.11') == 1 then + require('mason-lspconfig').setup({ + ensure_installed = vim.tbl_keys(servers), + automatic_enable = false, -- we call vim.lsp.enable() below + }) + for name, cfg in pairs(servers) do vim.lsp.config(name, cfg) end + vim.lsp.enable(vim.tbl_keys(servers)) + else + require('mason-lspconfig').setup({ ensure_installed = vim.tbl_keys(servers) }) + local lspconfig = require('lspconfig') + for name, cfg in pairs(servers) do lspconfig[name].setup(cfg) end end - vim.lsp.config('lua_ls', { - capabilities = capabilities, - settings = { - Lua = { - runtime = { version = 'LuaJIT' }, - workspace = { library = { vim.env.VIMRUNTIME }, checkThirdParty = false }, - diagnostics = { globals = { 'vim' } }, - }, - }, - }) - vim.lsp.enable({ 'pyright', 'clangd', 'bashls', 'lua_ls' }) vim.diagnostic.config({ severity_sort = true, - float = { border = 'rounded', source = true }, -- show server name per diagnostic + float = { border = 'rounded', source = true }, }) end, }, @@ -166,6 +183,7 @@ require('lazy').setup({ -- ── Completion ─────────────────────────────────────────────────────────── { 'saghen/blink.cmp', + cond = vim.fn.has('nvim-0.10') == 1, -- uses vim.snippet built-in (nvim 0.10+) version = '*', -- use release tags (pre-built Rust binary) dependencies = { 'rafamadriz/friendly-snippets' }, config = function() From 74b91875e0c5568c778ce9cdc53d8143eff49dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Thu, 9 Apr 2026 17:36:00 +0200 Subject: [PATCH 06/10] fix: gate nvim-lspconfig and treesitter-context on nvim 0.10+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nvim-lspconfig itself (not just the API) now enforces nvim >= 0.10 at load time. nvim-treesitter-context uses the LspRequest autocmd event added in nvim 0.10. Both crash on nvim 0.9.5 before config() runs, so version guards in config() alone are insufficient — cond is needed. --- nvim/.config/nvim/init.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index 832e401..ebf7ef9 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -73,12 +73,13 @@ require('lazy').setup({ opts = { style = 'palenight' } }, -- darker/dark/palenight/oceanic -- ── LSP ────────────────────────────────────────────────────────────────── - -- blink.cmp (loaded when nvim ≥ 0.10) is listed as a dependency so lazy.nvim - -- ensures it loads first on capable versions; on nvim 0.9 it is disabled - -- (cond below) and the lspconfig config falls back to default capabilities. + -- nvim-lspconfig ≥ 2024-12 requires nvim 0.10 at the plugin level (not just + -- API level), so gate the entire block. On nvim 0.9 the editor still works + -- fully; only LSP/completion is absent. { 'neovim/nvim-lspconfig', - lazy = false, + cond = vim.fn.has('nvim-0.10') == 1, + lazy = false, dependencies = { 'williamboman/mason.nvim', 'williamboman/mason-lspconfig.nvim', @@ -225,6 +226,7 @@ require('lazy').setup({ 'nvim-treesitter/nvim-treesitter-textobjects', { 'nvim-treesitter/nvim-treesitter-context', + cond = vim.fn.has('nvim-0.10') == 1, -- uses LspRequest event (nvim 0.10+) config = function() require('treesitter-context').setup({ max_lines = 3 }) end, From 26661d8c287638781a99dd7e59a9bb3318172e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Fri, 10 Apr 2026 23:35:19 +0200 Subject: [PATCH 07/10] fix: use correct nvim-treesitter API for parser auto-install replace `require('nvim-treesitter.install').ensure_installed` (does not exist in the post-2024 refactored API) with the correct `require('nvim-treesitter').install({...})` call which triggers async parser download on first launch. --- nvim/.config/nvim/init.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index ebf7ef9..e304c34 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -233,6 +233,13 @@ require('lazy').setup({ }, }, config = function() + -- Ensure parsers are present on fresh installs (async, no-op if already installed). + require('nvim-treesitter').install({ + 'bash', 'c', 'cpp', 'css', 'go', 'html', 'javascript', + 'json', 'lua', 'markdown', 'python', 'rust', 'toml', + 'typescript', 'vim', 'yaml', + }) + -- Highlighting: built-in vim.treesitter, enabled per filetype vim.api.nvim_create_autocmd('FileType', { group = vim.api.nvim_create_augroup('UserTreesitter', { clear = true }), From 07123b75ef31560a87a533125cf3dd7227d584bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Fri, 10 Apr 2026 23:54:35 +0200 Subject: [PATCH 08/10] fix: gate nvim-treesitter on nvim 0.10+ (uses vim.fs.joinpath) --- nvim/.config/nvim/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index e304c34..b0b5edb 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -220,6 +220,7 @@ require('lazy').setup({ -- ── Treesitter ─────────────────────────────────────────────────────────── { 'nvim-treesitter/nvim-treesitter', + cond = vim.fn.has('nvim-0.10') == 1, -- uses vim.fs.joinpath (nvim 0.10+) lazy = false, build = ':TSUpdate', dependencies = { From ad81e5c681055c7e4f9a15f2110fe079c2d653f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Sat, 11 Apr 2026 00:04:05 +0200 Subject: [PATCH 09/10] fix: gate mini.ai and mini.bracketed on nvim 0.10+ (soft-deprecated on 0.9) --- nvim/.config/nvim/init.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nvim/.config/nvim/init.lua b/nvim/.config/nvim/init.lua index b0b5edb..c3f4ff8 100644 --- a/nvim/.config/nvim/init.lua +++ b/nvim/.config/nvim/init.lua @@ -467,6 +467,7 @@ require('lazy').setup({ { 'andymass/vim-matchup', event = 'BufReadPost' }, { 'echasnovski/mini.ai', + cond = vim.fn.has('nvim-0.10') == 1, event = 'VeryLazy', config = function() require('mini.ai').setup({ @@ -499,6 +500,7 @@ require('lazy').setup({ }, { 'echasnovski/mini.bracketed', + cond = vim.fn.has('nvim-0.10') == 1, event = 'VeryLazy', config = function() require('mini.bracketed').setup({ From 5e09107cb8c898df3230f54654569c0e1ae0543a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20P=C4=99dzim=C4=85=C5=BC?= Date: Sat, 11 Apr 2026 12:49:43 +0200 Subject: [PATCH 10/10] docs: bump version to 1.3.0 --- CHANGELOG.md | 28 +++++++++++++++++++++++++++- VERSION | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a6ab75..cee000d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.3.0] - 2026-04-11 + +### Added +- `scripts/install-neovim-src.sh`: standalone script to build the latest + stable neovim from source; intended for systems where glibc < 2.32 prevents + running prebuilt GitHub release binaries (e.g. Ubuntu 20.04); supports + `NEOVIM_TAG` (pin version) and `NEOVIM_PREFIX` (install path) env vars + +### Fixed +- `modules/neovim.sh`: detect glibc version *before* downloading — saves + ~100 MB download on incompatible systems; fall back to v0.9.5 tarball + (`nvim-linux64.tar.gz`, built on Ubuntu 18.04 CI, glibc 2.17+ baseline) + when system glibc < 2.32; verify binary executes before declaring success; + clean up any broken binary left by a prior failed install when the glibc + fallback triggers; ARM64 systems with glibc < 2.32 fall back to apt +- `nvim/init.lua`: gate `nvim-treesitter`, `nvim-lspconfig`, + `nvim-treesitter-context`, `mini.ai`, and `mini.bracketed` behind + `cond = vim.fn.has('nvim-0.10') == 1` — these plugins use nvim 0.10+ APIs + (`vim.fs.joinpath`, `LspRequest` event) or declare nvim < 0.10 soft- + deprecated; nvim 0.9.5 now starts cleanly with regex highlighting and no LSP +- `nvim/init.lua`: use the correct post-2024 nvim-treesitter install API + (`require('nvim-treesitter').install({...})`) — the old + `require('nvim-treesitter.install').ensure_installed` no longer exists after + the nvim-treesitter refactor + ## [1.2.5] - 2026-04-02 ### Added @@ -307,7 +332,8 @@ Complete overhaul of the dotfiles infrastructure: modular profiles, Neovim, CI, ### Added - Initial dotfiles: Zsh (oh-my-zsh + fzf), Tmux, Vim, and monolithic `install.sh` -[Unreleased]: https://github.com/YASoftwareDev/dotfiles/compare/v1.2.5...HEAD +[Unreleased]: https://github.com/YASoftwareDev/dotfiles/compare/v1.3.0...HEAD +[1.3.0]: https://github.com/YASoftwareDev/dotfiles/compare/v1.2.5...v1.3.0 [1.2.5]: https://github.com/YASoftwareDev/dotfiles/compare/v1.2.4...v1.2.5 [1.2.4]: https://github.com/YASoftwareDev/dotfiles/compare/v1.2.3...v1.2.4 [1.2.3]: https://github.com/YASoftwareDev/dotfiles/compare/v1.2.2...v1.2.3 diff --git a/VERSION b/VERSION index c813fe1..f0bb29e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.5 +1.3.0