Skip to content

Instantly share code, notes, and snippets.

@bartman
Last active April 14, 2026 22:45
Show Gist options
  • Select an option

  • Save bartman/1ce0a21bdb2b4687e1aa6d92cb99f762 to your computer and use it in GitHub Desktop.

Select an option

Save bartman/1ce0a21bdb2b4687e1aa6d92cb99f762 to your computer and use it in GitHub Desktop.
nvim-0.12-config

This is a clean rewrite of my old nvim config.

git clone https://gist.github.com/bartman/1ce0a21bdb2b4687e1aa6d92cb99f762 bartman-nvim-config

I tried to stick with Neovim builtins that became available in 0.12.

You can copy the files here into ~/.config/nvim/ but replace the __ in filesnames with /. This is a gist, and gists cannot have subdirectories.

You run the install script in this repo. Note that it puts this config in ~/.config/nvim-new, so you'll have to rename it.

Something like...

mv ~/.config/nvim ~/.config/nvim-old
./install.sh
mv ~/.config/nvim-new ~/.config/nvim
{
"runtime.version": "LuaJIT",
"runtime.path": [
"lua/?.lua",
"lua/?/init.lua"
],
"diagnostics.globals": ["vim"],
"workspace.checkThirdParty": false,
"workspace.library": [
"$VIMRUNTIME"
]
}
vim.opt_local.cindent = true -- enable the full C/C++ indent engine
vim.opt_local.cinoptions = table.concat({
"N-s", -- ← NAMESPACE: contents NOT indented (exactly what you asked for)
"C0", -- no template<> indentation
"+0", -- no extra indent on continuation lines
":0", -- case labels NOT indented extra
"g0", -- C++ scope declarations (public:/private:) at column 0
"(0", -- function arguments: align under the opening (
"W4", -- if the line after ( is continued, indent 4 spaces
"l1", -- case labels get only 1 indent level
"i2", -- indent inside #if / #else etc.
"j1", -- indent Java anonymous classes (harmless for C++)
"t0", -- indent of function return type
}, ",")
-- letters that make up a keyword
vim.opt.iskeyword = "@,48-57,_,192-255" -- this is basic
--vim.opt.iskeyword = "a-z,A-Z,48-57,_,.,-,>" -- this is suggested in docs, but grabs too much
require('config.globals')
require('config.options')
require('config.keymap')
require('config.autocmd')
require('config.ui2')
require('config.alternate')
vim.cmd('packadd nvim.undotree')
vim.cmd('packadd nvim.difftool')
vim.cmd('packadd nvim.tohtml')
require('plugins.catppuccin')
require('plugins.mini')
require('plugins.treesitter')
require('plugins.lsp')
-- require('plugins.blink-edit') -- not stable
require('plugins.minuet-ai') -- almost working
require('plugins.blink-cmp')
require('plugins.git')
require('plugins.oil')
require('plugins.fzf')
require('plugins.dropbar')
require('plugins.tiny-code-action')
require('plugins.markdown')
--require('plugins.animation')
#!/usr/bin/env bash
set -e
SELF="$(realpath "$0")"
SRCDIR="${SELF%/*}"
DSTDIR="$HOME/.config/nvim-new"
FILES=( $(cd "${SRCDIR}" && find . ! -path '*/.git/*' ! -name '*~' -type f -printf '%P\n' ) )
for file in "${FILES[@]}" ; do
# Reverse the mangling:
# __ --> / ... restore directory structure
# _* --> .* ... restore dotfiles
target="${file//__//}"
[[ "${target:0:1}" == "_" ]] && target=".${target:1}"
src="${SRCDIR}/${file}"
dst="${DSTDIR}/${target}"
mkdir -p "$(dirname "$dst")"
cp -iv "$src" "$dst"
done
---------------------------------------------------------------------------
-- :A - switches between source and header files
-- :AS - open a horizontal split with alternate file
-- :AV - open a vertial split with alternate file
-- This is a lua port of :A from https://www.vim.org/scripts/script.php?script_id=31
-- Enhanced to handle multiple alternate suffixes
local function switch_to_alternate_file(split)
local current_path = vim.api.nvim_buf_get_name(0)
local current_ext = string.match(current_path, "%.([^%.]+)$")
local alternate_paths = {}
-- Define mapping of current extension to possible alternate extensions
local ext_map = {
c = { "h" },
cpp = { "h", "hpp" },
cxx = { "h", "hpp" },
cc = { "h", "hpp" },
h = { "c", "cc", "cpp", "cxx" },
hpp = { "cc", "cpp", "cxx" }
}
-- If the current extension is not in the map, notify and exit
if not current_ext or not ext_map[current_ext] then
print("Not a recognized C/C++ source or header file")
return
end
-- Build list of alternate file paths
for _, alt_ext in ipairs(ext_map[current_ext]) do
local alt_path = string.gsub(current_path, "%." .. current_ext .. "$", "." .. alt_ext)
table.insert(alternate_paths, alt_path)
end
-- handle split argument once we find the file we want to switch to
local show_file = function(path)
local cmd
if split == 's' or split == 'h' then
cmd = 'split'
elseif split == 'v' then
cmd = 'vsplit'
else
cmd = 'edit'
end
return vim.api.nvim_command(cmd .. ' ' .. vim.fn.fnameescape(path))
end
-- Check if any alternate file exists on the filesystem
for _, alt_path in ipairs(alternate_paths) do
local f = io.open(alt_path, "r")
if f then
io.close(f)
--vim.api.nvim_command('edit ' .. alt_path)
return show_file(alt_path)
end
end
-- If no file exists, check open buffers for matching filenames
for _, alt_path in ipairs(alternate_paths) do
local alternate_file = vim.fn.fnamemodify(alt_path, ":t")
for _, buf in ipairs(vim.api.nvim_list_bufs()) do
local buffer_path = vim.api.nvim_buf_get_name(buf)
if vim.api.nvim_buf_is_valid(buf) and buffer_path ~= "" then
local buffer_name = vim.fn.fnamemodify(buffer_path, ":t")
if buffer_name == alternate_file then
--vim.api.nvim_set_current_buf(buf)
return show_file(buffer_path)
end
end
end
end
-- If still not found, check recent buffers
for _, alt_path in ipairs(alternate_paths) do
local alternate_file = vim.fn.fnamemodify(alt_path, ":t")
for _, buf in ipairs(vim.fn.getbufinfo({ buflisted = 1 })) do
if buf.name ~= "" then
local buffer_name = vim.fn.fnamemodify(buf.name, ":t")
if buffer_name == alternate_file then
--vim.api.nvim_set_current_buf(buf.bufnr)
return show_file(buf.name)
end
end
end
end
-- If no alternate file or buffer is found, notify the user
print("No alternate file found for " .. vim.fn.fnamemodify(current_path, ":t"))
end
vim.api.nvim_create_user_command('A', function() switch_to_alternate_file() end, {})
vim.api.nvim_create_user_command('AS', function() switch_to_alternate_file('s') end, {})
vim.api.nvim_create_user_command('AV', function() switch_to_alternate_file('v') end, {})
-- autocmd
--------------------------------------------------------------------------------
-- Highlight when yanking
local UserConfig = vim.api.nvim_create_augroup('UserConfig', { clear = true })
-- wrap, linebreak and spellcheck on markdown and text files
vim.api.nvim_create_autocmd("FileType", {
group = UserConfig,
pattern = { "markdown", "text", "gitcommit" },
callback = function()
vim.opt_local.wrap = true
vim.opt_local.linebreak = true
vim.opt_local.spell = true
end,
})
vim.g.mapleader = ','
vim.g.maplocalleader = ','
vim.g.have_nerd_font = true
vim.keymap.set({ 'n', 'x' }, 'gs', '<CMD>vertical wincmd f<CR>', { desc = "Edit file under cursor, vertical split"})
vim.keymap.set({ 'n', 'x' }, '<leader>y', '"+y', { desc = 'Copy to system clipboard' })
vim.keymap.set({ 'n', 'x' }, '<leader>p', '"+p', { desc = 'Paste from system clipboard (before)' })
vim.keymap.set({ 'n', 'x' }, '<leader>P', '"+P', { desc = 'Paste from system clipboard (after)' })
vim.keymap.set({ 'n' }, '-', "<CMD>Oil<CR>", { desc = 'Oil' })
vim.keymap.set({ 'n', 'x' }, '<leader>:', '<CMD>:.lua<CR>', { desc = 'run current line as lua' })
vim.keymap.set({ 'n', 'x' }, '<leader>nh', function() MiniNotify.show_history() end, { desc = 'Notification history' })
vim.opt.list = true
vim.opt.listchars = { tab = '', trail = '', nbsp = '' }
vim.opt.inccommand = 'split'
vim.opt.breakindent = true
vim.opt.winborder = 'rounded'
vim.opt.termguicolors = true -- 24-bit color
vim.opt.number = true -- line number
vim.opt.relativenumber = true -- relative line numbers
vim.opt.cursorline = true -- highlight current line
vim.opt.wrap = false -- do not wrap lines by default
vim.opt.scrolloff = 10 -- keep 10 lines above/below cursor
vim.opt.sidescrolloff = 10 -- keep 10 lines to left/right of cursor
vim.opt.tabstop = 4 -- tabwidth
vim.opt.shiftwidth = 4 -- indent width
vim.opt.softtabstop = 4 -- soft tab stop not tabs on tab/backspace
vim.opt.expandtab = true -- use spaces instead of tabs
vim.opt.smartindent = true -- smart auto-indent
vim.opt.autoindent = true -- copy indent from current line
vim.opt.ignorecase = true -- case insensitive search
vim.opt.smartcase = true -- case sensitive if uppercase in string
vim.opt.hlsearch = true -- highlight search matches
vim.opt.incsearch = true -- show matches as you type
vim.opt.signcolumn = "yes" -- always show a sign column
vim.opt.colorcolumn = "100" -- show a column at 100 position chars
vim.opt.showmatch = true -- highlights matching brackets
vim.opt.cmdheight = 2 -- single line command line
vim.opt.completeopt = "menuone,noinsert,noselect" -- completion options
vim.opt.showmode = false -- do not show the mode, instead have it in statusline
vim.opt.pumheight = 10 -- popup menu height
vim.opt.pumblend = 10 -- popup menu transparency
vim.opt.pumborder = 'rounded' -- popup menu border
vim.opt.winblend = 0 -- floating window transparency
vim.opt.conceallevel = 0 -- do not hide markup
vim.opt.concealcursor = "" -- do not hide cursorline in markup
vim.opt.lazyredraw = true -- do not redraw during macros
vim.opt.synmaxcol = 300 -- syntax highlighting limit
vim.opt.fillchars = { eob = " " } -- hide "~" on empty lines
local undodir = vim.fn.expand("~/.vim/undodir")
if vim.fn.isdirectory(undodir) == 0 then
-- create undodir if nonexistent
vim.fn.mkdir(undodir, "p")
end
vim.opt.backup = false -- do not create a backup file
vim.opt.writebackup = false -- do not write to a backup file
vim.opt.swapfile = false -- do not create a swapfile
vim.opt.undofile = true -- do create an undo file
vim.opt.undodir = undodir -- set the undo directory
vim.opt.updatetime = 300 -- faster completion
vim.opt.timeoutlen = 500 -- timeout duration
vim.opt.ttimeoutlen = 0 -- key code timeout
vim.opt.autoread = true -- auto-reload changes if outside of neovim
vim.opt.autowrite = false -- do not auto-save
vim.opt.hidden = true -- allow hidden buffers
vim.opt.errorbells = false -- no error sounds
vim.opt.backspace = "indent,eol,start" -- better backspace behaviour
vim.opt.autochdir = false -- do not autochange directories
--vim.opt.iskeyword:append("-") -- include - in words
vim.opt.path:append("**") -- include subdirs in search
vim.opt.selection = "inclusive" -- include last char in selection
vim.opt.mouse = "a" -- enable mouse support
vim.opt.clipboard:append("unnamedplus") -- use system clipboard
vim.opt.modifiable = true -- allow buffer modifications
vim.opt.encoding = "utf-8" -- set encoding
vim.opt.guicursor =
"n-v-c:block,i-ci-ve:block,r-cr:hor20,o:hor50,a:blinkwait700-blinkoff400-blinkon250-Cursor/lCursor,sm:block-blinkwait175-blinkoff150-blinkon175" -- cursor blinking and settings
-- Folding: requires treesitter available at runtime; safe fallback if not
vim.opt.foldmethod = "expr" -- use expression for folding
vim.opt.foldexpr = "v:lua.vim.treesitter.foldexpr()" -- use treesitter for folding
vim.opt.foldlevel = 99 -- start with all folds open
vim.opt.splitbelow = true -- horizontal splits go below
vim.opt.splitright = true -- vertical splits go right
vim.opt.wildmenu = true -- tab completion
vim.opt.wildchar = ("\t"):byte() -- use tab character to invoke
vim.opt.wildmode = "list:longest" -- List all matches and complete till the longest common prefix.
vim.opt.wildignore:append({ "*~", "*.swp", "*.swo", "*.bak", "*.tmp", "*.o", "*.obj" })
vim.opt.wildoptions:append({ "fuzzy" })
vim.opt.diffopt:append("linematch:60") -- improve diff display
vim.opt.redrawtime = 10000 -- increase neovim redraw tolerance
vim.opt.maxmempattern = 20000 -- increase max memory
local augroup = vim.api.nvim_create_augroup('UserConfig', { clear = true })
vim.api.nvim_create_autocmd("TermClose", {
group = augroup,
callback = function()
if vim.v.event.status == 0 then
vim.api.nvim_buf_delete(0, {})
end
end,
})
vim.api.nvim_create_autocmd("TermOpen", {
group = augroup,
callback = function()
vim.opt_local.number = false
vim.opt_local.relativenumber = false
vim.opt_local.signcolumn = "no"
end,
})
local terminal_state = { buf = nil, win = nil, is_open = false }
local function FloatingTerminal()
if terminal_state.is_open and terminal_state.win and vim.api.nvim_win_is_valid(terminal_state.win) then
vim.api.nvim_win_close(terminal_state.win, false)
terminal_state.is_open = false
return
end
if not terminal_state.buf or not vim.api.nvim_buf_is_valid(terminal_state.buf) then
terminal_state.buf = vim.api.nvim_create_buf(false, true)
vim.bo[terminal_state.buf].bufhidden = "hide"
end
local width = math.floor(vim.opt.columns * 0.8)
local height = math.floor(vim.opt.lines * 0.8)
local row = math.floor((vim.opt.lines - height) / 2)
local col = math.floor((vim.opt.columns - width) / 2)
terminal_state.win = vim.api.nvim_open_win(terminal_state.buf, true, {
relative = "editor",
width = width,
height = height,
row = row,
col = col,
style = "minimal",
border = "rounded",
})
vim.wo[terminal_state.win].winblend = 0
vim.wo[terminal_state.win].winhighlight = "Normal:FloatingTermNormal,FloatBorder:FloatingTermBorder"
vim.api.nvim_set_hl(0, "FloatingTermNormal", { bg = "none" })
vim.api.nvim_set_hl(0, "FloatingTermBorder", { bg = "none" })
local has_terminal = false
local lines = vim.api.nvim_buf_get_lines(terminal_state.buf, 0, -1, false)
for _, line in ipairs(lines) do
if line ~= "" then
has_terminal = true
break
end
end
if not has_terminal then
vim.fn.termopen(os.getenv("SHELL"))
end
terminal_state.is_open = true
vim.cmd("startinsert")
vim.api.nvim_create_autocmd("BufLeave", {
buffer = terminal_state.buf,
callback = function()
if terminal_state.is_open and terminal_state.win and vim.api.nvim_win_is_valid(terminal_state.win) then
vim.api.nvim_win_close(terminal_state.win, false)
terminal_state.is_open = false
end
end,
once = true,
})
end
vim.keymap.set("n", "<leader>t", FloatingTerminal, { noremap = true, silent = true, desc = "Toggle floating terminal" })
vim.keymap.set("t", "<Esc>", function()
if terminal_state.is_open and terminal_state.win and vim.api.nvim_win_is_valid(terminal_state.win) then
vim.api.nvim_win_close(terminal_state.win, false)
terminal_state.is_open = false
end
end, { noremap = true, silent = true, desc = "Close floating terminal" })
require('vim._core.ui2').enable({
enable = true, -- Whether to enable or disable the UI.
msg = { -- Options related to the message module.
---@type 'cmd'|'msg' Default message target, either in the
---cmdline or in a separate ephemeral message window.
---@type string|table<string, 'cmd'|'msg'|'pager'> Default message target
---or table mapping |ui-messages| kinds and triggers to a target.
targets = 'cmd',
cmd = { -- Options related to messages in the cmdline window.
height = 0.5 -- Maximum height while expanded for messages beyond 'cmdheight'.
},
dialog = { -- Options related to dialog window.
height = 0.5, -- Maximum height.
},
msg = { -- Options related to msg window.
height = 0.5, -- Maximum height.
timeout = 4000, -- Time a message is visible in the message window.
},
pager = { -- Options related to message window.
height = 1, -- Maximum height.
},
},
})
vim.pack.add({
{ src = 'https://github.com/eandrju/cellular-automaton.nvim' },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
})
vim.pack.add({
'https://github.com/catppuccin/nvim'
})
require("catppuccin").setup({
flavour = "mocha",
})
vim.cmd[[colorscheme catppuccin]]
vim.api.nvim_set_hl(0, "MsgArea", { bg = "#1e1e2e" }) -- example dark purple-ish bg
vim.api.nvim_set_hl(0, "NormalFloat", { bg = "#1e1e2e" }) -- fallback for the floating window itself
vim.pack.add({
'https://github.com/Bekaboo/dropbar.nvim'
})
require('dropbar').setup({})
vim.pack.add({
{ src = 'https://github.com/ibhagwan/fzf-lua' }
})
local fzf = require('fzf-lua')
fzf.setup({})
vim.keymap.set("n", "<leader>f*", function() fzf.builtin() end, { desc = "All FZF builtins" })
vim.keymap.set("n", "<leader>fb", function() fzf.buffers() end, { desc = "FZF Buffers" })
vim.keymap.set("n", "<leader>ff", function() fzf.files() end, { desc = "FZF Files" })
vim.keymap.set("n", "<leader>fg", function() fzf.live_grep() end, { desc = "FZF Live Grep" })
vim.keymap.set("n", "<leader>fG", function() fzf.live_grep(
{ cmd = "git grep --line-number --column --color=always" }) end, { desc = "FZF Live Git Grep" })
vim.keymap.set("n", "<leader>fh", function() fzf.help_tags() end, { desc = "FZF Help Tags" })
vim.keymap.set("n", "<leader>fk", function() fzf.keymaps() end, { desc = "FZF Kemaps" })
vim.keymap.set("n", "<leader>fm", function() fzf.manpages() end, { desc = "FZF Man Pages" })
vim.keymap.set("n", "<leader>fo", function() fzf.nvim_options() end, { desc = "FZF Nvim Options" })
vim.keymap.set("n", "<leader>fu", function() fzf.undotree() end, { desc = "FZF Undotree" })
vim.keymap.set("n", "<leader>fx", function() fzf.diagnostics_document() end, { desc = "FZF Diagnostics Document" })
vim.keymap.set("n", "<leader>fX", function() fzf.diagnostics_workspace() end, { desc = "FZF Diagnostics Workspace" })
vim.pack.add({
{ src = 'https://github.com/lewis6991/gitsigns.nvim' },
{ src = 'https://github.com/bartman/git-wip' }
})
require('gitsigns').setup({})
require('git-wip').setup({
gpg_sign = false,
background = true,
untracked = true,
ignored = false,
filetypes = { "*" },
})
require("gitsigns").setup({
signs = {
add = { text = "\u{2590}" }, -- ▏ ⧽
change = { text = "\u{2590}" }, -- ▐ ⦚ ⌇ ⸾ ⦙ ⎬
delete = { text = "\u{2590}" }, --
topdelete = { text = "\u{25e6}" }, --
changedelete = { text = "\u{25cf}" }, --
untracked = { text = "\u{25cb}" }, --
},
signcolumn = true,
current_line_blame = false,
})
vim.keymap.set("n", "]h", function() require("gitsigns").next_hunk() end, { desc = "Next git hunk" })
vim.keymap.set("n", "[h", function() require("gitsigns").prev_hunk() end, { desc = "Previous git hunk" })
vim.keymap.set("n", "<leader>gs", function() require("gitsigns").stage_hunk() end, { desc = "Stage hunk" })
vim.keymap.set("n", "<leader>gr", function() require("gitsigns").reset_hunk() end, { desc = "Reset hunk" })
vim.keymap.set("n", "<leader>gp", function() require("gitsigns").preview_hunk() end, { desc = "Preview hunk" })
vim.keymap.set("n", "<leader>gb", function() require("gitsigns").blame_line({ full = true }) end, { desc = "Blame line" })
vim.keymap.set("n", "<leader>gB", function() require("gitsigns").toggle_current_line_blame() end, { desc = "Toggle inline blame" })
vim.keymap.set("n", "<leader>gd", function() require("gitsigns").diffthis() end, { desc = "Diff this" })
-- does git-grep with pattern, puts results in quickfix, and opens it
local git_grep_to_quickfix = function(pattern)
if pattern == '' then
vim.notify("No pattern in search register /", vim.log.levels.WARN)
return
end
-- Run git grep
local cmd = { 'git', 'grep', '--line-number', '--column', '-e', pattern }
local output = vim.fn.systemlist(cmd)
-- git grep returns exit code 1 when nothing is found
if vim.v.shell_error ~= 0 or #output == 0 then
vim.notify('Pattern not found: ' .. pattern, vim.log.levels.INFO)
return
end
-- Parse git grep output into quickfix list
local qf_list = {}
for _, line in ipairs(output) do
-- format: file:line:column:text
local file, lnum, col, text = line:match('^([^:]+):(%d+):(%d+):(.*)$')
if file then
table.insert(qf_list, {
filename = file,
lnum = tonumber(lnum),
col = tonumber(col),
text = text,
})
end
end
if #qf_list == 0 then
vim.notify('Pattern not found: ' .. pattern, vim.log.levels.INFO)
return
end
-- Populate and open quickfix
vim.fn.setqflist(qf_list, 'r') -- 'r' = replace
vim.cmd('copen')
vim.notify(string.format('Found %d matches for "%s"', #qf_list, pattern), vim.log.levels.INFO)
end
--- Returns the current visual selection as a string
local function get_visual_selection()
local reg_save = vim.fn.getreg('v')
local regtype_save = vim.fn.getregtype('v')
vim.cmd('noautocmd normal! "vy')
local text = vim.fn.getreg('v')
vim.fn.setreg('v', reg_save, regtype_save) -- restore register
return text
end
vim.keymap.set('n', '<leader>gg', function() git_grep_to_quickfix(vim.fn.getreg('/')) end, { desc = 'Git grep /-register to quickfix' })
vim.keymap.set('v', '<leader>gg', function() git_grep_to_quickfix(get_visual_selection()) end, { desc = 'Git grep /-register to quickfix' })
vim.pack.add({
{ src = 'https://github.com/neovim/nvim-lspconfig' }
})
-- for NixOS we need to use wrapped clang, so we have to tell clangd that it's safe to do so
vim.lsp.config('clangd', {
cmd = {
'clangd',
'--query-driver=/nix/store/*-clang-wrapper-*/bin/*',
-- "--log=verbose" -- for debugging
},
})
vim.lsp.config('neocmake', {
cmd = { 'neocmakelsp', 'stdio' },
filetypes = { 'cmake', 'CMakeLists.txt' },
root_markers = { '.neocmake.toml', '.git', 'build', 'cmake' },
single_file_support = true,
init_options = {
format = { enable = true },
lint = { enable = true },
scan_multiple_package = true,
},
})
-- ~/.local/share/nvim13/site/pack/core/opt/nvim-lspconfig/lsp/
vim.lsp.enable('bashls') -- bash-language-server
vim.lsp.enable('clangd') -- clangd
vim.lsp.enable('neocmake') -- neocmakelsp
vim.lsp.enable('jsonls') -- vscode-json-language-server
vim.lsp.enable('lua_ls') -- lua-language-server
vim.lsp.enable('markdown_oxide') -- markdown-oxide
vim.lsp.enable('pyright') -- pyright-langserver
vim.lsp.enable('rust_analyzer') -- rust-analyzer
vim.lsp.enable('vimls') -- vim-language-server
vim.lsp.enable('yamlls') -- yaml-language-server
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
-- make space for diagnostic markers
vim.opt.signcolumn = "yes:2"
-- Setup LSP completion
--[[
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client and client:supports_method('textDocument/completion') then
vim.opt.completeopt = { 'menu', 'menuone', 'noinsert', 'fuzzy', 'popup' }
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true })
-- manually trigger completion
vim.keymap.set('i', '<C-Space>', function() vim.lsp.completion.get() end)
end
--]]
local opts = { buffer = ev.buf }
-- Standard LSP keymaps
vim.keymap.set('n', 'gd', function() vim.lsp.buf.definition(opts) end, { desc = 'LSP go to definition' })
vim.keymap.set('n', 'gD', function() vim.lsp.buf.declaration(opts) end, { desc = 'LSP go to declaration' })
vim.keymap.set('n', 'K', function() vim.lsp.buf.hover(opts) end, { desc = 'LSP hover' })
vim.keymap.set('n', '<leader>cs', function() vim.lsp.buf.signature_help(opts) end, { desc = 'LSP signature help' })
vim.keymap.set('n', '<leader>cr', function() vim.lsp.buf.rename(nil, opts) end, { desc = 'LSP rename word under cursor' })
--vim.keymap.set('n', '<leader>ca', function() vim.lsp.buf.code_action(opts) end, { desc = 'LSP code action' })
vim.keymap.set('n', '<leader>cd', function() vim.lsp.buf.definition(opts) end, { desc = 'LSP go to definition' })
vim.keymap.set('n', '<leader>cD', function() vim.lsp.buf.declaration(opts) end, { desc = 'LSP go to declaration' })
vim.keymap.set('n', '<leader>cI', function() vim.lsp.buf.implementation(opts) end, { desc = 'LSP list implementations' })
vim.keymap.set('n', '<leader>ci', function() vim.lsp.buf.incoming_calls() end, { desc = 'LSP incoming calls' })
vim.keymap.set('n', '<leader>co', function() vim.lsp.buf.outgoing_calls() end, { desc = 'LSP outgoing calls' })
vim.keymap.set('n', '<leader>ct', function() vim.lsp.buf.typehierarchy('subtypes') end, { desc = 'LSP subtypes' })
vim.keymap.set('n', '<leader>cT', function() vim.lsp.buf.typehierarchy('supertypes') end, { desc = 'LSP supertypes' })
vim.keymap.set('n', '<leader>cw', function() vim.lsp.buf.workspace_diagnostics(opts) end, { desc = 'LSP workspace diagnostics' })
vim.keymap.set('n', '<leader>cS', function() vim.lsp.buf.workspace_symbol(nil, opts) end, { desc = 'LSP workspace symbols' })
end,
})
vim.diagnostic.config({
-- virtual_text = { prefix = "❌", spacing = 4 }, -- 📛⛔❌👻🐛🐞👀🐼🌀⚡💡
virtual_lines = {
current_line = true
},
underline = false,
update_in_insert = false,
severity_sort = false,
signs = {
text = {
[vim.diagnostic.severity.ERROR] = '', -- Ⓧ ⓧ ⦻ ⮾ ⮿ 🅧 ...
[vim.diagnostic.severity.WARN] = '', -- ⚠ ⁉ ⭍
[vim.diagnostic.severity.INFO] = '🛈 ', -- 🛈 👁
[vim.diagnostic.severity.HINT] = '🎔 ', -- 🎔
}
},
})
vim.pack.add({
{ src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" },
})
require('render-markdown').setup({})
vim.pack.add({
{ src = 'https://github.com/echasnovski/mini.nvim' }
})
require("mini.ai").setup({}) -- visual a/i selection
require("mini.align").setup({}) -- align text with ga / gA
require("mini.comment").setup({}) -- improved comments
--require("mini.move").setup({}) -- moves selection up/down/left/right
require("mini.surround").setup({}) -- surround inner outer block with brackets
require("mini.cursorword").setup({}) -- highlight the current word
require("mini.indentscope").setup({}) -- visualize indent
--require("mini.pairs").setup({}) -- adds a matching closing bracket
require("mini.trailspace").setup({}) -- highlight trailing space
require("mini.bufremove").setup({}) -- cleanup windows after buffer is removed
require("mini.notify").setup({}) -- show notifications in floating window
require("mini.icons").setup({}) -- provides icons
require('mini.keymap').setup({}) -- creates multi step key mappings
-- some nice to have things
require('mini.misc').setup_restore_cursor({
center = false, -- don't center the window
ignore_filetype = { 'gitcommit', 'gitrebase', 'hgcommit' }, -- add more if you want
})
-- status line
require('mini.statusline').setup({
use_icons = true
})
-- add some basic key binds
require("mini.basics").setup({
options = {
basic = true, -- basic configs (number, ignorecase, etc)
extra_ui = true, -- extra ui features (winblend, listchars, pumheight, etc)
win_borders = 'rounded', -- how popups look
},
mappings = {
basic = true, -- better jk, etc
option_toggle_prefix = '<leader>t', -- toggling keybinds
windows = false, -- windows mavigation keybinds with ctrl-hjkl
move_with_alt = false,
},
autocommands = {
basic = true, -- highlight on yank, terminal starts with insert, etc
}
})
-- highlight some words
local hip = require("mini.hipatterns")
hip.setup({
highlighters = {
-- Highlight standalone 'FIXME', 'HACK', 'TODO', 'NOTE'
fixme = { pattern = "%f[%w]()FIXME()%f[%W]", group = "MiniHipatternsFixme" },
hack = { pattern = "%f[%w]()HACK()%f[%W]", group = "MiniHipatternsHack" },
todo = { pattern = "%f[%w]()TODO()%f[%W]", group = "MiniHipatternsTodo" },
note = { pattern = "%f[%w]()NOTE()%f[%W]", group = "MiniHipatternsNote" },
-- Highlight hex color strings (`#rrggbb`) using that color
hex_color = hip.gen_highlighter.hex_color(),
},
})
-- maps [[ ]] sequences for jumping through blocks
local br = require("mini.bracketed")
br.setup({
buffer = { suffix = "b", options = {} },
comment = { suffix = "c", options = {} },
conflict = { suffix = "x", options = {} },
diagnostic = { suffix = "" }, -- DISABLED: { suffix = "d", options = {} }, -- prefer the one from lsp-config.lua
file = { suffix = "f", options = {} },
indent = { suffix = "i", options = {} },
jump = { suffix = "j", options = {} },
location = { suffix = "l", options = {} },
oldfile = { suffix = "o", options = {} },
quickfix = { suffix = "q", options = {} },
treesitter = { suffix = "t", options = {} },
undo = { suffix = "u", options = {} },
window = { suffix = "w", options = {} },
yank = { suffix = "y", options = {} },
})
-- shows list of motions as they are typed
local miniclue = require('mini.clue')
miniclue.setup({
triggers = {
-- Leader triggers
{ mode = { 'n', 'x' }, keys = '<Leader>' },
-- `[` and `]` keys
{ mode = 'n', keys = '[' },
{ mode = 'n', keys = ']' },
-- Built-in completion
{ mode = 'i', keys = '<C-x>' },
-- `g` key
{ mode = { 'n', 'x' }, keys = 'g' },
-- `s` key -- for mini.surround
{ mode = { 'n', 'x' }, keys = 's' },
-- `v` key -- for visual selection
{ mode = { 'v' }, keys = 'a' },
{ mode = { 'v' }, keys = 'i' },
{ mode = { 'v' }, keys = 'g' },
-- Marks
{ mode = { 'n', 'x' }, keys = "'" },
{ mode = { 'n', 'x' }, keys = '`' },
-- Registers
{ mode = { 'n', 'x' }, keys = '"' },
{ mode = { 'i', 'c' }, keys = '<C-r>' },
-- Window commands
{ mode = 'n', keys = '<C-w>' },
-- `z` key
{ mode = { 'n', 'x' }, keys = 'z' },
},
window = {
delay = 0,
config = {
width = 'auto',
border = 'rounded',
},
},
clues = {
-- Enhance this by adding descriptions for <Leader> mapping groups
miniclue.gen_clues.square_brackets(),
miniclue.gen_clues.builtin_completion(),
miniclue.gen_clues.g(),
miniclue.gen_clues.marks(),
miniclue.gen_clues.registers(),
miniclue.gen_clues.windows(),
miniclue.gen_clues.z(),
},
})
local mf = require('mini.files')
vim.keymap.set('n', '<leader>mf', function()
mf.open(vim.api.nvim_buf_get_name(0))
end, { desc = "Mini files" })
vim.pack.add({
'https://github.com/nvim-lua/plenary.nvim',
'https://github.com/milanglacier/minuet-ai.nvim'
})
-- ------------------------------------------------------------------------
local get_api_key = function(env_var)
local key = os.getenv(env_var)
local msg = key and "OK" or "empty"
vim.notify("[minuet-ai] " .. env_var .. " is " .. msg)
return key
end
local minuet_zen_api_key = get_api_key('OPENCODE_ZEN_KEY')
local minuet_xai_api_key = get_api_key('XAI_API_KEY')
local minuet_base_config = {
--notify = "debug",
cmp = { enable_auto_complete = false, },
blink = { enable_auto_complete = false, },
}
local minuet_variants = {
ollama = {
provider = 'openai_fim_compatible',
provider_options = {
openai_fim_compatible = {
name = 'Ollama',
end_point = 'http://localhost:11434/v1/completions',
api_key = 'TERM', -- dummy for local
--model = 'lennyerik/zeta',
--model = 'qwen2.5-coder:7b',
--model = 'qwen2.5-coder:14b',
--model = 'gemma4:31b', -- dense, slower, 20G
model = 'gemma4:e4b', -- effective 4B model, faster, 9G
optional = {
max_tokens = 512,
temperature = 0.0,
},
},
},
},
-- could not get any of these to work
-- probably because they are all reasoning models
--[[
zen = {
provider = 'openai_compatible',
provider_options = {
openai_compatible = {
name = 'OpenCode Zen',
end_point = 'https://opencode.ai/zen/v1/chat/completions',
api_key = function() return minuet_zen_api_key end,
--model = 'minimax-m2.1',
--model = 'kimi-k2.5',
--model = 'big-pickle',
--model = 'claude-sonnet-4-6',
--model = 'gpt-5.3-codex',
--model = 'gemini-3-flash',
model = 'gpt-5-nano',
--model = 'glm-5',
stream = true,
optional = {
max_tokens = 56,
temperature = 0.0,
top_p = 0.95,
provider = { sort = "throughput", }, -- bias toward faster providers
reasoning = { effort = 'none', },
},
},
}
},
--]]
xai = {
provider = 'openai_compatible',
provider_options = {
openai_compatible = {
name = 'xAI Grok',
end_point = 'https://api.x.ai/v1/chat/completions',
api_key = function() return minuet_xai_api_key end,
model = 'grok-4-1-fast-non-reasoning',
--model = 'grok-4.20-0309-non-reasoning',
optional = {
max_tokens = 2048,
temperature = 0.0,
top_p = 0.95,
},
},
}
}
}
local minuet_selected_variant = nil
local minuet_find_next_variant = function()
-- Get all keys and sort them so the order is predictable
local keys = {}
for k in pairs(minuet_variants) do
table.insert(keys, k)
end
table.sort(keys)
if #keys == 0 then
return nil
end
-- If current is invalid or not found → return first one
if not minuet_selected_variant or not minuet_variants[minuet_selected_variant] then
return keys[1]
end
-- Find current index and return the next one (with wrap-around)
for i, key in ipairs(keys) do
if key == minuet_selected_variant then
return keys[i % #keys + 1]
end
end
-- Fallback
return keys[1]
end
local minuet_activate_variant = function(name)
local minuet = require('minuet')
local cnf = minuet_variants[name]
local pro = cnf.provider
local mdl = cnf.provider_options[pro].model
vim.notify("[minuet-ai] activating " .. name .. " (model = " .. mdl .. ")", vim.log.levels.INFO)
local merged = vim.tbl_extend('force', minuet_base_config, minuet_variants[name])
minuet.setup(merged)
minuet_selected_variant = name
end
minuet_activate_variant('ollama')
--minuet_activate_variant('xai')
-- ------------------------------------------------------------------------
vim.keymap.set({ 'n' }, '<leader>ta', function()
minuet_activate_variant(minuet_find_next_variant())
end, { desc = "Cycle Minuet config" })
vim.pack.add({
'https://github.com/stevearc/oil.nvim',
'https://github.com/refractalize/oil-git-status.nvim',
'https://github.com/JezerM/oil-lsp-diagnostics.nvim'
})
require('oil').setup({
default_file_explorer = true,
delete_to_trash = true,
skip_confirm_for_simple_edits = true,
view_options = {
show_hidden = false,
natural_order = true,
is_always_hidden = function(name, _)
return name == '..'
--or name == '.git'
--or vim.startswith(name, '.')
or vim.endswith(name, '~')
end,
},
git = {
-- automatically rename files through git
mv = function(src_path, dest_path) return true end,
-- but add/delete are handled manually
add = function(path) return false end,
rm = function(path) return false end,
},
columns = { "icon", "permissions", "size", "mtime", },
win_options = {
wrap = true,
spell = false,
signcolumn = "yes:2", -- for oil-git-status.nvim
},
keymaps = {
["g?"] = { "actions.show_help", mode = "n" },
["<CR>"] = "actions.select",
["<C-s>"] = { "actions.select", opts = { vertical = true } },
["<C-h>"] = { "actions.select", opts = { horizontal = true } },
["<C-t>"] = { "actions.select", opts = { tab = true } },
["<C-p>"] = "actions.preview",
["<C-c>"] = { "actions.close", mode = "n" },
["<C-l>"] = "actions.refresh",
["-"] = { "actions.parent", mode = "n" },
["_"] = { "actions.open_cwd", mode = "n" },
["`"] = { "actions.cd", mode = "n" },
["g~"] = { "actions.cd", opts = { scope = "tab" }, mode = "n" },
["gs"] = { "actions.change_sort", mode = "n" },
["gx"] = "actions.open_external",
["g."] = { "actions.toggle_hidden", mode = "n" },
["g\\"] = { "actions.toggle_trash", mode = "n" },
},
})
require('oil-git-status').setup({})
require('oil-lsp-diagnostics').setup({})
vim.pack.add({
{ src = "https://github.com/rachartier/tiny-code-action.nvim" },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
{ src = "https://github.com/ibhagwan/fzf-lua" },
})
local tca = require("tiny-code-action")
tca.setup({
})
-- open a code action selection, using fzf picker
vim.keymap.set('n', '<leader>ca', tca.code_action, { desc = 'LSP code action' })
vim.pack.add({
{ src = 'https://github.com/nvim-treesitter/nvim-treesitter', version='main' },
{ src = 'https://github.com/nvim-treesitter/nvim-treesitter-textobjects', version='main' },
{ src = "https://github.com/jmbuhr/otter.nvim" },
})
local otter = require('otter')
otter.setup({
debug = false,
verbose = {
no_code_found = false,
},
})
local ts = require('nvim-treesitter')
-- https://github.com/nvim-treesitter/nvim-treesitter/blob/main/SUPPORTED_LANGUAGES.md
-- local ts_filetypes = ts.get_available() -- all languages under the sun
local ts_filetypes = {
'bash',
'c',
'cmake',
'cpp',
'diff',
'go',
'html',
'json',
'lua',
'markdown',
'python',
'rust',
'yaml',
'zsh',
}
ts.setup({})
--ts.install(ts_filetypes)
-- nvim-treesitter-textobjects: make [[ and ]] jump between functions (C++, C, Rust, Python, Lua, etc.)
require("nvim-treesitter-textobjects").setup({
move = {
set_jumps = true, -- so <C-o>/<C-i> work
},
})
-- [[ and ]] now jump between functions (@function.outer)
-- Works in normal, visual, and operator-pending modes
vim.keymap.set({ "n", "x", "o" }, "[[", function()
require("nvim-treesitter-textobjects.move").goto_previous_start("@function.outer", "textobjects")
end, { desc = "Previous function" })
vim.keymap.set({ "n", "x", "o" }, "]]", function()
require("nvim-treesitter-textobjects.move").goto_next_start("@function.outer", "textobjects")
end, { desc = "Next function" })
-- enable treesitter in supported filetypes
vim.api.nvim_create_autocmd('FileType', {
desc = "Install/enable treesitter in buffers matching supported filetypes",
group = vim.api.nvim_create_augroup("treesitter_autostart_handler", { clear = true }),
pattern = ts_filetypes,
callback = function(ev)
local lang = vim.treesitter.language.get_lang(ev.match)
local available_langs = ts.get_available()
local is_available = vim.tbl_contains(available_langs, lang)
if is_available then
local installed_langs = ts.get_installed()
local installed = vim.tbl_contains(installed_langs, lang)
if not installed then
vim.notify("nvim-treesitter installing: " .. lang, vim.log.levels.INFO)
ts.install(lang)
end
vim.notify("nvim-treesitter enabling: " .. lang, vim.log.levels.DEBUG)
-- syntax highlighting, provided by Neovim
vim.treesitter.start(ev.buf)
-- folds, provided by Neovim
vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.wo.foldmethod = 'expr'
-- indentation, provided by nvim-treesitter
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
-- delayed otter activation
otter.activate()
end
end,
})
-- automatically run TSUpdate when plugin update is detected
vim.api.nvim_create_autocmd("PackChanged", {
desc = "Automatically run :TSUpdate when nvim-treesitter is updated",
group = vim.api.nvim_create_augroup("treesitter_update_handler", { clear = true }),
callback = function(event)
-- Check if the updated plugin is nvim-treesitter and the event is an update
if event.data.spec.name == "nvim-treesitter" and event.data.kind == "update" then
local ok, err = pcall(vim.cmd, "TSUpdate")
if ok then
vim.notify("nvim-treesitter updated: TSUpdate successful.", vim.log.levels.INFO)
else
vim.notify("TSUpdate failed: " .. tostring(err), vim.log.levels.ERROR)
end
end
end,
})
{
"plugins": {
"99": {
"rev": "0172d3caae2d8b967c9d47aa7557295f1481e5df",
"src": "https://github.com/ThePrimeagen/99"
},
"actions-preview.nvim": {
"rev": "2b604b2e8e662c03b716436f6ffebcb19663e66a",
"src": "https://github.com/aznhe21/actions-preview.nvim"
},
"blink-edit.nvim": {
"rev": "220f5777f5597f6d7868981d6ff9b6218247fec4",
"src": "https://github.com/BlinkResearchLabs/blink-edit.nvim"
},
"blink.cmp": {
"rev": "456d38d1cd3743926f329204c2340f3e7840aad6",
"src": "https://github.com/saghen/blink.cmp"
},
"cellular-automaton.nvim": {
"rev": "1606e9d5d04ff254023c3f3c62842d065708d6d3",
"src": "https://github.com/eandrju/cellular-automaton.nvim"
},
"dropbar.nvim": {
"rev": "ce202248134e3949aac375fd66c28e5207785b10",
"src": "https://github.com/Bekaboo/dropbar.nvim"
},
"fzf-lua": {
"rev": "657c1bbb7357c61e26a20d868b53a460b05c18c0",
"src": "https://github.com/ibhagwan/fzf-lua"
},
"git-wip": {
"rev": "022fa8909442b51323cef6eaef000fbb6a477f16",
"src": "https://github.com/bartman/git-wip"
},
"gitsigns.nvim": {
"rev": "8d82c240f190fc33723d48c308ccc1ed8baad69d",
"src": "https://github.com/lewis6991/gitsigns.nvim"
},
"mini.nvim": {
"rev": "4182d64727fb4876407af65c181b85428a4a70d1",
"src": "https://github.com/echasnovski/mini.nvim"
},
"minuet-ai.nvim": {
"rev": "33c6f4ad809bb28347c275cffc3e5700057d1c3c",
"src": "https://github.com/milanglacier/minuet-ai.nvim"
},
"nui.nvim": {
"rev": "de740991c12411b663994b2860f1a4fd0937c130",
"src": "https://github.com/MunifTanjim/nui.nvim"
},
"nvim": {
"rev": "426dbebe06b5c69fd846ceb17b42e12f890aedf1",
"src": "https://github.com/catppuccin/nvim"
},
"nvim-colorizer.lua": {
"rev": "a065833f35a3a7cc3ef137ac88b5381da2ba302e",
"src": "https://github.com/norcalli/nvim-colorizer.lua"
},
"nvim-highlight-colors": {
"rev": "e2cb22089cc2358b2b995c09578224f142de6039",
"src": "https://github.com/brenoprata10/nvim-highlight-colors"
},
"nvim-lspconfig": {
"rev": "cb5bc0b2b35a6d513e3298d285db81453e791f4f",
"src": "https://github.com/neovim/nvim-lspconfig"
},
"nvim-treesitter": {
"rev": "4916d6592ede8c07973490d9322f187e07dfefac",
"src": "https://github.com/nvim-treesitter/nvim-treesitter",
"version": "'main'"
},
"nvim-treesitter-textobjects": {
"rev": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e",
"src": "https://github.com/nvim-treesitter/nvim-treesitter-textobjects",
"version": "'main'"
},
"oil-git-status.nvim": {
"rev": "a3e2ccb00cb8822115e28a9a1791eda051d940c9",
"src": "https://github.com/refractalize/oil-git-status.nvim"
},
"oil-lsp-diagnostics.nvim": {
"rev": "282308383d8d8485937aaf3c28b44fa1cb26007a",
"src": "https://github.com/JezerM/oil-lsp-diagnostics.nvim"
},
"oil.nvim": {
"rev": "0fcc83805ad11cf714a949c98c605ed717e0b83e",
"src": "https://github.com/stevearc/oil.nvim"
},
"otter.nvim": {
"rev": "a455e68a99d395889ab30a25ac3846a135e93c46",
"src": "https://github.com/jmbuhr/otter.nvim"
},
"plenary.nvim": {
"rev": "74b06c6c75e4eeb3108ec01852001636d85a932b",
"src": "https://github.com/nvim-lua/plenary.nvim"
},
"render-markdown.nvim": {
"rev": "54d4b5431e9634ee3d8d30784e017239b5b89d41",
"src": "https://github.com/MeanderingProgrammer/render-markdown.nvim"
},
"tiny-code-action.nvim": {
"rev": "1c75d7e121ea38bf362d939ddb9064ca9bb6884f",
"src": "https://github.com/rachartier/tiny-code-action.nvim"
},
"vim-wakatime": {
"rev": "d7973b157a632d1edeff01818f18d67e584eeaff",
"src": "https://github.com/wakatime/vim-wakatime"
},
"y9nika.nvim": {
"rev": "00c5530f3efa7dc865dcb35dfa50af894676ec64",
"src": "https://github.com/y9san9/y9nika.nvim"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment