refactor(nvim): modernize plugin stack

Removed dead weight:
- Drop nightfox, rose-pine, kanagawa, everforest colorschemes
- Remove fzf/fzf.vim (redundant with telescope)
- Remove vim-fugitive and its keymaps (lazygit covers this)
- Remove Comment.nvim (built into nvim 0.10+)

Replaced:
- nvim-cmp → blink.cmp (Rust-powered, faster, ghost text)
- none-ls/null-ls → conform.nvim (async, maintained)
- cmp-nvim-lsp capabilities → blink.cmp.get_lsp_capabilities()
- Copilot suggestions now routed through blink-copilot

Added:
- lazydev.nvim for proper Lua LSP in nvim config
- flash.nvim (s/S jump anywhere on screen)
- which-key.nvim (leader key popup with groups)
- snacks.nvim (notifier + word highlights)
- nvim-treesitter-textobjects (af/if, ac/ic, ]f/[f)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas Naderer
2026-03-01 21:26:55 +01:00
parent 82fc23530d
commit 61b1e3d2a9
6 changed files with 252 additions and 191 deletions

View File

@@ -5,7 +5,7 @@ local opt = { noremap = true }
local opts = { noremap = true, silent = true }
local term_opts = { silent = true }
local keymap = vim.api.nvim_set_keymap
local keymap = vim.keymap.set
-- {{{ Leader Key (moved to init.lua)
-- vim.g.mapleader = " " -- set <Space> as leader key
@@ -13,15 +13,15 @@ local keymap = vim.api.nvim_set_keymap
-- }}}
-- {{{ Basic Mappings
keymap("n", ";", ":", opt) -- remap ; to :
keymap("n", ":", ";", opt) -- remap : to ;
keymap("n", ";", ":", opt) -- remap ; to :
keymap("n", ":", ";", opt) -- remap : to ;
keymap("n", "<leader>w", ":w<cr>", opts) -- save
keymap("n", "<leader>q", ":q<cr>", opts) -- quit
keymap("n", "<leader>wq", ":wq<cr>", opts) -- save and quit
keymap("n", "<leader>W", ":w!<cr>", opts) -- force save
keymap("n", "<leader>Q", ":q!<cr>", opts) -- force quit
keymap("n", "<leader>WQ", ":wq!<cr>", opts) -- force save and quit
keymap("n", "<leader>w", ":w<cr>", opts) -- save current buffer
keymap("n", "<leader>q", ":confirm qall<cr>", opts) -- quit Neovim (prompt on unsaved changes)
keymap("n", "<leader>wq", ":wall | qa<cr>", opts) -- save all writable buffers and quit
keymap("n", "<leader>W", ":w!<cr>", opts) -- force save current buffer
keymap("n", "<leader>Q", ":qall!<cr>", opts) -- force quit Neovim
keymap("n", "<leader>WQ", ":wall! | qa!<cr>", opts) -- force save all and quit
-- }}}
-- {{{ Navigation
@@ -29,125 +29,122 @@ keymap("n", "j", "gj", opts) -- move visually down wrapped lines
keymap("n", "k", "gk", opts) -- move visually up wrapped lines
-- Keep arrow key navigation (non-standard but you requested it)
keymap("n", "<Left>", "<C-w>h", opts) -- move to left window
keymap("n", "<Right>", "<C-w>l", opts) -- move to right window
keymap("n", "<Up>", "<C-w>k", opts) -- move to upper window
keymap("n", "<Down>", "<C-w>j", opts) -- move to lower window
keymap("n", "<Left>", "<C-w>h", opts) -- move to left window
keymap("n", "<Right>", "<C-w>l", opts) -- move to right window
keymap("n", "<Up>", "<C-w>k", opts) -- move to upper window
keymap("n", "<Down>", "<C-w>j", opts) -- move to lower window
keymap("n", "<s-l>", ":bnext<cr>", opts) -- next buffer
keymap("n", "<s-l>", ":bnext<cr>", opts) -- next buffer
keymap("n", "<s-h>", ":bprevious<cr>", opts) -- previous buffer
-- }}}
-- {{{ Window Splitting
keymap("n", "<leader>sv", ":vsplit<cr>", opts) -- split vertically
keymap("n", "<leader>sh", ":split<cr>", opts) -- split horizontally
keymap("n", "<leader>sc", ":close<cr>", opts) -- close current split
keymap("n", "<leader>so", ":only<cr>", opts) -- close all other splits
keymap("n", "<leader>sh", ":split<cr>", opts) -- split horizontally
keymap("n", "<leader>sc", ":close<cr>", opts) -- close current split
keymap("n", "<leader>so", ":only<cr>", opts) -- close all other splits
-- }}}
-- {{{ Window Resizing
keymap("n", "<leader>+", ":resize +5<cr>", opts) -- increase window height
keymap("n", "<leader>-", ":resize -5<cr>", opts) -- decrease window height
keymap("n", "<leader>+", ":resize +5<cr>", opts) -- increase window height
keymap("n", "<leader>-", ":resize -5<cr>", opts) -- decrease window height
keymap("n", "<leader><", ":vertical resize -5<cr>", opts) -- decrease window width
keymap("n", "<leader>>", ":vertical resize +5<cr>", opts) -- increase window width
keymap("n", "<leader>=", "<C-w>=", opts) -- equalize window sizes
keymap("n", "<leader>=", "<C-w>=", opts) -- equalize window sizes
-- }}}
-- {{{ Visual Mode / Text, Clipboard
keymap("v", ">", ">gv", opts) -- indent right, stay in visual mode
keymap("v", "<", "<gv", opts) -- indent left, stay in visual mode
keymap("v", ">", ">gv", opts) -- indent right, stay in visual mode
keymap("v", "<", "<gv", opts) -- indent left, stay in visual mode
keymap("x", "<s-j>", ":move '>+1<CR>gv-gv", opts) -- move selected block down
keymap("x", "<s-k>", ":move '<-2<CR>gv-gv", opts) -- move selected block up
keymap("x", "<s-j>", ":move '>+1<CR>gv-gv", opts) -- move selected block down
keymap("x", "<s-k>", ":move '<-2<CR>gv-gv", opts) -- move selected block up
keymap("n", "Q", "gq", opts) -- format paragraph
keymap("x", "Q", "gq", opts) -- format selection
keymap("n", "Q", "gq", opts) -- format paragraph
keymap("x", "Q", "gq", opts) -- format selection
keymap("x", "Y", '"+y', opt) -- yank to system clipboard
keymap("x", "Y", '"+y', opt) -- yank to system clipboard
keymap("n", "<space><space>", [[:%s/\<<c-r>=expand("<cword>")<cr>\>/]], opt) -- replace word under cursor
-- }}}
-- {{{ Editing / Behavior
keymap("n", "q", "<nop>", opts) -- disable q (record macro)
keymap("n", "qq", "q", opts) -- if you really want to record macro use qq
keymap("n", "q", "<nop>", opts) -- disable q (record macro)
keymap("n", "qq", "q", opts) -- if you really want to record macro use qq
keymap("n", "c", '"_c', opts) -- change without yanking to default register
keymap("n", "C", '"_C', opts) -- change line without yanking to default register
keymap("n", "c", '"_c', opts) -- change without yanking to default register
keymap("n", "C", '"_C', opts) -- change line without yanking to default register
vim.keymap.set("n", "<leader>n", function() -- toggle line numbers
if vim.wo.number and vim.wo.relativenumber then
vim.wo.number = false
vim.wo.relativenumber = false
elseif vim.wo.number then
vim.wo.relativenumber = true
else
vim.wo.number = true
end
if vim.wo.number and vim.wo.relativenumber then
vim.wo.number = false
vim.wo.relativenumber = false
elseif vim.wo.number then
vim.wo.relativenumber = true
else
vim.wo.number = true
end
end, { desc = "Toggle line number modes" })
keymap("n", "<leader>c", ":set cursorcolumn! cursorline! <cr>", opts) -- toggle cursor column and line
keymap("n", "<esc>", ":nohlsearch<cr><esc>", opts) -- clear search highlight
keymap("n", "<esc>", ":nohlsearch<cr><esc>", opts) -- clear search highlight
-- }}}
-- {{{ Spellcheck
keymap("n", "<leader>se", ":setlocal spell! spelllang=en_us<cr>", opts) -- toggle English spell check
keymap("n", "<leader>sd", ":setlocal spell! spelllang=de_at<cr>", opts) -- toggle Austrian German spell check
keymap("n", "<leader>ss", ":setlocal spell! spelllang=es<cr>", opts) -- toggle Spanish spell check
keymap("n", "<leader>ss", ":setlocal spell! spelllang=es<cr>", opts) -- toggle Spanish spell check
-- }}}
-- {{{ Timestamp / Date
keymap("n", "<leader>dt", [[i<c-r>=strftime("%d.%m.%Y")<cr><space>]], opts) -- insert current date
keymap("n", "<leader>tt", [[i<c-r>=strftime("%H:%M")<cr><space>]], opts) -- insert current time
keymap("n", "<leader>tt", [[i<c-r>=strftime("%H:%M")<cr><space>]], opts) -- insert current time
-- }}}
-- {{{ External / System
keymap("n", "<leader>x", [[:!open %<cr><cr>]], opts) -- open current file with system default app
keymap("c", "w!!", [[w !sudo tee %]], opt) -- save file with sudo
keymap("c", "w!!", [[w !sudo tee %]], opt) -- save file with sudo
-- }}}
-- {{{ Diff / Git
keymap("n", "<leader>gd", ":Gvdiffsplit<cr>", opts) -- git diff split (requires fugitive)
keymap("n", "<leader>gs", ":Git<cr>", opts) -- open git status tree (requires fugitive)
keymap("n", "<leader>gr", ":terminal git log --graph --oneline --decorate --all<CR>i", opts) -- show git log graph in terminal
-- GitSigns toggles
vim.keymap.set('n', '<leader>gt', function() require('gitsigns').toggle_signs() end, { desc = 'Toggle git signs' })
vim.keymap.set('n', '<leader>gb', function() require('gitsigns').toggle_current_line_blame() end, { desc = 'Toggle git blame' })
vim.keymap.set('n', '<leader>gb', function() require('gitsigns').toggle_current_line_blame() end,
{ desc = 'Toggle git blame' })
vim.keymap.set('n', '<leader>gx', function() require('gitsigns').toggle_deleted() end, { desc = 'Toggle git deleted' })
vim.keymap.set('n', '<leader>gn', function() require('gitsigns').toggle_numhl() end, { desc = 'Toggle git number highlights' })
vim.keymap.set('n', '<leader>gn', function() require('gitsigns').toggle_numhl() end,
{ desc = 'Toggle git number highlights' })
vim.keymap.set('n', '<leader>gc', function() require('gitsigns').toggle_linehl() end, { desc = 'Toggle git line colors' })
-- LSP diagnostic toggle
vim.keymap.set('n', '<leader>ld', function()
local config = vim.diagnostic.config()
vim.diagnostic.config({
virtual_text = not config.virtual_text,
signs = not config.signs,
underline = not config.underline,
})
local config = vim.diagnostic.config()
vim.diagnostic.config({
virtual_text = not config.virtual_text,
signs = not config.signs,
underline = not config.underline,
})
end, { desc = 'Toggle LSP diagnostics' })
-- Toggle fold column
vim.keymap.set("n", "<leader>un", function()
vim.wo.foldcolumn = vim.wo.foldcolumn == "0" and "1" or "0"
vim.wo.foldcolumn = vim.wo.foldcolumn == "0" and "1" or "0"
end, { desc = "Toggle fold column" })
keymap("n", "<leader>si", ":source $MYVIMRC<CR>", opts) -- source init.lua ($MYVIMRC is auto path to your init.lua)
-- }}}
-- {{{ Plugins
-- Yazi (keeping this here since it's a simple command keymap)
keymap("n", "<leader>y", ":Yazi<cr>", opt) -- open Yazi file manager
-- mkdx checkbox toggle (disable default space key, use leader+t instead)
vim.g["mkdx#settings"] = {
checkbox = {
toggles = {' ', 'x', '-'},
toggle_key = ''
}
checkbox = {
toggles = { ' ', 'x', '-' },
toggle_key = ''
}
}
keymap("n", "<leader>t", "<Plug>(mkdx-checkbox-next-n)", opt) -- toggle markdown checkbox
-- }}}

View File

@@ -4,10 +4,6 @@ return {
{ "gruvbox-community/gruvbox", priority = 1000 },
{ "folke/tokyonight.nvim", priority = 1000 },
{ "catppuccin/nvim", name = "catppuccin", priority = 1000 },
{ "EdenEast/nightfox.nvim", priority = 1000 },
{ "rose-pine/neovim", name = "rose-pine", priority = 1000 },
{ "rebelot/kanagawa.nvim", priority = 1000 },
{ "sainnhe/everforest", priority = 1000 },
-- Auto-save
@@ -73,10 +69,6 @@ return {
current_line_blame = false,
}
},
{
"tpope/vim-fugitive",
cmd = { "Git", "Gvdiffsplit" },
},
{
"kdheepak/lazygit.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
@@ -107,30 +99,70 @@ return {
right_alt = "",
space = " ",
}
-- Tokyo Night Moon colors, transparent background
vim.g.tmuxline_theme = {
a = { "#1e2030", "#82aaff" },
b = { "#82aaff", "default" },
c = { "#636da6", "default" },
x = { "#636da6", "default" },
y = { "#82aaff", "default" },
z = { "#1e2030", "#82aaff" },
win = { "#636da6", "default" },
cwin = { "#1e2030", "#c099ff" },
bg = { "#636da6", "default" },
}
vim.g.tmuxline_preset = {
a = "#S",
win = "#I #W",
a = "#S",
win = "#I #W",
cwin = "#I #W",
y = "%H:%M",
z = "%d %b",
y = "%H:%M",
z = "%d %b",
}
end,
},
-- FZF
{
"junegunn/fzf",
build = function()
vim.fn["fzf#install"]()
end,
},
{ "junegunn/fzf.vim" },
-- Productivity
{ "numToStr/Comment.nvim", event = "VeryLazy", opts = {} },
{ "windwp/nvim-autopairs", event = "InsertEnter", opts = {} },
{ "tpope/vim-surround", event = "VeryLazy" },
-- Flash: jump anywhere with 2 chars (replaces f/t for long range)
{
"folke/flash.nvim",
event = "VeryLazy",
opts = {},
keys = {
{ "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "Flash jump" },
{ "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "Flash treesitter" },
},
},
-- Which-key: show available keybindings after leader
{
"folke/which-key.nvim",
event = "VeryLazy",
opts = {
spec = {
{ "<leader>f", group = "find" },
{ "<leader>g", group = "git" },
{ "<leader>s", group = "split/spell" },
{ "<leader>w", group = "write" },
{ "<leader>d", group = "date" },
{ "<leader>l", group = "lsp" },
},
},
},
-- Snacks: notifications + quality-of-life utilities
{
"folke/snacks.nvim",
priority = 1000,
lazy = false,
opts = {
notifier = { enabled = true },
words = { enabled = true },
},
},
-- -- Tmux navigation
-- { "christoomey/vim-tmux-navigator" },

View File

@@ -1,12 +1,23 @@
-- ~/.config/nvim/lua/plugins/lsp.lua
return {
-- Lazydev: proper Lua LSP for neovim config files
{
"folke/lazydev.nvim",
ft = "lua",
opts = {
library = {
{ path = "luvit-meta/library", words = { "vim%.uv" } },
},
},
},
-- Mason (LSP installer)
{
"williamboman/mason.nvim",
build = ":MasonUpdate",
opts = {},
},
-- Mason LSP config integration
{
"williamboman/mason-lspconfig.nvim",
@@ -15,19 +26,19 @@ return {
ensure_installed = { "lua_ls", "pyright", "texlab", "bashls", "marksman" },
},
},
-- LSP configuration
{
"neovim/nvim-lspconfig",
dependencies = {
dependencies = {
"mason.nvim",
"mason-lspconfig.nvim",
"hrsh7th/cmp-nvim-lsp",
"saghen/blink.cmp",
},
config = function()
local lspconfig = require("lspconfig")
local capabilities = require("cmp_nvim_lsp").default_capabilities()
local capabilities = require("blink.cmp").get_lsp_capabilities()
local servers = { "lua_ls", "pyright", "texlab", "bashls", "marksman" }
-- Configure diagnostics to be hidden by default
vim.diagnostic.config({
virtual_text = false,
@@ -36,7 +47,7 @@ return {
update_in_insert = false,
severity_sort = false,
})
-- Set up keymaps for LSP
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
@@ -51,86 +62,80 @@ return {
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
end,
})
-- Language servers setup with capabilities
lspconfig.lua_ls.setup({
capabilities = capabilities,
})
lspconfig.pyright.setup({
capabilities = capabilities,
})
lspconfig.texlab.setup({
capabilities = capabilities,
})
lspconfig.bashls.setup({
capabilities = capabilities,
})
lspconfig.marksman.setup({
capabilities = capabilities,
})
-- Use Neovim 0.11+ LSP API to avoid deprecated lspconfig setup calls.
if vim.lsp.config and vim.lsp.enable then
for _, server in ipairs(servers) do
vim.lsp.config(server, { capabilities = capabilities })
end
vim.lsp.enable(servers)
else
local lspconfig = require("lspconfig")
for _, server in ipairs(servers) do
lspconfig[server].setup({ capabilities = capabilities })
end
end
end,
},
-- Completion
-- Copilot (suggestion/panel disabled — blink-copilot handles completions)
{
"hrsh7th/nvim-cmp",
"zbirenbaum/copilot.lua",
event = "InsertEnter",
opts = {
suggestion = { enabled = false },
panel = { enabled = false },
},
},
-- blink.cmp: fast Rust-powered completion engine
{
"saghen/blink.cmp",
version = "*",
dependencies = {
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-nvim-lua",
"saadparwaiz1/cmp_luasnip",
"rafamadriz/friendly-snippets",
{
"L3MON4D3/LuaSnip",
dependencies = { "rafamadriz/friendly-snippets", "evesdropper/luasnip-latex-snippets.nvim" },
build = "make install_jsregexp",
dependencies = { "evesdropper/luasnip-latex-snippets.nvim" },
config = function()
require("luasnip.loaders.from_vscode").lazy_load()
require("luasnip.loaders.from_lua").load({ paths = "~/.config/nvim/lua/snippets" })
end,
},
{
"fmuaddel/blink-copilot",
dependencies = { "zbirenbaum/copilot.lua" },
},
},
config = function()
local cmp = require("cmp")
local luasnip = require("luasnip")
-- Load snippets
require("luasnip.loaders.from_vscode").lazy_load()
require("luasnip.loaders.from_lua").load({ paths = "~/.config/nvim/lua/snippets" })
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
opts = {
keymap = {
preset = "default",
["<Tab>"] = { "select_next", "snippet_forward", "fallback" },
["<S-Tab>"] = { "select_prev", "snippet_backward", "fallback" },
["<CR>"] = { "accept", "fallback" },
},
appearance = { nerd_font_variant = "mono" },
sources = {
default = { "lazydev", "lsp", "path", "snippets", "buffer", "copilot" },
providers = {
lazydev = {
name = "LazyDev",
module = "lazydev.integrations.blink",
score_offset = 100,
},
copilot = {
name = "copilot",
module = "blink-copilot",
score_offset = 50,
async = true,
},
},
mapping = cmp.mapping.preset.insert({
["<C-Space>"] = cmp.mapping.complete(),
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Tab>"] = cmp.mapping(function(fallback)
if require("copilot.suggestion").is_visible() then
require("copilot.suggestion").accept()
elseif cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
}),
sources = cmp.config.sources({
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "buffer" },
{ name = "path" },
}),
})
end,
},
snippets = { preset = "luasnip" },
completion = {
ghost_text = { enabled = true },
},
},
},
}
}

