diff --git a/lua/autocmd.lua b/lua/autocmd.lua index 2c55c78..75bf182 100644 --- a/lua/autocmd.lua +++ b/lua/autocmd.lua @@ -1,7 +1,16 @@ local function augroup(name) - return vim.api.nvim_create_augroup("nvim_" .. name, { clear = true }) + return vim.api.nvim_create_augroup('nvim_' .. name, { clear = true }) end +-- Yank highlight autocmd (built-in) +vim.api.nvim_create_autocmd('TextYankPost', { + group = vim.api.nvim_create_augroup('YankHighlight', { clear = true }), + pattern = '*', + callback = function() + vim.highlight.on_yank({ higroup = 'IncSearch', timeout = 150 }) + 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' }, { @@ -25,197 +34,211 @@ vim.api.nvim_create_autocmd({ 'CursorMoved', 'CursorMovedI', 'BufEnter' }, { }) -- Secure .env Masking -local env_ns = vim.api.nvim_create_namespace("secure_env") +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 + 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, +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, +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, +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, +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, +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 +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) - -- 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, + -- 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, +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, +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" }) - +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('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, +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 + 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({ '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, +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 diff --git a/lua/lsp.lua b/lua/lsp.lua index fda1df6..96e13a6 100644 --- a/lua/lsp.lua +++ b/lua/lsp.lua @@ -2,152 +2,152 @@ -- LSP -------------------------------------------------------------------------------- -vim.api.nvim_create_autocmd("User", { - pattern = "PackerComplete", -- Fallback or custom event if needed, but let's use a more standard one - callback = function() - -- This is where we would put it if we had a specific event. - -- Since we're using VimEnter, let's use that instead. - end, +vim.api.nvim_create_autocmd('User', { + pattern = 'PackerComplete', -- Fallback or custom event if needed, but let's use a more standard one + callback = function() + -- This is where we would put it if we had a specific event. + -- Since we're using VimEnter, let's use that instead. + end, }) -- Let's use a simple function and schedule it to run after plugins vim.schedule(function() - vim.lsp.config("*", { - capabilities = require("blink.cmp").get_lsp_capabilities(), - }) + vim.lsp.config('*', { + capabilities = require('blink.cmp').get_lsp_capabilities(), + }) - -- ts_ls - vim.lsp.config("ts_ls", { - settings = { - typescript = { - inlayHints = { - includeInlayParameterNameHints = "all", - includeInlayParameterNameHintsWhenArgumentMatchesName = false, - includeInlayFunctionParameterTypeHints = true, - includeInlayVariableTypeHints = true, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayEnumMemberValueHints = true, - }, - }, - }, - }) - vim.lsp.enable("ts_ls") + -- ts_ls + vim.lsp.config('ts_ls', { + settings = { + typescript = { + inlayHints = { + includeInlayParameterNameHints = 'all', + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, + }, + }) + vim.lsp.enable('ts_ls') - vim.lsp.enable("html") - vim.lsp.enable("cssls") - vim.lsp.config("tailwindcss", { - filetypes = { - "astro", - "blade", - "edge", - "ejs", - "erb", - "gohtml", - "gohtmltmpl", - "handlebars", - "hbs", - "html", - "jade", - "leaf", - "liquid", - "markdown", - "mdx", - "mustache", - "nunjucks", - "php", - "razor", - "slim", - "twig", - "css", - "less", - "postcss", - "sass", - "scss", - "stylus", - "sugarss", - "javascript", - "javascriptreact", - "rescript", - "typescript", - "typescriptreact", - "vue", - "svelte", - "templ", - }, - }) - vim.lsp.enable("tailwindcss") + vim.lsp.enable('html') + vim.lsp.enable('cssls') + vim.lsp.config('tailwindcss', { + filetypes = { + 'astro', + 'blade', + 'edge', + 'ejs', + 'erb', + 'gohtml', + 'gohtmltmpl', + 'handlebars', + 'hbs', + 'html', + 'jade', + 'leaf', + 'liquid', + 'markdown', + 'mdx', + 'mustache', + 'nunjucks', + 'php', + 'razor', + 'slim', + 'twig', + 'css', + 'less', + 'postcss', + 'sass', + 'scss', + 'stylus', + 'sugarss', + 'javascript', + 'javascriptreact', + 'rescript', + 'typescript', + 'typescriptreact', + 'vue', + 'svelte', + 'templ', + }, + }) + vim.lsp.enable('tailwindcss') - -- rust - vim.lsp.config("rust_analyzer", { - settings = { - ["rust-analyzer"] = { - diagnostics = { - enable = true, - experimental = { enable = true }, - }, - }, - }, - }) - vim.lsp.enable("rust_analyzer") + -- rust + vim.lsp.config('rust_analyzer', { + settings = { + ['rust-analyzer'] = { + diagnostics = { + enable = true, + experimental = { enable = true }, + }, + }, + }, + }) + vim.lsp.enable('rust_analyzer') - -- lua - vim.lsp.config("lua_ls", { - settings = { - Lua = { - diagnostics = { - disable = { - "missing-fields", - "undefined-global", - }, - }, - }, - }, - }) - vim.lsp.enable("lua_ls") + -- lua + vim.lsp.config('lua_ls', { + settings = { + Lua = { + diagnostics = { + disable = { + 'missing-fields', + 'undefined-global', + }, + }, + }, + }, + }) + vim.lsp.enable('lua_ls') - -- python - vim.lsp.config("basedpyright", { - settings = { - basedpyright = { - inlayHints = true, - analysis = { - diagnosticSeverityOverrides = { - reportUnusedImport = "none", - reportUnusedVariable = "none", - reportAttributeAccessIssue = "none", - reportUnusedClass = "none", - reportUnusedFunction = "none", - reportDuplicateImport = "none", - reportArgumentType = "error", - }, - typeCheckingMode = "standard", - }, - }, - }, - }) - vim.lsp.enable("basedpyright") + -- python + vim.lsp.config('basedpyright', { + settings = { + basedpyright = { + inlayHints = true, + analysis = { + diagnosticSeverityOverrides = { + reportUnusedImport = 'none', + reportUnusedVariable = 'none', + reportAttributeAccessIssue = 'none', + reportUnusedClass = 'none', + reportUnusedFunction = 'none', + reportDuplicateImport = 'none', + reportArgumentType = 'error', + }, + typeCheckingMode = 'standard', + }, + }, + }, + }) + vim.lsp.enable('basedpyright') - -- bash - vim.lsp.config("bashls", { - settings = { - bashIde = { - shellcheckArguments = { - "--exclude=SC1090,SC1091,SC2076,SC2164", - }, - }, - }, - }) - vim.lsp.enable("bashls") + -- bash + vim.lsp.config('bashls', { + settings = { + bashIde = { + shellcheckArguments = { + '--exclude=SC1090,SC1091,SC2076,SC2164', + }, + }, + }, + }) + vim.lsp.enable('bashls') - -- cpp - vim.lsp.config("clangd", { - cmd = { - "clangd", - "--fallback-style=llvm", - "--header-insertion=iwyu", - "-j=4", - }, - }) - vim.lsp.enable("clangd") + -- cpp + vim.lsp.config('clangd', { + cmd = { + 'clangd', + '--fallback-style=llvm', + '--header-insertion=iwyu', + '-j=4', + }, + }) + vim.lsp.enable('clangd') end)