repos / dotfiles

my dotfiles

dotfiles / dot_config / nvim
Eric Bower  ·  2025-07-20

init.lua

  1local o = vim.opt
  2o.tabstop = 2
  3o.shiftwidth = 2
  4o.softtabstop = 2
  5o.expandtab = true
  6o.wrap = false
  7o.autoread = true
  8o.list = true -- show trailing characters
  9o.signcolumn = "yes"
 10o.backspace = "indent,eol,start"
 11o.shell = "/bin/bash"
 12o.colorcolumn = "101"
 13o.completeopt = { "menuone", "noselect", "popup" }
 14o.laststatus = 0
 15o.winborder = "rounded"
 16o.undofile = true
 17o.ignorecase = true
 18o.smartcase = true
 19local g = vim.g
 20g.mapleader = ","
 21g.maplocalleader = ","
 22
 23local opts = { noremap = true, silent = true }
 24local map = vim.keymap.set
 25map("n", "<leader>b", "<C-O>", opts) -- prev item in jumplist
 26map("n", "Q", "<nop>", opts) -- disable "Q"
 27map("n", "<leader>w", ":!make fmt<CR>", opts) -- code format command
 28map("t", "<Esc>", [[<C-\><C-n>]], opts) -- exit terminal mode
 29map("n", "<C-k>", ":wincmd k<CR>", opts) -- navigate splits
 30map("n", "<C-j>", ":wincmd j<CR>", opts)
 31map("n", "<C-h>", ":wincmd h<CR>", opts)
 32map("n", "<C-l>", ":wincmd l<CR>", opts)
 33-- https://github.com/shell-pool/shpool/issues/71#issuecomment-2632396805
 34map({ "n", "v", "i", "t" }, "<C-space><C-d>", function()
 35	vim.cmd("!shpool detach")
 36end)
 37
 38local autocmd = vim.api.nvim_create_autocmd
 39autocmd("Filetype", { pattern = { "qf" }, command = "setlocal wrap" })
 40autocmd("Filetype", { pattern = { "make" }, command = "setlocal tabstop=4 shiftwidth=4 softtabstop=4" })
 41autocmd("Filetype", {
 42	pattern = { "markdown" },
 43	command = "setlocal wrap tw=79 formatoptions+=t tabstop=2 shiftwidth=2 softtabstop=2",
 44})
 45autocmd("FileType", {
 46	group = vim.api.nvim_create_augroup("close_with_q", { clear = true }),
 47	pattern = { "help", "man", "qf", "scratch", "fugitive", "nvim-pack" },
 48	callback = function(args)
 49		map("n", "q", "<cmd>quit<cr>", { buffer = args.buf })
 50	end,
 51})
 52
 53function setup_lsp()
 54	map("n", "<leader>e", vim.diagnostic.open_float, opts)
 55	map("n", "<leader>q", vim.diagnostic.setloclist, opts)
 56
 57	local on_attach = function(client, bufnr)
 58		local chars = {}
 59		for i = 32, 126 do
 60			table.insert(chars, string.char(i))
 61		end
 62		-- auto-complete for any char
 63		client.server_capabilities.completionProvider.triggerCharacters = chars
 64		vim.lsp.completion.enable(true, client.id, bufnr, { -- built-in auto-complete
 65			autotrigger = true,
 66			convert = function(item)
 67				return { abbr = item.label:gsub("%b()", "") }
 68			end,
 69		})
 70		local bufopts = { noremap = true, silent = true, buffer = bufnr }
 71
 72		-- See `:help vim.lsp.*` for documentation on any of the below functions
 73		map("n", "<leader>d", vim.lsp.buf.definition, bufopts)
 74		map("n", "<leader>D", vim.lsp.buf.type_definition, bufopts)
 75		map("n", "<leader>h", vim.lsp.buf.hover, bufopts)
 76		map("n", "<leader>r", vim.lsp.buf.references, bufopts)
 77		map("n", "<leader>i", vim.lsp.buf.implementation, bufopts)
 78		map("i", "<C-k>", vim.lsp.completion.get, bufopts) -- open completion menu manually
 79	end
 80
 81	local nvim_lsp = require("lspconfig")
 82	function handler(server_name)
 83		local opts = {
 84			capabilities = capabilities,
 85			on_attach = on_attach,
 86		}
 87		if server_name == "denols" then
 88			opts.root_dir = nvim_lsp.util.root_pattern("deno.json", "deno.jsonc")
 89		elseif server_name == "ts_ls" then
 90			opts.root_dir = nvim_lsp.util.root_pattern("package.json")
 91			-- https://github.com/neovim/nvim-lspconfig/issues/2507#issuecomment-1471438640
 92			opts.single_file_support = false
 93		end
 94		nvim_lsp[server_name].setup(opts)
 95	end
 96
 97	-- npm i -g vscode-langservers-extracted
 98	handler("cssls")
 99	handler("denols")
