local lsp_keymaps = function(buffer) local function map(mode, l, r, desc) vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc }) end map("n", "K", 'lua vim.lsp.buf.hover()', "See informations") map("n", "", 'lua vim.lsp.buf.signature_help()', "See signature help") map("n", "gD", 'lua vim.lsp.buf.declaration()', "Go to declaration") map("n", "gd", 'lua vim.lsp.buf.definition()', "Go to definition") map("n", "gI", 'lua vim.lsp.buf.implementation()', "Go to implementation") map("n", "gr", 'lua vim.lsp.buf.references()', "Go to reference(s)") map("n", "gs", 'lua vim.lsp.buf.type_definition()', "Type definition") map("n", "lr", 'lua vim.lsp.buf.rename()', "Rename") map("n", "la", 'lua vim.lsp.buf.code_action()', "Code action") map("n", "ll", 'lua vim.lsp.codelens.run()', "Run code lens") map("n", "lg", 'Telescope lsp_document_symbols', "Go to symbol") map("v", "lf", 'lua vim.lsp.buf.format({async=true})', "Range Format") end local function lsp_highlight_document(client) if client.server_capabilities.documentHighlightProvider then vim.cmd [[ augroup lsp_document_highlight autocmd! * autocmd! CursorHold lua vim.lsp.buf.document_highlight() autocmd! CursorMoved lua vim.lsp.buf.clear_references() augroup END ]] end end local kind_icons = { Text = "󰉿", Method = "󰆧", Function = "󰊕", Constructor = "", Field = "󰜢", Variable = "󰀫", Class = "󰠱", Interface = "", Module = "", Property = "󰜢", Unit = "󰑭", Value = "󰎠", Enum = "", Keyword = "󰌋", Snippet = "", Color = "󰏘", File = "󰈙", Reference = "󰈇", Folder = "󰉋", EnumMember = "", Constant = "󰏿", Struct = "󰙅", Event = "", Operator = "󰆕", TypeParameter = "", } return { { "dundalek/lazy-lsp.nvim", -- dev = true, event = { "BufReadPre", "BufNewFile" }, dependencies = { { "neovim/nvim-lspconfig", dependencies = { { "folke/neodev.nvim", opts = { experimental = { pathStrict = true } } }, }, }, "b0o/SchemaStore.nvim", "Hoffs/omnisharp-extended-lsp.nvim", "cmp-nvim-lsp", }, opts = function() local lsp_on_attach = function(client, buffer) lsp_keymaps(buffer) lsp_highlight_document(client) local ok, navic = pcall(require, "nvim-navic") if ok then navic.attach(client, buffer) end end local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities() local lspconfig = require("lspconfig") return { excluded_servers = { -- Disable generic purpose LSP that I don't care about. "efm", "diagnosticls", -- Bugged servers "sqls" }, preferred_servers = { haskell = { "hls" }, rust = { "rust_analyzer" }, c = { "clangd" }, cpp = { "clangd" }, python = { "pyright" }, nix = { "nil_ls" }, typescript = { "tsserver" }, javascript = { "tsserver" }, jsx = { "tsserver" }, tsx = { "tsserver" }, javascriptreact = { "tsserver" }, typescriptreact = { "tsserver" }, go = { "gopls" }, }, default_config = { on_attach = lsp_on_attach, capabilities = lsp_capabilities, }, configs = { jsonls = { settings = { json = { schemas = require('schemastore').json.schemas(), validate = { enable = true }, }, }, }, tsserver = { root_dir = lspconfig.util.root_pattern("yarn.lock", "package-lock.json", ".git"), single_file_support = false, }, omnisharp = { handlers = { ["textDocument/definition"] = require('omnisharp_extended').handler, }, enable_editorconfig_support = true, enable_roslyn_analyzers = true, organize_imports_on_format = true, enable_import_completion = true, cmd_env = { ["OMNISHARP_RoslynExtensionsOptions:enableDecompilationSupport"] = true, ["OMNISHARP_msbuild:EnablePackageAutoRestore"] = true, }, on_new_config = function(new_config, new_root_dir) pcall(require("lspconfig").omnisharp.document_config.default_config.on_new_config, new_config, new_root_dir) local custom_nix_pkgs = { "omnisharp-roslyn" } new_config.cmd = require("lazy-lsp").in_shell(custom_nix_pkgs, new_config.cmd) end, }, robotframework_ls = { cmd = { "nix-shell", "-p", "python3", "--command", "cd /tmp && python3 -m venv venv && . venv/bin/activate && pip install robotframework_lsp RESTInstance && robotframework_ls" }, settings = { robot = { codeFormatter = "robotidy", }, } }, nil_ls = { settings = { ["nil"] = { formatting = { command = { "nix-shell", "-p", "alejandra", "--run", "alejandra -" }, }, }, }, }, gopls = { settings = { -- https://go.googlesource.com/vscode-go/+/HEAD/docs/settings.md#settings-for gopls = { analyses = { nilness = true, unusedparams = true, unusedwrite = true, useany = true }, experimentalPostfixCompletions = true, gofumpt = true, staticcheck = true, usePlaceholders = true, hints = { assignVariableTypes = true, compositeLiteralFields = true, compositeLiteralTypes = true, constantValues = true, functionTypeParameters = true, parameterNames = true, rangeVariableTypes = true } } } }, }, } end, init = function() local signs = { { name = "DiagnosticSignError", text = "󰅚" }, { name = "DiagnosticSignWarn", text = "" }, { name = "DiagnosticSignHint", text = "󰌶" }, { name = "DiagnosticSignInfo", text = "" }, } for _, sign in ipairs(signs) do vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = "" }) end local function map(l, r, desc) vim.keymap.set("n", l, r, { desc = desc }) end map("[d", 'lua vim.diagnostic.goto_prev()', "Prev diagnostic") map("]d", 'lua vim.diagnostic.goto_next()', "Next diagnostic") map("gl", "lua vim.diagnostic.open_float()", "See diagnostics") map("li", "LspInfo", "Info") vim.diagnostic.config({ virtual_text = false, update_in_insert = true, float = { border = "rounded", source = "always", }, }) vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded", }) end, }, { "zbirenbaum/neodim", event = "LspAttach", opts = { alpha = 0.75, blend_color = "#000000", update_in_insert = { enable = true, delay = 100, }, hide = { virtual_text = true, signs = false, underline = true, } } }, { "L3MON4D3/LuaSnip", dependencies = { { "rafamadriz/friendly-snippets", config = function() require("luasnip.loaders.from_vscode").lazy_load() end, }, }, opts = { history = true, delete_check_events = "TextChanged", }, -- I'm never using snippets and it only bother me so for now I am disabling it. -- keys = { -- { -- "", -- function() -- return require("luasnip").jumpable(1) and "luasnip-jump-next" or "" -- end, -- expr = true, silent = true, mode = "i", -- }, -- { "", function() require("luasnip").jump(1) end, mode = "s" }, -- { "", function() require("luasnip").jump(-1) end, mode = { "i", "s" } }, -- }, }, { "hrsh7th/nvim-cmp", version = false, -- last release is way too old event = "InsertEnter", dependencies = { "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-buffer", "hrsh7th/cmp-path", "saadparwaiz1/cmp_luasnip", "LuaSnip", }, opts = function() local cmp = require("cmp") return { completion = { completeopt = "menu,menuone,noinsert", }, snippet = { expand = function(args) require("luasnip").lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.select_next_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.select_prev_item({ behavior = cmp.SelectBehavior.Insert }), [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.complete(), [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items. }), sources = cmp.config.sources({ { name = "nvim_lsp" }, { name = "luasnip" }, { name = "path" }, }), formatting = { fields = { "abbr", "kind" }, format = function(_, vim_item) vim_item.kind = string.format('%s %s', kind_icons[vim_item.kind], vim_item.kind) return vim_item end, }, navigation = { documentation = { border = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, }, }, experimental = { ghost_text = true, }, } end, init = function() vim.opt.completeopt = { "menuone", "preview", } vim.opt.pumheight = 15 end }, { "ray-x/lsp_signature.nvim", opts = { doc_lines = 100, fix_pos = true, always_trigger = true, toggle_key = "", floating_window = false, } }, { "stevearc/conform.nvim", keys = { { "lf", function() require("conform").format({ async = true, lsp_fallback = true }) end, desc = "Format", mode = { "n", "v" }, }, }, config = function(_, opts) require("conform").setup(opts) vim.o.formatexpr = "v:lua.require'conform'.formatexpr()" end, opts = { formatters_by_ft = { python = { "black" }, javascript = { { "prettierd", "prettier" } }, typescript = { { "prettierd", "prettier" } }, javascriptreact = { { "prettierd", "prettier" } }, typescriptreact = { { "prettierd", "prettier" } }, css = { { "prettierd", "prettier" } }, html = { { "prettierd", "prettier" } }, sql = { "pg_format" }, }, } }, { "mfussenegger/nvim-lint", event = { "BufReadPre", "BufNewFile" }, config = function(_, opts) require("lint").linters_by_ft = opts vim.api.nvim_create_autocmd({ "BufWritePost", "BufEnter" }, { callback = function() require("lint").try_lint() end, }) end, opts = { javascript = { "eslint_d" }, typescript = { "eslint_d" }, javascriptreact = { "eslint_d" }, typescriptreact = { "eslint_d" }, }, }, { "kosayoda/nvim-lightbulb", event = { "CursorHold", "CursorHoldI" }, opts = { sign = { enable = false, }, float = { enable = true, text = "" }, autocmd = { enabled = true, }, }, } }