Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions core.lock
Original file line number Diff line number Diff line change
@@ -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.7.0
core_sha=e9cf907f5849dfae2f3313d840fcbafb3772b83a
core_branch=e9cf907f5849dfae2f3313d840fcbafb3772b83a
core_tag=v3.7.0
core_version=3.8.0
core_sha=da1541206be1f7e0b36a1592a1a775ae6f2f0bf0
core_branch=da1541206be1f7e0b36a1592a1a775ae6f2f0bf0
core_tag=v3.8.0
47 changes: 47 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,53 @@ commit (`git tag -a vX.Y.Z -m vX.Y.Z`).

## [Unreleased]

## [v3.8.0] - 2026-07-18

### Changed

- **Neovim UI moves to an NvChad-styled statusline + bufferline.** `lualine` now uses a
hand-built theme derived from tokyonight's resolved palette (mode/location render as rounded
accent **pills**, git/cwd as a lighter block, filename on the base run) instead of the bundled
`tokyonight` theme — so the blocks read as opaque islands on the transparent bar and follow
NvChad's structure. `bufferline` gains palette-aware highlights so the active buffer lifts as a
subtle raised block with an accent underline while inactive buffers dim into the bar. Both are
computed at plugin-load (pcall-guarded), so a fresh box falls back to the bundled/auto theming.
- **LSP hover, signature help, and the diagnostic float share one padded, rounded card style.**
Hover/signature pass an explicit rounded border with width/height caps (a huge docstring becomes
a tidy box); the diagnostic float drops its header row and gains a left pad + width cap.
Signature help now also pops **automatically** when you rest inside a function's arguments
(`CursorHoldI`, gated on server support, suppressed while the completion menu is open).
- **`which-key` and the `<leader>?` cheatsheet restyled to mirror NvChad's keymap visualizer.**
which-key gets a minimal rounded, padded, left-aligned column popup with NvChad-palette colors
(blue keys, red descriptions, green groups); the cheatsheet's category headings become
full-width accent **pill** bars (cycling colors) with blue keys — both palette-aware, with a
semantic-link fallback on a bare box.

### Fixed

- **Neovim `taplo` (TOML) root detection.** `root_markers` listed the glob `"*.toml"`, which
`vim.fs.root`/`vim.fs.find` do not support — so it never matched and taplo always fell back to
`.git`, giving a lone TOML file outside a repo a cwd root. Replaced with real manifest names
(`pyproject.toml`, `Cargo.toml`, `foundry.toml`, `taplo.toml`, `.taplo.toml`, `.git`).
- **Neovim `<leader>oi` (organize imports) no longer binds where it can't work or races the
formatter.** A server that ENUMERATES its code-action kinds without `source[.organizeImports]` is
now skipped (so the map no longer silently no-ops on e.g. `lua_ls`); a server that only reports a
bare `true` or a provider table without kinds still gets the map, since it can't be ruled out. The
racy fixed-`50ms` post-format timer is dropped — formatting stays owned by format-on-save and
`<leader>cf`.
- **Neovim cursor-restore skips commit buffers.** `gitcommit`/`gitrebase` buffers open at the top
again instead of jumping to a stale mark from a previous commit.
- **Neovim folding has a single owner.** `nvim-ufo` computes folds via its own treesitter+indent
providers, so the global `foldmethod=expr` + treesitter `foldexpr` in `options.lua` was redundant
per-buffer work (UFO never reads `foldexpr`). Dropped it; UFO now owns folding outright.

### Changed (internal)

- Deduped the identical `snippetSupport` capability boilerplate in the Neovim `html`/`cssls`
server specs into a shared `utils.lsp.with_snippets` helper; standardized autocmd augroups on an
explicit `{ clear = true }`; corrected a stale comment claiming no `vim.notify`-competing
notifier is installed (fidget is, for LSP progress only — no clash).

## [v3.7.0] - 2026-07-17

### Changed
Expand Down
2 changes: 1 addition & 1 deletion core/core.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.7.0
3.8.0
58 changes: 45 additions & 13 deletions core/nvim/lua/gerrrt/cheatsheet.lua
Original file line number Diff line number Diff line change
Expand Up @@ -236,21 +236,46 @@ local HL = {
footer = "GerrrtCheatFooter",
}

-- Number of accent "pill" highlight groups; cards cycle through them by index so adjacent headings
-- get different colors — NvChad's grid look (black text on a vivid accent bar). Populated by
-- define_highlights when the palette is available; 0 on a bare box (headings fall back to plain).
local NPILL = 0

local function define_highlights()
-- default = true so a user's colorscheme / overrides always win. Linked to semantic groups
-- every theme defines, so it inherits tokyonight here and Just Works on a bare box too.
local set = vim.api.nvim_set_hl
set(0, HL.title, { link = "Title", default = true })
set(0, HL.key, { link = "Constant", default = true })
set(0, HL.rule, { link = "Comment", default = true })
set(0, HL.sep, { link = "Comment", default = true })
set(0, HL.footer, { link = "Comment", default = true })
-- 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
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
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 })
set(0, HL.sep, { fg = c.comment })
set(0, HL.footer, { fg = c.comment, italic = true })
else
-- bare-box fallback: link to semantic groups every colorscheme defines (previous behavior).
NPILL = 0
set(0, HL.title, { link = "Title", default = true })
set(0, HL.key, { link = "Constant", default = true })
set(0, HL.rule, { link = "Comment", default = true })
set(0, HL.sep, { link = "Comment", default = true })
set(0, HL.footer, { link = "Comment", default = true })
end
end