View File

@@ -188,6 +188,6 @@ return {
tabline = {},
winbar = {},
inactive_winbar = {},
extensions = { "nvim-tree", "fzf", "lazy" },
extensions = { "nvim-tree", "lazy" },
},
}

View File

@@ -1,28 +1,29 @@
return {
"nvimtools/none-ls.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
config = function()
local null_ls = require("null-ls")
null_ls.setup({
debug = false,
sources = {
-- null_ls.builtins.diagnostics.markdownlint.with({
-- filetypes = { "markdown", "markdown.pandoc", "pandoc" },
-- }),
null_ls.builtins.formatting.prettier.with({
filetypes = { "markdown", "markdown.pandoc", "pandoc" },
}),
},
on_attach = function(client, bufnr)
if client.supports_method("textDocument/formatting") then
vim.api.nvim_create_autocmd("BufWritePre", {
buffer = bufnr,
callback = function()
vim.lsp.buf.format({ bufnr = bufnr })
end,
})
end
end,
})
end,
}
"stevearc/conform.nvim",
event = { "BufWritePre" },
cmd = { "ConformInfo" },
keys = {
{
"<leader>fm",
function() require("conform").format({ async = true }) end,
desc = "Format buffer",
},
},
opts = {
formatters_by_ft = {
javascript = { "prettier" },
typescript = { "prettier" },
javascriptreact = { "prettier" },
typescriptreact = { "prettier" },
json = { "prettier" },
html = { "prettier" },
css = { "prettier" },
markdown = { "prettier" },
yaml = { "prettier" },
},
format_on_save = {
timeout_ms = 500,
lsp_fallback = true,
},
},
}

View File

@@ -1,6 +1,8 @@
return {
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
dependencies = { "nvim-treesitter/nvim-treesitter-textobjects" },
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = { "c", "lua", "python", "javascript", "markdown", "markdown_inline", "html", "css", "bash", "vim", "vimdoc" },
@@ -39,6 +41,29 @@ return {
node_decremental = "grm",
},
},
textobjects = {
select = {
enable = true,
lookahead = true,
keymaps = {
["af"] = "@function.outer",
["if"] = "@function.inner",
["ac"] = "@class.outer",
["ic"] = "@class.inner",
["aa"] = "@parameter.outer",
["ia"] = "@parameter.inner",
},
},
move = {
enable = true,
set_jumps = true,
goto_next_start = { ["]f"] = "@function.outer", ["]c"] = "@class.outer" },
goto_next_end = { ["]F"] = "@function.outer", ["]C"] = "@class.outer" },
goto_previous_start = { ["[f"] = "@function.outer", ["[c"] = "@class.outer" },
goto_previous_end = { ["[F"] = "@function.outer", ["[C"] = "@class.outer" },
},
},
})
-- Better folding setup
@@ -47,4 +72,5 @@ return {
vim.opt.foldlevel = 20
vim.opt.foldenable = false
end,
},
}