feat: add plugins, formatting, and editor quality-of-life improvements

- Add leap.nvim (<CR> to jump, S for cross-window) with LeapBackdrop dimming
- Add mini.surround with default s-prefix keymaps
- Add conform.nvim with format-on-save and <leader>cf keymap
- Add undotree with <leader>uu toggle and nerd font shapes
- Add nvim-treesitter-context for sticky scope header (max 3 lines)
- Add inc-rename.nvim with Noice input dialog and <leader>cr keymap
- Add lazydev.nvim for proper Neovim Lua type definitions in lua_ls
- Enable Snacks modules: scratch, zen, terminal (<C-/> toggle), and expand picker with flash integration and frecency matcher
- Configure flash to suppress default keymaps (owned by leap/mini.surround)
- Switch gitsigns from numhl to signcolumn for Snacks.statuscolumn rendering
- Set 2-space indentation with expandtab
- Enable persistent undo via undofile
- Auto-restore persistence session on startup when no file args given

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-17 18:24:47 -04:00
parent 444b5739bd
commit 21ec297431
4 changed files with 426 additions and 100 deletions
+28 -2
View File
@@ -100,7 +100,15 @@ vim.keymap.set("n", "gao", function() Snacks.picker.lsp_outgoing_calls() end, {
vim.keymap.set("n", "<leader>ss", function() Snacks.picker.lsp_symbols() end, { desc = "LSP Symbols" })
vim.keymap.set("n", "<leader>sS", function() Snacks.picker.lsp_workspace_symbols() end, { desc = "LSP Workspace Symbols" })
-- Standard LSP
vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" })
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "Code Action" })
vim.keymap.set("n", "<leader>cr", function()
return ":" .. require("inc_rename").config.cmd_name .. " " .. vim.fn.expand("<cword>")
end, { expr = true, desc = "Rename Symbol" })
-- Other
vim.keymap.set("n", "<leader>sq", "<cmd>nohlsearch<cr>", { desc = "Clear Search Highlights" })
vim.keymap.set("n", "<leader>z", function() Snacks.zen() end, { desc = "Toggle Zen Mode" })
vim.keymap.set("n", "<leader>Z", function() Snacks.zen.zoom() end, { desc = "Toggle Zoom" })
vim.keymap.set("n", "<leader>.", function() Snacks.scratch() end, { desc = "Toggle Scratch Buffer" })
@@ -111,8 +119,8 @@ vim.keymap.set("n", "<leader>cR", function() Snacks.rename.rename_file() end, {
vim.keymap.set({ "n", "v" }, "<leader>gB", function() Snacks.gitbrowse() end, { desc = "Git Browse" })
vim.keymap.set("n", "<leader>gg", function() Snacks.lazygit() end, { desc = "Lazygit" })
vim.keymap.set("n", "<leader>un", function() Snacks.notifier.hide() end, { desc = "Dismiss All Notifications" })
vim.keymap.set("n", "<c-/>", function() Snacks.terminal() end, { desc = "Toggle Terminal" })
vim.keymap.set("n", "<c-_>", function() Snacks.terminal() end, { desc = "which_key_ignore" })
vim.keymap.set({ "n", "t" }, "<c-/>", function() Snacks.terminal() end, { desc = "Toggle Terminal" })
vim.keymap.set({ "n", "t" }, "<c-_>", function() Snacks.terminal() end, { desc = "which_key_ignore" })
vim.keymap.set({ "n", "t" }, "]]", function() Snacks.words.jump(vim.v.count1) end, { desc = "Next Reference" })
vim.keymap.set({ "n", "t" }, "[[", function() Snacks.words.jump(-vim.v.count1) end, { desc = "Prev Reference" })
vim.keymap.set("n", "<leader>N", function()
@@ -132,6 +140,24 @@ end, { desc = "Neovim News" })
----------------------------------------------------------
-- Leap Keymaps
vim.keymap.set({ 'n', 'x', 'o' }, '<CR>', '<Plug>(leap)')
vim.keymap.set('n', 'S', '<Plug>(leap-from-window)')
----------------------------------------------------------
-- Conform Keymaps
vim.keymap.set({ "n", "v" }, "<leader>cf", function()
require("conform").format({ lsp_format = "fallback" })
end, { desc = "Format Buffer" })
----------------------------------------------------------
-- Undotree Keymaps
vim.keymap.set("n", "<leader>uu", "<cmd>UndotreeToggle<cr>", { desc = "Toggle Undotree" })
----------------------------------------------------------
-- Persistence Keymaps
vim.keymap.set("n", "<leader>qs", function() require("persistence").load() end, { desc = "Restore Session" })
vim.keymap.set("n", "<leader>qS", function() require("persistence").select() end, { desc = "Select Session" })
+37 -8
View File
@@ -7,14 +7,14 @@
-- Autowrite/Autosave
-- This ensures changes are saved on every buffer change or when leaving insert mode.
vim.api.nvim_create_autocmd({ "InsertLeave", "TextChanged" }, {
group = vim.api.nvim_create_augroup("autosave", { clear = true }),
pattern = { "*" },
callback = function()
local buftype = vim.api.nvim_get_option_value("buftype", { buf = 0 })
if buftype == "" and vim.bo.modified then
vim.cmd("silent! update")
end
end,
group = vim.api.nvim_create_augroup("autosave", { clear = true }),
pattern = { "*" },
callback = function()
local buftype = vim.api.nvim_get_option_value("buftype", { buf = 0 })
if buftype == "" and vim.bo.modified then
vim.cmd("silent! update")
end
end,
})
-- Performance and UI defaults
@@ -22,3 +22,32 @@ vim.opt.updatetime = 200 -- Faster completion and CursorHold events
vim.opt.autowrite = true -- Enable auto write
vim.opt.number = true -- Show line numbers
vim.opt.relativenumber = true -- Relative line numbers
-- Persistent undo across sessions
vim.opt.undofile = true
-- Indentation
vim.opt.tabstop = 2 -- Tab width in spaces
vim.opt.shiftwidth = 2 -- Indent width for >> and auto-indent
vim.opt.expandtab = true -- Use spaces instead of tabs
-- FormatOnSave
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*",
callback = function(args)
require("conform").format({ bufnr = args.buf })
end,
})
-- Execute Format
vim.api.nvim_create_user_command("Format", function(args)
local range = nil
if args.count ~= -1 then
local end_line = vim.api.nvim_buf_get_lines(0, args.line2 - 1, args.line2, true)[1]
range = {
start = { args.line1, 0 },
["end"] = { args.line2, end_line:len() },
}
end
require("conform").format({ async = true, lsp_format = "fallback", range = range })
end, { range = true })
+300 -89
View File
@@ -6,39 +6,93 @@
-- Catppuccin.nvim
-- Eagerly load the colorscheme plugin.
vim.pack.add { { src = "https://github.com/catppuccin/nvim", name = "catppuccin" } }
vim.pack.add({ { src = "https://github.com/catppuccin/nvim", name = "catppuccin" } })
-- Catppuccin Config
Config.plugins.catppuccin = {
flavour = "mocha",
flavour = "mocha",
}
vim.cmd.colorscheme "catppuccin"
vim.cmd.colorscheme("catppuccin")
-- Snacks.nvim
-- Eagerly load snacks for dashboard and performance features.
vim.pack.add { { src = "https://github.com/folke/snacks.nvim", name = "snacks" } }
vim.pack.add({ { src = "https://github.com/folke/snacks.nvim", name = "snacks" } })
-- Snacks Config
-- Store opts in the registry first.
Config.plugins.snacks = {
bigfile = { enabled = true },
dashboard = {
enabled = true,
sections = {
{ section = "header" },
{ section = "keys", gap = 1, padding = 1 },
},
},
explorer = { enabled = true },
indent = { enabled = true },
input = { enabled = true },
picker = { enabled = true },
notifier = { enabled = true },
quickfile = { enabled = true },
scope = { enabled = true },
scroll = { enabled = true },
statuscolumn = { enabled = true },
words = { enabled = true },
bigfile = { enabled = true },
dashboard = {
enabled = true,
sections = {
{ section = "header" },
{ section = "keys", gap = 1, padding = 1 },
},
preset = {
header = require("data").header,
},
},
explorer = { enabled = true },
indent = { enabled = true },
input = { enabled = true },
picker = {
enabled = true,
matcher = {
fuzzy = true,
smartcase = true,
ignorecase = true,
sort_empty = false,
filename_bonus = true,
file_pos = true,
cwd_bonus = true,
frecency = true,
history_bonus = true,
},
win = {
input = {
keys = {
["<a-s>"] = { "flash", mode = { "n", "i" } },
["s"] = { "flash" },
},
},
},
actions = {
flash = function(picker)
require("flash").jump({
pattern = "^",
label = { after = { 0, 0 } },
search = {
mode = "search",
exclude = {
function(win)
return vim.bo[vim.api.nvim_win_get_buf(win)].filetype ~= "snacks_picker_list"
end,
},
},
action = function(match)
local idx = picker.list:row2idx(match.pos[1])
picker.list:_move(idx, true, true)
end,
})
end,
},
},
notifier = { enabled = true },
quickfile = { enabled = true },
scope = { enabled = true },
scratch = { enabled = true },
scroll = { enabled = true },
statuscolumn = { enabled = true },
terminal = {
enabled = true,
win = {
keys = {
toggle = { "<c-/>", function(self) self:hide() end, mode = "t", desc = "Toggle Terminal" },
},
},
},
words = { enabled = true },
zen = { enabled = true },
}
-- Setup Snacks with the registered opts.
@@ -46,13 +100,13 @@ require("snacks").setup(Config.plugins.snacks)
-- Persistence.nvim
-- Simple session management.
vim.pack.add { { src = "https://github.com/folke/persistence.nvim", name = "persistence" } }
vim.pack.add({ { src = "https://github.com/folke/persistence.nvim", name = "persistence" } })
-- Persistence Config
Config.plugins.persistence = {
dir = vim.fn.stdpath("state") .. "/sessions/",
need = 1,
branch = true,
dir = vim.fn.stdpath("state") .. "/sessions/",
need = 1,
branch = true,
}
require("persistence").setup(Config.plugins.persistence)
@@ -60,76 +114,233 @@ require("persistence").setup(Config.plugins.persistence)
local lazyload = require("lazyload")
lazyload.on_vim_enter(function()
-- Gitsigns.nvim
vim.pack.add { { src = "https://github.com/lewis6991/gitsigns.nvim", name = "gitsigns" } }
require("gitsigns").setup({
numhl = true, -- Enable line number highlighting
})
-- Gitsigns.nvim
vim.pack.add({ { src = "https://github.com/lewis6991/gitsigns.nvim", name = "gitsigns" } })
require("gitsigns").setup({
numhl = false,
signcolumn = true,
current_line_blame = true, -- Required for the statusline variable to update
current_line_blame_opts = {
virt_text = false, -- Disable virtual text as we'll use the statusline
},
})
-- Grug-far.nvim
vim.pack.add { { src = "https://github.com/MagicDuck/grug-far.nvim", name = "grug-far" } }
require("grug-far").setup()
-- Treesitter Context
vim.pack.add({
{ src = "https://github.com/nvim-treesitter/nvim-treesitter-context", name = "nvim-treesitter-context" },
})
require("treesitter-context").setup({
max_lines = 3,
trim_scope = "outer",
})
-- Flash.nvim
vim.pack.add { { src = "https://github.com/folke/flash.nvim", name = "flash" } }
require("flash").setup()
-- Grug-far.nvim
vim.pack.add({ { src = "https://github.com/MagicDuck/grug-far.nvim", name = "grug-far" } })
require("grug-far").setup()
-- Which-key.nvim
vim.pack.add { { src = "https://github.com/folke/which-key.nvim", name = "which-key" } }
require("which-key").setup()
-- Flash.nvim
vim.pack.add({ { src = "https://github.com/folke/flash.nvim", name = "flash" } })
require("flash").setup({
modes = { char = { keys = {} } },
keys = {},
})
-- Mini.ai
vim.pack.add { { src = "https://github.com/echasnovski/mini.ai", name = "mini.ai" } }
-- Leap.nvim
vim.pack.add({ { src = "https://git.disroot.org/andyg/leap.nvim", name = "leap" } })
vim.api.nvim_set_hl(0, "LeapBackdrop", { link = "Comment" })
Config.plugins.mini_ai = {
custom_textobjects = {
g = function()
local n_lines = vim.api.nvim_buf_line_count(0)
return {
from = { line = 1, col = 1 },
to = { line = n_lines, col = math.max(vim.fn.getline(n_lines):len(), 1) },
}
end,
},
}
require("mini.ai").setup(Config.plugins.mini_ai)
-- Mini.surround
vim.pack.add({ { src = "https://github.com/echasnovski/mini.surround", name = "mini.surround" } })
require("mini.surround").setup()
-- Icons
vim.pack.add { { src = "https://github.com/nvim-tree/nvim-web-devicons", name = "nvim-web-devicons" } }
-- Undotree
vim.g.undotree_ShortIndicators = 0
vim.g.undotree_SplitWidth = 32
vim.g.undotree_SetFocusWhenToggle = 1
vim.g.undotree_TreeNodeShape = ""
vim.g.undotree_TreeVertShape = ""
vim.g.undotree_TreeSplitShape = ""
vim.g.undotree_TreeReturnShape = ""
vim.g.undotree_HelpLine = 0
vim.g.undotree_DiffAutoOpen = 0
vim.pack.add({ { src = "https://github.com/mbbill/undotree", name = "undotree" } })
-- Lualine
vim.pack.add { { src = "https://github.com/nvim-lualine/lualine.nvim", name = "lualine" } }
require("lualine").setup({
options = {
theme = "auto",
globalstatus = true,
},
sections = {
lualine_b = { "branch", "diff", "diagnostics" },
}
})
-- Conform.nvim
vim.pack.add({ { src = "https://github.com/stevearc/conform.nvim", name = "conform" } })
Config.plugins.conform = {
formatters_by_ft = {
lua = { "stylua" },
c = { "clang-format" },
cpp = { "clang-format" },
rust = { "rustfmt" },
python = { "ruff_format" },
fish = { "fish_indent" },
sh = { "shfmt" },
bash = { "shfmt" },
},
format_on_save = function(bufnr)
-- Disable with a global or buffer-local variable
if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then
return
end
return { timeout_ms = 500, lsp_format = "fallback" }
end,
}
require("conform").setup(Config.plugins.conform)
-- Noice dependencies
vim.pack.add { { src = "https://github.com/MunifTanjim/nui.nvim", name = "nui" } }
-- Which-key.nvim
vim.pack.add({ { src = "https://github.com/folke/which-key.nvim", name = "which-key" } })
require("which-key").setup()
-- Noice.nvim
vim.pack.add { { src = "https://github.com/folke/noice.nvim", name = "noice" } }
require("noice").setup({
lsp = {
-- override markdown rendering so that **cmp** and other plugins use **Treesitter**
override = {
["vim.lsp.util.convert_input_to_markdown_lines"] = true,
["vim.lsp.util.set_autocmds"] = true,
["vim.ui.codelens.display_inline"] = true,
},
},
-- you can enable a preset for easier configuration
presets = {
bottom_search = true, -- use a classic bottom cmdline for search
command_palette = true, -- position the cmdline and popupmenu together
long_message_to_split = true, -- long messages will be sent to a split
inc_rename = false, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
},
})
-- Lazydev.nvim (Neovim Lua type definitions for lua_ls)
vim.pack.add({ { src = "https://github.com/folke/lazydev.nvim", name = "lazydev" } })
require("lazydev").setup({
library = {
{ path = "snacks.nvim", words = { "Snacks" } },
},
})
-- LSP Support
vim.pack.add({ { src = "https://github.com/williamboman/mason.nvim", name = "mason" } })
vim.pack.add({ { src = "https://github.com/williamboman/mason-lspconfig.nvim", name = "mason-lspconfig" } })
vim.pack.add({ { src = "https://github.com/neovim/nvim-lspconfig", name = "nvim-lspconfig" } })
-- Completion
vim.pack.add({ { src = "https://github.com/saghen/blink.cmp", name = "blink.cmp" } })
vim.pack.add({ { src = "https://github.com/rafamadriz/friendly-snippets", name = "friendly-snippets" } })
vim.pack.add({ { src = "https://github.com/fang2hou/blink-copilot", name = "blink-copilot" } })
require("mason").setup()
-- Blink.cmp setup
require("blink.cmp").setup({
keymap = { preset = "default" },
appearance = {
use_nvim_cmp_as_default = true,
nerd_font_variant = "mono",
kind_icons = {
Copilot = "",
},
},
sources = {
default = { "lsp", "path", "snippets", "buffer", "copilot" },
providers = {
copilot = {
name = "copilot",
module = "blink-copilot",
kind = "lsp",
server_name = "copilot",
score_offset = 100,
async = true,
opts = {
max_completions = 3,
max_attempts = 4,
},
},
},
},
signature = { enabled = true },
})
local lspconfig = require("lspconfig")
local capabilities = require("blink.cmp").get_lsp_capabilities()
require("mason-lspconfig").setup({
ensure_installed = {
"lua_ls",
"clangd",
"rust_analyzer",
"pyright",
"fish_lsp",
"bashls",
"copilot",
},
handlers = {
-- Default handler
function(server_name)
lspconfig[server_name].setup({ capabilities = capabilities })
end,
-- Specific overrides
["lua_ls"] = function()
lspconfig.lua_ls.setup({
capabilities = capabilities,
settings = {
Lua = {
diagnostics = { globals = { "Config" } },
},
},
})
end,
},
})
-- Mini.ai
vim.pack.add({ { src = "https://github.com/echasnovski/mini.ai", name = "mini.ai" } })
Config.plugins.mini_ai = {
custom_textobjects = {
g = function()
local n_lines = vim.api.nvim_buf_line_count(0)
return {
from = { line = 1, col = 1 },
to = { line = n_lines, col = math.max(vim.fn.getline(n_lines):len(), 1) },
}
end,
},
}
require("mini.ai").setup(Config.plugins.mini_ai)
-- Icons
vim.pack.add({ { src = "https://github.com/nvim-tree/nvim-web-devicons", name = "nvim-web-devicons" } })
-- Lualine
vim.pack.add({ { src = "https://github.com/nvim-lualine/lualine.nvim", name = "lualine" } })
require("lualine").setup({
options = {
theme = "auto",
globalstatus = true,
},
sections = {
lualine_b = { "branch", "diff", "diagnostics" },
lualine_c = {
{ "filename" },
{
function()
return vim.b.gitsigns_blame_line or ""
end,
cond = function()
return vim.b.gitsigns_blame_line ~= nil and vim.b.gitsigns_blame_line ~= ""
end,
},
},
},
})
-- Inc-rename.nvim
vim.pack.add({ { src = "https://github.com/smjonas/inc-rename.nvim", name = "inc-rename" } })
require("inc_rename").setup()
-- Noice dependencies
vim.pack.add({ { src = "https://github.com/MunifTanjim/nui.nvim", name = "nui" } })
-- Noice.nvim
vim.pack.add({ { src = "https://github.com/folke/noice.nvim", name = "noice" } })
require("noice").setup({
lsp = {
-- override markdown rendering so that **cmp** and other plugins use **Treesitter**
override = {
["vim.lsp.util.convert_input_to_markdown_lines"] = true,
["vim.lsp.util.set_autocmds"] = true,
["vim.ui.codelens.display_inline"] = true,
},
},
-- you can enable a preset for easier configuration
presets = {
bottom_search = true, -- use a classic bottom cmdline for search
command_palette = true, -- position the cmdline and popupmenu together
long_message_to_split = true, -- long messages will be sent to a split
inc_rename = true, -- enables an input dialog for inc-rename.nvim
lsp_doc_border = false, -- add a border to hover docs and signature help
},
})
end)
+60
View File
@@ -1,13 +1,33 @@
{
"plugins": {
"blink-copilot": {
"rev": "7ad8209b2f880a2840c94cdcd80ab4dc511d4f39",
"src": "https://github.com/fang2hou/blink-copilot"
},
"blink.cmp": {
"rev": "c573a15a62bd0bfd4006ee0849b24f5404395500",
"src": "https://github.com/saghen/blink.cmp"
},
"catppuccin": {
"rev": "426dbebe06b5c69fd846ceb17b42e12f890aedf1",
"src": "https://github.com/catppuccin/nvim"
},
"conform": {
"rev": "086a40dc7ed8242c03be9f47fbcee68699cc2395",
"src": "https://github.com/stevearc/conform.nvim"
},
"flash": {
"rev": "fcea7ff883235d9024dc41e638f164a450c14ca2",
"src": "https://github.com/folke/flash.nvim"
},
"friendly-snippets": {
"rev": "6cd7280adead7f586db6fccbd15d2cac7e2188b9",
"src": "https://github.com/rafamadriz/friendly-snippets"
},
"git-blame": {
"rev": "5c536e2d4134d064aa3f41575280bc8a2a0e03d7",
"src": "https://github.com/f-person/git-blame.nvim"
},
"gitsigns": {
"rev": "8d82c240f190fc33723d48c308ccc1ed8baad69d",
"src": "https://github.com/lewis6991/gitsigns.nvim"
@@ -16,14 +36,38 @@
"rev": "21604255d0e8f9968322f61f2b6c09e5efe1285a",
"src": "https://github.com/MagicDuck/grug-far.nvim"
},
"inc-rename": {
"rev": "0074b551a17338ccdcd299bd86687cc651bcb33d",
"src": "https://github.com/smjonas/inc-rename.nvim"
},
"lazydev": {
"rev": "ff2cbcba459b637ec3fd165a2be59b7bbaeedf0d",
"src": "https://github.com/folke/lazydev.nvim"
},
"leap": {
"rev": "b960d5038c5c505c52e56a54490f9bbb1f0e6ef6",
"src": "https://git.disroot.org/andyg/leap.nvim"
},
"lualine": {
"rev": "a905eeebc4e63fdc48b5135d3bf8aea5618fb21c",
"src": "https://github.com/nvim-lualine/lualine.nvim"
},
"mason": {
"rev": "b03fb0f20bc1d43daf558cda981a2be22e73ac42",
"src": "https://github.com/williamboman/mason.nvim"
},
"mason-lspconfig": {
"rev": "0a3b42c3e503df87aef6d6513e13148381495c3a",
"src": "https://github.com/williamboman/mason-lspconfig.nvim"
},
"mini.ai": {
"rev": "43eb2074843950a3a25aae56a5f41362ec043bfa",
"src": "https://github.com/echasnovski/mini.ai"
},
"mini.surround": {
"rev": "2715e04bea3ec9244f15b421dc5b18c0fe326210",
"src": "https://github.com/echasnovski/mini.surround"
},
"noice": {
"rev": "7bfd942445fb63089b59f97ca487d605e715f155",
"src": "https://github.com/folke/noice.nvim"
@@ -32,6 +76,18 @@
"rev": "de740991c12411b663994b2860f1a4fd0937c130",
"src": "https://github.com/MunifTanjim/nui.nvim"
},
"nvim-lspconfig": {
"rev": "4b7fbaa239c5db6b36f424a4521ca9f1a401be33",
"src": "https://github.com/neovim/nvim-lspconfig"
},
"nvim-treesitter": {
"rev": "4916d6592ede8c07973490d9322f187e07dfefac",
"src": "https://github.com/nvim-treesitter/nvim-treesitter"
},
"nvim-treesitter-context": {
"rev": "b0c45cefe2c8f7b55fc46f34e563bc428ef99636",
"src": "https://github.com/nvim-treesitter/nvim-treesitter-context"
},
"nvim-web-devicons": {
"rev": "c72328a5494b4502947a022fe69c0c47e53b6aa6",
"src": "https://github.com/nvim-tree/nvim-web-devicons"
@@ -44,6 +100,10 @@
"rev": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e",
"src": "https://github.com/folke/snacks.nvim"
},
"undotree": {
"rev": "6fa6b57cda8459e1e4b2ca34df702f55242f4e4d",
"src": "https://github.com/mbbill/undotree"
},
"which-key": {
"rev": "3aab2147e74890957785941f0c1ad87d0a44c15a",
"src": "https://github.com/folke/which-key.nvim"