update:nvim11->12 config

This commit is contained in:
2026-04-13 21:38:27 +09:00
parent f6cb9e99f9
commit 50b410d323
22 changed files with 1093 additions and 1251 deletions

15
nvim/lua/plugins/ai.lua Normal file
View File

@@ -0,0 +1,15 @@
local M = {}
local pack = require("utils.pack")
function M.setup()
vim.api.nvim_create_autocmd("InsertEnter", {
once = true,
callback = function()
pack.add({ "supermaven-nvim" })
require("supermaven-nvim").setup({})
end,
})
end
return M

View File

@@ -0,0 +1,20 @@
local M = {}
local pack = require("utils.pack")
function M.setup()
vim.api.nvim_create_autocmd("FileType", {
pattern = { "html", "xml", "javascriptreact", "typescriptreact", "astro", "templ" },
once = true,
callback = function()
pack.add({ "nvim-ts-autotag" })
require("nvim-ts-autotag").setup({
aliases = {
astro = "html",
},
})
end,
})
end
return M

View File

@@ -0,0 +1,65 @@
local M = {}
local ui = require("utils.ui")
local pack = require("utils.pack")
local function apply_theme_overrides()
local transparent_groups = {
"NormalFloat",
"FloatBorder",
"TelescopeNormal",
"TelescopeBorder",
"TelescopePromptNormal",
"TelescopePromptBorder",
"TelescopeResultsNormal",
"TelescopeResultsBorder",
"TelescopePreviewNormal",
"TelescopePreviewBorder",
}
for _, g in ipairs(transparent_groups) do
vim.api.nvim_set_hl(0, g, { bg = "none" })
end
for _, group in ipairs(vim.fn.getcompletion("", "highlight")) do
local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = group })
if ok and hl and hl.italic then
hl.italic = nil
vim.api.nvim_set_hl(0, group, hl)
end
end
end
function M.setup()
pack.add({ "catppuccin", "nvim-web-devicons" })
local theme_group = vim.api.nvim_create_augroup("UserThemeTweaks", { clear = true })
vim.api.nvim_create_autocmd("ColorScheme", {
group = theme_group,
callback = apply_theme_overrides,
})
require("catppuccin").setup({
flavour = "macchiato",
transparent_background = true,
compile_path = vim.fn.stdpath("cache") .. "/catppuccin",
integrations = {
cmp = true,
treesitter = true,
},
telescope = {
enabled = true,
},
})
vim.cmd.colorscheme("catppuccin")
apply_theme_overrides()
local orig = vim.lsp.util.open_floating_preview
vim.lsp.util.open_floating_preview = function(contents, syntax, opts, ...)
opts = opts or {}
opts.border = opts.border or ui.border("FloatBorder")
return orig(contents, syntax, opts, ...)
end
end
return M

65
nvim/lua/plugins/cmp.lua Normal file
View File

@@ -0,0 +1,65 @@
local M = {}
local ui = require("utils.ui")
local pack = require("utils.pack")
function M.setup()
pack.add({ "nvim-cmp", "cmp-nvim-lsp", "cmp-buffer", "cmp-path", "luasnip", "cmp_luasnip" })
local cmp = require("cmp")
local luasnip = require("luasnip")
cmp.setup({
window = {
completion = {
border = ui.border("CmpBorder"),
winhighlight = "Normal:CmpPmenu,CursorLine:PmenuSel,Search:None",
},
documentation = {
border = ui.border("CmpDocBorder"),
},
},
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
["<CR>"] = cmp.mapping.confirm({ select = true }),
["<Tab>"] = cmp.mapping(function(fallback)
if 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 = "path" },
{
name = "buffer",
option = {
keyword_length = 4,
get_bufnrs = function()
return { vim.api.nvim_get_current_buf() }
end,
},
},
}),
})
end
return M

162
nvim/lua/plugins/lsp.lua Normal file
View File