100	handler("gopls")
101	handler("html")
102	handler("jsonls")
103	-- npm i -g pyright
104	handler("pyright")
105	-- npm i -g typescript typescript-language-server
106	handler("ts_ls")
107	handler("zls")
108end
109
110function setup_fzf()
111	local fzf = require("fzf-lua")
112	local fzf_files = function()
113		fzf.files({ winopts = { preview = { hidden = "hidden" } } })
114	end
115	local fzf_symbols = function()
116		fzf.lsp_document_symbols({ winopts = { preview = { hidden = "hidden" } } })
117	end
118	map("n", "<leader>s", fzf_files, { desc = "Fzf Files", noremap = true, silent = true })
119	map("n", "<leader>F", fzf_symbols, { desc = "Fzf Symbols", noremap = true, silent = true })
120	map("n", "<leader>f", fzf.buffers, { desc = "Fzf Buffers", noremap = true, silent = true })
121	map("n", "<leader>S", fzf.live_grep, { desc = "Fzf Grep", noremap = true, silent = true })
122	fzf.setup({ "max-perf" })
123end
124
125vim.pack.add({
126	"https://github.com/nvim-lua/plenary.nvim",
127	"https://github.com/Mofiqul/dracula.nvim",
128	{ src = "https://github.com/nvim-treesitter/nvim-treesitter", version = "main" },
129	"https://github.com/nvim-treesitter/nvim-treesitter-context",
130	"https://github.com/neovim/nvim-lspconfig",
131	"https://github.com/ibhagwan/fzf-lua",
132	"https://github.com/karb94/neoscroll.nvim",
133	"https://github.com/ruifm/gitlinker.nvim",
134	"https://github.com/tpope/vim-fugitive",
135})
136require("dracula").setup({})
137vim.cmd([[colorscheme dracula]])
138
139local ts_parsers = {
140	"bash",
141	"c",
142	"dockerfile",
143	"fish",
144	"git_config",
145	"git_rebase",
146	"gitattributes",
147	"gitcommit",
148	"gitignore",
149	"go",
150	"gomod",
151	"gosum",
152	"html",
153	"javascript",
154	"json",
155	"lua",
156	"make",
157	"markdown",
158	"python",
159	"rust",
160	"sql",
161	"toml",
162	"tsx",
163	"typescript",
164	"typst",
165	"vim",
166	"yaml",
167	"zig",
168}
169local nts = require("nvim-treesitter")
170nts.install(ts_parsers)
171autocmd("PackChanged", {
172	callback = function(args)
173		local spec = args.data.spec
174		if spec and spec.name == "nvim-treesitter" and args.data.kind == "update" then
175			vim.notify("nvim-treesitter was updated, updating parsers", vim.log.levels.INFO)
176			vim.schedule(function()
177				nts.update()
178			end)
179		end
180	end,
181})
182
183setup_lsp()
184setup_fzf()
185require("treesitter-context").setup({
186	max_lines = 3,
187	multiline_threshold = 1,
188	separator = "-",
189	min_window_height = 20,
190	line_numbers = true,
191})
192require("neoscroll").setup({ duration_multiplier = 0.4 })
193require("gitlinker").setup({})
194
195autocmd("FileType", { -- enable treesitter highlighting and indents
196	callback = function(args)
197		local filetype = args.match
198		local lang = vim.treesitter.language.get_lang(filetype)
199		if vim.treesitter.language.add(lang) then
200			vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
201			vim.treesitter.start()
202		end
203	end,
204})