diff --git a/nvim/dot-config/nvim/init.lua b/nvim/dot-config/nvim/init.lua index 108d1bd..c2fbd0e 100644 --- a/nvim/dot-config/nvim/init.lua +++ b/nvim/dot-config/nvim/init.lua @@ -34,3 +34,24 @@ require("lazy").setup({ backdrop = 100, }, }) + +local lsp = require("tools.lsp") +for _, tool in pairs(lsp) do + if type(tool) == "table" then + local name = tool[1] + + -- Apply additional config if specified + local config = tool[2] + if config ~= nil then + vim.lsp.config(name, config) + end + + -- System LSP are not managed by mason and need to be enabled manually + if + (type(tool.system) == "boolean" and tool.system and vim.fn.executable(name) > 0) + or (type(tool.system) == "string" and vim.fn.executable(tool.system) > 0) + then + vim.lsp.enable(name) + end + end +end diff --git a/nvim/dot-config/nvim/lazy-lock.json b/nvim/dot-config/nvim/lazy-lock.json index 82b0c6e..b18495e 100644 --- a/nvim/dot-config/nvim/lazy-lock.json +++ b/nvim/dot-config/nvim/lazy-lock.json @@ -7,7 +7,6 @@ "cmp-path": { "branch": "main", "commit": "c6635aae33a50d6010bf1aa756ac2398a2d54c32" }, "cmp_luasnip": { "branch": "master", "commit": "98d9cb5c2c38532bd9bdb481067b20fea8f32e90" }, "conform.nvim": { "branch": "master", "commit": "6feb2f28f9a9385e401857b21eeac3c1b66dd628" }, - "document-color.nvim": { "branch": "main", "commit": "74c487f0e5accfaae033755451b9e367220693fd" }, "fidget.nvim": { "branch": "main", "commit": "d9ba6b7bfe29b3119a610892af67602641da778e" }, "gitsigns.nvim": { "branch": "main", "commit": "8b729e489f1475615dc6c9737da917b3bc163605" }, "gruvbox.nvim": { "branch": "main", "commit": "00e38a379bab3389e187b3953566d67d494dfddd" }, diff --git a/nvim/dot-config/nvim/lua/autocmds.lua b/nvim/dot-config/nvim/lua/autocmds.lua index 5a2af57..32b2461 100644 --- a/nvim/dot-config/nvim/lua/autocmds.lua +++ b/nvim/dot-config/nvim/lua/autocmds.lua @@ -1,15 +1,13 @@ +local window = require("symbols.window") + -- Highlight on yank -local highlight_group = vim.api.nvim_create_augroup("YankHighlight", { clear = true }) vim.api.nvim_create_autocmd("TextYankPost", { callback = function() vim.highlight.on_yank({ higroup = "YankHighlight" }) end, - group = highlight_group, - pattern = "*", }) -- show cursor line only in active window -local cursor_group = vim.api.nvim_create_augroup("ActiveCursor", { clear = true }) vim.api.nvim_create_autocmd({ "InsertLeave", "WinEnter" }, { callback = function() local ok, cl = pcall(vim.api.nvim_win_get_var, 0, "auto-cursorline") @@ -18,8 +16,6 @@ vim.api.nvim_create_autocmd({ "InsertLeave", "WinEnter" }, { vim.api.nvim_win_del_var(0, "auto-cursorline") end end, - group = cursor_group, - pattern = "*", }) vim.api.nvim_create_autocmd({ "InsertEnter", "WinLeave" }, { callback = function() @@ -29,8 +25,124 @@ vim.api.nvim_create_autocmd({ "InsertEnter", "WinLeave" }, { vim.wo.cursorline = false end end, - group = cursor_group, - pattern = "*", +}) + +-- Setup lsp keybindings +vim.api.nvim_create_autocmd("LspAttach", { + callback = function(event) + -- Symbols + vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Goto definition" }) + vim.keymap.set("n", "gD", vim.lsp.buf.declaration, { desc = "Goto declaration" }) + vim.keymap.set("n", "D", vim.lsp.buf.type_definition, { desc = "Type definition" }) + + if pcall(require, "telescope") then + vim.keymap.set("n", "gr", require("telescope.builtin").lsp_references, { desc = "Goto references" }) + vim.keymap.set( + "n", + "gI", + require("telescope.builtin").lsp_implementations, + { desc = "Goto implementation" } + ) + vim.keymap.set( + "n", + "ds", + require("telescope.builtin").lsp_document_symbols, + { desc = "Document symbols" } + ) + vim.keymap.set( + "n", + "ws", + require("telescope.builtin").lsp_dynamic_workspace_symbols, + { desc = "Workspace symbols" } + ) + end + + -- Diagnostics + vim.keymap.set("n", "[d", function() + vim.diagnostic.jump({ count = -1 }) + end, { desc = "Go to previous diagnostic message" }) + vim.keymap.set("n", "]d", function() + vim.diagnostic.jump({ count = 1 }) + end, { desc = "Go to next diagnostic message" }) + -- vim.keymap.set("n", "e", vim.diagnostic.open_float, { desc = "Open floating diagnostic message" }) + vim.keymap.set("n", "e", function() + if vim.diagnostic.config().virtual_lines then + vim.diagnostic.config({ virtual_lines = false }) + else + vim.diagnostic.config({ + virtual_lines = { + current_line = true, + format = vim.diagnostic.config().virtual_text.format, + }, + }) + end + end, { desc = "Show virtual diagnostic line" }) + + -- Helpers + vim.keymap.set("n", "rn", function() + return ":IncRename " .. vim.fn.expand("") + end, { buffer = event.buf, expr = true, desc = "Rename" }) + vim.keymap.set( + "n", + "ca", + vim.lsp.buf.code_action, + { buffer = event.buf, desc = "Code actions", remap = true } + ) + + -- Documentation + vim.keymap.set("n", "K", function() + vim.lsp.buf.hover({ border = window.border }) + end, { desc = "Hover Documentation" }) + vim.keymap.set("n", "", function() + vim.lsp.buf.signature_help({ border = border }) + end, { desc = "Signature Documentation" }) + end, +}) + +-- Setup cursor hover symbol highlight +vim.api.nvim_create_autocmd("LspAttach", { + callback = function(event) + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client and client:supports_method(vim.lsp.protocol.Methods.textDocument_documentHighlight, event.buf) then + local lsp_hover_hl = vim.api.nvim_create_augroup("LspHoverHighlight", { clear = false }) + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { + buffer = event.buf, + group = lsp_hover_hl, + callback = vim.lsp.buf.document_highlight, + }) + + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + buffer = event.buf, + group = lsp_hover_hl, + callback = vim.lsp.buf.clear_references, + }) + + vim.api.nvim_create_autocmd("LspDetach", { + group = vim.api.nvim_create_augroup("LspHoverHighlightDetach", { clear = true }), + callback = function(event2) + vim.lsp.buf.clear_references() + vim.api.nvim_clear_autocmds({ group = lsp_hover_hl, buffer = event2.buf }) + end, + }) + end + end, +}) + +-- Setup cursor hover symbol highlight +vim.api.nvim_create_autocmd("LspAttach", { + callback = function(event) + local client = vim.lsp.get_client_by_id(event.data.client_id) + if client and client.server_capabilities.semanticTokensProvider then + client.server_capabilities.semanticTokensProvider = nil + end + end, +}) + +-- +vim.api.nvim_create_autocmd("CursorMoved", { + callback = function() + vim.diagnostic.config({ virtual_lines = false }) + end, }) -- Auto install treesitter parser and start them diff --git a/nvim/dot-config/nvim/lua/keymaps.lua b/nvim/dot-config/nvim/lua/keymaps.lua index b046b5d..b68f0cd 100644 --- a/nvim/dot-config/nvim/lua/keymaps.lua +++ b/nvim/dot-config/nvim/lua/keymaps.lua @@ -13,11 +13,6 @@ vim.keymap.set("n", "", "resize -2") vim.keymap.set("n", "", "vertical resize -2") vim.keymap.set("n", "", "vertical resize +2") --- Diagnostic keymaps -vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Go to previous diagnostic message" }) -vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Go to next diagnostic message" }) -vim.keymap.set("n", "e", vim.diagnostic.open_float, { desc = "Open floating diagnostic message" }) - -- Some nice adjustments vim.keymap.set("n", "", "zz") vim.keymap.set("n", "", "zz") diff --git a/nvim/dot-config/nvim/lua/options.lua b/nvim/dot-config/nvim/lua/options.lua index 39aff05..8a8813d 100644 --- a/nvim/dot-config/nvim/lua/options.lua +++ b/nvim/dot-config/nvim/lua/options.lua @@ -1,3 +1,6 @@ +local diagnostic = require("symbols.diagnostic") +local border = require("symbols.window").border + -- Set highlight on search vim.o.hlsearch = true @@ -39,7 +42,7 @@ vim.o.termguicolors = true -- Default tab settings -- Tab settings are automatically detected by vim-sleuth --- Can be overriden by .editorconfig and modeline +-- Can be overridden by .editorconfig and modeline vim.o.tabstop = 4 vim.o.softtabstop = 4 vim.o.shiftwidth = 4 @@ -64,3 +67,22 @@ vim.o.list = true -- Fold settings vim.o.foldlevelstart = 99 + +-- LSP config +vim.diagnostic.config({ + severity_sort = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = diagnostic.error, + [vim.diagnostic.severity.WARN] = diagnostic.warn, + [vim.diagnostic.severity.HINT] = diagnostic.hint, + [vim.diagnostic.severity.INFO] = diagnostic.info, + }, + }, + virtual_text = { + virt_text_pos = "eol_right_align", + format = function(d) + return ("%s [%s]"):format(d.message, d.source) + end, + }, +}) diff --git a/nvim/dot-config/nvim/lua/plugins/lsp.lua b/nvim/dot-config/nvim/lua/plugins/lsp.lua deleted file mode 100644 index c1747e4..0000000 --- a/nvim/dot-config/nvim/lua/plugins/lsp.lua +++ /dev/null @@ -1,140 +0,0 @@ -return { - -- LSP Configuration & Plugins - "neovim/nvim-lspconfig", - dependencies = { - "williamboman/mason.nvim", - "williamboman/mason-lspconfig.nvim", - "WhoIsSethDaniel/mason-tool-installer.nvim", - - -- Some of the lsp keybindings rely on telescope - "nvim-telescope/telescope.nvim", - -- Set capabilities from cmp - "hrsh7th/cmp-nvim-lsp", - - -- Add document color - "mrshmllow/document-color.nvim", - - "b0o/schemastore.nvim", - - -- Rename with immediate visual feedback - }, - config = function() - local border = require("symbols.window").border - - -- Set borders - local handlers = { - ["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = border }), - ["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = border }), - } - - require("lspconfig.ui.windows").default_options = { - border = border, - } - - vim.diagnostic.config({ - severity_sort = true, - }) - - -- Create the signs for diagnostic symbols - local diagnostic = require("symbols.diagnostic") - local signs = { - Error = diagnostic.error, - Warn = diagnostic.warn, - Hint = diagnostic.hint, - Info = diagnostic.info, - } - for type, icon in pairs(signs) do - local hl_sign = "DiagnosticSign" .. type - local hl_text = "Diagnostic" .. type - vim.fn.sign_define(hl_sign, { text = icon, texthl = hl_sign }) - end - - vim.api.nvim_create_autocmd("LspAttach", { - group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }), - callback = function(event) - local map = function(keys, func, desc) - vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP:" .. desc }) - end - - map("gd", vim.lsp.buf.definition, "Goto definition") - map("gr", require("telescope.builtin").lsp_references, "Goto references") - map("gI", require("telescope.builtin").lsp_implementations, "Goto implementation") - map("D", vim.lsp.buf.type_definition, "Type definition") - map("ds", require("telescope.builtin").lsp_document_symbols, "Document symbols") - map("ws", require("telescope.builtin").lsp_dynamic_workspace_symbols, "Workspace symbols") - - vim.keymap.set("n", "rn", function() - return ":IncRename " .. vim.fn.expand("") - end, { buffer = event.buf, expr = true, desc = "Rename" }) - - -- TODO: Do we need this to work in visal mode? - vim.keymap.set( - { "v", "n" }, - "ca", - vim.lsp.buf.code_action, - { buffer = event.buf, desc = "Code actions", remap = true } - ) - - -- Signature help - map("K", vim.lsp.buf.hover, "Hover Documentation") - map("", vim.lsp.buf.signature_help, "Signature Documentation") - - -- Lesser used LSP functionality - map("gD", vim.lsp.buf.declaration, "Goto declaration") - - local client = vim.lsp.get_client_by_id(event.data.client_id) - -- Turn of lsp based syntax highlighting - if client then - client.server_capabilities.semanticTokensProvider = nil - if client.server_capabilities.documentHighlightProvider then - local highlight_augrup = vim.api.nvim_create_augroup("lsp-highlight", { clear = false }) - vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { - buffer = event.buf, - group = highlight_augrup, - callback = vim.lsp.buf.document_highlight, - }) - - vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { - buffer = event.buf, - group = highlight_augrup, - callback = vim.lsp.buf.clear_references, - }) - - vim.api.nvim_create_autocmd("LspDetach", { - group = vim.api.nvim_create_augroup("lsp-detach", { clear = true }), - callback = function(event2) - vim.lsp.buf.clear_references() - vim.api.nvim_clear_autocmds({ group = highlight_augrup, buffer = event2.buf }) - end, - }) - end - end - end, - }) - - local capabilities = vim.lsp.protocol.make_client_capabilities() - -- TODO: Only do this is cmp_nvim_lsp is enabled - capabilities = vim.tbl_deep_extend("force", capabilities, require("cmp_nvim_lsp").default_capabilities()) - capabilities.textDocument.colorProvider = { - dynamicRegistration = true, - } - - local handler = function(server_name) - local server = require("tools").servers()[server_name] or {} - server.capabilities = vim.tbl_deep_extend("force", capabilities, server.capabilities or {}) - server.handlers = handlers - - require("lspconfig")[server_name].setup(server) - end - - for server, config in pairs(require("tools").servers()) do - if config.system then - handler(server) - end - end - - require("mason-lspconfig").setup({ - handlers = { handler }, - }) - end, -} diff --git a/nvim/dot-config/nvim/lua/plugins/mason.lua b/nvim/dot-config/nvim/lua/plugins/mason.lua index 2d0241a..8e64d34 100644 --- a/nvim/dot-config/nvim/lua/plugins/mason.lua +++ b/nvim/dot-config/nvim/lua/plugins/mason.lua @@ -1,28 +1,26 @@ return { - { - "williamboman/mason.nvim", - opts = { - ui = { - border = require("symbols.window").border, - height = 0.8, - }, - }, - }, { "WhoIsSethDaniel/mason-tool-installer.nvim", dependencies = { - "williamboman/mason.nvim", + { "mason-org/mason.nvim", opts = {} }, + "mason-org/mason-lspconfig.nvim", }, config = function() - local tools = require("tools") - local ensure_installed = vim.tbl_keys(vim.tbl_map(function(tool) - if tool.system then - return nil + local lsp = require("tools.lsp") + + local ensure_installed = vim.tbl_values(vim.tbl_map(function(tool) + if type(tool) == "table" then + if not tool.system then + return { + tool[1], + condition = tool.condition, + } + end else return tool end - end, tools.servers())) - ensure_installed = vim.list_extend(ensure_installed, tools.extra) + return nil + end, lsp)) require("mason-tool-installer").setup({ ensure_installed = ensure_installed, @@ -30,6 +28,14 @@ return { }) end, }, + { + "mason-org/mason-lspconfig.nvim", + opts = {}, + dependencies = { + { "mason-org/mason.nvim", opts = {} }, + "neovim/nvim-lspconfig", + }, + }, { "zapling/mason-conform.nvim", opts = {}, diff --git a/nvim/dot-config/nvim/lua/plugins/schemastore.lua b/nvim/dot-config/nvim/lua/plugins/schemastore.lua new file mode 100644 index 0000000..f8f912d --- /dev/null +++ b/nvim/dot-config/nvim/lua/plugins/schemastore.lua @@ -0,0 +1,13 @@ +return { + "b0o/schemastore.nvim", + config = function() + vim.lsp.config("jsonls", { + settings = { + json = { + validate = { enable = true }, + schemas = require("schemastore").json.schemas(), + }, + }, + }) + end +} diff --git a/nvim/dot-config/nvim/lua/plugins/yaml-companion.lua b/nvim/dot-config/nvim/lua/plugins/yaml-companion.lua index 065a821..efcec4a 100644 --- a/nvim/dot-config/nvim/lua/plugins/yaml-companion.lua +++ b/nvim/dot-config/nvim/lua/plugins/yaml-companion.lua @@ -1,11 +1,19 @@ return { "someone-stole-my-name/yaml-companion.nvim", dependencies = { - "neovim/nvim-lspconfig", "nvim-lua/plenary.nvim", "nvim-telescope/telescope.nvim", + "nvim-telescope/telescope.nvim", + "diogo464/kubernetes.nvim", }, config = function() require("telescope").load_extension("yaml_schema") + + vim.lsp.config("yamlls", require("yaml-companion").setup({ + builtin_matchers = { + kubernetes = { enabled = false }, + kubernetes_custom = { enabled = true }, + }, + })) end, } diff --git a/nvim/dot-config/nvim/lua/tools.lua b/nvim/dot-config/nvim/lua/tools.lua deleted file mode 100644 index 62332ad..0000000 --- a/nvim/dot-config/nvim/lua/tools.lua +++ /dev/null @@ -1,79 +0,0 @@ -local tools = {} - --- https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md -tools.servers = function() - return { - clangd = { - cmd = { "clangd", "--offset-encoding=utf-16", "--clang-tidy" }, - }, - gopls = {}, - pyright = {}, - rust_analyzer = { - system = true, - settings = { - ["rust-analyzer"] = { - check = { - command = "clippy", - }, - }, - }, - }, - lua_ls = { - settings = { - Lua = { - workspace = { checkThirdParty = false }, - telemetry = { enable = false }, - }, - }, - }, - jsonls = { - settings = { - json = { - validate = { enable = true }, - schemas = require("schemastore").json.schemas(), - }, - }, - }, - yamlls = require("yaml-companion").setup({ - builtin_matchers = { - kubernetes = { enabled = false }, - kubernetes_custom = { enabled = true }, - }, - }), - taplo = {}, - neocmake = {}, - nil_ls = { - system = true, - }, - typos_lsp = { - init_options = { - diagnosticSeverity = "Hint", - }, - }, - } -end - --- https://github.com/stevearc/conform.nvim -tools.formatters = require("util.conform").assign_formatters({ - { { "c", "cpp" }, { "clang-format" } }, - go = { "goimports", "gofmt" }, - python = { "ruff_format" }, - rust = { "rustfmt" }, - { - { "javascript", "typescript", "typescriptreact", "javascriptreact", "css", "markdown", "yaml" }, - { "prettierd" }, - }, - lua = { "stylua" }, - json = { "jq" }, - toml = { "taplo" }, - nix = { "nixfmt" }, - -- ["*"] = { "injected" }, - ["_"] = { "trim_whitespace", "trim_newlines" }, -}) - --- https://mason-registry.dev/registry/list -tools.extra = { - "cpptools", -} - -return tools diff --git a/nvim/dot-config/nvim/lua/tools/lsp.lua b/nvim/dot-config/nvim/lua/tools/lsp.lua new file mode 100644 index 0000000..c6be033 --- /dev/null +++ b/nvim/dot-config/nvim/lua/tools/lsp.lua @@ -0,0 +1,45 @@ +return { + { + "rust_analyzer", + { + settings = { + ["rust-analyzer"] = { + check = { + command = "clippy", + }, + }, + }, + }, + system = "rust-analyzer", + }, + { "typos_lsp", { + init_options = { + diagnosticSeverity = "Hint", + }, + } }, + { "clangd", { + cmd = { "clangd", "--offset-encoding=utf-16", "--clang-tidy" }, + } }, + "pyright", + { + "lua_ls", + { + settings = { + Lua = { + workspace = { checkThirdParty = false }, + telemetry = { enable = false }, + }, + }, + }, + }, + { + "gopls", + condition = function() + return vim.fn.executable("go") > 0 + end, + }, + "jsonls", + "yamlls", + "taplo", + "neocmake", +}