Files
nvim/lua/plugins.lua
T

328 lines
12 KiB
Lua

vim.pack.add({
{ src = "https://github.com/ellisonleao/gruvbox.nvim" },
{ src = "https://github.com/stevearc/oil.nvim" },
{ src = "https://github.com/echasnovski/mini.pick" },
{ src = "https://github.com/echasnovski/mini.extra" },
{ src = "https://github.com/echasnovski/mini.icons" },
{ src = "https://github.com/echasnovski/mini.jump" },
{ src = "https://github.com/echasnovski/mini.jump2d" },
{ src = "https://github.com/neovim/nvim-lspconfig" },
{ 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/Saghen/blink.cmp" },
{ src = "https://github.com/saghen/blink.lib" },
{ src = "https://github.com/mason-org/mason.nvim" },
{ src = "https://github.com/nvim-lualine/lualine.nvim.git" },
{ src = "https://github.com/chomosuke/typst-preview.nvim" },
{ src = "https://codeberg.org/mfussenegger/nvim-jdtls.git" },
{ src = "https://github.com/windwp/nvim-autopairs" },
{ src = "https://codeberg.org/mfussenegger/nvim-dap.git" },
{ src = "https://github.com/echasnovski/mini.ai" },
{ src = "https://github.com/windwp/nvim-ts-autotag" },
{ src = "https://github.com/nvim-lua/plenary.nvim" },
{ src = "https://github.com/folke/todo-comments.nvim" },
{ src = "https://github.com/stevearc/conform.nvim" },
{ src = "https://github.com/lewis6991/gitsigns.nvim" },
{ src = "https://github.com/MeanderingProgrammer/render-markdown.nvim" },
{ src = "https://github.com/folke/trouble.nvim" },
{ src = "https://github.com/nvim-neotest/nvim-nio" },
{ src = "https://github.com/rcarriga/nvim-dap-ui" },
{ src = "https://github.com/theHamsta/nvim-dap-virtual-text" },
{ src = "https://github.com/jay-babu/mason-nvim-dap.nvim" },
{ src = "https://github.com/michaelrommel/nvim-silicon" },
{ src = "https://github.com/hat0uma/csvview.nvim.git" },
{ src = "https://github.com/folke/snacks.nvim" },
})
pcall(vim.cmd.colorscheme, "gruvbox")
-- Simple setup({}) plugins
for _, name in ipairs({
"mini.pick", "mini.extra", "mini.icons", "mason", "typst-preview",
"nvim-autopairs", "mini.jump",
"mini.ai", "nvim-ts-autotag", "todo-comments", "csvview",
}) do
pcall(function() require(name).setup() end)
end
-- Auto-refresh the oil buffer when the filesystem changes externally.
require("oil").setup({ watch_for_changes = true })
-- Open the Trouble window even when there are no results (e.g. no
-- diagnostics) instead of erroring out with "No results".
require("trouble").setup({ open_no_results = true })
require("mini.icons").mock_nvim_web_devicons()
-- Labeled jump-anywhere motion (flash replacement); trigger with <leader>j.
require("mini.jump2d").setup({
mappings = { start_jumping = "<leader>j" },
})
local cmp = require('blink.cmp')
cmp.build():pwait()
cmp.setup({
keymap = {
preset = "super-tab" }
})
local prettier = { "prettierd", "prettier", stop_after_first = true }
require("conform").setup({
formatters_by_ft = {
python = { "black" },
c = { "clang-format" },
cpp = { "clang-format" },
java = { "clang-format" },
javascript = prettier,
typescript = prettier,
css = prettier,
html = prettier,
json = prettier,
markdown = prettier,
yaml = prettier,
haskell = { "fourmolu" },
},
formatters = {
prettier = { prepend_args = { "--tab-width", "4", "--use-tabs", "false" } },
prettierd = { env = { PRETTIERD_DEFAULT_CONFIG = vim.fn.expand("~/.config/nvim/.prettierrc.json") } },
}
})
require("render-markdown").setup({
code = { inline_pad = 0, highlight_inline = "RenderMarkdownCode" },
})
require("snacks").setup({
image = {
enabled = true,
doc = { inline = false },
},
terminal = {},
})
-- Toggle a bottom terminal panel (reuses the same shell instance).
vim.keymap.set({ "n", "t" }, "<leader>t",
function()
Snacks.terminal(nil, {
win = { position = "bottom", height = 10 },
})
end,
{ desc = "Toggle terminal" })
vim.api.nvim_create_autocmd("FileType", {
pattern = "markdown",
callback = function(ev)
local win = vim.api.nvim_get_current_win()
if vim.api.nvim_win_get_config(win).relative == "" then return end
local buf = ev.buf
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)
local changed = false
for i, line in ipairs(lines) do
local new = line:gsub("`(\\[^`]-)`", "$%1$")
if new ~= line then
lines[i] = new
changed = true
end
end
if changed then
vim.bo[buf].modifiable = true
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.bo[buf].modifiable = false
end
end,
})
local silicon_bg = {
typescript = "#1e3a5f",
javascript = "#5c4a1a",
java = "#5c2a1a",
svelte = "#5c1f0a",
css = "#1f3a5c",
python = "#1a3556",
haskell = "#3d1f5c",
c = "#2a3a4d",
cpp = "#2a4d3d",
swift = "#5c3a1a",
lua = "#1f1f5c",
markdown = "#3a2e1f",
tex = "#3a2e1f",
typst = "#3a2e1f",
toml = "#2e2e2e",
yaml = "#2e2e2e",
conf = "#2e2e2e",
ini = "#2e2e2e",
json = "#2e2e2e",
}
require("nvim-silicon").setup({
font = "JetBrainsMono Nerd Font=16",
theme = "gruvbox-dark",
pad_horiz = 60,
pad_vert = 50,
shadow_color = "#0a0a0a",
shadow_blur_radius = 10,
no_round_corner = true,
output = function()
return vim.fn.expand("~/Desktop/silicon_")
.. os.date("!%Y%m%dT%H%M%SZ") .. ".png"
end,
window_title = function()
return vim.fn.fnamemodify(vim.api.nvim_buf_get_name(0), ":t")
end,
})
-- silicon's --tab-width replaces each tab with a fixed number of spaces
-- instead of advancing to the next tab stop, so tab-indented files (e.g.
-- assembly) come out misaligned. Expand tabs ourselves before shooting.
local s = require("nvim-silicon")
local function expand_tabs(line, ts)
local out, col = {}, 0
for i = 1, #line do
local ch = line:sub(i, i)
if ch == "\t" then
local n = ts - (col % ts)
out[#out + 1] = string.rep(" ", n)
col = col + n
else
out[#out + 1] = ch
col = col + 1
end
end
return table.concat(out)
end
local orig_format_lines = s.format_lines
s.format_lines = function(cmdline, args, options)
local lines, cl = orig_format_lines(cmdline, args, options)
local ts = vim.bo.tabstop
for i, line in ipairs(lines) do
lines[i] = expand_tabs(line, ts)
end
return lines, cl
end
local function silicon_shot(to_clipboard)
s.options.background = silicon_bg[vim.bo.filetype] or "#1d2021"
if to_clipboard then s.clip() else s.file() end
end
vim.keymap.set("x", "<leader>cc", function() silicon_shot(true) end,
{ desc = "Silicon: copy code screenshot to clipboard" })
vim.keymap.set("x", "<leader>cs", function() silicon_shot(false) end,
{ desc = "Silicon: save code screenshot to file" })
require("gitsigns").setup({
current_line_blame = true,
current_line_blame_opts = { virt_text_pos = "eol", delay = 300, ignore_whitespace = true },
current_line_blame_formatter = " <author>, <author_time:%R> — <summary>",
-- Buffer-local so the maps only exist in git-tracked files.
on_attach = function(buf)
local gs = require("gitsigns")
local function map(mode, lhs, rhs, desc, opts)
opts = vim.tbl_extend("force", { buffer = buf, desc = "Git: " .. desc }, opts or {})
vim.keymap.set(mode, lhs, rhs, opts)
end
-- Navigation. In a diff window, fall back to builtin ]c/[c.
map("n", "]c", function()
if vim.wo.diff then return "]c" end
vim.schedule(function() gs.nav_hunk("next") end)
return "<Ignore>"
end, "next hunk", { expr = true })
map("n", "[c", function()
if vim.wo.diff then return "[c" end
vim.schedule(function() gs.nav_hunk("prev") end)
return "<Ignore>"
end, "prev hunk", { expr = true })
-- Stage/reset. stage_hunk toggles: run it on a staged hunk to unstage.
map("n", "<leader>hs", gs.stage_hunk, "stage hunk (toggle)")
map("n", "<leader>hr", gs.reset_hunk, "reset hunk")
map("x", "<leader>hs", function() gs.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) end,
"stage selected lines")
map("x", "<leader>hr", function() gs.reset_hunk({ vim.fn.line("."), vim.fn.line("v") }) end,
"reset selected lines")
map("n", "<leader>hS", gs.stage_buffer, "stage buffer")
map("n", "<leader>hR", gs.reset_buffer, "reset buffer")
-- Inspect
map("n", "<leader>hp", gs.preview_hunk, "preview hunk")
map("n", "<leader>hi", gs.preview_hunk_inline, "preview hunk inline")
map("n", "<leader>hb", function() gs.blame_line({ full = true }) end, "blame line (full)")
map("n", "<leader>hB", gs.blame, "blame file")
map("n", "<leader>hd", gs.diffthis, "diff against index")
map("n", "<leader>hD", function() gs.diffthis("~") end, "diff against last commit")
map("n", "<leader>hq", gs.setqflist, "hunks to quickfix")
-- Toggles
map("n", "<leader>htb", gs.toggle_current_line_blame, "toggle inline blame")
map("n", "<leader>htd", gs.toggle_deleted, "toggle deleted lines")
map("n", "<leader>htw", gs.toggle_word_diff, "toggle word diff")
-- Hunk textobject: `dih`, `vih`, ...
map({ "o", "x" }, "ih", gs.select_hunk, "select hunk")
end,
})
-- Start commit messages in insert mode with the cursor on line 1.
vim.api.nvim_create_autocmd("FileType", {
pattern = "gitcommit",
callback = function(ev)
vim.bo[ev.buf].textwidth = 72
vim.wo.spell = true
vim.cmd("startinsert")
end,
})
require("lualine").setup({ options = { theme = "gruvbox_dark" } })
-- Treesitter (main branch: no configs.setup; install parsers manually)
require("nvim-treesitter").install({
"lua", "vim", "vimdoc", "bash", "c", "cpp", "rust", "python",
"javascript", "typescript", "tsx", "svelte", "css", "html",
"json", "toml", "yaml", "markdown", "markdown_inline",
"java", "typst", "vala", "diff",
})
vim.api.nvim_create_autocmd("FileType", {
callback = function()
local lang = vim.treesitter.language.get_lang(vim.bo.filetype)
if lang and not pcall(vim.treesitter.language.inspect, lang) then
local ok, list = pcall(require("nvim-treesitter").language_list)
if ok and vim.list_contains(list, lang) then
require("nvim-treesitter").install(lang)
end
end
pcall(vim.treesitter.start)
end,
})
-- TS textobjects
local tso = require("nvim-treesitter-textobjects.select")
local textobj = {
af = "@function.outer",
["if"] = "@function.inner",
ac = "@class.outer",
ic = "@class.inner",
al = "@loop.outer",
il = "@loop.inner"
}
for lhs, query in pairs(textobj) do
vim.keymap.set({ "x", "o" }, lhs,
function() tso.select_textobject(query, "textobjects") end,
{ desc = "Textobject: " .. query:gsub("@", "") })
end
-- Mason: ensure tools
local registry = require("mason-registry")
local ensure = {
"bash-language-server", "clang-format", "clangd", "java-debug-adapter",
"jdtls", "json-lsp", "lua-language-server", "rust-analyzer",
"svelte-language-server", "tailwindcss-language-server", "taplo",
"typescript-language-server", "pylsp", "black", "vala",
"prettierd",
}
registry.refresh(function()
for _, tool in ipairs(ensure) do
local ok, pkg = pcall(registry.get_package, tool)
if ok and not pkg:is_installed() then pkg:install() end
end
end)