From 2ddf69c2449e9f5a4f360b00852083a816d54dd0 Mon Sep 17 00:00:00 2001 From: Marty Oehme Date: Tue, 30 Jul 2024 14:37:20 +0200 Subject: [PATCH] nvim: Refactor lsp, linting and outliners away from ide Start splitting up ide plugin module by splitting out individual modules. --- nvim/.config/nvim/lua/plugins/ide.lua | 125 +------ nvim/.config/nvim/lua/plugins/linting.lua | 38 +++ nvim/.config/nvim/lua/plugins/lsp.lua | 357 ++++++++++++++++++++ nvim/.config/nvim/lua/plugins/outliners.lua | 51 +++ 4 files changed, 447 insertions(+), 124 deletions(-) create mode 100644 nvim/.config/nvim/lua/plugins/linting.lua create mode 100644 nvim/.config/nvim/lua/plugins/lsp.lua create mode 100644 nvim/.config/nvim/lua/plugins/outliners.lua diff --git a/nvim/.config/nvim/lua/plugins/ide.lua b/nvim/.config/nvim/lua/plugins/ide.lua index 40bb8f1..e82bd18 100644 --- a/nvim/.config/nvim/lua/plugins/ide.lua +++ b/nvim/.config/nvim/lua/plugins/ide.lua @@ -1,15 +1,3 @@ -local linters = { - astro = { "eslint_d" }, - bash = { "shellcheck" }, - javascript = { "eslint_d" }, - javascriptreact = { "eslint_d" }, - markdown = { "markdownlint" }, - quarto = { "markdownlint" }, - sh = { "shellcheck" }, - svelte = { "eslint_d" }, - text = {}, - typescript = { "eslint_d" }, - typescriptreact = { "eslint_d" }, } local formatters = { angular = { { "prettierd", "prettier" } }, @@ -36,102 +24,8 @@ local formatters = { } return { - -- vista-like outline view for code - { - "stevearc/aerial.nvim", - config = true, - -- Optional dependencies - dependencies = { - "nvim-treesitter/nvim-treesitter", - "nvim-tree/nvim-web-devicons", - }, - cmd = { - "AerialToggle", - "AerialOpen", - "AerialOpenAll", - "AerialClose", - "AerialCloseAll", - "AerialNext", - "AerialPrev", - "AerialGo", - "AerialInfo", - "AerialNavToggle", - "AerialNavOpen", - "AerialNavClose", - }, - opts = { - backends = { "treesitter", "lsp", "markdown", "man" }, - }, - keys = { - { "so", "AerialNavToggle", silent = true, desc = "symbol navigator" }, - { "sO", "AerialToggle", silent = true, desc = "symbol outline" }, - }, - }, - -- lsp setup - { - "junnplus/lsp-setup.nvim", - dependencies = { - { - "neovim/nvim-lspconfig", - -- will sometimes not keep up with lsp changes if set to stable - version = false, - }, - { - "williamboman/mason.nvim", - cmd = { - "Mason", - "MasonInstall", - "MasonUninstall", - "MasonUninstallAll", - "MasonLog", - "MasonUpdate", - }, - build = ":MasonUpdate", - keys = { - { "vm", ":Mason", desc = "Mason" }, - }, - }, - { - "williamboman/mason-lspconfig.nvim", - cmd = { "LspInstall", "LspUninstall" }, - }, - }, - event = { "BufReadPost", "BufNewFile", "BufWritePre" }, - config = function() - require("plugins.config.lsp") - end, - keys = { { "vs", ":LspInfo", desc = "LspInfo" } }, - }, - -- pretty lsp 'peek' menus - { - "DNLHC/glance.nvim", - opts = { border = { enable = true }, theme = { enable = true, mode = "auto" } }, - cmd = { "Glance" }, - }, - -- linting setup - { - "rshkarin/mason-nvim-lint", - dependencies = { - { - "mfussenegger/nvim-lint", - config = function() - require("lint").linters_by_ft = linters - vim.api.nvim_create_autocmd({ "BufWritePost", "InsertLeave" }, { - callback = function() - if not vim.g.disable_autolint then - require("lint").try_lint() - end - end, - }) - end, - dependencies = { "williamboman/mason.nvim" }, - }, - }, - event = { "BufReadPost", "BufNewFile", "BufWritePre" }, - opts = {}, - }, -- formatting setup { @@ -177,6 +71,7 @@ return { function() require("conform").format({ async = true, lsp_fallback = true }) end, + mode = { "n", "v" }, desc = "Format buffer", }, { @@ -202,24 +97,6 @@ return { opts = {}, }, - -- useful quickfix-like buffer - { - "folke/trouble.nvim", - dependencies = { "nvim-tree/nvim-web-devicons" }, - opts = {}, - cmd = { - "Trouble", - }, - keys = { - { "sd", "Trouble diagnostics toggle", silent = true, desc = "diagnostics workspace" }, - { - "sD", - "Trouble diagnostics toggle filter.buf=0", - silent = true, - desc = "diagnostics document", - }, - }, - }, -- automatic docstring creation for a variety of languages { diff --git a/nvim/.config/nvim/lua/plugins/linting.lua b/nvim/.config/nvim/lua/plugins/linting.lua new file mode 100644 index 0000000..89af1e8 --- /dev/null +++ b/nvim/.config/nvim/lua/plugins/linting.lua @@ -0,0 +1,38 @@ +local linters = { + astro = { "eslint_d" }, + bash = { "shellcheck" }, + javascript = { "eslint_d" }, + javascriptreact = { "eslint_d" }, + markdown = { "markdownlint" }, + quarto = { "markdownlint" }, + sh = { "shellcheck" }, + svelte = { "eslint_d" }, + text = {}, + typescript = { "eslint_d" }, + typescriptreact = { "eslint_d" }, +} + +return { + -- linting setup + { + "rshkarin/mason-nvim-lint", + dependencies = { + { + "mfussenegger/nvim-lint", + config = function() + require("lint").linters_by_ft = linters + vim.api.nvim_create_autocmd({ "BufWritePost", "InsertLeave" }, { + callback = function() + if not vim.g.disable_autolint then + require("lint").try_lint() + end + end, + }) + end, + dependencies = { "williamboman/mason.nvim" }, + }, + }, + event = { "BufReadPost", "BufNewFile", "BufWritePre" }, + opts = {}, + }, +} diff --git a/nvim/.config/nvim/lua/plugins/lsp.lua b/nvim/.config/nvim/lua/plugins/lsp.lua new file mode 100644 index 0000000..41a4f4f --- /dev/null +++ b/nvim/.config/nvim/lua/plugins/lsp.lua @@ -0,0 +1,357 @@ +local servers = { + ansiblels = {}, + arduino_language_server = {}, + astro = {}, + bashls = {}, + beancount = {}, + clangd = {}, + cssls = {}, + docker_compose_language_service = {}, + dockerls = {}, + emmet_ls = {}, + eslint = {}, + gopls = {}, + harper_ls = {}, + julials = {}, + jsonls = {}, + ltex = { autostart = false }, + lua_ls = { + settings = { + Lua = { + diagnostics = { globals = { "vim" } }, + -- enable when working on neovim stuff. Takes *long* to load + -- workspace = { library = vim.api.nvim_get_runtime_file("", true) }, + telemetry = { enable = false }, + hint = { + enable = true, + setType = true, + }, + }, + }, + }, + marksman = {}, + basedpyright = {}, + ruff = {}, + serve_d = {}, + taplo = {}, + texlab = {}, + tsserver = {}, + yamlls = {}, +} + +return { + -- lsp setup + { + "junnplus/lsp-setup.nvim", + dependencies = { + { + "neovim/nvim-lspconfig", + -- will sometimes not keep up with lsp changes if set to stable + version = false, + }, + { + "williamboman/mason.nvim", + cmd = { + "Mason", + "MasonInstall", + "MasonUninstall", + "MasonUninstallAll", + "MasonLog", + "MasonUpdate", + }, + build = ":MasonUpdate", + keys = { + { "vm", ":Mason", desc = "Mason" }, + }, + }, + { + "williamboman/mason-lspconfig.nvim", + cmd = { "LspInstall", "LspUninstall" }, + }, + }, + event = { "BufReadPost", "BufNewFile", "BufWritePre" }, + config = function() + vim.diagnostic.config({ virtual_text = true }) + vim.fn.sign_define("DiagnosticSignError", { text = "✘", texthl = "DiagnosticSignError" }) + vim.fn.sign_define("DiagnosticSignWarn", { text = "", texthl = "DiagnosticSignWarn" }) + vim.fn.sign_define("DiagnosticSignInfo", { text = "", texthl = "DiagnosticSignInfo" }) + vim.fn.sign_define("DiagnosticSignHint", { text = "", texthl = "DiagnosticSignHint" }) + + local lsp = require("lsp-setup") + + local function on_attach(_, bufnr) + local map = vim.keymap.set + map( + "n", + "[d", + "lua vim.diagnostic.goto_prev()", + { buffer = bufnr, desc = "Previous diagnostic" } + ) + map("n", "]d", "lua vim.diagnostic.goto_next()", { buffer = bufnr, desc = "Next diagnostic" }) + map( + "n", + "[D", + "lua vim.diagnostic.goto_prev({severity = vim.diagnostic.severity.ERROR})", + { buffer = bufnr, desc = "Previous error" } + ) + map( + "n", + "]D", + "lua vim.diagnostic.goto_next({severity = vim.diagnostic.severity.ERROR})", + { buffer = bufnr, desc = "Next error" } + ) + + if require("core.util").is_available("which-key") then + require("which-key").add({ "l", group = "language" }) + end + map( + "n", + "ld", + "lua vim.diagnostic.open_float()", + { buffer = bufnr, desc = "Line diagnostics" } + ) + map("n", "li", function() + vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) + end, { buffer = bufnr, desc = "Inlay hints" }) + map( + "n", + "la", + "lua vim.lsp.buf.code_action()", + { buffer = bufnr, desc = "Codeactions" } + ) + map( + "n", + "ln", + "lua vim.lsp.buf.rename()", + { buffer = bufnr, desc = "Rename element" } + ) + if vim.fn.exists(":Glance") then + map("n", "lr", "Glance references", { buffer = bufnr, desc = "References" }) + map("n", "lf", "Glance definitions", { buffer = bufnr, desc = "Definition" }) + map( + "n", + "lt", + "Glance type_definitions", + { buffer = bufnr, desc = "Type definition" } + ) + map( + "n", + "lm", + "Glance implementations", + { buffer = bufnr, desc = "Implementation" } + ) + elseif vim.fn.exists(":Telescope") then + map( + "n", + "lr", + "Telescope lsp_references", + { buffer = bufnr, desc = "References" } + ) + map( + "n", + "lf", + "Telescope lsp_definitions", + { buffer = bufnr, desc = "Definition" } + ) + map( + "n", + "lt", + "Telescope lsp_type_definitions", + { buffer = bufnr, desc = "Type definition" } + ) + map( + "n", + "lm", + "Telescope lsp_implementations", + { buffer = bufnr, desc = "Implementation" } + ) + else + map( + "n", + "lr", + "lua vim.lsp.buf.references()", + { buffer = bufnr, desc = "References" } + ) + map( + "n", + "lf", + "lua vim.lsp.buf.definition()", + { buffer = bufnr, desc = "Definition" } + ) + map( + "n", + "lt", + "lua vim.lsp.buf.type_definition()", + { buffer = bufnr, desc = "Type definition" } + ) + map( + "n", + "lm", + "lua vim.lsp.buf.implementation()", + { buffer = bufnr, desc = "Implementation" } + ) + end + map("n", "K", "lua vim.lsp.buf.hover()", { buffer = bufnr, desc = "Hover definition" }) + map( + "n", + "lc", + "lua vim.lsp.buf.declaration()", + { buffer = bufnr, desc = "Declaration" } + ) + map( + "n", + "ls", + "lua vim.lsp.buf.signature_help()", + { buffer = bufnr, desc = "Signature help" } + ) + map("n", "lo", function() + if vim.diagnostic.is_disabled(0) then + vim.diagnostic.enable(0) + else + vim.diagnostic.disable(0) + end + end, { buffer = bufnr, desc = "Toggle Diagnostics" }) + end + + -- Display diagnostics as virtual text only if not in insert mode + -- /r/neovim/comments/12inp4c/disable_diagnostics_virtual_text_when_in_insert/jqqifwk/ + vim.api.nvim_create_autocmd("InsertEnter", { + callback = function() + vim.diagnostic.config({ virtual_text = false }) + end, + }) + vim.api.nvim_create_autocmd("InsertLeave", { + callback = function() + vim.diagnostic.config({ virtual_text = true }) + end, + }) + + lsp.setup({ + default_mappings = false, + servers = servers, + on_attach = on_attach, + inlay_hints = { + enabled = vim.fn.has("nvim-0.10") == true and true or false, + }, + }) + + local lspconfig = require("lspconfig") + lspconfig.nushell.setup({}) + + lspconfig.marksman.setup({ + filetypes = { "markdown", "quarto" }, + on_attach = function(client, bufnr) + -- TODO: for some reason this stays true even after rootdir switch? + if client.config.in_zk_notebook then + vim.defer_fn(function() + vim.lsp.buf_detach_client(bufnr, client.id) + end, 1000) + end + on_attach(client, bufnr) + end, + on_new_config = function(conf, new_root) + if require("lspconfig.util").root_pattern(".zk")(new_root) then + conf.in_zk_notebook = true + else + conf.in_zk_notebook = false + end + end, + }) + lspconfig.harper_ls.setup({ + filetypes = { -- standard filetypes plus quarto + "c", + "cpp", + "csharp", + "gitcommit", + "go", + "html", + "java", + "javascript", + "lua", + "markdown", + "python", + "quarto", + "ruby", + "rust", + "swift", + "toml", + "typescript", + "typescriptreact", + }, + }) + + local python_path + -- ensure python virtualenv is determined automatically on lsp start + lspconfig.basedpyright.setup({ + on_attach = function(client, bufnr) + on_attach(client, bufnr) + require("core.util").set_python_env() + if python_path == nil then + python_path, _ = vim.fn.expand(require("core.util").get_python_venv_bin(client.config.root_dir)) + end + -- print(string.format("[PYTHON VENV]: %s", vim.inspect(python_path))) + client.config.settings.python = {} or client.config.settings.python + client.config.settings.python.pythonPath = python_path + end, + settings = { + -- disable imports and linting since, we use ruff for that + pyright = { + disableOrganizeImports = true, + }, + python = { + analysis = { + ignore = { "*" }, + }, + }, + }, + }) + lspconfig.ruff.setup({ + on_attach = function(client, bufnr) + on_attach(client, bufnr) + require("core.util").set_python_env() + client.server_capabilities.hoverProvider = false -- we use pyright for hover info + if python_path == nil then + python_path, _ = vim.fn.expand(require("core.util").get_python_venv_bin(client.config.root_dir)) + end + client.config.settings.python = {} or client.config.settings.python + client.config.settings.python.pythonPath = python_path + end, + }) + + -- set up arduino with the help of arduino.nvim plugin + if require("core.util").is_available("arduino") then + lspconfig.arduino_language_server.setup({ + on_new_config = require("arduino").on_new_config, + }) + end + + -- attach ltex for fitting ft only when spell checking becomes enabled + vim.api.nvim_create_autocmd("User", { + pattern = "SpellEnable", + callback = function() + lspconfig.ltex.setup({ + on_attach = function(client, bufnr) + on_attach(client, bufnr) + if require("core.util").is_available("ltex_extra") then + require("ltex_extra").setup() + end + end, + settings = { + ltex = { + language = vim.opt.spelllang:get(), + }, + }, + }) + vim.cmd("LspStart ltex") + end, + }) + end, + keys = { { "vs", ":LspInfo", desc = "LspInfo" } }, + }, + -- pretty lsp 'peek' menus + { + "DNLHC/glance.nvim", + opts = { border = { enable = true }, theme = { enable = true, mode = "auto" } }, + cmd = { "Glance" }, + }, +} diff --git a/nvim/.config/nvim/lua/plugins/outliners.lua b/nvim/.config/nvim/lua/plugins/outliners.lua new file mode 100644 index 0000000..86a3129 --- /dev/null +++ b/nvim/.config/nvim/lua/plugins/outliners.lua @@ -0,0 +1,51 @@ +return { + -- vista-like outline view for code + { + "stevearc/aerial.nvim", + config = true, + -- Optional dependencies + dependencies = { + "nvim-treesitter/nvim-treesitter", + "nvim-tree/nvim-web-devicons", + }, + cmd = { + "AerialToggle", + "AerialOpen", + "AerialOpenAll", + "AerialClose", + "AerialCloseAll", + "AerialNext", + "AerialPrev", + "AerialGo", + "AerialInfo", + "AerialNavToggle", + "AerialNavOpen", + "AerialNavClose", + }, + opts = { + backends = { "treesitter", "lsp", "markdown", "man" }, + }, + keys = { + { "so", "AerialNavToggle", silent = true, desc = "symbol navigator" }, + { "sO", "AerialToggle", silent = true, desc = "symbol outline" }, + }, + }, + -- useful quickfix-like buffer + { + "folke/trouble.nvim", + dependencies = { "nvim-tree/nvim-web-devicons" }, + opts = {}, + cmd = { + "Trouble", + }, + keys = { + { "sd", "Trouble diagnostics toggle", silent = true, desc = "diagnostics workspace" }, + { + "sD", + "Trouble diagnostics toggle filter.buf=0", + silent = true, + desc = "diagnostics document", + }, + }, + }, +}