@@ -0,0 +1,162 @@
local M = {}
local pack = require("utils.pack")
local tools = {
{ kind = "lsp", lsp = "lua_ls", mason = "lua-language-server" },
{ kind = "lsp", lsp = "bashls", mason = "bash-language-server" },
{ kind = "lsp", lsp = "astro", mason = "astro-language-server" },
{ kind = "lsp", lsp = "tailwindcss", mason = "tailwindcss-language-server" },
{ kind = "lsp", lsp = "ts_ls", mason = "typescript-language-server" },
{ kind = "lsp", lsp = "html", mason = "html-lsp" },
{ kind = "lsp", lsp = "pyright", mason = "pyright" },
{ kind = "lsp", lsp = "templ", mason = "templ" },
{ kind = "lsp", lsp = "gopls", mason = "gopls" },
{ kind = "lsp", lsp = "emmet_ls", mason = "emmet-language-server" },
{ kind = "lsp", lsp = "rust_analyzer", mason = "rust-analyzer" },
{ kind = "formatter", mason = "stylua", ft = { "lua" } },
{ kind = "formatter", mason = "shfmt", ft = { "sh", "bash" } },
{ kind = "formatter", mason = "isort", ft = { "python" } },
{ kind = "formatter", mason = "black", ft = { "python" } },
{ kind = "formatter", mason = "prettierd", ft = { "javascript", "typescript", "astro", "html", "css", "json", "jsonc" } },
}
function M.setup()
pack.add({ "mason", "nvim-lspconfig", "conform" })
require("mason").setup()
local capabilities = vim.lsp.protocol.make_client_capabilities()
pcall(function()
capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities)
end)
vim.lsp.config("*", { capabilities = capabilities })
vim.lsp.config("tailwindcss", {
settings = {
tailwindCSS = {
experimental = {
classRegex = {
"Css = (\\{[^\\{\\}]+\\}|\\[[^\\[\\]]+\\]|'[^']+'|\"[^\"]+\")",
},
},
},
},
filetypes = { "htmldjango", "templ", "html", "css", "javascript", "typescript", "jsx", "tsx" },
})
vim.lsp.config("html", { filetypes = { "html", "htmldjango", "templ" } })
vim.lsp.config("lua_ls", {
settings = {
Lua = {
diagnostics = { globals = { "vim" } },
telemetry = { enable = false },
workspace = { checkThirdParty = false },
hint = { enable = true },
},
},
})
local lsp_names = {}
for _, t in ipairs(tools) do
if t.kind == "lsp" then
table.insert(lsp_names, t.lsp)
end
end
vim.lsp.enable(lsp_names)
require("conform").setup({
formatters_by_ft = {
lua = { "stylua" },
sh = { "shfmt" },
bash = { "shfmt" },
python = { "isort", "black" },
javascript = { "prettierd" },
typescript = { "prettierd" },
astro = { "prettierd" },
html = { "prettierd" },
css = { "prettierd" },
json = { "prettierd" },
jsonc = { "prettierd" },
},
})
vim.keymap.set("n", "<leader>F", function()
require("conform").format({ async = true, lsp_fallback = true })
end, { desc = "Format buffer" })
vim.api.nvim_create_user_command("MasonInstallDefaults", function()
local registry = require("mason-registry")
registry.refresh(function()
local seen, to_install = {}, {}
for _, t in ipairs(tools) do
if t.mason and not seen[t.mason] then
seen[t.mason] = true
local ok, pkg = pcall(registry.get_package, t.mason)
if ok and not pkg:is_installed() then
table.insert(to_install, pkg)
end
end
end
if #to_install == 0 then
vim.notify("MasonInstallDefaults: all tools already installed", vim.log.levels.INFO)
return
end
for _, pkg in ipairs(to_install) do
pkg:install()
end
vim.notify(("MasonInstallDefaults: installing %d tool(s)"):format(#to_install), vim.log.levels.INFO)
end)
end, { desc = "Install missing Mason tools from `tools` table" })
vim.diagnostic.config({ virtual_text = false })
local lsp_group = vim.api.nvim_create_augroup("UserLspAttach", { clear = true })
vim.api.nvim_create_autocmd("LspAttach", {
group = lsp_group,
callback = function(ev)
local bufnr = ev.buf
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if not client then
return
end
if client:supports_method("textDocument/completion") then
vim.bo[bufnr].omnifunc = "v:lua.vim.lsp.omnifunc"
end
if client:supports_method("textDocument/definition") then
vim.bo[bufnr].tagfunc = "v:lua.vim.lsp.tagfunc"
end
local map = function(mode, lhs, rhs, desc)
vim.keymap.set(mode, lhs, rhs, {
buffer = bufnr,
silent = true,
noremap = true,
desc = desc,
})
end
map("n", "gD", vim.lsp.buf.declaration, "LSP declaration")
map("n", "K", vim.lsp.buf.hover, "LSP hover")
map("n", "gi", vim.lsp.buf.implementation, "LSP implementation")
map("n", "<C-k>", vim.lsp.buf.signature_help, "LSP signature help")
map("n", "<leader>wa", vim.lsp.buf.add_workspace_folder, "LSP add workspace folder")
map("n", "<leader>wr", vim.lsp.buf.remove_workspace_folder, "LSP remove workspace folder")
map("n", "<leader>wl", function()
print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
end, "LSP list workspace folders")
map("n", "<leader>D", vim.lsp.buf.type_definition, "LSP type definition")
map("n", "<leader>rn", vim.lsp.buf.rename, "LSP rename")
map({ "n", "v" }, "<leader>ca", vim.lsp.buf.code_action, "LSP code action")
map("n", "gd", function()
require("plugins.telescope").lsp_definitions()
end, "LSP definitions (Telescope)")
map("n", "gr", function()
require("plugins.telescope").lsp_references()
end, "LSP references (Telescope)")
end,
})
end
return M

41
nvim/lua/plugins/mini.lua Normal file
View File

@@ -0,0 +1,41 @@
local M = {}
local pack = require("utils.pack")
function M.setup()
pack.add({ "mini.nvim" })
require("mini.comment").setup({
options = {
custom_commentstring = function()
local ft = vim.bo.filetype
if ft == "typescriptreact" then
return "{/* %s */}"
end
if ft == "htmldjango" then
return "{# %s #}"
end
if ft == "templ" then
return "// %s"
end
return nil
end,
},
})
vim.keymap.set("n", "<leader>cc", function()
require("mini.comment").toggle_lines(vim.fn.line("."), vim.fn.line("."))
end, { desc = "Toggle comment line" })
vim.keymap.set("v", "<leader>cc", function()
local s, e = vim.fn.line("v"), vim.fn.line(".")
if s > e then
s, e = e, s
end
require("mini.comment").toggle_lines(s, e)
end, { desc = "Toggle comment selection" })
require("mini.pairs").setup()
end
return M

View File

@@ -0,0 +1,56 @@
local M = {}
M.map = {
catppuccin = { name = "catppuccin", src = "https://github.com/catppuccin/nvim" },
["nvim-web-devicons"] = { name = "nvim-web-devicons", src = "https://github.com/nvim-tree/nvim-web-devicons" },
mason = { name = "mason", src = "https://github.com/mason-org/mason.nvim" },
["nvim-lspconfig"] = { name = "nvim-lspconfig", src = "https://github.com/neovim/nvim-lspconfig" },
conform = { name = "conform", src = "https://github.com/stevearc/conform.nvim" },
["nvim-cmp"] = { name = "nvim-cmp", src = "https://github.com/hrsh7th/nvim-cmp" },
["cmp-nvim-lsp"] = { name = "cmp-nvim-lsp", src = "https://github.com/hrsh7th/cmp-nvim-lsp" },
["cmp-buffer"] = { name = "cmp-buffer", src = "https://github.com/hrsh7th/cmp-buffer" },
["cmp-path"] = { name = "cmp-path", src = "https://github.com/hrsh7th/cmp-path" },
luasnip = { name = "luasnip", src = "https://github.com/L3MON4D3/LuaSnip" },
cmp_luasnip = { name = "cmp_luasnip", src = "https://github.com/saadparwaiz1/cmp_luasnip" },
["nvim-treesitter"] = { name = "nvim-treesitter", src = "https://github.com/nvim-treesitter/nvim-treesitter" },
["mini.nvim"] = { name = "mini.nvim", src = "https://github.com/echasnovski/mini.nvim" },
["indent-blankline.nvim"] = {
name = "indent-blankline.nvim",
src = "https://github.com/lukas-reineke/indent-blankline.nvim",
},
["lualine.nvim"] = { name = "lualine.nvim", src = "https://github.com/nvim-lualine/lualine.nvim" },
["bufferline.nvim"] = { name = "bufferline.nvim", src = "https://github.com/akinsho/bufferline.nvim" },
["plenary.nvim"] = { name = "plenary.nvim", src = "https://github.com/nvim-lua/plenary.nvim" },
["telescope.nvim"] = { name = "telescope.nvim", src = "https://github.com/nvim-telescope/telescope.nvim" },
["trouble.nvim"] = { name = "trouble.nvim", src = "https://github.com/folke/trouble.nvim" },
["grug-far.nvim"] = { name = "grug-far.nvim", src = "https://github.com/MagicDuck/grug-far.nvim" },
["nvim-ts-autotag"] = { name = "nvim-ts-autotag", src = "https://github.com/windwp/nvim-ts-autotag" },
["supermaven-nvim"] = { name = "supermaven-nvim", src = "https://github.com/supermaven-inc/supermaven-nvim" },
}
function M.by_names(names)
local out = {}
for _, name in ipairs(names) do
local spec = M.map[name]
if not spec then
error("Unknown plugin spec: " .. tostring(name))
end
table.insert(out, spec)
end
return out
end
function M.names()
local keys = {}
for name, _ in pairs(M.map) do
table.insert(keys, name)
end
table.sort(keys)
return keys
end
function M.all()
return M.by_names(M.names())
end
return M

View File

@@ -0,0 +1,70 @@
local M = {}
local lazy = require("utils.lazy")
local pack = require("utils.pack")
local function with_telescope(fn)
lazy.load_once("telescope", pack.registry({ "plenary.nvim", "telescope.nvim" }), function()
require("telescope").setup({
defaults = { file_ignore_patterns = { "%.git/" } },
pickers = {
find_files = {
find_command = { "rg", "--files", "--hidden", "--glob", "!**/.git/*" },
},
live_grep = {
additional_args = function()
return { "--glob", "!**/.git/*", "--glob", "!**/go.sum", "--glob", "!**/go.mod" }
end,
},
lsp_definitions = {
show_line = false,
theme = "dropdown",
file_ignore_patterns = { ".*_templ.go" },
},
lsp_references = {
show_line = false,
include_declaration = false,
theme = "dropdown",
file_ignore_patterns = { ".*_templ.go" },
},
},
})
end)
fn(require("telescope.builtin"))
end
function M.lsp_definitions()
with_telescope(function(builtin)
builtin.lsp_definitions()
end)
end
function M.lsp_references()
with_telescope(function(builtin)
builtin.lsp_references()
end)
end
function M.setup_keymaps()
vim.keymap.set("n", "<leader>f", function()
with_telescope(function(builtin)
builtin.find_files()
end)
end, { desc = "Find files" })
vim.keymap.set("n", "<leader>fg", function()
with_telescope(function(builtin)
builtin.live_grep()
end)
end, { desc = "Live grep" })
vim.keymap.set("n", "<C-f>", function()
with_telescope(function(builtin)
if not pcall(builtin.git_files, { show_untracked = true }) then
vim.notify("Not a git project. Try running git init in root.", vim.log.levels.WARN)
end
end)
end, { desc = "Git files" })
end
return M

View File

@@ -0,0 +1,58 @@
local M = {}
local lazy = require("utils.lazy")
local pack = require("utils.pack")
local function with_trouble(fn)
lazy.load_once("trouble", pack.registry({ "trouble.nvim" }), function()
require("trouble").setup({})
end)
fn()
end
local function with_grug(fn)
lazy.load_once("grug-far", pack.registry({ "grug-far.nvim" }), function()
require("grug-far").setup({})
end)
fn(require("grug-far"))
end
function M.setup()
vim.keymap.set("n", "<leader>xx", function()
with_trouble(function()
vim.cmd("Trouble diagnostics toggle")
end)
end, { desc = "Diagnostics (Trouble)" })
vim.keymap.set("n", "<leader>xX", function()
with_trouble(function()
vim.cmd("Trouble diagnostics toggle filter.buf=0")
end)
end, { desc = "Buffer diagnostics" })
vim.keymap.set("n", "<leader>xQ", function()
with_trouble(function()
vim.cmd("Trouble qflist toggle")
end)
end, { desc = "Quickfix list" })
vim.keymap.set("n", "<leader>S", function()
with_grug(function()
vim.cmd("GrugFar")
end)
end, { desc = "Search/replace project" })
vim.keymap.set("n", "<leader>s", function()
with_grug(function(grug)
grug.open({ prefills = { paths = vim.fn.expand("%") } })
end)
end, { desc = "Search/replace current file" })
vim.keymap.set("v", "<leader>s", function()
with_grug(function()
vim.cmd("'<,'>GrugFarWithin")
end)
end, { desc = "Search/replace in selection" })
end
return M

View File

@@ -0,0 +1,50 @@
local M = {}
local pack = require("utils.pack")
function M.setup()
pack.add({ "nvim-treesitter" })
require("nvim-treesitter").setup({
install_dir = vim.fn.stdpath("data") .. "/site",
})
require("nvim-treesitter").install({
"lua",
"vim",
"python",
"bash",
"javascript",
"typescript",
"html",
"css",
"json",
"toml",
"go",
"astro",
"templ",
})
vim.api.nvim_create_autocmd("FileType", {
pattern = {
"lua",
"vim",
"python",
"bash",
"javascript",
"typescript",
"html",
"css",
"json",
"toml",
"go",
"astro",
"templ",
},
callback = function(args)
pcall(vim.treesitter.start, args.buf)
end,
})
end
return M

22
nvim/lua/plugins/ui.lua Normal file
View File

@@ -0,0 +1,22 @@
local M = {}
local pack = require("utils.pack")
function M.setup()
pack.add({ "indent-blankline.nvim", "lualine.nvim", "bufferline.nvim" })
require("ibl").setup({
indent = { char = "" },
scope = { enabled = false },
})
require("lualine").setup()
require("bufferline").setup({
options = { mode = "tabs", separator_style = "thin" },
})
vim.keymap.set("n", "<Tab>", "<Cmd>BufferLineCycleNext<CR>", {})
vim.keymap.set("n", "<S-Tab>", "<Cmd>BufferLineCyclePrev<CR>", {})
end
return M

View File

@@ -1,204 +0,0 @@
vim.g.mapleader = " "
-- vim.cmd [[autocmd CursorHold,CursorHoldI * lua vim.diagnostic.open_float(nil, {focus=false})]]
-- Open project folder view
vim.keymap.set('n', '<leader>E', '<cmd>:Ex<CR>')
vim.keymap.set('n', '<leader>ER', '<cmd>:bw<CR>')
-- Set current window as current root directory for searching
vim.keymap.set("n", "<leader>sr", ":cd %:p:h<CR>")
-- Split window movement
vim.keymap.set("n", "<A-Left>", "<C-w>h")
vim.keymap.set("n", "<A-Down>", "<C-w>j")
vim.keymap.set("n", "<A-Up>", "<C-w>k")
vim.keymap.set("n", "<A-Right>", "<C-w>l")
-- netrw duplicate file, <leader>d
vim.api.nvim_create_autocmd('FileType', {
pattern = 'netrw',
callback = function()
vim.keymap.set('n', '<leader>d', function()
-- Save current directory
local original_dir = vim.fn.getcwd()
-- Change to the directory shown in netrw
vim.cmd('lcd %:p:h')
-- Feed the keys with proper mode flag
vim.api.nvim_feedkeys('mt', 'x', false)
vim.api.nvim_feedkeys('mf', 'x', false)
vim.api.nvim_feedkeys('mc', 'x', false)
-- Return to original directory after delay
vim.defer_fn(function()
vim.fn.chdir(original_dir)
end, 500)
end, { buffer = true, desc = 'Duplicate file in netrw' })
end,
})
-- Jump buffers movement
local tab_buffer_histories = {}
local is_navigating = false
local function get_current_tab_history()
local tab = vim.fn.tabpagenr()
if not tab_buffer_histories[tab] then
tab_buffer_histories[tab] = {
buffers = {},
index = 1
}
end
return tab_buffer_histories[tab]
end
vim.api.nvim_create_autocmd("BufEnter", {
callback = function()
if is_navigating then return end
local buf = vim.fn.bufnr('%')
if not vim.bo[buf].buflisted then return end
local history = get_current_tab_history()
-- Remove any existing occurrence of this buffer from history
for i = #history.buffers, 1, -1 do
if history.buffers[i] == buf then
table.remove(history.buffers, i)
if i < history.index then
history.index = history.index - 1
elseif i == history.index then
history.index = math.max(1, history.index - 1)
end
end
end
-- If we're in the middle of history and switch to a new buffer,
-- truncate future history
if history.index < #history.buffers then
for i = #history.buffers, history.index + 1, -1 do
table.remove(history.buffers)
end
end
-- Add the buffer to history
table.insert(history.buffers, buf)
history.index = #history.buffers
end
})
vim.keymap.set("n", "<A-b>", function()
local history = get_current_tab_history()
if history.index > 1 then
is_navigating = true
history.index = history.index - 1
local target_buf = history.buffers[history.index]
-- Check if buffer still exists and is valid
if vim.fn.bufexists(target_buf) == 1 and vim.bo[target_buf].buflisted then
vim.cmd('buffer ' .. target_buf)
else
-- Skip invalid buffers
table.remove(history.buffers, history.index)
history.index = math.max(1, history.index - 1)
end
vim.schedule(function() is_navigating = false end)
end
end)
vim.keymap.set("n", "<A-n>", function()
local history = get_current_tab_history()
if history.index < #history.buffers then
is_navigating = true
history.index = history.index + 1
local target_buf = history.buffers[history.index]
-- Check if buffer still exists and is valid
if vim.fn.bufexists(target_buf) == 1 and vim.bo[target_buf].buflisted then
vim.cmd('buffer ' .. target_buf)
else
-- Skip invalid buffers
table.remove(history.buffers, history.index)
history.index = math.min(#history.buffers, history.index)
end
vim.schedule(function() is_navigating = false end)
end
end)
vim.keymap.set("n", "<A-c>", function()
local current_buf = vim.fn.bufnr('%')
local history = get_current_tab_history()
history.buffers = { current_buf }
history.index = 1
print("Buffer history cleared")
end)
vim.keymap.set("n", "<A-q>", function()
local current_buf = vim.fn.bufnr('%')
local history = get_current_tab_history()
-- Remove current buffer from history
for i = #history.buffers, 1, -1 do
if history.buffers[i] == current_buf then
table.remove(history.buffers, i)
if i <= history.index then
history.index = math.max(1, history.index - 1)
end
end
end
-- Navigate to previous buffer in history if available
if #history.buffers > 0 and history.index <= #history.buffers then
is_navigating = true
vim.cmd('buffer ' .. history.buffers[history.index])
vim.schedule(function() is_navigating = false end)
end
-- Delete the buffer
vim.cmd('bd ' .. current_buf)
end)
-- Clean up history when a tab is closed
vim.api.nvim_create_autocmd("TabClosed", {
callback = function()
local closed_tab = tonumber(vim.fn.expand("<afile>"))
if closed_tab then
tab_buffer_histories[closed_tab] = nil
end
end
})
-- Makes shift+j not move cursor to the end
vim.keymap.set("n", "J", "mzJ`z")
-- collapse a tag with the cursor at the start of the tag
vim.keymap.set("n", "<leader>j", "gJdw:j!<CR>", { silent = true })
-- nnoremap <silent> <C-l> :nohl<CR><C-l>
-- vim.keymap.set("n", "<C-l>", vim.cmd(":nohl<CR><C-l>"))
-- Visual Mode: Move blocks of lines up or down
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv'")
vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv'")
-- Autopairs sometimes wraps things, and sometimes doesnt
-- This is for wrapping a word in a pair
vim.keymap.set("n", "<leader>e{", "bcw{}<ESC>P")
vim.keymap.set("n", "<leader>e[", "bcw[]<ESC>P")
vim.keymap.set("n", "<leader>e<", "bcw<><ESC>P")
vim.keymap.set("n", "<leader>e(", "bcw()<ESC>P")
vim.keymap.set("n", "<leader>e'", "bcw''<ESC>P")
vim.keymap.set("n", "<leader>e\"", "bcw\"\"<ESC>P")
vim.keymap.set("n", "<leader>e`", "bcw``<ESC>P")
-- vertical movements
-- center cursor after going up or down
vim.keymap.set("n", "<C-d>", "<C-d>zz")
vim.keymap.set("n", "<C-u>", "<C-u>zz")
-- lsp restart
vim.keymap.set('n', '<leader>l', function()
vim.cmd('LspRestart')
vim.defer_fn(function()
-- Reload the plugin module
package.loaded['symbol-usage'] = nil
require('symbol-usage').refresh()
end, 1000)
end, { desc = 'Restart LSP and reload symbol-usage' })

View File

@@ -1,83 +0,0 @@
-- leader timeout
vim.opt.timeoutlen = 350
-- Vim sets and globals
vim.opt.wrap = true
vim.opt.relativenumber = true
vim.opt.mouse = "nvi"
vim.opt.clipboard = "unnamedplus" -- Able to yank and paste crap from anywhere
vim.opt.guicursor = "i-ci:ver30-iCursor-blinkwait300-blinkon200-blinkoff150"
vim.opt.termguicolors = true
vim.opt.encoding = "utf-8"
vim.opt.cursorline = true -- Current line tracking
vim.opt.number = true -- Current line number display
vim.opt.backup = false
vim.opt.writebackup = false
vim.opt.undodir = os.getenv("HOME") .. "/.vim/undodir"
vim.opt.undofile = true
vim.opt.updatetime = 50
vim.opt.signcolumn = "no"
vim.opt.scrolloff = 8
-- Indenting
-- vim.opt.smartindent = true
vim.opt.tabstop = 4
vim.opt.softtabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.api.nvim_create_autocmd({"FileType"}, {
pattern = {"typescriptreact", "typescript", "javascript", "css", "html", "htmldjango", "yaml", "json", "md", "toml"},
command = "setlocal shiftwidth=2 tabstop=2 softtabstop=2"
})
vim.g.grepper = {tools = {"rg"}} -- This is for replace in project, ripgrep required
vim.opt.wildignore:append{"*/node_modules/*", "*/venv/*"}
vim.opt.path:append{"**"} -- find files down subfolders
vim.g.python_host_prog = "/usr/bin/python2"
vim.g.python3_host_prog = "/usr/bin/python3"
-- skeletons
vim.cmd [[autocmd BufNewFile *.py 0r ~/.config/nvim/templates/skeleton.py]]
vim.cmd [[autocmd BufNewFile *.sh 0r ~/.config/nvim/templates/skeleton.sh]]
-- filetypes
vim.filetype.add({
extension = {
templ = "templ",
},
})
-- popout styling
vim.api.nvim_create_autocmd("ColorScheme", {
callback = function()
vim.api.nvim_set_hl(0, "NormalFloat", { bg = "none" })
vim.api.nvim_set_hl(0, "FloatBorder", { bg = "none" })
end,
})
vim.keymap.set('n', '<leader>x', function()
vim.lsp.buf.clear_references()
local win_ids = vim.fn.getwininfo()
for _, win in pairs(win_ids) do
if win.quickfix == 0 and win.loclist == 0 and win.terminal == 0 and win.tabnr == vim.fn.tabpagenr() then
if vim.api.nvim_win_get_config(win.winid).relative ~= '' then
vim.api.nvim_win_close(win.winid, false)
end
end
end
end, { desc = "Close LSP floating windows" })
-- disable italics on conditionals
vim.api.nvim_create_autocmd("ColorScheme", {
pattern = "*",
callback = function()
-- Get all highlight groups and remove italic styling
for _, group in ipairs(vim.fn.getcompletion("", "highlight")) do
local hl = vim.api.nvim_get_hl(0, { name = group })
if hl.italic then
hl.italic = nil
vim.api.nvim_set_hl(0, group, hl)
end
end
end,
})

View File

@@ -0,0 +1,165 @@
-- project / netrw
vim.keymap.set("n", "<leader>E", "<cmd>Ex<CR>", { desc = "Open netrw" })
vim.keymap.set("n", "<leader>ER", "<cmd>bw<CR>", { desc = "Close buffer" })
vim.keymap.set("n", "<leader>sr", ":cd %:p:h<CR>", { desc = "Set cwd to file dir" })
-- split navigation
vim.keymap.set("n", "<A-Left>", "<C-w>h")
vim.keymap.set("n", "<A-Down>", "<C-w>j")
vim.keymap.set("n", "<A-Up>", "<C-w>k")
vim.keymap.set("n", "<A-Right>", "<C-w>l")
-- netrw duplicate helper (<leader>d)
vim.api.nvim_create_autocmd("FileType", {
pattern = "netrw",
callback = function()
vim.keymap.set("n", "<leader>d", function()
local cwd = vim.fn.getcwd()
vim.cmd("lcd %:p:h")
vim.api.nvim_feedkeys("mt", "x", false)
vim.api.nvim_feedkeys("mf", "x", false)
vim.api.nvim_feedkeys("mc", "x", false)
vim.defer_fn(function()
vim.fn.chdir(cwd)
end, 500)
end, { buffer = true, desc = "Duplicate file in netrw" })
end,
})
-- buffer history (per-tab)
local hist_by_tab = {}
local navigating = false
local function tab_hist()
local t = vim.fn.tabpagenr()
hist_by_tab[t] = hist_by_tab[t] or { bufs = {}, idx = 1 }
return hist_by_tab[t]
end
vim.api.nvim_create_autocmd("BufEnter", {
callback = function()
if navigating then
return
end
local b = vim.fn.bufnr("%")
if not vim.bo[b].buflisted then
return
end
local h = tab_hist()
for i = #h.bufs, 1, -1 do
if h.bufs[i] == b then
table.remove(h.bufs, i)
if i <= h.idx then
h.idx = math.max(1, h.idx - 1)
end
end
end
while h.idx < #h.bufs do
table.remove(h.bufs)
end
table.insert(h.bufs, b)
h.idx = #h.bufs
end,
})
vim.keymap.set("n", "<A-b>", function()
local h = tab_hist()
if h.idx <= 1 then
return
end
navigating = true
h.idx = h.idx - 1
local b = h.bufs[h.idx]
if vim.fn.bufexists(b) == 1 and vim.bo[b].buflisted then
vim.cmd("buffer " .. b)
else
table.remove(h.bufs, h.idx)
h.idx = math.max(1, h.idx - 1)
end
vim.schedule(function()
navigating = false
end)
end, { desc = "Prev buffer (history)" })
vim.keymap.set("n", "<A-n>", function()
local h = tab_hist()
if h.idx >= #h.bufs then
return
end
navigating = true
h.idx = h.idx + 1
local b = h.bufs[h.idx]
if vim.fn.bufexists(b) == 1 and vim.bo[b].buflisted then
vim.cmd("buffer " .. b)
else
table.remove(h.bufs, h.idx)
h.idx = math.min(#h.bufs, h.idx)
end
vim.schedule(function()
navigating = false
end)
end, { desc = "Next buffer (history)" })
vim.keymap.set("n", "<A-c>", function()
local h = tab_hist()
h.bufs = { vim.fn.bufnr("%") }
h.idx = 1
vim.notify("Buffer history cleared")
end, { desc = "Clear buffer history" })
vim.keymap.set("n", "<A-q>", function()
local current = vim.fn.bufnr("%")
local h = tab_hist()
for i = #h.bufs, 1, -1 do
if h.bufs[i] == current then
table.remove(h.bufs, i)
if i <= h.idx then
h.idx = math.max(1, h.idx - 1)
end
end
end
if #h.bufs > 0 and h.idx <= #h.bufs then
navigating = true
vim.cmd("buffer " .. h.bufs[h.idx])
vim.schedule(function()
navigating = false
end)
end
vim.cmd("bd " .. current)
end, { desc = "Close buffer + keep history" })
vim.api.nvim_create_autocmd("TabClosed", {
callback = function()
local closed = tonumber(vim.fn.expand("<afile>"))
if closed then
hist_by_tab[closed] = nil
end
end,
})
-- editing helpers
vim.keymap.set("n", "J", "mzJ`z")
vim.keymap.set("n", "<leader>j", "gJdw:j!<CR>", { silent = true, desc = "Collapse tag line" })
vim.keymap.set("v", "J", ":m '>+1<CR>gv=gv")
vim.keymap.set("v", "K", ":m '<-2<CR>gv=gv")
-- centered paging
vim.keymap.set("n", "<C-d>", "<C-d>zz")
vim.keymap.set("n", "<C-u>", "<C-u>zz")
-- close floats + clear refs
vim.keymap.set("n", "<leader>x", function()
vim.lsp.buf.clear_references()
for _, win in ipairs(vim.api.nvim_list_wins()) do
local cfg = vim.api.nvim_win_get_config(win)
if cfg.relative ~= "" then
pcall(vim.api.nvim_win_close, win, false)
end
end
end, { desc = "Close floating windows" })

View File

@@ -0,0 +1,72 @@
vim.g.mapleader = " "
vim.opt.timeoutlen = 350
vim.opt.updatetime = 50
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.cursorline = true
vim.opt.wrap = true
vim.opt.termguicolors = true
vim.opt.signcolumn = "no"
vim.opt.scrolloff = 8
vim.opt.mouse = "nvi"
vim.opt.guicursor = "i-ci:ver30-iCursor-blinkwait300-blinkon200-blinkoff150"
vim.opt.clipboard = "unnamedplus"
vim.opt.backup = false
vim.opt.writebackup = false
local undo_dir = vim.fs.joinpath(vim.fn.stdpath("state"), "undo")
vim.fn.mkdir(undo_dir, "p")
vim.opt.undodir = undo_dir
vim.opt.undofile = true
vim.opt.tabstop = 4
vim.opt.softtabstop = 4
vim.opt.shiftwidth = 4
vim.opt.expandtab = true
vim.api.nvim_create_autocmd("FileType", {
pattern = {
"typescriptreact",
"typescript",
"javascript",
"css",
"html",
"htmldjango",
"yaml",
"json",
"markdown",
"toml",
},
callback = function()
vim.opt_local.shiftwidth = 2
vim.opt_local.tabstop = 2
vim.opt_local.softtabstop = 2
end,
})
vim.opt.wildignore:append({ "*/node_modules/*", "*/venv/*" })
vim.opt.path:append({ "**" })
vim.g.python3_host_prog = "/usr/bin/python3"
vim.filetype.add({
extension = { templ = "templ" },
})
vim.api.nvim_create_autocmd("BufNewFile", {
pattern = "*.py",
callback = function()
vim.cmd("0r " .. vim.fn.fnameescape(vim.fs.joinpath(vim.fn.stdpath("config"), "templates", "skeleton.py")))
end,
})
vim.api.nvim_create_autocmd("BufNewFile", {
pattern = "*.sh",
callback = function()
vim.cmd("0r " .. vim.fn.fnameescape(vim.fs.joinpath(vim.fn.stdpath("config"), "templates", "skeleton.sh")))
end,
})

16
nvim/lua/utils/lazy.lua Normal file
View File

@@ -0,0 +1,16 @@
local M = {}
local loaded = {}
function M.load_once(key, specs, setup)
if loaded[key] then
return
end
loaded[key] = true
vim.pack.add(specs)
if setup then
setup()
end
end
return M

92
nvim/lua/utils/pack.lua Normal file
View File

@@ -0,0 +1,92 @@
local M = {}
local registry = require("plugins.registry")
function M.registry(names)
return registry.by_names(names)
end
-- Backward-compatible alias
M.specs = M.registry
function M.add(names, opts)
vim.pack.add(M.registry(names), opts)
end
function M.names()
return registry.names()
end
function M.setup()
local group = vim.api.nvim_create_augroup("UserPackHooks", { clear = true })
vim.api.nvim_create_autocmd("PackChanged", {
group = group,
callback = function(ev)
local name, kind = ev.data.spec.name, ev.data.kind
if name == "nvim-treesitter" and kind == "update" then
if not ev.data.active then
vim.cmd.packadd("nvim-treesitter")
end
pcall(vim.cmd, "TSUpdate")
end
end,
})
vim.api.nvim_create_user_command("PackInstall", function()
M.add(M.names(), {
confirm = false,
load = function() end,
})
vim.notify("PackInstall: ensured all configured plugins are installed", vim.log.levels.INFO)
end, { desc = "Install all configured vim.pack plugins without loading" })
vim.api.nvim_create_user_command("PackUpdate", function(opts)
local names = (#opts.fargs > 0) and opts.fargs or nil
vim.pack.update(names)
end, {
nargs = "*",
complete = function(arglead)
local out = {}
for _, name in ipairs(M.names()) do
if name:find("^" .. vim.pesc(arglead)) then
table.insert(out, name)
end
end
return out
end,
desc = "Update vim.pack plugins (optionally pass plugin names)",
})
vim.api.nvim_create_user_command("PackSync", function()
vim.pack.update(nil, { target = "lockfile" })
end, { desc = "Sync installed plugins to nvim-pack-lock.json" })
vim.api.nvim_create_user_command("PackClean", function()
local stale = vim.iter(vim.pack.get())
:filter(function(p)
return not p.active
end)
:map(function(p)
return p.spec.name
end)
:totable()
if #stale == 0 then
vim.notify("PackClean: nothing to clean", vim.log.levels.INFO)
return
end
local msg = "PackClean will remove:\n - " .. table.concat(stale, "\n - ")
local choice = vim.fn.confirm(msg, "&Yes\n&No", 2)
if choice ~= 1 then
vim.notify("PackClean: cancelled", vim.log.levels.INFO)
return
end
vim.pack.del(stale)
vim.notify("PackClean: removed " .. #stale .. " plugin(s)", vim.log.levels.INFO)
end, { desc = "Delete inactive vim.pack plugins from disk" })
end
return M

16
nvim/lua/utils/ui.lua Normal file
View File

@@ -0,0 +1,16 @@
local M = {}
function M.border(hl)
return {
{ "", hl },
{ "", hl },
{ "", hl },
{ "", hl },
{ "", hl },
{ "", hl },
{ "", hl },
{ "", hl },
}
end
return M