-- Build one card into an array of "rich lines" ({ text = str, hls = { {s,e,hl}, ... } }) where s/e
-- are BYTE offsets local to that line. Multibyte (the ─ rule) is fine because everything downstream
-- measures with #str (bytes) for offsets and strdisplaywidth() for padding.
local function build_card(section)
local function build_card(section, idx)
local lines = {}
local function rich(text, hls)
table.insert(lines, { text = text, hls = hls or {} })
Expand All @@ -263,9 +288,16 @@ local function build_card(section)
end
keyw = math.min(keyw, CARD_W - 6) -- never let keys eat the whole card

rich(section[1], { { s = 0, e = #section[1], hl = HL.title } })
local rule = string.rep("─", CARD_W)
rich(rule, { { s = 0, e = #rule, hl = HL.rule } })
-- Heading as a full-width PILL: one leading space, title, padded to the card width, and the whole
-- run painted with a cycling accent group (black bold text on a vivid bar) — NvChad's grid look.
-- Falls back to the plain HL.title span on a bare box where no pill groups were defined.
local head = " " .. section[1]
local pad = CARD_W - vim.fn.strdisplaywidth(head)
if pad > 0 then
head = head .. string.rep(" ", pad)
end
local head_hl = NPILL > 0 and ("GerrrtCheatPill" .. ((idx - 1) % NPILL + 1)) or HL.title
rich(head, { { s = 0, e = #head, hl = head_hl } })

for i = 2, #section do
local key, desc = section[i][1], section[i][2]
Expand Down Expand Up @@ -352,8 +384,8 @@ function M.open()
ncol = math.min(ncol, #M.sections)

local cards = {}
for _, s in ipairs(M.sections) do
table.insert(cards, build_card(s))
for i, s in ipairs(M.sections) do
table.insert(cards, build_card(s, i))
end

local cols, tallest = pack(cards, ncol)
Expand Down
14 changes: 10 additions & 4 deletions core/nvim/lua/gerrrt/config/autocmds.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@
local on_attach = require("gerrrt.utils.lsp").on_attach

-- Restore last cursor position when reopening a file
local last_cursor_group = vim.api.nvim_create_augroup("LastCursorGroup", {})
local last_cursor_group = vim.api.nvim_create_augroup("LastCursorGroup", { clear = true })
vim.api.nvim_create_autocmd("BufReadPost", {
group = last_cursor_group,
callback = function()
-- Commit/rebase buffers should open at the top (you're writing a new message / editing the
-- todo list), not wherever the cursor last sat in a previous commit — skip the restore there.
local ft = vim.bo.filetype
if ft == "gitcommit" or ft == "gitrebase" then
return
end
local mark = vim.api.nvim_buf_get_mark(0, '"')
local lcount = vim.api.nvim_buf_line_count(0)
if mark[1] > 0 and mark[1] <= lcount then
Expand All @@ -18,7 +24,7 @@ vim.api.nvim_create_autocmd("BufReadPost", {
})

-- Highlight the yanked text for 200ms
local highlight_yank_group = vim.api.nvim_create_augroup("HighlightYank", {})
local highlight_yank_group = vim.api.nvim_create_augroup("HighlightYank", { clear = true })
vim.api.nvim_create_autocmd("TextYankPost", {
group = highlight_yank_group,
pattern = "*",
Expand All @@ -37,7 +43,7 @@ vim.api.nvim_create_autocmd("TextYankPost", {
-- Format on save: trim trailing whitespace, then run conform.
-- lsp_format = "fallback" means filetypes without a conform formatter still get
-- formatted by their LSP (e.g. gopls), and filetypes with neither are left alone.
local lsp_fmt_group = vim.api.nvim_create_augroup("FormatOnSaveGroup", {})
local lsp_fmt_group = vim.api.nvim_create_augroup("FormatOnSaveGroup", { clear = true })
vim.api.nvim_create_autocmd("BufWritePre", {
group = lsp_fmt_group,
callback = function(args)
Expand All @@ -55,7 +61,7 @@ vim.api.nvim_create_autocmd("BufWritePre", {
})

-- on attach function shortcuts
local lsp_on_attach_group = vim.api.nvim_create_augroup("LspMappings", {})
local lsp_on_attach_group = vim.api.nvim_create_augroup("LspMappings", { clear = true })
vim.api.nvim_create_autocmd("LspAttach", {
group = lsp_on_attach_group,
callback = on_attach,
Expand Down
8 changes: 6 additions & 2 deletions core/nvim/lua/gerrrt/config/options.lua
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,12 @@ vim.opt.guicursor = {
}

-- Folding Settings
vim.opt.foldmethod = "expr" -- Use expression for folding
vim.opt.foldexpr = "v:lua.vim.treesitter.foldexpr()" -- Use treesitter for folding
-- Folds are owned by nvim-ufo (plugins/nvim-ufo.lua), which computes them via its own treesitter +
-- indent providers. We deliberately do NOT set foldmethod=expr + a global treesitter foldexpr here:
-- UFO does not read 'foldexpr', so those only added redundant per-buffer fold computation on top of
-- what UFO already does. We keep just the "folds open on open" intent; UFO re-asserts
-- foldlevel/foldlevelstart=99 in its init. To fall back to plain folding, remove nvim-ufo.lua AND
-- restore `foldmethod=expr` + `foldexpr=v:lua.vim.treesitter.foldexpr()` here.
vim.opt.foldlevel = 99 -- Keep all folds open by default

-- Split Behavior
Expand Down
62 changes: 62 additions & 0 deletions core/nvim/lua/gerrrt/plugins/bufferline-nvim.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,62 @@
--
-- 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.
-- ================================================================================================

-- Build bufferline's `highlights` from the tokyonight 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
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
return {
fill = { bg = none },
background = dim,
buffer_visible = { fg = c.fg_dark, bg = none },
-- `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 },
-- 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 },
-- 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 },
-- 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 },
}
end

return {
"akinsho/bufferline.nvim",
version = "*",
Expand Down Expand Up @@ -95,4 +150,11 @@ return {
hover = { enabled = true, delay = 150, reveal = { "close" } },
},
},
config = function(_, opts)
-- Attach the palette-aware highlights (nil on a fresh box → bufferline uses its own
-- colorscheme defaults) and hand the merged table to setup. Kept in `config` rather than
-- `opts` so build_highlights() runs at bufferline load, when tokyonight is loaded.
opts.highlights = build_highlights()
require("bufferline").setup(opts)
end,
}
50 changes: 47 additions & 3 deletions core/nvim/lua/gerrrt/plugins/lualine-nvim.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
-- right : search count · attached LSP servers · diagnostics · filetype · cwd · location
-- 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 lualine's tokyonight theme
-- (which sets a bg per section), so this stays readable even under transparency.
-- half reads as one clean run of blocks. Colors come from a HAND-BUILT theme derived from
-- tokyonight's resolved palette (build_theme below) — not lualine's bundled tokyonight
-- theme — so the blocks map onto NvChad's structure (accent mode/location PILLS at both
-- 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").
-- 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
Expand All @@ -26,6 +32,44 @@ return {
event = "VeryLazy",
dependencies = { "nvim-tree/nvim-web-devicons" },
config = function()
-- Build a lualine theme from tokyonight's resolved palette so the statusline mirrors NvChad's
-- St_* block structure: a/z = accent PILLS (mode on the left, cursor location on the right —
-- lualine feeds theme `a` to both), b/y = a lighter git/cwd block, c/x = the base filename
-- run. Mode → accent follows NvChad (Normal=blue, Insert=purple, Visual=cyan, Replace=orange,
-- Command/Terminal=green). Dark text (bg_dark) on the bright accents keeps the pills legible.
-- 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
return "tokyonight"
end
local base, block = c.bg_dark, c.bg_highlight
local function mk(accent)
return {
a = { fg = c.bg_dark, bg = accent, gui = "bold" },
b = { fg = c.fg_dark, bg = block },
c = { fg = c.fg, bg = base },
}
end
return {
normal = mk(c.blue),
insert = mk(c.magenta), -- NvChad Insert pill = purple
visual = mk(c.cyan),
replace = mk(c.orange),
command = mk(c.green),
terminal = mk(c.green),
inactive = {
a = { fg = c.comment, bg = base },
b = { fg = c.comment, bg = base },
c = { fg = c.comment, bg = base },
},
}
end

-- Show the language servers attached to the current buffer.
local function lsp_servers()
local clients = vim.lsp.get_clients({ bufnr = 0 })
Expand All @@ -47,7 +91,7 @@ return {

require("lualine").setup({
options = {
theme = "tokyonight",
theme = build_theme(),
icons_enabled = true,
globalstatus = true,
-- NvChad's rounded blocks: half-circle section caps, and NO component separators
Expand Down
5 changes: 3 additions & 2 deletions core/nvim/lua/gerrrt/plugins/mini-nvim.lua
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ return {
require("mini.notify").setup({})
-- setup() alone does NOT replace vim.notify — without this line mini.notify is configured
-- but unused, and vim.notify(...) calls (e.g. harpoon's "added" toast) still hit Neovim's
-- built-in notifier. make_notify() returns a drop-in replacement. (No competing notifier
-- like noice/fidget is installed, so there's nothing to clash with.)
-- built-in notifier. make_notify() returns a drop-in replacement. fidget.nvim is also
-- installed (plugins/fidget-nvim.lua) but only renders LSP *progress* — it is not a
-- vim.notify backend, so the two don't clash; this owns vim.notify, fidget owns $/progress.
vim.notify = require("mini.notify").make_notify()
end,
}
Loading