My nvim configuration
| 1 | local diagnostics_enabled = true |
| 2 | vim.api.nvim_create_user_command("ToggleDiagnostics", function(_) |
| 3 | vim.diagnostic.enable(not diagnostics_enabled) |
| 4 | end, { desc = "Toggles Diagnostics" }) |
| 5 | |
| 6 | -- Open DBUI in a new tab. |
| 7 | vim.api.nvim_create_user_command("DBUITab", function(_) |
| 8 | -- Make directory in /tmp/sql so the directory is called sql |
| 9 | if vim.fn.isdirectory("/tmp/sql") == 0 then |
| 10 | vim.fn.mkdir("/tmp/sql") |
| 11 | end |
| 12 | |
| 13 | -- Open new tab to /tmp/sql and load DBUI |
| 14 | vim.cmd("tabnew") |
| 15 | vim.cmd("tcd /tmp/sql") |
| 16 | vim.cmd("DBUI") |
| 17 | end, { desc = "Open new tab in /tmp/sql with DBUI" }) |
| 18 | |
| 19 | --- New buffer for given file type |
| 20 | vim.api.nvim_create_user_command("Enew", function(opts) |
| 21 | vim.cmd("enew") |
| 22 | vim.bo.filetype = opts.args |
| 23 | end, { |
| 24 | desc = "New buffer for file type", |
| 25 | nargs = 1, |
| 26 | complete = function(arglead) |
| 27 | return vim.fn.getcompletion(arglead, "filetype") |
| 28 | end, |
| 29 | }) |
| 30 | |
| 31 | -- ########################################################################## -- |
| 32 | -- -Scratch |
| 33 | -- ########################################################################## -- |
| 34 | vim.api.nvim_create_user_command("ScratchFromCurrent", function() |
| 35 | -- create new scratch buffer |
| 36 | vim.cmd("enew") |
| 37 | vim.bo.buftype = "nofile" |
| 38 | vim.bo.bufhidden = "hide" |
| 39 | vim.bo.swapfile = false |
| 40 | vim.bo.buflisted = false |
| 41 | -- fill it with the contents of the previous buffer |
| 42 | local prev = vim.fn.bufnr("#") -- previous buffer |
| 43 | if prev ~= -1 then |
| 44 | local lines = vim.api.nvim_buf_get_lines(prev, 0, -1, false) |
| 45 | vim.api.nvim_buf_set_lines(0, 0, -1, false, lines) |
| 46 | end |
| 47 | vim.notify("📄 Copied current buffer into a scratch buffer") |
| 48 | end, { desc = "Copy current buffer contents into scratch" }) |
| 49 | |
| 50 | -- In your main config (init.lua) |
| 51 | vim.api.nvim_create_autocmd("FileType", { |
| 52 | pattern = "javascript", |
| 53 | callback = function() |
| 54 | vim.bo.shiftwidth = 2 |
| 55 | vim.bo.tabstop = 2 |
| 56 | vim.bo.softtabstop = 2 |
| 57 | vim.bo.expandtab = true |
| 58 | end, |
| 59 | }) |
| 60 | -- ########################################################################## -- |
| 61 | -- -Filetypes |
| 62 | -- ########################################################################## -- |
| 63 | vim.api.nvim_create_autocmd("BufEnter", { |
| 64 | pattern = ".env*", |
| 65 | callback = function(_) |
| 66 | vim.bo.filetype = "env" |
| 67 | vim.bo.syntax = "sh" |
| 68 | end, |
| 69 | }) |
| 70 | |
| 71 | vim.api.nvim_create_autocmd("BufEnter", { |
| 72 | pattern = "*.tf", |
| 73 | callback = function(_) |
| 74 | vim.bo.filetype = "terraform" |
| 75 | end, |
| 76 | }) |
| 77 | |
| 78 | vim.api.nvim_create_autocmd("BufEnter", { |
| 79 | pattern = "*.zsh", |
| 80 | callback = function() |
| 81 | vim.bo.filetype = "sh" |
| 82 | vim.bo.syntax = "sh" |
| 83 | end, |
| 84 | }) |
| 85 | |
| 86 | -- ########################################################################## -- |
| 87 | -- -BigFile |
| 88 | -- ########################################################################## -- |
| 89 | local bigfile_group = vim.api.nvim_create_augroup("BigFile", { clear = true }) |
| 90 | local BIGFILE_BYTES = 1024 * 1024 -- 1 MB |
| 91 | |
| 92 | vim.api.nvim_create_autocmd("BufReadPre", { |
| 93 | group = bigfile_group, |
| 94 | callback = function(args) |
| 95 | local ok, stat = pcall(vim.loop.fs_stat, vim.api.nvim_buf_get_name(args.buf)) |
| 96 | if not ok or not stat or stat.size < BIGFILE_BYTES then |
| 97 | return |
| 98 | end |
| 99 | vim.b[args.buf].bigfile = true |
| 100 | vim.bo[args.buf].swapfile = false |
| 101 | vim.bo[args.buf].undolevels = -1 |
| 102 | vim.opt_local.foldmethod = "manual" |
| 103 | vim.opt_local.spell = false |
| 104 | end, |
| 105 | }) |
| 106 | |
| 107 | vim.api.nvim_create_autocmd("BufReadPost", { |
| 108 | group = bigfile_group, |
| 109 | callback = function(args) |
| 110 | if not vim.b[args.buf].bigfile then |
| 111 | return |
| 112 | end |
| 113 | vim.cmd("syntax clear") |
| 114 | vim.bo[args.buf].syntax = "off" |
| 115 | pcall(vim.treesitter.stop, args.buf) |
| 116 | pcall(vim.cmd, "NoMatchParen") |
| 117 | vim.opt_local.cursorline = false |
| 118 | vim.opt_local.relativenumber = false |
| 119 | end, |
| 120 | }) |
| 121 | |
| 122 | -- ########################################################################## -- |
| 123 | -- -Compiler |
| 124 | -- ########################################################################## -- |
| 125 | vim.api.nvim_create_user_command("Comp", function(args) |
| 126 | vim.cmd("comp " .. args.args) |
| 127 | vim.g.compiler = args.args |
| 128 | end, { |
| 129 | nargs = 1, |
| 130 | complete = "compiler", |
| 131 | desc = "Wrapper around compiler to make current compiler available to UI", |
| 132 | }) |
| 133 | |
| 134 | local |
| 135 | local handle = io.popen("grep -o -P '^\\w.*(?=:)' Makefile 2>/dev/null") |
| 136 | if not handle then |
| 137 | return {} |
| 138 | end |
| 139 | |
| 140 | local result = {} |
| 141 | for line in handle:lines() do |
| 142 | table.insert(result, line) |
| 143 | end |
| 144 | handle:close() |
| 145 | |
| 146 | return result |
| 147 | end |
| 148 | |
| 149 | vim.api.nvim_create_user_command("DJ", function(args) |
| 150 | vim.cmd("Comp django") |
| 151 | vim.cmd("set makeprg=make") |
| 152 | vim.cmd("Make " .. args.args) |
| 153 | end, { |
| 154 | nargs = "*", |
| 155 | complete = get_make_completions, |
| 156 | desc = "Run make commands with django compiler", |
| 157 | }) |
| 158 | |
| 159 | vim.api.nvim_create_user_command("DJTest", function(args) |
| 160 | vim.cmd("Comp django") |
| 161 | vim.cmd([[set makeprg=python\ manage.py]]) |
| 162 | vim.cmd("Make test --keepdb " .. args.args) |
| 163 | end, { |
| 164 | nargs = "*", |
| 165 | complete = "file", |
| 166 | desc = "Run django test --keepdb into quickfix", |
| 167 | }) |
| 168 | |
| 169 | -- ########################################################################## -- |
| 170 | -- -Tabs |
| 171 | -- ########################################################################## -- |
| 172 | vim.api.nvim_create_user_command("Tab", function(args) |
| 173 | vim.cmd("tabnew") |
| 174 | vim.cmd("tcd " .. args.args) |
| 175 | end, { |
| 176 | nargs = 1, |
| 177 | complete = "dir", |
| 178 | }) |
| 179 | |
| 180 | vim.api.nvim_create_user_command("TabRename", function(opts) |
| 181 | vim.t.tabname = opts.args |
| 182 | vim.cmd.redrawtabline() |
| 183 | end, { nargs = 1, complete = "file", desc = "Rename current tab" }) |
| 184 | |
| 185 | -- ########################################################################## -- |
| 186 | -- -Buffers |
| 187 | -- ########################################################################## -- |
| 188 | |
| 189 | -- Clean buffers |
| 190 | vim.api.nvim_create_user_command("BufClean", function() |
| 191 | -- Collect all visible buffers from every tab/window |
| 192 | local visible = {} |
| 193 | for _, win in ipairs(vim.api.nvim_list_wins()) do |
| 194 | local buf = vim.api.nvim_win_get_buf(win) |
| 195 | visible[buf] = true |
| 196 | end |
| 197 | |
| 198 | local deleted = 0 |
| 199 | for _, buf in ipairs(vim.api.nvim_list_bufs()) do |
| 200 | ---@diagnostic disable-next-line |
| 201 | if vim.api.nvim_buf_is_loaded(buf) and not visible[buf] and vim.api.nvim_buf_get_option(buf, "buflisted") then |
| 202 | vim.api.nvim_buf_delete(buf, { force = true }) |
| 203 | deleted = deleted + 1 |
| 204 | end |
| 205 | end |
| 206 | |
| 207 | vim.notify("🧹 Deleted " .. deleted .. " hidden buffers (tabs kept intact)") |
| 208 | end, { desc = "Delete hidden buffers but keep tab buffers intact" }) |
| 209 | |
| 210 | local last_buf = nil |
| 211 | vim.api.nvim_create_autocmd("BufLeave", { |
| 212 | callback = function(args) |
| 213 | local buf = vim.bo[args.buf] |
| 214 | if buf.buflisted and vim.api.nvim_buf_is_valid(args.buf) and not buf.readonly then |
| 215 | last_buf = args.buf |
| 216 | end |
| 217 | end, |
| 218 | }) |
| 219 | vim.api.nvim_create_user_command("LastFile", function() |
| 220 | if last_buf and vim.api.nvim_buf_is_valid(last_buf) then |
| 221 | vim.api.nvim_set_current_buf(last_buf) |
| 222 | else |
| 223 | vim.notify("No last buffer recorded", vim.log.levels.WARN) |
| 224 | end |
| 225 | end, {}) |
| 226 | |
| 227 | -- Runs pyright on a directory |
| 228 | vim.api.nvim_create_user_command("Pyright", function(opts) |
| 229 | local lsp_file = vim.api.nvim_get_runtime_file("lsp/basedpyright.lua", false)[1] |
| 230 | local analysis = vim.tbl_get(dofile(lsp_file), "settings", "basedpyright", "analysis") or {} |
| 231 | |
| 232 | local cwd = vim.fn.getcwd() |
| 233 | local target = opts.args ~= "" and vim.fn.fnamemodify(opts.args, ":p") or cwd |
| 234 | |
| 235 | local cfg = { |
| 236 | include = { target }, |
| 237 | typeCheckingMode = analysis.typeCheckingMode, |
| 238 | useLibraryCodeForTypes = analysis.useLibraryCodeForTypes, |
| 239 | } |
| 240 | for k, v in pairs(analysis.diagnosticSeverityOverrides or {}) do |
| 241 | if type(v) == "boolean" then |
| 242 | cfg[k] = v and "error" or "none" |
| 243 | else |
| 244 | cfg[k] = v |
| 245 | end |
| 246 | end |
| 247 | |
| 248 | -- extend project's pyrightconfig.json if present so venv/exclude/extraPaths are preserved |
| 249 | local project_cfg = vim.fn.findfile("pyrightconfig.json", cwd .. ";") |
| 250 | if project_cfg ~= "" then |
| 251 | cfg.extends = vim.fn.fnamemodify(project_cfg, ":p") |
| 252 | end |
| 253 | |
| 254 | -- place the temp config inside the project so relative paths, venv, and site-packages resolve |
| 255 | local tmp = cwd .. "/.pyright-qf-tmp.json" |
| 256 | local f = assert(io.open(tmp, "w")) |
| 257 | f:write(vim.json.encode(cfg)) |
| 258 | f:close() |
| 259 | |
| 260 | local result = vim.system({ "basedpyright", "-p", tmp }, { cwd = cwd, text = true }):wait() |
| 261 | os.remove(tmp) |
| 262 | |
| 263 | local lines = vim.split((result.stdout or "") .. (result.stderr or ""), "\n") |
| 264 | vim.fn.setqflist({}, " ", { |
| 265 | title = "basedpyright", |
| 266 | lines = lines, |
| 267 | efm = "%f:%l:%c - error: %m,%f:%l:%c - warning: %m", |
| 268 | }) |
| 269 | vim.cmd("copen") |
| 270 | end, { nargs = "?", complete = "dir", desc = "Run basedpyright into quickfix using LSP settings" }) |
| 271 | |
| 272 | -- ########################################################################## -- |
| 273 | -- -Vimscript |
| 274 | -- ########################################################################## -- |
| 275 | vim.cmd([[ |
| 276 | command! -nargs=+ SetMakePrg execute 'set makeprg='.substitute(<q-args>, ' ', '\\ ', 'g') |
| 277 | command! ToggleClist if empty(filter(getwininfo(), 'v:val.quickfix')) | copen | else | cclose | endif |
| 278 | command! EditCurrentFiletype execute 'edit ~/.config/nvim/after/ftplugin/'.&filetype.'.lua' |
| 279 | command! Format lua require("conform").format() |
| 280 | command! TreeSitterFold setlocal foldexpr=v:lua.vim.treesitter.foldexpr() | setlocal foldmethod=expr |
| 281 | command! IndentFold setlocal foldmethod=indent |
| 282 | command! SyntaxFold setlocal foldmethod=syntax |
| 283 | command! -nargs=* Scratch enew | setlocal buftype=nofile bufhidden=hide noswapfile |
| 284 | command! -nargs=+ R enew | setlocal buftype=nofile bufhidden=hide noswapfile | silent read !<args> |
| 285 | command! -nargs=+ LinesOfCode execute '!find ./'.substitute(split(<q-args>)[0], ',', ' ./', '-g').' -name "*.'.substitute(split(<q-args>)[1], ',', '" -o -name "*.', 'g').'" | xargs wc -l' |
| 286 | command! SafeBD if winnr('$')==1 | echoerr 'Refuse to close last window' | else | silent! bd! | endif |
| 287 | command! -nargs=* TN tabe | tcd <args> |
| 288 | command! -nargs=+ Qfjob call add(g:qfjobs, [jobstart(<q-args>, {'on_stdout':'JobHandler', 'on_stderr':'JobHandler'}), <q-args>]) |
| 289 | command! RuffCheck cgetexpr system('ruff check --output-format=concise') | copen |
| 290 | command! Killqfjobs for j in g:qfjobs | call jobstop(j[0]) | endfor | set g:qfjobs=[] |
| 291 | command! Restartqfjobs for j in g:qfjobs | call jobstop(j[0]) | let j[0] = jobstart(j[1]) | endfor |
| 292 | command! -nargs=1 Resize silent! exe 'resize '.(&lines*<args>/100) |
| 293 | command! -nargs=1 ConfigTab tabnew | exe 'tcd ~/.config/'.<q-args> |
| 294 | |
| 295 | augroup AutoHighlighting |
| 296 | au! |
| 297 | autocmd CmdlineEnter /,\? set hlsearch |
| 298 | autocmd CmdlineLeave /,\? set nohlsearch |
| 299 | augroup END |
| 300 | |
| 301 | autocmd InsertLeave,TextChanged,FocusLost * if &modifiable && !&readonly | silent! wall | endif |
| 302 | autocmd BufWritePre * silent! lua vim.lsp.buf.format() |
| 303 | ]]) |