local function augroup(name) return vim.api.nvim_create_augroup("nvim_" .. name, { clear = true }) end -- smart column only when needed local smart_column_group = vim.api.nvim_create_augroup('SmartColumn', { clear = true }) vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI', 'BufEnter' }, { group = smart_column_group, callback = function() local limit = 120 local disabled_fts = { 'help', 'text', 'markdown', 'oil', 'snacks_dashboard', 'dashboard' } if vim.tbl_contains(disabled_fts, vim.bo.filetype) then vim.wo.colorcolumn = '' return end local curr_line = vim.api.nvim_get_current_line() if vim.fn.strdisplaywidth(curr_line) > limit then vim.wo.colorcolumn = tostring(limit) else vim.wo.colorcolumn = '' end end, }) -- Secure .env Masking local env_ns = vim.api.nvim_create_namespace("secure_env") local function toggle_env(buf) local is_mod = vim.bo[buf].modified vim.bo[buf].modifiable = true if vim.b[buf].env_cache then vim.api.nvim_buf_set_lines(buf, 0, -1, false, vim.b[buf].env_cache) vim.api.nvim_buf_clear_namespace(buf, env_ns, 0, -1) vim.b[buf].env_cache = nil else local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) vim.b[buf].env_cache = vim.deepcopy(lines) for i, l in ipairs(lines) do if not l:match("^%s*#") then lines[i] = l:gsub("(=%s*[\"']?)(.-)([\"']?%s*)$", function(p, v, s) return #v > 0 and (p .. string.rep("*", math.max(#v, 8)) .. s) or l end) end end vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) vim.api.nvim_buf_set_extmark(buf, env_ns, 0, 0, { virt_text = {{" [Values Hidden]", "WarningMsg"}}, virt_text_pos = "eol" }) vim.bo[buf].modifiable = false end vim.bo[buf].modified = is_mod end vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile", "BufWriteCmd" }, { group = augroup("secure_env"), pattern = { ".env", ".env.*", "*.env" }, callback = function(args) local ev, buf = args.event, args.buf if ev == "BufReadPost" or ev == "BufNewFile" then vim.keymap.set("n", "et", function() toggle_env(buf) end, { buffer = buf, desc = "Toggle env" }) if not vim.b[buf].env_cache then toggle_env(buf) end elseif ev == "BufWriteCmd" then local file = vim.api.nvim_buf_get_name(buf) if file ~= "" then local lines = vim.b[buf].env_cache or vim.api.nvim_buf_get_lines(buf, 0, -1, false) if pcall(vim.fn.writefile, lines, file) then vim.bo[buf].modified = false else vim.notify("Write failed!", vim.log.levels.ERROR) end end end end, }) -- Strip trailing spaces before write vim.api.nvim_create_autocmd("BufWritePre", { group = augroup("strip_space"), pattern = "*", callback = function() local save = vim.fn.winsaveview() vim.cmd([[keeppatterns %s/\s\+$//e]]) vim.fn.winrestview(save) end, }) -- Resize splits if window got resized vim.api.nvim_create_autocmd("VimResized", { group = augroup("resize_splits"), callback = function() vim.cmd("tabdo wincmd =") end, }) -- Close specific filetypes with vim.api.nvim_create_autocmd("FileType", { group = augroup("close_with_q"), pattern = { "help", "lspinfo", "man", "notify", "qf", "query", "spectre_panel", "startuptime", "tsplayground", "neotest-output", "checkhealth", }, callback = function(event) vim.bo[event.buf].buflisted = false vim.keymap.set("n", "q", "close", { buffer = event.buf, silent = true }) end, }) -- Auto-create directories on save vim.api.nvim_create_autocmd("BufWritePre", { group = augroup("auto_create_dir"), callback = function(event) if event.match:match("^%w%w+://") then return end local file = vim.loop.fs_realpath(event.match) or event.match vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p") end, }) -- LSP Attach Features vim.api.nvim_create_autocmd("LspAttach", { group = augroup("lsp_attach_autocmds"), callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) -- Document Highlight if client and client:supports_method("textDocument/documentHighlight") then vim.api.nvim_create_autocmd({ "CursorHold" }, { buffer = args.buf, callback = vim.lsp.buf.document_highlight, }) vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { buffer = args.buf, callback = vim.lsp.buf.clear_references, }) end -- Inlay Hints if client and client.server_capabilities.inlayHintProvider and vim.lsp.inlay_hint then vim.lsp.inlay_hint.enable(true, { bufnr = args.buf }) end end, }) -- Wrap and spellcheck in text filetypes vim.api.nvim_create_autocmd("FileType", { group = augroup("wrap_spell"), pattern = { "gitcommit", "markdown", "text" }, callback = function() vim.opt_local.wrap = true vim.opt_local.spell = true end, }) -- Disable auto-commenting on new lines vim.api.nvim_create_autocmd("FileType", { group = augroup("no_auto_comment"), callback = function() vim.opt_local.formatoptions:remove({ "c", "r", "o" }) end, }) -- Manual Treesitter Installation command vim.api.nvim_create_user_command("TSInstallAll", function() local parsers = require("extensions").ts_parsers vim.notify("Installing all configured Tree-sitter parsers...", vim.log.levels.INFO, { title = "Tree-sitter" }) require("nvim-treesitter.install").install(parsers) end, { desc = "Install all configured Tree-sitter parsers" }) -- Macro Notifications vim.api.nvim_create_autocmd("RecordingEnter", { callback = function() vim.notify("Recording macro...", vim.log.levels.INFO, { title = "Macro", timeout = 1000 }) end, }) vim.api.nvim_create_autocmd("RecordingLeave", { callback = function() local reg = vim.v.recording vim.notify("Stopped recording @" .. reg, vim.log.levels.INFO, { title = "Macro", timeout = 1000 }) end, }) -- Auto-Save on InsertLeave with 3s Debounce local save_timer = nil local function clear_timer() if save_timer then save_timer:stop() save_timer = nil end end vim.api.nvim_create_autocmd({ "InsertEnter" }, { group = augroup("autosave_cancel"), callback = clear_timer, }) vim.api.nvim_create_autocmd({ "InsertLeave" }, { group = augroup("autosave"), callback = function(args) clear_timer() if vim.api.nvim_buf_is_valid(args.buf) and vim.bo[args.buf].modified and vim.bo[args.buf].buftype == "" then save_timer = vim.defer_fn(function() if vim.api.nvim_buf_is_valid(args.buf) and vim.bo[args.buf].modified then vim.api.nvim_buf_call(args.buf, function() vim.cmd("silent! write") vim.notify("Autosaved " .. vim.fn.expand("%:t"), vim.log.levels.INFO, { title = "Auto-Save" }) end) end end, 3000) end end, }) -- Autoinstall missing plugins on startup vim.api.nvim_create_autocmd('VimEnter', { group = augroup('autoinstall'), callback = function() local ok, items = pcall(vim.pack.get, nil, { info = true }) if ok then local missing = {} for _, item in ipairs(items) do if not item.path or vim.fn.isdirectory(item.path) == 0 then table.insert(missing, item.spec.name or item.spec.src:match('([^/]+)/*$')) end end if #missing > 0 then vim.notify('Installing missing plugins...', vim.log.levels.INFO, { title = 'vim.pack' }) vim.pack.update(missing, { force = true }) end end end, })