From f2eeb756a337c92ab09805305b71ded41411bfab Mon Sep 17 00:00:00 2001 From: dotfiles-core sync bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 14:17:22 +0000 Subject: [PATCH 1/2] Squashed 'core/' changes from da15412..dcdeda5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dcdeda5 Merge pull request #245 from dotgibson/release/v3.9.0 8fc799e release v3.9.0 a5eb9cb Merge pull request #244 from dotgibson/nvim-nvchad-refactor 17ef23e fix(nvim): address PR review — renamer cursor, same-session LSP, doc drift ef98c38 fix(nvim): wipe renamer scratch buffer + gate on rename-capable client 4c647e0 feat(nvim): hybrid NvChad UI overhaul, bug/perf fixes, and plugin trim git-subtree-dir: core git-subtree-split: dcdeda541fdcc1c1a855f064bebaa2d1c56211af --- CHANGELOG.md | 55 +++++ core.version | 2 +- nvim/lazy-lock.json | 25 +-- nvim/lua/gerrrt/cheatsheet.lua | 59 ++---- nvim/lua/gerrrt/config/autocmds.lua | 9 +- nvim/lua/gerrrt/config/globals.lua | 3 +- nvim/lua/gerrrt/plugins/aerial-nvim.lua | 31 --- nvim/lua/gerrrt/plugins/blink-cmp.lua | 13 +- nvim/lua/gerrrt/plugins/bufferline-nvim.lua | 78 +++---- nvim/lua/gerrrt/plugins/ccc-nvim.lua | 9 +- nvim/lua/gerrrt/plugins/conform.lua | 62 +----- nvim/lua/gerrrt/plugins/dropbar-nvim.lua | 2 +- nvim/lua/gerrrt/plugins/git-conflict.lua | 30 --- nvim/lua/gerrrt/plugins/incline-nvim.lua | 46 ---- nvim/lua/gerrrt/plugins/lualine-nvim.lua | 25 ++- .../gerrrt/plugins/mason-tool-installer.lua | 83 ++++++++ nvim/lua/gerrrt/plugins/mini-nvim.lua | 1 - nvim/lua/gerrrt/plugins/neotest.lua | 85 -------- nvim/lua/gerrrt/plugins/nvim-colorizer.lua | 49 +++++ nvim/lua/gerrrt/plugins/nvim-dap-ui.lua | 197 ------------------ nvim/lua/gerrrt/plugins/nvim-lint.lua | 12 +- nvim/lua/gerrrt/plugins/nvim-spectre.lua | 69 ------ nvim/lua/gerrrt/plugins/vim-dadbod.lua | 44 ---- nvim/lua/gerrrt/plugins/vimade.lua | 6 +- nvim/lua/gerrrt/plugins/which-key.lua | 4 - nvim/lua/gerrrt/servers/bashls.lua | 9 + nvim/lua/gerrrt/servers/init.lua | 40 ++-- nvim/lua/gerrrt/utils/lsp.lua | 42 +--- nvim/lua/gerrrt/utils/palette.lua | 76 +++++++ nvim/lua/gerrrt/utils/renamer.lua | 76 +++++++ nvim/lua/gerrrt/utils/ui-highlights.lua | 26 +++ 31 files changed, 529 insertions(+), 739 deletions(-) delete mode 100644 nvim/lua/gerrrt/plugins/aerial-nvim.lua delete mode 100644 nvim/lua/gerrrt/plugins/git-conflict.lua delete mode 100644 nvim/lua/gerrrt/plugins/incline-nvim.lua create mode 100644 nvim/lua/gerrrt/plugins/mason-tool-installer.lua delete mode 100644 nvim/lua/gerrrt/plugins/neotest.lua create mode 100644 nvim/lua/gerrrt/plugins/nvim-colorizer.lua delete mode 100644 nvim/lua/gerrrt/plugins/nvim-dap-ui.lua delete mode 100644 nvim/lua/gerrrt/plugins/nvim-spectre.lua delete mode 100644 nvim/lua/gerrrt/plugins/vim-dadbod.lua create mode 100644 nvim/lua/gerrrt/utils/palette.lua create mode 100644 nvim/lua/gerrrt/utils/renamer.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ed29d6..00db974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,61 @@ commit (`git tag -a vX.Y.Z -m vX.Y.Z`). ## [Unreleased] +## [v3.9.0] - 2026-07-19 + +### Added + +- **Neovim: shared `utils/palette.lua`** — a single source of truth for the active tokyonight + palette. The `"storm"` style string and the `require("tokyonight.colors").setup{}` pcall dance + were duplicated across lualine, bufferline, and the cheatsheet; they now all resolve through this + one module (change the style once). It also exposes a NvChad-`base_30` semantic map (`black2`, + `statusline_bg`, `nord_blue`, `dark_purple`, …) so the block/pill styling is written in NvChad's + own vocabulary while still tracking the theme. +- **Neovim: scroll-percentage indicator** in the lualine statusline (right bubble, next to the + cursor location) so you can see how far through a file you are. +- **Neovim: NvChad-style inline LSP renamer** (`utils/renamer.lua`) — `rn` now opens a + small cursor-anchored, git-red-bordered prompt prefilled with the symbol (`` applies across + the workspace, ``/`q` cancels) instead of the bare cmdline prompt. +- **Neovim: colorify-style colour highlighter** (`nvim-colorizer.lua`, catgoose fork) — inline + colour swatches over the visible viewport: CSS colour literals (`#rrggbb`, `rgb()/hsl()`) plus + Tailwind utility-class colours via the Tailwind LSP. ccc.nvim is kept for the interactive + `:CccPick` picker (its always-on highlighter is now off). + +### Changed + +- **Neovim: statusline & tabline go hybrid-NvChad.** The bufferline adopts NvChad's tabufline model + where buffer state is conveyed by BACKGROUND on a solid opaque bar — the active buffer lifts to a + lighter raised block, inactive buffers recede to the bar colour — while the editor stays + transparent. The blink.cmp menu gains NvChad's colored kind-icon column (via `BlinkCmpKind*` + highlights) with an icon-left / kind-text-right layout. The `?` cheatsheet renders as a + solid opaque card. +- **Neovim: signature help is owned by blink.cmp.** The manual `CursorHoldI` + `vim.lsp.buf.signature_help` autocmd was removed — blink's own signature window handled the same + case and the two floats could stack while idle. `` stays as the manual trigger. +- **Neovim: the central Mason install manifest moved** out of conform.nvim (which is lazy on + `BufWritePre`, so `run_on_start` really meant "on first save") into its own `VeryLazy`-loaded + `plugins/mason-tool-installer.lua`, so a fresh box installs its toolchain near startup. + +### Removed + +- **Neovim: trimmed unused plugins** — the full in-editor **debugger stack** (nvim-dap, + nvim-dap-ui, nvim-dap-virtual-text, mason-nvim-dap, and every `d*` keymap), the **test + runner** (neotest + neotest-python/-golang), vim-dadbod (DB UI), incline.nvim (dropbar's winbar + covers split identity), aerial.nvim (Trouble + fzf-lua + dropbar cover symbols), nvim-spectre, + git-conflict.nvim, and mini.indentscope — along with their keymaps, which-key groups, and + cheatsheet sections. (16 entries removed from `lazy-lock.json`, including transitive dependencies.) + +### Fixed + +- **Neovim: heavy linters no longer run on `InsertLeave`.** golangci-lint / cpplint scan the whole + package per run; they are now restricted to `BufWritePost` (save-only) while fast per-file linters + keep the snappier cadence. +- **Neovim: bash-language-server no longer emits `SC1071` on zsh.** Its built-in shellcheck + integration is disabled (`bashIde.shellcheckPath = ""`) so zsh buffers keep completion/hover + without the "shellcheck only supports sh/bash/…" phantom diagnostic. +- **Neovim: `:w` can't be broken by a missing mini.nvim.** The format-on-save + `mini.trailspace.trim()` call is now pcall-guarded. + ## [v3.8.0] - 2026-07-18 ### Changed diff --git a/core.version b/core.version index 1981190..a5c4c76 100644 --- a/core.version +++ b/core.version @@ -1 +1 @@ -3.8.0 +3.9.0 diff --git a/nvim/lazy-lock.json b/nvim/lazy-lock.json index 92bfac6..d6d8a21 100644 --- a/nvim/lazy-lock.json +++ b/nvim/lazy-lock.json @@ -1,7 +1,5 @@ { - "FixCursorHold.nvim": { "branch": "master", "commit": "1900f89dc17c603eec29960f57c00bd9ae696495" }, "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" }, - "aerial.nvim": { "branch": "master", "commit": "28fe6e822ae344544c379d60fcb13c9519a1f08a" }, "alpha-nvim": { "branch": "main", "commit": "6c6a89d5b068b5251c8bdf0dd57bb921bcfeeb09" }, "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" }, @@ -14,37 +12,27 @@ "flash.nvim": { "branch": "main", "commit": "b6346946d10d07998efee029fb0f7a593806d0cd" }, "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, "fzf-lua": { "branch": "main", "commit": "532d463f5c83595192fe740572d8fd6902b2217a" }, - "git-conflict.nvim": { "branch": "main", "commit": "4bbfdd92d547d2862a75b4e80afaf30e73f7bbb4" }, "gitlinker.nvim": { "branch": "master", "commit": "a1b74070bbd5e50128190c85b09f1431ea5fbd83" }, "gitsigns.nvim": { "branch": "main", "commit": "31d6fb2d618bca1482b9f274751ead5f03461408" }, "harpoon": { "branch": "harpoon2", "commit": "87b1a3506211538f460786c23f98ec63ad9af4e5" }, - "incline.nvim": { "branch": "main", "commit": "debd628e9395f7a9da57bdc31ce75ca6b40a880b" }, "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, "lazydev.nvim": { "branch": "main", "commit": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d" }, "lazygit.nvim": { "branch": "main", "commit": "a04ad0dbc725134edbee3a5eea29290976695357" }, "lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" }, "luvit-meta": { "branch": "main", "commit": "cc9b2d412d2fbd30b94a70cfc214c2a3be27a0a2" }, - "mason-nvim-dap.nvim": { "branch": "main", "commit": "9a10e096703966335bd5c46c8c875d5b0690dade" }, "mason-tool-installer.nvim": { "branch": "main", "commit": "443f1ef8b5e6bf47045cb2217b6f748a223cf7dc" }, "mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" }, "mini.nvim": { "branch": "main", "commit": "1345d191bb3da9c7b0e977f4387c5761f9bff68d" }, "neogen": { "branch": "main", "commit": "23e7e9f883d01289ebd90e98025acc860ea26366" }, - "neotest": { "branch": "master", "commit": "4e2cd42c4252ee9d2435571d9adcdbc1d47931fe" }, - "neotest-golang": { "branch": "main", "commit": "542cbaf37f1233a2723ccd64ce8ed7e3acbd192b" }, - "neotest-python": { "branch": "master", "commit": "1b56ca4ba51c6014f986d6548ee629bdc95589d1" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, "nvim-bqf": { "branch": "main", "commit": "c282a62bec6c0621a1ef5132aa3f4c9fc4dcc2c7" }, - "nvim-dap": { "branch": "master", "commit": "9e848e09a697ee95302a3ef2dd43fd6eb709e570" }, - "nvim-dap-ui": { "branch": "master", "commit": "cc9dd33aade7f20bae414d0cba163bc60d4d4b43" }, - "nvim-dap-virtual-text": { "branch": "master", "commit": "fbdb48c2ed45f4a8293d0d483f7730d24467ccb6" }, + "nvim-colorizer.lua": { "branch": "master", "commit": "72a05f62c52241bc7441c820eb53946f92b2e6a4" }, "nvim-lint": { "branch": "master", "commit": "a219b2c9e5b4765e5c845aba119dad55806fcaf1" }, - "nvim-lspconfig": { "branch": "master", "commit": "b386c50cd7816f8c8a2b13b298a218af1f5a75c6" }, - "nvim-nio": { "branch": "master", "commit": "edcc181a875301dd21840189aa2f2f9ad69fc172" }, - "nvim-spectre": { "branch": "master", "commit": "72f56f7585903cd7bf92c665351aa585e150af0f" }, + "nvim-lspconfig": { "branch": "master", "commit": "e7ca2c95ba316a8b846d3f3546d407908c5c4ccb" }, "nvim-tree.lua": { "branch": "master", "commit": "4213bd6eabac38b16dd6615002b6243b23cf3bf6" }, - "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, + "nvim-treesitter": { "branch": "main", "commit": "24977147550d53589e53b874ec75e14e4fbc304e" }, "nvim-treesitter-context": { "branch": "master", "commit": "b311b30818951d01f7b4bf650521b868b3fece16" }, - "nvim-treesitter-textobjects": { "branch": "main", "commit": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "898ee307df58f854d11cd7edd06472574d48014e" }, "nvim-ufo": { "branch": "main", "commit": "ab3eb124062422d276fae49e0dd63b3ad1062cfc" }, "nvim-web-devicons": { "branch": "master", "commit": "0ca28b61a04fe7426cefbdd52c2647ef0e335b5f" }, "oil.nvim": { "branch": "master", "commit": "b73018b75affd13fa38e2fc94ef753b465f770d7" }, @@ -55,16 +43,13 @@ "rainbow-delimiters.nvim": { "branch": "master", "commit": "a798325b7f36acc62741d1029930a7b96d4dd4bf" }, "render-markdown.nvim": { "branch": "main", "commit": "f422cb5c6855f150e2ddcfaf44e7157b98b34f6a" }, "rustaceanvim": { "branch": "main", "commit": "88575b98bb9937fb9983ddec5e532b67e75ce677" }, - "schemastore.nvim": { "branch": "main", "commit": "e954496f8ef22904e8a84f5078f4a110fdc7a0d3" }, + "schemastore.nvim": { "branch": "main", "commit": "0df41ab13b54151fcb6ab023cc2a761482070f76" }, "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, "tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" }, "treesj": { "branch": "main", "commit": "79aedb401bbdc7e4202f7881eab5f6feb2105b0a" }, "trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" }, "twilight.nvim": { "branch": "main", "commit": "664e752f4a219801265cc3fc18782b457b58c1e1" }, "undotree": { "branch": "master", "commit": "6fa6b57cda8459e1e4b2ca34df702f55242f4e4d" }, - "vim-dadbod": { "branch": "master", "commit": "6d1d41da4873a445c5605f2005ad2c68c99d8770" }, - "vim-dadbod-completion": { "branch": "master", "commit": "a8dac0b3cf6132c80dc9b18bef36d4cf7a9e1fe6" }, - "vim-dadbod-ui": { "branch": "master", "commit": "afd07819d8efcefc3317205b855ad4e3513b0011" }, "vim-fugitive": { "branch": "master", "commit": "3b753cf8c6a4dcde6edee8827d464ba9b8c4a6f0" }, "vim-sleuth": { "branch": "master", "commit": "be69bff86754b1aa5adcbb527d7fcd1635a84080" }, "vim-tmux-navigator": { "branch": "master", "commit": "e41c431a0c7b7388ae7ba341f01a0d217eb3a432" }, diff --git a/nvim/lua/gerrrt/cheatsheet.lua b/nvim/lua/gerrrt/cheatsheet.lua index 7c767da..6356772 100644 --- a/nvim/lua/gerrrt/cheatsheet.lua +++ b/nvim/lua/gerrrt/cheatsheet.lua @@ -111,7 +111,6 @@ M.sections = { { "", "Signature help (i)" }, { "oi", "Organize imports" }, { "cf", "Format buffer / range" }, - { "co", "Code outline (Aerial)" }, { "cs", "Symbols (Trouble)" }, { "cn", "Annotation (Neogen)" }, { ";", "Breadcrumb pick (dropbar)" }, @@ -145,41 +144,6 @@ M.sections = { { "gH / gL", "History: file / repo" }, { "gy / gY", "Permalink: yank / open" }, }, - { - "Git — conflicts", - { "]x / [x", "Next / prev conflict" }, - { "gxo / gxt", "Choose ours / theirs" }, - { "gxb / gx0", "Choose both / none" }, - { "gxl", "List conflicts (quickfix)" }, - }, - { - "Debug (DAP)", - { "db / dB", "Breakpoint / conditional" }, - { "dc", "Continue / start" }, - { "do / di", "Step over / into" }, - { "du", "Step out" }, - { "dr", "Open REPL" }, - { "dl", "Run last" }, - { "dt", "Toggle UI" }, - { "de", "Evaluate expression" }, - { "dx", "Terminate" }, - }, - { - "Test (neotest)", - { "tt", "Run nearest" }, - { "tf", "Run current file" }, - { "td", "Debug nearest (DAP)" }, - { "ts", "Summary panel" }, - { "to / tO", "Show output / panel" }, - { "tx", "Stop" }, - }, - { - "Search & Replace", - { "Sp", "Spectre panel (toggle)" }, - { "Sw", "Search current word" }, - { "Sc", "Search current file" }, - { "Sr", "Search selection (v)" }, - }, { "Folds (ufo)", { "zR / zM", "Open / close all folds" }, @@ -209,7 +173,6 @@ M.sections = { { "z", "Zen mode" }, { "U", "Undotree" }, { "um", "Markdown render" }, - { "uD / uF", "Database UI / find buffer" }, }, { "Packages", @@ -229,6 +192,7 @@ local GUTTER = 3 -- blank cells between columns local MARGIN = 2 -- blank cells inside the window border, left/right local HL = { + normal = "GerrrtCheatNormal", title = "GerrrtCheatTitle", rule = "GerrrtCheatRule", key = "GerrrtCheatKey", @@ -243,19 +207,22 @@ local NPILL = 0 local function define_highlights() local set = vim.api.nvim_set_hl - -- Prefer the tokyonight palette so the panel reads as NvChad's grid: heading bars in cycling - -- accents, blue keys, dim rules/footer. pcall so a fresh box (tokyonight not loaded) degrades to - -- the old semantic links instead of erroring — the cheatsheet is deps-free by design. - local ok, c = pcall(function() - return require("tokyonight.colors").setup({ style = "storm" }) -- mirror plugins/theme.lua - end) - if ok and type(c) == "table" then + -- Prefer the resolved tokyonight palette (one source of truth in utils/palette.lua) so the panel + -- reads as NvChad's grid: heading bars in cycling accents, blue keys, dim rules/footer. nil on a + -- fresh box (tokyonight not loaded) → degrade to the semantic links below instead of erroring — + -- the cheatsheet stays deps-free by design. + local c = require("gerrrt.utils.palette").colors() + if type(c) == "table" then local accents = { c.blue, c.green, c.magenta, c.cyan, c.orange, c.yellow, c.red, c.teal, c.purple } for i, accent in ipairs(accents) do -- black (bg_dark) bold text on a vivid accent → the pill heading set(0, "GerrrtCheatPill" .. i, { fg = c.bg_dark, bg = accent, bold = true }) end NPILL = #accents + -- Solid panel background (NvChad's cheatsheet is an opaque card, not transparent) — the one + -- place the hybrid look goes solid inside a float. bg_dark is the darkest surface so the accent + -- pills and blue keys pop off it. + set(0, HL.normal, { bg = c.bg_dark }) set(0, HL.title, { fg = c.blue, bold = true }) -- heading fallback (unused when NPILL>0) set(0, HL.key, { fg = c.blue, bold = true }) set(0, HL.rule, { fg = c.fg_gutter }) @@ -264,6 +231,7 @@ local function define_highlights() else -- bare-box fallback: link to semantic groups every colorscheme defines (previous behavior). NPILL = 0 + set(0, HL.normal, { link = "NormalFloat", default = true }) set(0, HL.title, { link = "Title", default = true }) set(0, HL.key, { link = "Constant", default = true }) set(0, HL.rule, { link = "Comment", default = true }) @@ -426,6 +394,9 @@ function M.open() }) vim.wo[win].wrap = false vim.wo[win].cursorline = false + -- Paint the panel as a solid card (NvChad's cheatsheet is opaque). Only NormalFloat is + -- remapped; the border/title keep the config-wide FloatBorder/FloatTitle tint. + vim.wo[win].winhighlight = "NormalFloat:" .. HL.normal -- close keys — the buffer wipes on hide, so just close the window for _, key in ipairs({ "q", "" }) do diff --git a/nvim/lua/gerrrt/config/autocmds.lua b/nvim/lua/gerrrt/config/autocmds.lua index da4ec97..b2e31f9 100644 --- a/nvim/lua/gerrrt/config/autocmds.lua +++ b/nvim/lua/gerrrt/config/autocmds.lua @@ -47,7 +47,12 @@ local lsp_fmt_group = vim.api.nvim_create_augroup("FormatOnSaveGroup", { clear = vim.api.nvim_create_autocmd("BufWritePre", { group = lsp_fmt_group, callback = function(args) - require("mini.trailspace").trim() + -- pcall-guarded: on a fresh box (or if mini failed to load) a bare require().trim() would + -- throw here and abort the whole BufWritePre before conform ever runs, breaking `:w`. mini + -- loads on VeryLazy so this is rare, but the rest of Core guards cross-plugin calls the same way. + pcall(function() + require("mini.trailspace").trim() + end) -- Never auto-format zsh. shfmt (whether reached through conform OR through the -- lsp_format="fallback" path via bash-language-server, which shells out to shfmt) -- parses zsh as bash and silently corrupts zsh-only syntax. Skipping by FILETYPE @@ -68,7 +73,7 @@ vim.api.nvim_create_autocmd("LspAttach", { }) -- custom options for text/markdown files -local markdown_options = vim.api.nvim_create_augroup("MarkdownOptions", {}) +local markdown_options = vim.api.nvim_create_augroup("MarkdownOptions", { clear = true }) vim.api.nvim_create_autocmd("FileType", { group = markdown_options, pattern = { "markdown", "text", "gitcommit" }, diff --git a/nvim/lua/gerrrt/config/globals.lua b/nvim/lua/gerrrt/config/globals.lua index 09720ad..c82bba9 100644 --- a/nvim/lua/gerrrt/config/globals.lua +++ b/nvim/lua/gerrrt/config/globals.lua @@ -12,8 +12,7 @@ vim.g.loaded_netrwPlugin = 1 -- Fleet "offline" switch. When the environment exports DOTFILES_OFFLINE=1 (the offensive/Kali -- layer sets it on engagement boxes), Neovim suppresses unattended/background network activity: -- • lazy.nvim's update checker — config/lazy.lua --- • mason-tool-installer run_on_start — plugins/conform.lua --- • mason-nvim-dap automatic_installation — plugins/nvim-dap-ui.lua +-- • mason-tool-installer run_on_start — plugins/mason-tool-installer.lua -- Read once here into a boolean so every consumer just checks `vim.g.dotfiles_offline`. globals -- is required before lazy.setup, so this is set before any plugin spec/opts/config evaluates. vim.g.dotfiles_offline = vim.env.DOTFILES_OFFLINE == "1" diff --git a/nvim/lua/gerrrt/plugins/aerial-nvim.lua b/nvim/lua/gerrrt/plugins/aerial-nvim.lua deleted file mode 100644 index 0e8e548..0000000 --- a/nvim/lua/gerrrt/plugins/aerial-nvim.lua +++ /dev/null @@ -1,31 +0,0 @@ --- ================================================================================================ --- TITLE : aerial.nvim | a persistent symbol outline sidebar --- LINKS : https://github.com/stevearc/aerial.nvim --- ABOUT : dropbar (breadcrumbs) tells you WHERE you are; Trouble symbols and fzf-lua document --- symbols are momentary pickers. aerial is the missing third: a docked, always-current --- outline of the file's structure you can keep open and click/scroll through — invaluable --- in large multi-language files. Sources from the LSP document symbols you already get on --- attach, with a treesitter fallback, so it needs nothing new. --- LAZY : cmd + a single `co` toggle under your `c` (code) group. --- ================================================================================================ -return { - "stevearc/aerial.nvim", - dependencies = { - "nvim-treesitter/nvim-treesitter", - "nvim-tree/nvim-web-devicons", - }, - cmd = { "AerialToggle", "AerialOpen", "AerialNavToggle" }, - keys = { - { "co", "AerialToggle!", desc = "Code outline (Aerial)" }, - }, - opts = { - backends = { "lsp", "treesitter", "markdown", "man" }, - layout = { default_direction = "right", min_width = 28 }, - show_guides = true, - -- jump through symbols with { and } when the outline has focus - keymaps = { - ["{"] = "actions.prev", - ["}"] = "actions.next", - }, - }, -} diff --git a/nvim/lua/gerrrt/plugins/blink-cmp.lua b/nvim/lua/gerrrt/plugins/blink-cmp.lua index 0c252a5..39f9de4 100644 --- a/nvim/lua/gerrrt/plugins/blink-cmp.lua +++ b/nvim/lua/gerrrt/plugins/blink-cmp.lua @@ -55,7 +55,18 @@ return { }, menu = { border = "rounded", - draw = { treesitter = { "lsp" } }, -- syntax-highlight the LSP items in the menu + -- NvChad-style menu draw: a colored kind ICON on the left (colors via BlinkCmpKind* + -- in utils/ui-highlights.lua), the label in the middle, and the kind TEXT trailing on + -- the right — the same three-column rhythm as NvChad's cmp. treesitter still syntax- + -- highlights the LSP label text so identifiers read like code. + draw = { + treesitter = { "lsp" }, + columns = { + { "kind_icon" }, + { "label", "label_description", gap = 1 }, + { "kind", gap = 1 }, + }, + }, }, documentation = { auto_show = true, auto_show_delay_ms = 200, window = { border = "rounded" } }, ghost_text = { enabled = true }, diff --git a/nvim/lua/gerrrt/plugins/bufferline-nvim.lua b/nvim/lua/gerrrt/plugins/bufferline-nvim.lua index d3be3a9..43d3750 100644 --- a/nvim/lua/gerrrt/plugins/bufferline-nvim.lua +++ b/nvim/lua/gerrrt/plugins/bufferline-nvim.lua @@ -23,59 +23,59 @@ -- -- ICONS : diagnostic glyphs use \u{XXXX} escapes (matching utils/diagnostics.lua + lualine) so -- they survive transfer — raw Nerd-Font private-use glyphs get silently stripped. --- LOOK : palette-aware highlights (build_highlights below) push the line toward NvChad's tabufline: --- the ACTIVE buffer lifts as a subtle raised block (bg = bg_highlight) with a bright accent --- underline; inactive buffers dim into the transparent bar (bg = NONE, fg = comment). Colors --- come from tokyonight's resolved palette so they track the theme, computed at load time (in --- `config`, when tokyonight is guaranteed loaded) rather than at spec-eval — same reasoning --- as the hand-built lualine theme. pcall-guarded so a fresh box falls back to bufferline's --- own auto-theming instead of erroring. +-- LOOK : palette-aware highlights (build_highlights below) push the line onto NvChad's tabufline +-- model — state is conveyed by BACKGROUND, not separators. The tabline is a SOLID opaque bar +-- (the "hybrid": the editor stays transparent, the chrome bars go solid); the ACTIVE buffer +-- lifts to a lighter raised block (one_bg) with a bright accent underline, while inactive +-- buffers sit at the bar color (black2) and recede. Colors come from utils/palette.lua's +-- NvChad-semantic map so they track the theme, computed at load time (in `config`, when +-- tokyonight is guaranteed loaded) rather than at spec-eval — same reasoning as the +-- hand-built lualine theme. nil-guarded so a fresh box falls back to bufferline's own +-- auto-theming instead of erroring. -- ================================================================================================ --- Build bufferline's `highlights` from the tokyonight palette. Returns nil on a box where +-- Build bufferline's `highlights` from the NvChad-semantic palette. Returns nil on a box where -- tokyonight hasn't loaded, so setup() falls back to bufferline's colorscheme-derived defaults. local function build_highlights() - local ok, c = pcall(function() - return require("tokyonight.colors").setup({ style = "storm" }) -- mirror plugins/theme.lua - end) - if not ok or type(c) ~= "table" then + local p = require("gerrrt.utils.palette").nvchad() + if not p then return nil end local none = "NONE" - local active = { fg = c.fg, bg = c.bg_highlight } -- the raised active-buffer block - local dim = { fg = c.comment, bg = none } -- inactive, blended into the transparent bar + local bar = p.black2 -- the solid tabline bar; inactive buffers sit here and recede + local raised = p.one_bg -- the active buffer lifts to this lighter block return { - fill = { bg = none }, - background = dim, - buffer_visible = { fg = c.fg_dark, bg = none }, + fill = { bg = bar }, + background = { fg = p.light_grey, bg = bar }, + buffer_visible = { fg = p.light_grey, bg = bar }, -- `sp` set here too: for indicator style="underline" bufferline draws the accent line on the -- selected buffer's own highlight using its `sp`, so pin it to the accent explicitly. - buffer_selected = { fg = c.fg, bg = c.bg_highlight, bold = true, italic = false, sp = c.blue }, - -- thin separators kept hairline-subtle, never heavy dividers - separator = { fg = c.bg_dark, bg = none }, - separator_visible = { fg = c.bg_dark, bg = none }, - separator_selected = { fg = c.bg_dark, bg = c.bg_highlight }, + buffer_selected = { fg = p.white, bg = raised, bold = true, italic = false, sp = p.blue }, + -- separators dissolve into the bar (NvChad has none) — state is the bg swap, not a divider + separator = { fg = bar, bg = bar }, + separator_visible = { fg = bar, bg = bar }, + separator_selected = { fg = bar, bg = raised }, -- accent underline under the active buffer (indicator style = "underline"). The underline -- color is taken from `sp`, not `fg` — and because setup deep-merges with bufferline's -- defaults, an unset `sp` would keep the default and the blue line wouldn't render. Set both. - indicator_selected = { fg = c.blue, sp = c.blue, bg = c.bg_highlight }, - indicator_visible = { fg = none, bg = none }, - -- unsaved dot: green when active (matches lualine/incline), amber otherwise - modified = { fg = c.orange, bg = none }, - modified_visible = { fg = c.orange, bg = none }, - modified_selected = { fg = c.green, bg = c.bg_highlight }, + indicator_selected = { fg = p.blue, sp = p.blue, bg = raised }, + indicator_visible = { fg = none, bg = bar }, + -- unsaved dot: green when active (matches lualine), amber otherwise + modified = { fg = p.orange, bg = bar }, + modified_visible = { fg = p.orange, bg = bar }, + modified_selected = { fg = p.green, bg = raised }, -- per-buffer diagnostic counts track the gutter/statusline colors - error = { fg = c.red, bg = none }, - error_visible = { fg = c.red, bg = none }, - error_selected = { fg = c.red, bg = c.bg_highlight, bold = true }, - warning = { fg = c.yellow, bg = none }, - warning_visible = { fg = c.yellow, bg = none }, - warning_selected = { fg = c.yellow, bg = c.bg_highlight, bold = true }, + error = { fg = p.red, bg = bar }, + error_visible = { fg = p.red, bg = bar }, + error_selected = { fg = p.red, bg = raised, bold = true }, + warning = { fg = p.yellow, bg = bar }, + warning_visible = { fg = p.yellow, bg = bar }, + warning_selected = { fg = p.yellow, bg = raised, bold = true }, -- tab-mode (mode="tabs") blocks, styled to match the buffer blocks - tab = dim, - tab_selected = active, - tab_separator = { fg = c.bg_dark, bg = none }, - tab_separator_selected = { fg = c.bg_dark, bg = c.bg_highlight }, + tab = { fg = p.light_grey, bg = bar }, + tab_selected = { fg = p.white, bg = raised }, + tab_separator = { fg = bar, bg = bar }, + tab_separator_selected = { fg = bar, bg = raised }, } end @@ -115,7 +115,7 @@ return { numbers = "none", -- jump-by-number is harpoon's job; keep the line uncluttered indicator = { style = "underline" }, -- subtle; reads cleanly with your transparency separator_style = "thin", -- flat rectangular tabs like NvChad's tabufline (no slant) - modified_icon = "\u{f111}", -- f111 nf-fa-circle (●) — same unsaved dot as lualine/incline + modified_icon = "\u{f111}", -- f111 nf-fa-circle (●) — same unsaved dot as lualine show_buffer_close_icons = false, show_close_icon = false, always_show_bufferline = true, -- you like the visual — keep it up even at 1 buffer diff --git a/nvim/lua/gerrrt/plugins/ccc-nvim.lua b/nvim/lua/gerrrt/plugins/ccc-nvim.lua index 995b766..422d8da 100644 --- a/nvim/lua/gerrrt/plugins/ccc-nvim.lua +++ b/nvim/lua/gerrrt/plugins/ccc-nvim.lua @@ -1,14 +1,17 @@ -- ================================================================================================ --- TITLE : ccc.nvim | colour picker & highlighter +-- TITLE : ccc.nvim | colour PICKER (:CccPick / :CccConvert) -- LINKS : https://github.com/uga-rosa/ccc.nvim +-- NOTE : ccc's always-on highlighter is intentionally OFF here (auto_enable = false). The inline +-- colour swatches / LSP document colours are now rendered by plugins/nvim-colorizer.lua +-- (colorify-style, visible-range) so the two don't double-render. ccc stays for the +-- interactive picker + format conversion, which nvim-colorizer doesn't provide. -- ================================================================================================ return { "uga-rosa/ccc.nvim", - ft = { "css", "scss", "sass", "less", "html", "javascript", "javascriptreact", "typescript", "typescriptreact", "svelte", "vue" }, cmd = { "CccPick", "CccConvert", "CccHighlighterToggle" }, config = function() require("ccc").setup({ - highlighter = { auto_enable = true, lsp = true }, + highlighter = { auto_enable = false, lsp = true }, -- picker-only; highlighting → nvim-colorizer highlight_mode = "virtual", }) end, diff --git a/nvim/lua/gerrrt/plugins/conform.lua b/nvim/lua/gerrrt/plugins/conform.lua index eb523db..c056933 100644 --- a/nvim/lua/gerrrt/plugins/conform.lua +++ b/nvim/lua/gerrrt/plugins/conform.lua @@ -7,16 +7,13 @@ -- (the Astral way), NOT mason — run once: -- uv tool install ruff -- uv tool install ty --- mason-tool-installer below covers the NON-Python tools. Prefer mason for ruff? add --- "ruff" back to ensure_installed. +-- The NON-Python tools (formatters + linters + servers) are installed by the central Mason +-- manifest in plugins/mason-tool-installer.lua. Prefer mason for ruff? add "ruff" there. -- ================================================================================================ return { "stevearc/conform.nvim", event = { "BufWritePre" }, cmd = { "ConformInfo" }, - dependencies = { - { "WhoIsSethDaniel/mason-tool-installer.nvim", dependencies = { "mason-org/mason.nvim" } }, - }, keys = { { "cf", @@ -58,60 +55,5 @@ return { }, config = function(_, opts) require("conform").setup(opts) - - -- One Mason manifest for EVERYTHING Mason owns: LSP servers, formatters, linters. - -- This is the central install pass — previously only formatters/linters were listed, so the - -- 11 servers enabled in servers/init.lua relied on their binaries already being on PATH - -- (`vim.lsp.enable` fails silently when a server binary is missing). Listing the servers - -- here closes that gap: a fresh machine ends up with a working LSP stack after one start. - -- - -- DELIBERATELY NOT here (installed by other channels — listing them would double-install): - -- • ruff, ty .......... uv tool install (Astral; see header + servers/ruff.lua, ty.lua) - -- • rust-analyzer ..... rustaceanvim / rustup (plugins/rustaceanvim.lua) - -- • debugpy, codelldb . mason-nvim-dap (plugins/nvim-dap-ui.lua) - -- • nomicfoundation-solidity-language-server — npm i -g @nomicfoundation/solidity-language-server - -- (not carried in the Mason registry under a stable name; servers/solidity_*.lua expects - -- the binary on PATH). solhint (its linter) IS mason-managed, below. - require("mason-tool-installer").setup({ - ensure_installed = { - -- ── LSP servers (mason package names; enabled in servers/init.lua) ────────── - "lua-language-server", - "gopls", - "json-lsp", - "typescript-language-server", - "bash-language-server", - "clangd", - "dockerfile-language-server", - "emmet-ls", - "yaml-language-server", - "tailwindcss-language-server", - "taplo", -- TOML (also the conform formatter for toml) - "marksman", -- Markdown - "html-lsp", -- HTML validation - "css-lsp", -- CSS/SCSS/LESS validation - "svelte-language-server", -- Svelte component LSP (you already format/lint svelte) - "vue-language-server", -- Vue/Volar LSP (also ships @vue/typescript-plugin for ts_ls) - -- ── formatters (conform) ─────────────────────────────────────────────────── - "stylua", - "shfmt", - "gofumpt", - "clang-format", - "prettierd", - -- ── linters (nvim-lint) ──────────────────────────────────────────────────── - "shellcheck", - "golangci-lint", -- Go meta-linter (supersedes revive; richer diagnostics) - "eslint_d", - "hadolint", - "cpplint", - "luacheck", - "solhint", - "stylelint", -- CSS/SCSS/LESS lint (only runs when a project stylelint config exists) - "markdownlint-cli2", -- markdown lint (mirrors the repo's markdown gate) - "yamllint", -- yaml lint - }, - -- Skip the startup install/update pass on engagement boxes (DOTFILES_OFFLINE=1), - -- which would otherwise hit the mason registry and download tools. See globals.lua. - run_on_start = not vim.g.dotfiles_offline, - }) end, } diff --git a/nvim/lua/gerrrt/plugins/dropbar-nvim.lua b/nvim/lua/gerrrt/plugins/dropbar-nvim.lua index 49a6569..5d8bf9c 100644 --- a/nvim/lua/gerrrt/plugins/dropbar-nvim.lua +++ b/nvim/lua/gerrrt/plugins/dropbar-nvim.lua @@ -32,7 +32,7 @@ return { return false end local ft = vim.bo[buf].filetype - local skip = { NvimTree = true, ["dapui_scopes"] = true, ["dapui_breakpoints"] = true, help = true } + local skip = { NvimTree = true, help = true } return not skip[ft] end, }, diff --git a/nvim/lua/gerrrt/plugins/git-conflict.lua b/nvim/lua/gerrrt/plugins/git-conflict.lua deleted file mode 100644 index cba4ec9..0000000 --- a/nvim/lua/gerrrt/plugins/git-conflict.lua +++ /dev/null @@ -1,30 +0,0 @@ --- ================================================================================================ --- TITLE : git-conflict.nvim | resolve merge/rebase conflicts in-place --- LINKS : https://github.com/akinsho/git-conflict.nvim --- ABOUT : Highlights conflict regions (ours/theirs/ancestor) right in the buffer and lets you pick --- a side with one keystroke. diffview's merge_tool (diffview-nvim.lua) is the full-window --- 3-way resolver; this is the lightweight inline path for the common 2-or-3 marker conflict --- you hit mid-rebase — no need to open a separate review surface. --- KEYMAPS: `default_mappings = false` is deliberate — the plugin's defaults bind `co`/`ct`/`cb`, --- which would shadow the everyday `ct{char}` (change-till) operator. We rebind the choices --- under `gx` (git group, free prefix) and conflict navigation to `]x`/`[x`. --- LAZY : event = BufReadPost/BufNewFile so markers are detected as soon as a file opens. --- ================================================================================================ -return { - "akinsho/git-conflict.nvim", - version = "*", - event = { "BufReadPost", "BufNewFile" }, - opts = { - default_mappings = false, - disable_diagnostics = false, - }, - keys = { - { "]x", "GitConflictNextConflict", desc = "Next git conflict" }, - { "[x", "GitConflictPrevConflict", desc = "Prev git conflict" }, - { "gxo", "GitConflictChooseOurs", desc = "Conflict: choose ours" }, - { "gxt", "GitConflictChooseTheirs", desc = "Conflict: choose theirs" }, - { "gxb", "GitConflictChooseBoth", desc = "Conflict: choose both" }, - { "gx0", "GitConflictChooseNone", desc = "Conflict: choose none" }, - { "gxl", "GitConflictListQf", desc = "Conflict: list (quickfix)" }, - }, -} diff --git a/nvim/lua/gerrrt/plugins/incline-nvim.lua b/nvim/lua/gerrrt/plugins/incline-nvim.lua deleted file mode 100644 index 6c8d10b..0000000 --- a/nvim/lua/gerrrt/plugins/incline-nvim.lua +++ /dev/null @@ -1,46 +0,0 @@ --- ================================================================================================ --- TITLE : incline.nvim | floating per-window filename labels --- LINKS : https://github.com/b0o/incline.nvim --- ABOUT : You run globalstatus=true (one lualine for the whole UI) and a split-heavy workflow --- (vim-tmux-navigator, sv/sh). The tradeoff of a global statusline is you can't tell --- at a glance WHICH split holds WHICH file. incline draws a small, unobtrusive floating --- label in the top-right corner of every window with the filename + a modified marker — the --- missing per-window identity, without giving up your single global statusline. --- LAZY : event = BufReadPost/BufNewFile. Honors your transparency (winblend/tokyonight). The --- modified-dot glyph is a \u{XXXX} escape (Nerd Font codepoint) so it survives transfer, --- matching the house convention in lualine.lua / diagnostics.lua. --- ================================================================================================ -return { - "b0o/incline.nvim", - dependencies = { "nvim-tree/nvim-web-devicons" }, - event = { "BufReadPost", "BufNewFile" }, - config = function() - local devicons_ok, devicons = pcall(require, "nvim-web-devicons") - - require("incline").setup({ - window = { - margin = { vertical = 0, horizontal = 1 }, - padding = 1, - placement = { horizontal = "right", vertical = "top" }, - }, - render = function(props) - local fname = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(props.buf), ":t") - if fname == "" then - fname = "[No Name]" - end - local modified = vim.bo[props.buf].modified - - local parts = {} - if devicons_ok then - local icon, color = devicons.get_icon_color(fname, nil, { default = true }) - parts[#parts + 1] = { icon .. " ", guifg = color } - end - parts[#parts + 1] = { fname, gui = modified and "bold,italic" or "None" } - if modified then - parts[#parts + 1] = { " \u{f111}", guifg = "#e0af68" } -- f111 nf-fa-circle (unsaved dot) - end - return parts - end, - }) - end, -} diff --git a/nvim/lua/gerrrt/plugins/lualine-nvim.lua b/nvim/lua/gerrrt/plugins/lualine-nvim.lua index ed3cb4e..5787894 100644 --- a/nvim/lua/gerrrt/plugins/lualine-nvim.lua +++ b/nvim/lua/gerrrt/plugins/lualine-nvim.lua @@ -6,7 +6,8 @@ -- NvChad's rounded "bubble" separators and section layout: -- left : mode (rounded bubble) · git branch · git diff (+~-) -- center: filename (relative) with modified/readonly markers --- right : search count · attached LSP servers · diagnostics · filetype · cwd · location +-- right : search count · attached LSP servers · diagnostics · filetype · cwd · +-- scroll-percentage + location (one rounded bubble) -- LOOK : the signature NvChad move is the ROUNDED block — half-circle caps (U+E0B6) and -- (U+E0B4) instead of powerline arrows, with NO inner component separators so each -- half reads as one clean run of blocks. Colors come from a HAND-BUILT theme derived from @@ -15,8 +16,8 @@ -- ends, a lighter git/cwd block, a base filename run) and each section keeps a solid bg, -- which is what makes the pills read as opaque islands on the transparent bar. Because it -- pulls from the same palette tokyonight hands `on_highlights` (utils/ui-highlights.lua), --- it stays theme- and transparency-aware; swap `style` in plugins/theme.lua and the mirror --- `style` in build_theme to keep them in sync (both default to "storm"). +-- it stays theme- and transparency-aware; the tokyonight `style` is resolved once in +-- utils/palette.lua (mirror it in plugins/theme.lua) — both default to "storm". -- ICONS : All glyphs are written as \u{XXXX} escapes (Nerd Font private-use codepoints), -- NOT raw glyphs. Raw glyphs get silently stripped when text passes through tools -- that don't preserve the private-use area; escapes are plain ASCII in the file and @@ -40,11 +41,10 @@ return { -- pcall so a fresh box where tokyonight hasn't loaded falls back to lualine's bundled theme -- rather than aborting the whole statusline. local function build_theme() - local ok, c = pcall(function() - -- mirror plugins/theme.lua's `style`; the palette keys used below are style-stable - return require("tokyonight.colors").setup({ style = "storm" }) - end) - if not ok or type(c) ~= "table" then + -- palette resolved once in utils/palette.lua (single source of the tokyonight `style`); + -- nil on a fresh box where tokyonight hasn't loaded → fall back to lualine's bundled theme. + local c = require("gerrrt.utils.palette").colors() + if type(c) ~= "table" then return "tokyonight" end local base, block = c.bg_dark, c.bg_highlight @@ -98,7 +98,7 @@ return { -- (an empty string) so each half is one clean run instead of arrow-chevroned. section_separators = { left = "\u{e0b4}", right = "\u{e0b6}" }, -- e0b4 / e0b6 component_separators = "", - disabled_filetypes = { statusline = { "NvimTree", "dapui_scopes", "dapui_breakpoints" } }, + disabled_filetypes = { statusline = { "NvimTree" } }, }, sections = { lualine_a = { @@ -157,7 +157,12 @@ return { { cwd }, }, lualine_z = { - -- outer half-circle cap (e0b4) closes the right bubble, mirroring the mode block + -- Scroll PERCENTAGE through the file — the "how far in am I" cue. lualine's + -- `progress` renders Top / Bot / NN% (NvChad itself shows line/col here; this is the + -- one deliberate divergence). The outer half-circle cap (e0b6) opens the right + -- bubble, mirroring how the mode block opens the left one. + { "progress", icon = "\u{f0d7}", separator = { left = "\u{e0b6}" } }, -- f0d7 caret-down, e0b6 + -- location closes the right bubble with e0b4 — progress + location read as one pill. { "location", icon = "\u{e0a1}", separator = { right = "\u{e0b4}" } }, -- e0a1 line-number, e0b4 }, }, diff --git a/nvim/lua/gerrrt/plugins/mason-tool-installer.lua b/nvim/lua/gerrrt/plugins/mason-tool-installer.lua new file mode 100644 index 0000000..cb48390 --- /dev/null +++ b/nvim/lua/gerrrt/plugins/mason-tool-installer.lua @@ -0,0 +1,83 @@ +-- ================================================================================================ +-- TITLE : mason-tool-installer | the central Mason install manifest +-- LINKS : https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim +-- ABOUT : ONE manifest for EVERYTHING Mason owns — LSP servers, formatters (conform), linters +-- (nvim-lint). This is the install pass a fresh machine relies on to end up with a working +-- toolchain after a start. +-- WHY ITS OWN SPEC (not inside conform): this used to live in conform.nvim's `config`, but conform +-- is lazy (`event = BufWritePre`), so `run_on_start = true` really meant "run on the first +-- :w". Meanwhile servers enable earlier at BufReadPre and `vim.lsp.enable` silently skips a +-- server whose binary isn't on PATH yet (servers/init.lua's binary_available guard) — so on a +-- fresh box the LSP stack stayed dark until a save AND a restart. Loading on VeryLazy runs the +-- install pass near startup on EVERY launch. +-- SAME-SESSION LSP : the install is async, so the BufReadPre enable pass has already run (and skipped +-- the not-yet-installed servers) by the time it finishes. The `MasonToolsUpdateCompleted` +-- handler below re-runs servers/init.lua's enable pass when installs complete — +-- `vim.lsp.enable` attaches the freshly-installed servers to the already-open buffer, so a +-- fresh box gets a working LSP stack WITHIN the first session, no restart required. +-- DELIBERATELY NOT here (installed by other channels — listing them would double-install): +-- • ruff, ty ......... uv tool install (Astral; see plugins/conform.lua header + servers/ruff.lua) +-- • rust-analyzer .... rustaceanvim / rustup (plugins/rustaceanvim.lua) +-- • nomicfoundation-solidity-language-server — npm i -g @nomicfoundation/solidity-language-server +-- (not carried in the Mason registry under a stable name; servers/solidity_*.lua expects the +-- binary on PATH). solhint (its linter) IS mason-managed, below. +-- ================================================================================================ +return { + "WhoIsSethDaniel/mason-tool-installer.nvim", + event = "VeryLazy", + dependencies = { "mason-org/mason.nvim" }, + config = function() + require("mason-tool-installer").setup({ + ensure_installed = { + -- ── LSP servers (mason package names; enabled in servers/init.lua) ────────── + "lua-language-server", + "gopls", + "json-lsp", + "typescript-language-server", + "bash-language-server", + "clangd", + "dockerfile-language-server", + "emmet-ls", + "yaml-language-server", + "tailwindcss-language-server", + "taplo", -- TOML (also the conform formatter for toml) + "marksman", -- Markdown + "html-lsp", -- HTML validation + "css-lsp", -- CSS/SCSS/LESS validation + "svelte-language-server", -- Svelte component LSP (you already format/lint svelte) + "vue-language-server", -- Vue/Volar LSP (also ships @vue/typescript-plugin for ts_ls) + -- ── formatters (conform) ─────────────────────────────────────────────────── + "stylua", + "shfmt", + "gofumpt", + "clang-format", + "prettierd", + -- ── linters (nvim-lint) ──────────────────────────────────────────────────── + "shellcheck", + "golangci-lint", -- Go meta-linter (supersedes revive; richer diagnostics) + "eslint_d", + "hadolint", + "cpplint", + "luacheck", + "solhint", + "stylelint", -- CSS/SCSS/LESS lint (only runs when a project stylelint config exists) + "markdownlint-cli2", -- markdown lint (mirrors the repo's markdown gate) + "yamllint", -- yaml lint + }, + -- Skip the startup install/update pass on engagement boxes (DOTFILES_OFFLINE=1), + -- which would otherwise hit the mason registry and download tools. See globals.lua. + run_on_start = not vim.g.dotfiles_offline, + }) + + -- When installs finish, re-run the server enable pass so servers whose binaries the initial + -- BufReadPre pass skipped (fresh box) get enabled + attached to the open buffer this session. + vim.api.nvim_create_autocmd("User", { + pattern = "MasonToolsUpdateCompleted", + callback = function() + pcall(function() + require("gerrrt.servers").enable_available() + end) + end, + }) + end, +} diff --git a/nvim/lua/gerrrt/plugins/mini-nvim.lua b/nvim/lua/gerrrt/plugins/mini-nvim.lua index 9fb19fb..edf5e08 100644 --- a/nvim/lua/gerrrt/plugins/mini-nvim.lua +++ b/nvim/lua/gerrrt/plugins/mini-nvim.lua @@ -66,7 +66,6 @@ return { }, }) require("mini.cursorword").setup({}) - require("mini.indentscope").setup({}) require("mini.pairs").setup({}) require("mini.trailspace").setup({}) require("mini.bufremove").setup({}) diff --git a/nvim/lua/gerrrt/plugins/neotest.lua b/nvim/lua/gerrrt/plugins/neotest.lua deleted file mode 100644 index 68671e7..0000000 --- a/nvim/lua/gerrrt/plugins/neotest.lua +++ /dev/null @@ -1,85 +0,0 @@ --- ================================================================================================ --- TITLE : neotest | a unified, multi-language test runner --- LINKS : https://github.com/nvim-neotest/neotest --- ABOUT : Run the nearest test / file / suite without leaving the buffer, with pass/fail signs in --- the gutter, an output panel, and a tree summary. Genuinely multi-language via adapters — --- wired here for Python (neotest-python), Go (neotest-golang) and Rust (rustaceanvim's --- built-in adapter, picked up automatically when present). nvim-nio is already in your tree --- (nvim-dap-ui dependency), and `td` runs the nearest test under your DAP setup. --- LAZY : keys-only, under a new `t` (test) group — see which-key.lua. Adapters load with it. --- ================================================================================================ -return { - "nvim-neotest/neotest", - dependencies = { - "nvim-neotest/nvim-nio", - "nvim-lua/plenary.nvim", - "antoinemadec/FixCursorHold.nvim", - "nvim-treesitter/nvim-treesitter", - "nvim-neotest/neotest-python", - "fredrikaverpil/neotest-golang", - }, - keys = { - { - "tt", - function() - require("neotest").run.run() - end, - desc = "Test: nearest", - }, - { - "tf", - function() - require("neotest").run.run(vim.fn.expand("%")) - end, - desc = "Test: current file", - }, - { - "td", - function() - require("neotest").run.run({ strategy = "dap" }) - end, - desc = "Test: debug nearest (DAP)", - }, - { - "ts", - function() - require("neotest").summary.toggle() - end, - desc = "Test: summary panel", - }, - { - "to", - function() - require("neotest").output.open({ enter = true }) - end, - desc = "Test: show output", - }, - { - "tO", - function() - require("neotest").output_panel.toggle() - end, - desc = "Test: output panel", - }, - { - "tx", - function() - require("neotest").run.stop() - end, - desc = "Test: stop", - }, - }, - config = function() - local adapters = { - require("neotest-python")({ dap = { justMyCode = false } }), - require("neotest-golang")({}), - } - -- rustaceanvim ships a neotest adapter; add it only when rustaceanvim is installed. - local ok_rust, rust_adapter = pcall(require, "rustaceanvim.neotest") - if ok_rust then - table.insert(adapters, rust_adapter) - end - - require("neotest").setup({ adapters = adapters }) - end, -} diff --git a/nvim/lua/gerrrt/plugins/nvim-colorizer.lua b/nvim/lua/gerrrt/plugins/nvim-colorizer.lua new file mode 100644 index 0000000..ed73bb7 --- /dev/null +++ b/nvim/lua/gerrrt/plugins/nvim-colorizer.lua @@ -0,0 +1,49 @@ +-- ================================================================================================ +-- TITLE : nvim-colorizer.lua | colorify-style inline colour highlighter +-- LINKS : https://github.com/catgoose/nvim-colorizer.lua (maintained fork) +-- ABOUT : The always-on colour highlighter, styled after NvChad's `colorify`: it renders an inline +-- swatch next to each colour literal, processing only the VISIBLE viewport (cheap, updates on +-- scroll). CSS colour values — `#rrggbb`, `rgb()/hsl()` — are matched by regex (`css = true`). +-- TailwindCSS utility classes (`bg-red-500`) get a swatch via the Tailwind LSP's +-- `textDocument/documentColor` (`tailwind = "lsp"`), so classes are covered too, not just hex. +-- SCOPE : this covers CSS colour LITERALS + Tailwind LSP colours. It does NOT wire up generic +-- cssls `documentColor` (colorizer requests documentColor only from the `tailwindcss` +-- client) — for CSS files the regex path already swatches every real colour value. +-- SPLIT WITH ccc : ccc.nvim (plugins/ccc-nvim.lua) keeps the :CccPick colour PICKER / :CccConvert; +-- its always-on highlighter is turned off there so the two don't double-render. This module +-- owns the highlighting; ccc owns the interactive picking. +-- ICONS : the swatch uses U+25A0 (■ BLACK SQUARE) — a plain, universally-present glyph (no Nerd Font +-- private-use codepoint), so it can never render as tofu on a box with a partial font. +-- ================================================================================================ +local web_fts = { + "css", + "scss", + "sass", + "less", + "html", + "javascript", + "javascriptreact", + "typescript", + "typescriptreact", + "svelte", + "vue", +} + +return { + "catgoose/nvim-colorizer.lua", + ft = web_fts, + config = function() + require("colorizer").setup({ + filetypes = web_fts, + user_default_options = { + names = false, -- don't colourize bare words like "red"/"blue" — too noisy in code + css = true, -- rgb()/hsl()/#rgb/#rrggbb everywhere + css_fn = true, -- rgb()/hsl() function forms + tailwind = "lsp", -- Tailwind class colours via the LSP documentColor provider + mode = "virtualtext", -- inline swatch, not a full-text background (colorify's look) + virtualtext = "\u{25a0}", -- 25a0 ■ BLACK SQUARE swatch + virtualtext_inline = true, + }, + }) + end, +} diff --git a/nvim/lua/gerrrt/plugins/nvim-dap-ui.lua b/nvim/lua/gerrrt/plugins/nvim-dap-ui.lua deleted file mode 100644 index 4d73e71..0000000 --- a/nvim/lua/gerrrt/plugins/nvim-dap-ui.lua +++ /dev/null @@ -1,197 +0,0 @@ --- ================================================================================================ --- TITLE : nvim-dap (+ dap-ui, virtual-text, mason-nvim-dap) --- ABOUT : Debug Adapter Protocol — set breakpoints, step through code, inspect variables. --- LINKS : --- > nvim-dap : https://github.com/mfussenegger/nvim-dap --- > nvim-dap-ui : https://github.com/rcarriga/nvim-dap-ui --- > mason-nvim-dap : https://github.com/jay-babu/mason-nvim-dap.nvim --- > dap-virtual-text : https://github.com/theHamsta/nvim-dap-virtual-text --- LEARNING NOTES : --- Cursor on a line, db to set a breakpoint, dc to launch. Execution pauses --- at the breakpoint; dap-ui shows scopes/variables/call-stack and virtual text shows each --- variable's value inline. Step with do (over) / di (into) / du (out). --- ASTRAL/uv : --- The Python config below runs YOUR code with the project's uv virtualenv interpreter: --- it prefers $VIRTUAL_ENV, then ./.venv/bin/python (uv's default), then system python. --- debugpy itself runs from its isolated Mason env, separate from your project venv. --- ICONS : --- The breakpoint/stopped signs use \u{XXXX} escapes (Nerd Font codepoints) so the glyphs --- survive transfer — raw private-use glyphs get silently stripped. Requires a Nerd Font. --- ================================================================================================ -return { - "rcarriga/nvim-dap-ui", - dependencies = { - "mfussenegger/nvim-dap", - "nvim-neotest/nvim-nio", - "theHamsta/nvim-dap-virtual-text", - { "jay-babu/mason-nvim-dap.nvim", dependencies = { "mason-org/mason.nvim" } }, - }, - keys = { - { - "db", - function() - require("dap").toggle_breakpoint() - end, - desc = "DAP: toggle breakpoint", - }, - { - "dB", - function() - require("dap").set_breakpoint(vim.fn.input("Condition: ")) - end, - desc = "DAP: conditional breakpoint", - }, - { - "dc", - function() - require("dap").continue() - end, - desc = "DAP: continue / start", - }, - { - "do", - function() - require("dap").step_over() - end, - desc = "DAP: step over", - }, - { - "di", - function() - require("dap").step_into() - end, - desc = "DAP: step into", - }, - { - "du", - function() - require("dap").step_out() - end, - desc = "DAP: step out", - }, - { - "dr", - function() - require("dap").repl.open() - end, - desc = "DAP: open REPL", - }, - { - "dl", - function() - require("dap").run_last() - end, - desc = "DAP: run last", - }, - { - "dx", - function() - require("dap").terminate() - end, - desc = "DAP: terminate", - }, - { - "dt", - function() - require("dapui").toggle() - end, - desc = "DAP: toggle UI", - }, - { - "de", - function() - require("dapui").eval() - end, - mode = { "n", "v" }, - desc = "DAP: evaluate expression", - }, - }, - config = function() - local dap, dapui = require("dap"), require("dapui") - - dapui.setup() - require("nvim-dap-virtual-text").setup({}) - - require("mason-nvim-dap").setup({ - ensure_installed = { "python", "codelldb" }, - -- No auto-download of debug adapters on engagement boxes (DOTFILES_OFFLINE=1). See globals.lua. - automatic_installation = not vim.g.dotfiles_offline, - handlers = {}, -- sensible defaults; Python is overridden below to be uv-aware - }) - - -- ── uv-aware Python debugging ──────────────────────────────────────────── - -- Windows venvs put the interpreter at \Scripts\python.exe (not /bin/python) and ship - -- only `python` on PATH (no `python3`), so the interpreter paths below branch on OS. - local is_win = vim.fn.has("win32") == 1 - local venv_python = is_win and "\\Scripts\\python.exe" or "/bin/python" - local function uv_python() - if vim.env.VIRTUAL_ENV and vim.env.VIRTUAL_ENV ~= "" then - return vim.env.VIRTUAL_ENV .. venv_python - end - local venv = vim.fn.getcwd() .. (is_win and "/.venv\\Scripts\\python.exe" or "/.venv/bin/python") - if vim.fn.executable(venv) == 1 then - return venv - end - local sys = vim.fn.exepath(is_win and "python" or "python3") - return sys ~= "" and sys or "python" - end - - local debugpy_python = vim.fn.stdpath("data") - .. (is_win and "/mason/packages/debugpy/venv\\Scripts\\python.exe" or "/mason/packages/debugpy/venv/bin/python") - - dap.adapters.python = function(cb, config) - if config.request == "attach" then - local c = config.connect or config - cb({ type = "server", host = c.host or "127.0.0.1", port = c.port or 5678 }) - else - cb({ - type = "executable", - command = vim.fn.executable(debugpy_python) == 1 and debugpy_python or (is_win and "python" or "python3"), - args = { "-m", "debugpy.adapter" }, - options = { source_filetype = "python" }, - }) - end - end - - dap.configurations.python = { - { - type = "python", - request = "launch", - name = "Launch file (uv .venv)", - program = "${file}", - pythonPath = uv_python, - console = "integratedTerminal", - }, - { - type = "python", - request = "launch", - name = "Launch module", - module = function() - return vim.fn.input("Module: ") - end, - pythonPath = uv_python, - console = "integratedTerminal", - }, - } - - dap.listeners.before.attach.dapui_config = function() - dapui.open() - end - dap.listeners.before.launch.dapui_config = function() - dapui.open() - end - dap.listeners.before.event_terminated.dapui_config = function() - dapui.close() - end - dap.listeners.before.event_exited.dapui_config = function() - dapui.close() - end - - -- Signs (Nerd Font glyphs as escapes so they don't get stripped): - vim.fn.sign_define("DapBreakpoint", { text = "\u{f111}", texthl = "DiagnosticError", linehl = "", numhl = "" }) -- f111 nf-fa-circle - vim.fn.sign_define( - "DapStopped", - { text = "\u{f061}", texthl = "DiagnosticWarn", linehl = "Visual", numhl = "" } - ) -- f061 nf-fa-arrow_right - end, -} diff --git a/nvim/lua/gerrrt/plugins/nvim-lint.lua b/nvim/lua/gerrrt/plugins/nvim-lint.lua index 1cdfe12..23b2df1 100644 --- a/nvim/lua/gerrrt/plugins/nvim-lint.lua +++ b/nvim/lua/gerrrt/plugins/nvim-lint.lua @@ -3,7 +3,7 @@ -- LINKS : https://github.com/mfussenegger/nvim-lint -- ABOUT : Runs a filetype's linter on write / leaving insert mode, surfacing results as -- normal diagnostics (Trouble, cd, [d/]d all work). Binaries installed by --- mason-tool-installer in conform.lua. +-- mason-tool-installer in plugins/mason-tool-installer.lua. -- ASTRAL: Python is intentionally NOT here — the ruff language server (servers/ruff.lua) -- provides Python lint diagnostics AND code actions. Listing ruff here too would -- double-report. @@ -98,11 +98,19 @@ return { })[1] ~= nil end + -- HEAVY linters that scan the WHOLE package/translation-unit per run (golangci-lint on go, + -- cpplint on c/cpp) are too costly to fire on every InsertLeave — async, but the invocations + -- pile up while you edit. Restrict them to BufWritePost (save-only); the fast per-file linters + -- (luacheck, shellcheck, eslint_d, ...) keep the snappier BufWritePost+InsertLeave cadence. + local heavy_fts = { go = true, c = true, cpp = true } local grp = vim.api.nvim_create_augroup("NvimLint", { clear = true }) vim.api.nvim_create_autocmd({ "BufWritePost", "InsertLeave" }, { group = grp, - callback = function() + callback = function(args) local ft = vim.bo.filetype + if args.event == "InsertLeave" and heavy_fts[ft] then + return -- heavy whole-package linter → save-only, don't run on InsertLeave + end if eslint_fts[ft] and not has_eslint_config() then return -- no eslint config in tree → skip (avoids eslint_d's hard error) end diff --git a/nvim/lua/gerrrt/plugins/nvim-spectre.lua b/nvim/lua/gerrrt/plugins/nvim-spectre.lua deleted file mode 100644 index 21bf0dc..0000000 --- a/nvim/lua/gerrrt/plugins/nvim-spectre.lua +++ /dev/null @@ -1,69 +0,0 @@ --- ================================================================================================ --- TITLE : nvim-spectre | project-wide search & replace with live preview --- LINKS : https://github.com/nvim-pack/nvim-spectre --- ================================================================================================ -return { - "nvim-pack/nvim-spectre", - dependencies = { "nvim-lua/plenary.nvim" }, - cmd = { "Spectre" }, - keys = { - { - "Sr", - function() - require("spectre").toggle() - end, - desc = "Spectre: toggle panel", - }, - { - "Sw", - function() - require("spectre").open_visual({ select_word = true }) - end, - desc = "Spectre: search current word", - }, - { - "Sp", - function() - require("spectre").open_file_search({ select_word = true }) - end, - desc = "Spectre: search current file", - }, - { - "Sc", - mode = "v", - function() - require("spectre").open_visual() - end, - desc = "Spectre: search selection", - }, - }, - opts = { - open_cmd = "vnew", - live_update = false, - find_engine = { - ["rg"] = { - cmd = "rg", - args = { - "--color=never", - "--no-heading", - "--with-filename", - "--line-number", - "--column", - "--hidden", - "--glob=!.git/", - }, - options = { - ["ignore-case"] = { value = "--ignore-case", icon = "[I]", desc = "ignore case" }, - ["hidden"] = { value = "--hidden", icon = "[H]", desc = "hidden files" }, - }, - }, - }, - replace_engine = { - ["sed"] = { cmd = "sed", args = nil }, - }, - default = { - find = { cmd = "rg", options = { "ignore-case" } }, - replace = { cmd = "sed" }, - }, - }, -} diff --git a/nvim/lua/gerrrt/plugins/vim-dadbod.lua b/nvim/lua/gerrrt/plugins/vim-dadbod.lua deleted file mode 100644 index 7561211..0000000 --- a/nvim/lua/gerrrt/plugins/vim-dadbod.lua +++ /dev/null @@ -1,44 +0,0 @@ --- ================================================================================================ --- TITLE : vim-dadbod (+ ui +completion) | a database client inside Neovim --- LINKS : https://github.com/tpope/vim-dadbod --- https://github.com/kristijanhusak/vim-dadbod-ui --- https://github.com/kristijanhusak/vim-dadbod-completion --- ABOUT : The one editing capability the rest of this config didn't cover. dadbod runs queries --- against live connections (postgres/mysql/sqlite/redis/…); dadbod-ui is the drawer on --- `uD` that lists connections, lets you browse schemas/tables, and saves queries. --- Pairs with your existing DAP/neotest/LSP flow so a DB round-trip never leaves the editor. --- LAZY : on the DBUI* commands + the SQL filetypes only — zero startup cost. Connections come --- from $DBUI_URL / the `g:dbs` table / a saved-queries dir; nothing is hard-coded here, so --- this is safe to vendor to every OS repo (no machine-specific connection strings). --- COMPLETION: wired engine-agnostically via buffer-local `omnifunc` () so it works --- regardless of blink.cmp. To fold it INTO the blink menu instead, add `saghen/blink.compat` --- and register `vim-dadbod-completion` as a compat source for ft={sql,mysql,plsql}. --- ================================================================================================ -return { - "kristijanhusak/vim-dadbod-ui", - dependencies = { - { "tpope/vim-dadbod", lazy = true }, - { "kristijanhusak/vim-dadbod-completion", ft = { "sql", "mysql", "plsql" }, lazy = true }, - }, - cmd = { "DBUI", "DBUIToggle", "DBUIAddConnection", "DBUIFindBuffer" }, - keys = { - { "uD", "DBUIToggle", desc = "Toggle Database UI (dadbod)" }, - { "uF", "DBUIFindBuffer", desc = "Find DB query buffer" }, - }, - init = function() - -- dadbod-ui is configured through globals (it has no setup() function). - vim.g.db_ui_use_nerd_fonts = 1 - vim.g.db_ui_win_position = "left" - vim.g.db_ui_execute_on_save = 0 -- never run a query just because you :w — explicit only - vim.g.db_ui_show_database_icon = 1 - - -- Buffer-local omni completion for SQL dialects (engine-agnostic; see COMPLETION note). - vim.api.nvim_create_autocmd("FileType", { - group = vim.api.nvim_create_augroup("DadbodCompletion", { clear = true }), - pattern = { "sql", "mysql", "plsql" }, - callback = function() - vim.bo.omnifunc = "vim_dadbod_completion#omni" - end, - }) - end, -} diff --git a/nvim/lua/gerrrt/plugins/vimade.lua b/nvim/lua/gerrrt/plugins/vimade.lua index 25bd895..8697feb 100644 --- a/nvim/lua/gerrrt/plugins/vimade.lua +++ b/nvim/lua/gerrrt/plugins/vimade.lua @@ -2,9 +2,9 @@ -- TITLE : vimade | dim inactive windows for split focus -- LINKS : https://github.com/tadaa/vimade -- ABOUT : You run globalstatus=true and a split-heavy workflow (vim-tmux-navigator, sv/sh), --- which leaves no cue for WHICH split is live. incline (plugins/incline-nvim.lua) labels each --- window with its filename; vimade completes the picture by fading the INACTIVE windows so --- the focused split pops. Paired with the active-only cursorline autocmd (config/autocmds.lua). +-- which leaves no cue for WHICH split is live. dropbar's winbar (plugins/dropbar-nvim.lua) +-- names the file in each window; vimade completes the picture by fading the INACTIVE windows +-- so the focused split pops. Paired with the active-only cursorline autocmd (config/autocmds.lua). -- THEME : Works under tokyonight transparent=true (theme.lua) — the minimalist recipe fades the -- FOREGROUND text, it does not rely on painting a background, so transparency is preserved. -- LAZY : VeryLazy — purely visual, nothing needs it before first paint. diff --git a/nvim/lua/gerrrt/plugins/which-key.lua b/nvim/lua/gerrrt/plugins/which-key.lua index 12b60e7..0f9e0bb 100644 --- a/nvim/lua/gerrrt/plugins/which-key.lua +++ b/nvim/lua/gerrrt/plugins/which-key.lua @@ -24,16 +24,12 @@ return { spec = { { "b", group = "buffer" }, { "c", group = "code / LSP" }, - { "d", group = "debug (DAP)" }, { "f", group = "find (fzf)" }, { "g", group = "git" }, - { "gx", group = "git conflict" }, { "h", group = "harpoon" }, { "n", group = "npm (package.json)" }, { "q", group = "session" }, { "s", group = "split / window" }, - { "S", group = "search & replace" }, - { "t", group = "test (neotest)" }, { "u", group = "ui / toggles" }, { "w", group = "which-key" }, { "x", group = "trouble / lists" }, diff --git a/nvim/lua/gerrrt/servers/bashls.lua b/nvim/lua/gerrrt/servers/bashls.lua index 2c3288b..0e6bf07 100644 --- a/nvim/lua/gerrrt/servers/bashls.lua +++ b/nvim/lua/gerrrt/servers/bashls.lua @@ -2,5 +2,14 @@ return function(capabilities) vim.lsp.config("bashls", { capabilities = capabilities, filetypes = { "sh", "bash", "zsh" }, + settings = { + -- bash-language-server runs shellcheck ITSELF (separate from nvim-lint). shellcheck only + -- supports sh/bash/dash/ksh, so on a zsh buffer it emits SC1071 ("only supports ...") — the + -- exact noise nvim-lint (plugins/nvim-lint.lua) and the format-on-save guard deliberately + -- avoid for zsh. Empty shellcheckPath disables bashls's built-in shellcheck integration so + -- zsh stays attached (completion/hover) without the phantom diagnostic. sh/bash are linted + -- by nvim-lint's shellcheck instead, so nothing is lost. + bashIde = { shellcheckPath = "" }, + }, }) end diff --git a/nvim/lua/gerrrt/servers/init.lua b/nvim/lua/gerrrt/servers/init.lua index 770c289..3525d57 100644 --- a/nvim/lua/gerrrt/servers/init.lua +++ b/nvim/lua/gerrrt/servers/init.lua @@ -64,8 +64,8 @@ local wanted = { -- every such buffer. That is exactly what produced the periodic vscode-json-language-server -- errors: jsonls (servers/jsonls.lua) has no explicit cmd, so it inherits lspconfig's default -- { "vscode-json-language-server", "--stdio" }, whose binary ships in Mason's json-lsp package — --- which nothing installed before. Mason now installs it (plugins/conform.lua), and this guard --- makes the whole stack resilient on any box where a server binary isn't present yet (fresh +-- which nothing installed before. Mason now installs it (plugins/mason-tool-installer.lua), and this +-- guard makes the whole stack resilient on any box where a server binary isn't present yet (fresh -- machine, DOTFILES_OFFLINE, or a uv/npm-provided server like ruff/ty/solidity not installed). local function binary_available(name) local cfg = vim.lsp.config[name] @@ -77,20 +77,32 @@ local function binary_available(name) return vim.fn.executable(cmd[1]) == 1 end -local to_enable, missing = {}, {} -for _, name in ipairs(wanted) do - if binary_available(name) then - to_enable[#to_enable + 1] = name - else - missing[#missing + 1] = name +local M = {} + +-- Enable every WANTED server whose binary is currently present; return the list still missing. +-- Safe to call REPEATEDLY: vim.lsp.enable is idempotent and, on 0.11+, attaches a newly-enabled +-- server to already-open matching buffers. That is what lets the post-install hook in +-- plugins/mason-tool-installer.lua (User MasonToolsUpdateCompleted) bring a fresh box's LSP up in +-- the SAME session — the initial pass ran at BufReadPre before the binaries existed and skipped +-- them; re-running after the install attaches them without a restart. +function M.enable_available() + local to_enable, missing = {}, {} + for _, name in ipairs(wanted) do + if binary_available(name) then + to_enable[#to_enable + 1] = name + else + missing[#missing + 1] = name + end end + vim.lsp.enable(to_enable) + return missing end -vim.lsp.enable(to_enable) - --- Surface (once) which servers were skipped so a missing binary is discoverable, not silent. --- Suppressed on engagement/offline boxes (DOTFILES_OFFLINE=1, see config/globals.lua), where --- tools are intentionally not installed and the warning would just be startup noise. +-- Initial pass at load. Surface (once) which servers were skipped so a missing binary is +-- discoverable, not silent. Suppressed on engagement/offline boxes (DOTFILES_OFFLINE=1, see +-- config/globals.lua), where tools are intentionally not installed and the warning would be noise. +-- (The post-install re-enable hook does NOT re-notify — it only enables what's now available.) +local missing = M.enable_available() if #missing > 0 and not vim.g.dotfiles_offline then vim.schedule(function() vim.notify( @@ -102,3 +114,5 @@ if #missing > 0 and not vim.g.dotfiles_offline then ) end) end + +return M diff --git a/nvim/lua/gerrrt/utils/lsp.lua b/nvim/lua/gerrrt/utils/lsp.lua index 025ad84..7b73c9c 100644 --- a/nvim/lua/gerrrt/utils/lsp.lua +++ b/nvim/lua/gerrrt/utils/lsp.lua @@ -4,8 +4,7 @@ -- NOTE : Neovim 0.12 ships capable native LSP, so this uses vim.lsp.buf.* directly -- (hover / rename / code action / signature) and fzf-lua for the picker-style -- lookups (definitions / references / symbols). lspsaga was removed — it only --- duplicated what's now built in. DAP keymaps live in the nvim-dap plugin spec, --- not here, so they aren't gated behind an LSP attach. +-- duplicated what's now built in. -- ================================================================================================ local M = {} @@ -98,40 +97,21 @@ M.on_attach = function(event) vim.lsp.buf.hover(float_opts) end, opts("Hover documentation")) keymap("n", "gD", vim.lsp.buf.declaration, opts("Go to declaration")) - keymap("n", "rn", vim.lsp.buf.rename, opts("Rename symbol")) + -- NvChad-style inline rename float (prefilled prompt at the cursor) instead of the bare + -- cmdline vim.lsp.buf.rename. Falls back to the native prompt when there's no . + keymap("n", "rn", function() + require("gerrrt.utils.renamer").rename() + end, opts("Rename symbol")) keymap({ "n", "v" }, "ca", vim.lsp.buf.code_action, opts("Code action")) keymap("i", "", function() vim.lsp.buf.signature_help(float_opts) end, opts("Signature help")) - -- Auto signature help while resting in a function's arguments. blink.cmp already surfaces - -- signatures DURING completion; this covers the other case — you've paused typing inside the - -- parens and want the params without reaching for . Gated on server support, and otherwise - -- self-gating (signature_help draws nothing when the cursor isn't inside a signature). Skipped - -- while the blink menu is open so two signature floats never stack. focusable=false so it can't - -- steal the cursor; silent=true swallows the "no signature help" message. Fires after - -- 'updatetime' (300ms, options.lua) of no typing. Per-buffer augroup (clear=true) dedupes across - -- multiple attached clients. - if client:supports_method("textDocument/signatureHelp", bufnr) then - local sig_group = vim.api.nvim_create_augroup("GerrrtLspSignature_" .. bufnr, { clear = true }) - vim.api.nvim_create_autocmd("CursorHoldI", { - group = sig_group, - buffer = bufnr, - callback = function() - local blink_ok, blink = pcall(require, "blink.cmp") - if blink_ok and blink.is_visible() then - return - end - pcall(vim.lsp.buf.signature_help, { - border = "rounded", - max_width = 80, - max_height = 25, -- same bounded card as manual K/ so many-overload sigs stay tidy - focusable = false, - silent = true, - }) - end, - }) - end + -- AUTOMATIC signature help is owned by blink.cmp (plugins/blink-cmp.lua, signature.enabled): + -- it pops the params float as you type inside the parens, in its own rounded window. A manual + -- CursorHoldI vim.lsp.buf.signature_help used to live here too, but blink's signature window is + -- a SEPARATE surface from its completion menu, so the two floats could stack while idle. blink + -- owns the automatic case now; above stays the on-demand manual trigger. -- ── Diagnostics (native) ───────────────────────────────────────────────── keymap("n", "cd", vim.diagnostic.open_float, opts("Line diagnostics")) diff --git a/nvim/lua/gerrrt/utils/palette.lua b/nvim/lua/gerrrt/utils/palette.lua new file mode 100644 index 0000000..c4828c4 --- /dev/null +++ b/nvim/lua/gerrrt/utils/palette.lua @@ -0,0 +1,76 @@ +-- ================================================================================================ +-- TITLE : palette | single source of truth for the active theme's colors +-- ABOUT : Every UI module that hand-paints its own chrome (lualine, bufferline, cheatsheet) needs +-- tokyonight's RESOLVED palette. Before this module each one re-called +-- `require("tokyonight.colors").setup({ style = "storm" })` inline — duplicating both the +-- pcall dance AND the "storm" string across four files, so a style swap meant four edits. +-- This centralizes both: change M.style here (and the mirror in plugins/theme.lua) and the +-- whole hand-painted UI follows. +-- SEMANTIC MAP : M.nvchad() re-expresses the palette in NvChad's base_30 vocabulary (black / black2, +-- statusline_bg, lightbg, nord_blue, dark_purple, ...) so the block/pill styling can be +-- written the way NvChad documents it while still tracking whatever `style` is active. +-- FRESH BOX : every getter is pcall-guarded and returns nil when tokyonight hasn't loaded, so +-- callers degrade to their plugin's own defaults instead of erroring — Core stays bootable +-- on a bare machine (same contract the inline calls had). +-- ================================================================================================ +local M = {} + +-- The active tokyonight style. Mirrors `style` in plugins/theme.lua — keep the two in sync. +M.style = "storm" + +-- Resolve tokyonight's palette for M.style. Returns the raw color table, or nil on a box where +-- tokyonight isn't installed/loaded yet. Deliberately NOT cached: the table is cheap to rebuild and +-- staying un-cached keeps it correct if the colorscheme is ever reloaded at runtime. +function M.colors() + local ok, c = pcall(function() + return require("tokyonight.colors").setup({ style = M.style }) + end) + if ok and type(c) == "table" then + return c + end + return nil +end + +-- NvChad base_30-style semantic names mapped onto the resolved palette. Returns nil when the +-- palette is unavailable. Surfaces run darkest → raised (darker_black → black → black2 → one_bg*); +-- accents keep NvChad's own names so block styling reads like NvChad's docs. +-- +-- HYBRID NOTE : theme.lua runs transparent=true, so the EDITOR stays see-through. The bars that go +-- opaque in the hybrid look (statusline / tabline) use black2 = the darkest solid tint, with +-- the active block lifting to one_bg (lighter) so it reads as raised off the bar. +function M.nvchad() + local c = M.colors() + if not c then + return nil + end + return { + -- surfaces, darkest → raised + darker_black = c.bg_dark, + black = c.bg, + black2 = c.bg_dark, -- the solid tabline/statusline bar (opaque, not NONE) + one_bg = c.bg_highlight, -- raised block (active buffer body / pill body) + one_bg2 = c.fg_gutter, + one_bg3 = c.terminal_black or c.fg_gutter, + statusline_bg = c.bg_dark, + lightbg = c.bg_highlight, + -- text / neutrals + white = c.fg, + light_grey = c.fg_dark, + grey = c.comment, + line = c.border, + -- accents (NvChad name → tokyonight) + red = c.red, + green = c.green, + blue = c.blue, + nord_blue = c.blue, + yellow = c.yellow, + orange = c.orange, + purple = c.purple, + magenta = c.magenta, + dark_purple = c.magenta, -- NvChad's Insert-mode accent is purple + teal = c.teal, + cyan = c.cyan, + } +end + +return M diff --git a/nvim/lua/gerrrt/utils/renamer.lua b/nvim/lua/gerrrt/utils/renamer.lua new file mode 100644 index 0000000..0ce7c06 --- /dev/null +++ b/nvim/lua/gerrrt/utils/renamer.lua @@ -0,0 +1,76 @@ +-- ================================================================================================ +-- TITLE : renamer | NvChad-style inline LSP rename prompt +-- ABOUT : Replaces the bare `vim.lsp.buf.rename()` (which prompts on the cmdline) with a small, +-- cursor-anchored floating input prefilled with the symbol under the cursor — NvChad's +-- renamer look. applies the rename across the workspace, / q cancels. +-- SAFE : the float is a scratch buffer; on we return focus to the ORIGINAL window (so the +-- rename runs against the real symbol, not the float) before calling vim.lsp.buf.rename, +-- which handles prepareRename + the workspace edit itself. Border/title colors come from +-- utils/ui-highlights.lua (GerrrtRenamer*), so they track the theme. +-- ================================================================================================ +local M = {} + +function M.rename() + local cword = vim.fn.expand("") + -- Gate on a rename-capable client so we don't take input into a float that can only end in a + -- "no client supports rename" error. No cword to prefill → hand off to the native prompt too. + local can_rename = #vim.lsp.get_clients({ bufnr = 0, method = "textDocument/rename" }) > 0 + if cword == "" or not can_rename then + vim.lsp.buf.rename() -- native path: prompts, and reports cleanly if unsupported + return + end + + -- Capture where we launched from: the rename must run in THIS window/buffer with the cursor on + -- the symbol, not inside the float we're about to open. + local from_win = vim.api.nvim_get_current_win() + + local buf = vim.api.nvim_create_buf(false, true) + vim.bo[buf].bufhidden = "wipe" -- wipe the scratch buffer when the float closes (no leaked buffers) + local win = vim.api.nvim_open_win(buf, true, { + relative = "cursor", + row = 1, + col = 1, + width = math.max(#cword + 15, 25), + height = 1, + style = "minimal", + border = "rounded", -- matches the global winborder + the rest of the config's floats + title = { { " Rename ", "GerrrtRenamerTitle" } }, + title_pos = "center", + }) + vim.wo[win].winhighlight = "Normal:NormalFloat,FloatBorder:GerrrtRenamerBorder" + + vim.api.nvim_buf_set_lines(buf, 0, -1, false, { cword }) + -- `startinsert!` = enter insert at END of line (like `A`), so you can immediately edit/extend the + -- prefilled name. Robust across nvim versions — no manual, version-dependent cursor-column math + -- (some builds clamp an out-of-range col to EOL, others would error). + vim.cmd("startinsert!") + + local function close() + vim.cmd("stopinsert") + if vim.api.nvim_win_is_valid(win) then + vim.api.nvim_win_close(win, true) + end + end + + local function apply() + local newname = vim.trim(vim.api.nvim_buf_get_lines(buf, 0, 1, false)[1] or "") + close() + if newname == "" or newname == cword then + return -- empty or unchanged → no-op + end + -- Back to the source window so vim.lsp.buf.rename sees the real symbol under the cursor. + if vim.api.nvim_win_is_valid(from_win) then + vim.api.nvim_set_current_win(from_win) + end + vim.lsp.buf.rename(newname) + end + + local map = function(mode, lhs, fn) + vim.keymap.set(mode, lhs, fn, { buffer = buf, nowait = true, silent = true }) + end + map({ "i", "n" }, "", apply) + map({ "i", "n" }, "", close) + map("n", "q", close) +end + +return M diff --git a/nvim/lua/gerrrt/utils/ui-highlights.lua b/nvim/lua/gerrrt/utils/ui-highlights.lua index 95d0f3a..eae03f5 100644 --- a/nvim/lua/gerrrt/utils/ui-highlights.lua +++ b/nvim/lua/gerrrt/utils/ui-highlights.lua @@ -56,6 +56,32 @@ function M.apply(hl, c) hl.BlinkCmpSignatureHelpBorder = { fg = c.border_highlight, bg = none } hl.BlinkCmpLabelMatch = { fg = c.blue, bold = true } + -- ── blink.cmp kind icons: NvChad's colored-kind look. blink draws each item's kind icon (and the + -- trailing kind text column) with the group `BlinkCmpKind`; coloring those by semantic role + -- gives the menu NvChad's rainbow kind column. Grouped so related kinds share a palette accent + -- (func=blue, var=magenta, type=yellow, keyword=purple, const/value=orange, text=green, misc=cyan). + local kind_palette = { + { c.blue, { "Function", "Method", "Constructor" } }, + { c.magenta, { "Variable", "Field", "Property" } }, + { c.yellow, { "Class", "Struct", "Interface", "Enum", "EnumMember", "TypeParameter", "Event" } }, + { c.purple, { "Keyword", "Operator" } }, + { c.orange, { "Constant", "Value", "Unit" } }, + { c.green, { "Text", "String", "Snippet" } }, + { c.cyan, { "Module", "File", "Folder", "Reference", "Color" } }, + } + for _, spec in ipairs(kind_palette) do + local color, kinds = spec[1], spec[2] + for _, kind in ipairs(kinds) do + hl["BlinkCmpKind" .. kind] = { fg = color } + end + end + + -- ── LSP renamer float (utils/renamer.lua): NvChad tints the rename prompt's border git-red as a + -- "this edits everything" cue, with a matching bold red title. Border/title only; the body uses the + -- normal float bg so the input text stays readable. + hl.GerrrtRenamerBorder = { fg = c.red, bg = none } + hl.GerrrtRenamerTitle = { fg = c.red, bg = none, bold = true } + -- ── which-key: NvChad's palette on the minimal rounded float — blue keys, red descriptions, ── -- green groups, dim separators. Border/title tint match the LSP + finder floats above so every -- popup in the config reads as one system. (Layout/border geometry is set in plugins/which-key.lua.) From b07f61456d03fbb2458a2e1fd3b364f0db640340 Mon Sep 17 00:00:00 2001 From: dotfiles-core sync bot <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 14:17:22 +0000 Subject: [PATCH 2/2] =?UTF-8?q?chore(core):=20core.lock=20=E2=86=92=20dcde?= =?UTF-8?q?da541fdc=20(v3.9.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core.lock b/core.lock index 263b3d0..49810ba 100644 --- a/core.lock +++ b/core.lock @@ -1,6 +1,6 @@ # GENERATED by dotfiles-core sync-core.sh — vendored Core provenance (B1). # Regenerate after a manual 'git subtree pull' with: make core-lock -core_version=3.8.0 -core_sha=da1541206be1f7e0b36a1592a1a775ae6f2f0bf0 -core_branch=da1541206be1f7e0b36a1592a1a775ae6f2f0bf0 -core_tag=v3.8.0 +core_version=3.9.0 +core_sha=dcdeda541fdcc1c1a855f064bebaa2d1c56211af +core_branch=dcdeda541fdcc1c1a855f064bebaa2d1c56211af +core_tag=v3.9.0