diff options
-rw-r--r-- | README.md | 24 | ||||
-rw-r--r-- | lua/core/galaxyline.lua | 30 | ||||
-rw-r--r-- | lua/default-config.lua | 521 | ||||
-rw-r--r-- | lua/lsp/init.lua | 98 | ||||
-rw-r--r-- | lua/lsp/keybinds.lua | 67 | ||||
-rw-r--r-- | lua/lsp/null-ls.lua | 113 | ||||
-rw-r--r-- | lua/lsp/service.lua | 122 | ||||
-rw-r--r-- | lua/utils/init.lua | 6 | ||||
-rw-r--r-- | utils/installer/lv-config.example-no-ts.lua | 15 | ||||
-rw-r--r-- | utils/installer/lv-config.example.lua | 15 |
10 files changed, 576 insertions, 435 deletions
@@ -90,11 +90,24 @@ lvim.builtin.treesitter.ensure_installed = "maintained" lvim.builtin.treesitter.ignore_install = { "haskell" } lvim.builtin.treesitter.highlight.enabled = true -lvim.lang.python.formatter.exe = "black" -lvim.lang.python.linters = "" - lvim.lsp.diagnostics.virtual_text = false +-- set a formatter if you want to override the default lsp one (if it exists) +lvim.lang.python.formatters = { + { + exe = "black", + args = {} + } +} +-- set an additional linter +lvim.lang.python.linters = { + { + exe = "flake8", + args = {} + } +} + + -- Additional Plugins lvim.plugins = { {"lunarvim/colorschemes"}, @@ -145,11 +158,6 @@ To update plugins: To update LunarVim: ```bash -# Master Branch -cd ~/.config/nvim && git pull -:PackerSync - -# Rolling Branch cd ~/.local/share/lunarvim/lvim && git pull :PackerSync ``` diff --git a/lua/core/galaxyline.lua b/lua/core/galaxyline.lua index cf7d35d0..2aae0242 100644 --- a/lua/core/galaxyline.lua +++ b/lua/core/galaxyline.lua @@ -6,6 +6,8 @@ if not status_ok then return end +local utils = require "utils" + -- NOTE: if someone defines colors but doesn't have them then this will break local palette_status_ok, colors = pcall(require, lvim.colorscheme .. ".palette") if not palette_status_ok then @@ -200,36 +202,22 @@ table.insert(gls.right, { }, }) --- TODO: this function doesn't need to be this complicated local function get_attached_provider_name(msg) msg = msg or "LSP Inactive" - local buf_ft = vim.bo.filetype local buf_clients = vim.lsp.buf_get_clients() if next(buf_clients) == nil then return msg end - - local utils = require "utils" - local config = require("null-ls.config").get() - local builtins = require "null-ls.builtins" - -- concat all the builtin formatters and linters from null-ls - local all_things = builtins.formatting - for k, v in pairs(builtins.diagnostics) do - all_things[k] = v - end - - -- if we open multiple filetypes in the same session - -- null-ls will register multiple formatter/linters - -- but only use the ones that support vim.bo.filetype - -- so we need to filter them + local buf_ft = vim.bo.filetype local buf_client_names = {} + local null_ls_providers = require("lsp.null-ls").requested_providers for _, client in pairs(buf_clients) do if client.name == "null-ls" then - -- for every registered formatter/linter in the current buffer - for _, v in pairs(config._names) do - -- show only the ones that are being used for the current filetype - if utils.has_value(all_things[v].filetypes, buf_ft) then - table.insert(buf_client_names, v) + for _, provider in pairs(null_ls_providers) do + if vim.tbl_contains(provider.filetypes, buf_ft) then + if not vim.tbl_contains(buf_client_names, provider.name) then + table.insert(buf_client_names, provider.name) + end end end else diff --git a/lua/default-config.lua b/lua/default-config.lua index 25c6dcef..41636757 100644 --- a/lua/default-config.lua +++ b/lua/default-config.lua @@ -47,6 +47,7 @@ lvim = { popup_border = "single", default_keybinds = true, on_attach_callback = nil, + on_init_callback = nil, }, plugins = { @@ -54,11 +55,13 @@ lvim = { }, autocommands = {}, + debug = false, } local schemas = nil -local common_on_attach = require("lsp.service").common_on_attach -local common_capabilities = require("lsp.service").common_capabilities() +local common_on_attach = require("lsp").common_on_attach +local common_capabilities = require("lsp").common_capabilities() +local common_on_init = require("lsp").common_on_init local status_ok, jsonls_settings = pcall(require, "nlspsettings.jsonls") if status_ok then schemas = jsonls_settings.get_default_schemas() @@ -67,9 +70,12 @@ end -- TODO move all of this into lang specific files, only require when using lvim.lang = { asm = { - formatter = { - exe = "asmfmt", - args = {}, + formatters = { + { + -- @usage can be asmfmt + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -78,9 +84,12 @@ lvim.lang = { }, }, beancount = { - formatter = { - exe = "bean_format", - args = {}, + formatters = { + { + -- @usage can be bean_format + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -88,19 +97,21 @@ lvim.lang = { setup = { cmd = { "beancount-langserver" }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, c = { - formatter = { - exe = "clang_format", - args = {}, - stdin = true, - }, - linters = { - "clangtidy", + formatters = { + { + -- @usage can be clang_format or uncrustify + exe = "", + args = {}, + stdin = true, + }, }, + linters = {}, lsp = { provider = "clangd", setup = { @@ -113,20 +124,21 @@ lvim.lang = { "--clang-tidy-checks=-*,llvm-*,clang-analyzer-*", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, cpp = { - formatter = { - exe = "clang_format", - args = {}, - stdin = true, - }, - linters = { - "cppcheck", - "clangtidy", + formatters = { + { + -- @usage can be clang_format or uncrustify + exe = "", + args = {}, + stdin = true, + }, }, + linters = {}, lsp = { provider = "clangd", setup = { @@ -139,14 +151,18 @@ lvim.lang = { "--clang-tidy-checks=-*,llvm-*,clang-analyzer-*", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, crystal = { - formatter = { - exe = "crystal_format", - args = {}, + formatters = { + { + -- @usage can be crystal_format + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -154,14 +170,18 @@ lvim.lang = { setup = { cmd = { "crystalline" }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, cs = { - formatter = { - exe = "clang_format", - args = {}, + formatters = { + { + -- @usage can be clang_format or uncrustify + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -174,14 +194,18 @@ lvim.lang = { tostring(vim.fn.getpid()), }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, cmake = { - formatter = { - exe = "cmake_format", - args = {}, + formatters = { + { + -- @usage can be cmake_format + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -192,15 +216,16 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, clojure = { - formatter = { + formatters = { { exe = "", args = {}, - }, + } }, linters = {}, lsp = { provider = "clojure_lsp", @@ -210,14 +235,18 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, css = { - formatter = { - exe = "prettier", - args = {}, + formatters = { + { + -- @usage can be prettier or prettierd + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -229,14 +258,18 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, d = { - formatter = { - exe = "dfmt", - args = {}, + formatters = { + { + -- @usage can be dfmt + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -244,15 +277,19 @@ lvim.lang = { setup = { cmd = { "serve-d" }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, dart = { - formatter = { - exe = "dart_format", - args = {}, - stdin = true, + formatters = { + { + -- @usage can be dart_format + exe = "", + args = {}, + stdin = true, + }, }, linters = {}, lsp = { @@ -264,14 +301,18 @@ lvim.lang = { "--lsp", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, docker = { - formatter = { - exe = "", - args = {}, + formatters = { + { + exe = "", + args = {}, + }, + -- @usage can be {"hadolint"} }, linters = {}, lsp = { @@ -282,15 +323,19 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, elixir = { - formatter = { - exe = "mix", - args = {}, - stdin = true, + formatters = { + { + -- @usage can be mix + exe = "", + args = {}, + stdin = true, + }, }, linters = {}, lsp = { @@ -300,15 +345,19 @@ lvim.lang = { DATA_PATH .. "/lspinstall/elixir/elixir-ls/language_server.sh", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, elm = { - formatter = { - exe = "elm_format", - args = {}, - stdin = true, + formatters = { + { + -- @usage can be elm_format + exe = "", + args = {}, + stdin = true, + }, }, linters = {}, lsp = { @@ -318,6 +367,7 @@ lvim.lang = { DATA_PATH .. "/lspinstall/elm/node_modules/.bin/elm-language-server", }, on_attach = common_on_attach, + on_init = common_on_init, init_options = { elmAnalyseTrigger = "change", elmFormatPath = DATA_PATH .. "/lspinstall/elm/node_modules/.bin/elm-format", @@ -328,9 +378,12 @@ lvim.lang = { }, }, erlang = { - formatter = { - exe = "erlfmt", - args = {}, + formatters = { + { + -- @usage can be erlfmt + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -340,35 +393,40 @@ lvim.lang = { "erlang_ls", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, emmet = { active = false }, fish = { - formatter = { - exe = "fish_indent", - args = {}, + formatters = { + { + -- @usage can be fish_indent + exe = "", + args = {}, + }, }, linters = {}, lsp = { provider = "", setup = { on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, go = { - formatter = { - exe = "gofmt", - args = {}, - stdin = true, - }, - linters = { - "golangcilint", - "revive", + formatters = { + { + -- @usage can be gofmt or goimports or gofumpt + exe = "", + args = {}, + stdin = true, + }, }, + linters = {}, lsp = { provider = "gopls", setup = { @@ -376,15 +434,16 @@ lvim.lang = { DATA_PATH .. "/lspinstall/go/gopls", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, graphql = { - formatter = { + formatters = { { exe = "", args = {}, - }, + } }, linters = {}, lsp = { provider = "graphql", @@ -396,20 +455,20 @@ lvim.lang = { "stream", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, html = { - formatter = { - exe = "prettier", - args = {}, - }, - linters = { - "tidy", - -- https://docs.errata.ai/vale/scoping#html - "vale", + formatters = { + { + -- @usage can be prettier or prettierd + exe = "", + args = {}, + }, }, + linters = {}, lsp = { provider = "html", setup = { @@ -419,14 +478,18 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, java = { - formatter = { - exe = "prettier", - args = { "--stdin-filepath", vim.api.nvim_buf_get_name(0) }, + formatters = { + { + -- @usage can be clang_format or uncrustify + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -434,15 +497,19 @@ lvim.lang = { setup = { cmd = { DATA_PATH .. "/lspinstall/java/jdtls.sh" }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, json = { - formatter = { - exe = "json_tool", - args = {}, - stdin = true, + formatters = { + { + -- @usage can be json_tool or prettier or prettierd + exe = "", + args = {}, + stdin = true, + }, }, linters = {}, lsp = { @@ -454,6 +521,7 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, settings = { json = { @@ -477,10 +545,10 @@ lvim.lang = { }, }, julia = { - formatter = { + formatters = { { exe = "", args = {}, - }, + } }, linters = {}, lsp = { provider = "julials", @@ -493,15 +561,16 @@ lvim.lang = { CONFIG_PATH .. "/utils/julia/run.jl", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, kotlin = { - formatter = { + formatters = { { exe = "", args = {}, - }, + } }, linters = {}, lsp = { provider = "kotlin_language_server", @@ -510,6 +579,7 @@ lvim.lang = { DATA_PATH .. "/lspinstall/kotlin/server/bin/kotlin-language-server", }, on_attach = common_on_attach, + on_init = common_on_init, root_dir = function(fname) local util = require "lspconfig/util" @@ -530,11 +600,14 @@ lvim.lang = { }, }, lua = { - formatter = { - exe = "stylua", - args = {}, + formatters = { + { + -- @usage can be stylua or lua_format + exe = "stylua", + args = {}, + }, }, - linters = { "luacheck" }, + linters = {}, lsp = { provider = "sumneko_lua", setup = { @@ -543,7 +616,9 @@ lvim.lang = { "-E", DATA_PATH .. "/lspinstall/lua/main.lua", }, + capabilities = common_capabilities, on_attach = common_on_attach, + on_init = common_on_init, settings = { Lua = { runtime = { @@ -572,20 +647,26 @@ lvim.lang = { }, }, nginx = { - formatter = { - exe = "nginx_beautifier", - args = { - provider = "", - setup = {}, + formatters = { + { + -- @usage can be nginx_beautifier + exe = "", + args = { + provider = "", + setup = {}, + }, }, }, linters = {}, lsp = {}, }, perl = { - formatter = { - exe = "perltidy", - args = {}, + formatters = { + { + -- @usage can be perltidy + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -594,9 +675,12 @@ lvim.lang = { }, }, sql = { - formatter = { - exe = "sqlformat", - args = {}, + formatters = { + { + -- @usage can be sqlformat + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -607,9 +691,12 @@ lvim.lang = { }, }, php = { - formatter = { - exe = "phpcbf", - args = {}, + formatters = { + { + -- @usage can be phpcbf + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -620,6 +707,7 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, filetypes = { "php", "phtml" }, settings = { intelephense = { @@ -632,28 +720,30 @@ lvim.lang = { }, }, puppet = { - formatter = { + formatters = { { exe = "", args = {}, - }, + } }, linters = {}, lsp = { provider = "puppet", setup = { on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, javascript = { - -- @usage can be prettier or eslint - formatter = { - exe = "prettier", - args = {}, - }, - linters = { - "eslint", + -- @usage can be prettier or prettier_d_slim or prettierd + formatters = { + { + exe = "", + args = {}, + }, }, + -- @usage can be {"eslint"} or {"eslint_d"} + linters = {}, lsp = { provider = "tsserver", setup = { @@ -663,19 +753,21 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, javascriptreact = { - -- @usage can be prettier or eslint - formatter = { - exe = "prettier", - args = {}, - }, - linters = { - "eslint", + formatters = { + { + -- @usage can be prettier or prettier_d_slim or prettierd + exe = "", + args = {}, + }, }, + -- @usage can be {"eslint"} or {"eslint_d"} + linters = {}, lsp = { provider = "tsserver", setup = { @@ -685,21 +777,20 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, python = { - -- @usage can be flake8 or yapf - formatter = { - exe = "black", - args = {}, - }, - linters = { - "flake8", - "pylint", - "mypy", + formatters = { + { + -- @usage can be black or yapf or isort + exe = "", + args = {}, + }, }, + linters = {}, lsp = { provider = "pyright", setup = { @@ -708,6 +799,7 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, @@ -715,9 +807,12 @@ lvim.lang = { -- R -e 'install.packages("formatR",repos = "http://cran.us.r-project.org")' -- R -e 'install.packages("readr",repos = "http://cran.us.r-project.org")' r = { - formatter = { - exe = "format_r", - args = {}, + formatters = { + { + -- @usage can be format_r + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -730,16 +825,20 @@ lvim.lang = { "languageserver::run()", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, ruby = { - formatter = { - exe = "rufo", - args = {}, + formatters = { + { + -- @usage can be rufo + exe = "", + args = {}, + }, }, - linters = { "ruby" }, + linters = {}, lsp = { provider = "solargraph", setup = { @@ -748,14 +847,18 @@ lvim.lang = { "stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, rust = { - formatter = { - exe = "rustfmt", - args = {}, + formatters = { + { + -- @usage can be rustfmt + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -765,32 +868,38 @@ lvim.lang = { DATA_PATH .. "/lspinstall/rust/rust-analyzer", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, scala = { - formatter = { - exe = "scalafmt", - args = {}, + formatters = { + { + -- @usage can be scalafmt + exe = "", + args = {}, + }, }, linters = { "" }, lsp = { provider = "metals", setup = { on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, sh = { - -- @usage can be 'shfmt' - formatter = { - exe = "shfmt", - args = {}, + formatters = { + { + -- @usage can be shfmt + exe = "", + args = {}, + }, }, - -- @usage can be 'shellcheck' - linters = { "shellcheck" }, + linters = {}, lsp = { provider = "bashls", setup = { @@ -799,15 +908,16 @@ lvim.lang = { "start", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, svelte = { - formatter = { + formatters = { { exe = "", args = {}, - }, + } }, linters = {}, lsp = { provider = "svelte", @@ -817,14 +927,18 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, swift = { - formatter = { - exe = "swiftformat", - args = {}, + formatters = { + { + -- @usage can be swiftformat + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -835,6 +949,7 @@ lvim.lang = { "sourcekit-lsp", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, @@ -852,9 +967,12 @@ lvim.lang = { }, }, terraform = { - formatter = { - exe = "terraform_fmt", - args = {}, + formatters = { + { + -- @usage can be terraform_fmt + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -865,35 +983,41 @@ lvim.lang = { "serve", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, tex = { - formatter = { - exe = "latexindent", - args = {}, - stdin = false, + formatters = { + { + exe = "", + args = {}, + stdin = false, + }, + -- @usage can be chktex or vale }, - linters = { "chktex" }, + linters = {}, lsp = { provider = "texlab", setup = { cmd = { DATA_PATH .. "/lspinstall/latex/texlab" }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, typescript = { - -- @usage can be prettier or eslint - formatter = { - exe = "prettier", - args = {}, - }, - linters = { - "eslint", + formatters = { + { + -- @usage can be prettier or prettierd or prettier_d_slim + exe = "", + args = {}, + }, + -- @usage can be {"eslint"} or {"eslint_d"} }, + linters = {}, lsp = { provider = "tsserver", setup = { @@ -903,19 +1027,21 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, typescriptreact = { - -- @usage can be prettier or eslint - formatter = { - exe = "prettier", - args = {}, - }, - linters = { - "eslint", + formatters = { + { + -- @usage can be prettier or prettierd or prettier_d_slim + exe = "", + args = {}, + }, }, + -- @usage can be {"eslint"} or {"eslint_d"} + linters = {}, lsp = { provider = "tsserver", setup = { @@ -925,15 +1051,19 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, vim = { - formatter = { - exe = "", - args = {}, + formatters = { + { + exe = "", + args = {}, + }, }, + -- @usage can be {"vint"} linters = { "" }, lsp = { provider = "vimls", @@ -943,15 +1073,20 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, vue = { - formatter = { - exe = "prettier", - args = {}, + formatters = { + { + -- @usage can be prettier or prettierd or prettier_d_slim + exe = "", + args = {}, + }, }, + -- @usage can be {"eslint"} or {"eslint_d"} linters = {}, lsp = { provider = "vuels", @@ -960,14 +1095,18 @@ lvim.lang = { DATA_PATH .. "/lspinstall/vue/node_modules/.bin/vls", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, yaml = { - formatter = { - exe = "prettier", - args = {}, + formatters = { + { + -- @usage can be prettier or prettierd + exe = "", + args = {}, + }, }, linters = {}, lsp = { @@ -978,16 +1117,17 @@ lvim.lang = { "--stdio", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, }, zig = { - formatter = { + formatters = { { exe = "", args = {}, stdin = false, - }, + } }, linters = {}, lsp = { provider = "zls", @@ -996,6 +1136,7 @@ lvim.lang = { "zls", }, on_attach = common_on_attach, + on_init = common_on_init, capabilities = common_capabilities, }, }, diff --git a/lua/lsp/init.lua b/lua/lsp/init.lua index 62c42fd8..67007e81 100644 --- a/lua/lsp/init.lua +++ b/lua/lsp/init.lua @@ -1,55 +1,79 @@ -local utils = require "utils" -local service = require "lsp.service" -local null_ls = require "lsp.null-ls" local M = {} - +local u = require "utils" function M.config() require("lsp.kind").setup() require("lsp.handlers").setup() require("lsp.signs").setup() - require("lsp.keybinds").setup() end -function M.setup(lang) - local lang_server = lvim.lang[lang].lsp - local provider = lang_server.provider - if utils.check_lsp_client_active(provider) then - return +local function lsp_highlight_document(client) + if lvim.lsp.document_highlight == false then + return -- we don't need further + end + -- Set autocommands conditional on server_capabilities + if client.resolved_capabilities.document_highlight then + vim.api.nvim_exec( + [[ + hi LspReferenceRead cterm=bold ctermbg=red guibg=#464646 + hi LspReferenceText cterm=bold ctermbg=red guibg=#464646 + hi LspReferenceWrite cterm=bold ctermbg=red guibg=#464646 + augroup lsp_document_highlight + autocmd! * <buffer> + autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() + autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() + augroup END + ]], + false + ) end +end - local overrides = lvim.lsp.override +local function formatter_handler(client) + local buffer_filetype = vim.bo.filetype + local ext_provider = lvim.lang[buffer_filetype].formatter.exe - if utils.is_table(overrides) then - if utils.has_value(overrides, lang) then - return - end + if ext_provider then + client.resolved_capabilities.document_formatting = false + u.lvim_log( + string.format("Overriding [%s] formatting if exists, Using provider [%s] instead", client.name, ext_provider) + ) end +end - if utils.is_string(overrides) then - if overrides == lang then - return - end +function M.common_capabilities() + local capabilities = vim.lsp.protocol.make_client_capabilities() + capabilities.textDocument.completion.completionItem.snippetSupport = true + capabilities.textDocument.completion.completionItem.resolveSupport = { + properties = { + "documentation", + "detail", + "additionalTextEdits", + }, + } + return capabilities +end + +function M.common_on_init(client, bufnr) + if lvim.lsp.on_init_callback then + lvim.lsp.on_init_callback(client, bufnr) + return end - local sources = null_ls.setup(lang) - - for _, source in pairs(sources) do - local method = source.method - local format_method = "NULL_LS_FORMATTING" - - if utils.is_table(method) then - if utils.has_value(method, format_method) then - lang_server.setup.on_attach = service.no_formatter_on_attach - end - end - - if utils.is_string(method) then - if method == format_method then - lang_server.setup.on_attach = service.no_formatter_on_attach - end - end + formatter_handler(client) +end + +function M.common_on_attach(client, bufnr) + if lvim.lsp.on_attach_callback then + lvim.lsp.on_attach_callback(client, bufnr) end + lsp_highlight_document(client) + require("lsp.keybinds").setup() + require("lsp.null-ls").setup(vim.bo.filetype) +end - if provider == "" or provider == nil then +function M.setup(lang) + local lang_server = lvim.lang[lang].lsp + local provider = lang_server.provider + if require("utils").check_lsp_client_active(provider) then return end diff --git a/lua/lsp/keybinds.lua b/lua/lsp/keybinds.lua index 820ebce9..cc0d4ec9 100644 --- a/lua/lsp/keybinds.lua +++ b/lua/lsp/keybinds.lua @@ -1,5 +1,70 @@ local M = {} +-- Taken from https://www.reddit.com/r/neovim/comments/gyb077/nvimlsp_peek_defination_javascript_ttserver/ +function M.preview_location(location, context, before_context) + -- location may be LocationLink or Location (more useful for the former) + context = context or 15 + before_context = before_context or 0 + local uri = location.targetUri or location.uri + if uri == nil then + return + end + local bufnr = vim.uri_to_bufnr(uri) + if not vim.api.nvim_buf_is_loaded(bufnr) then + vim.fn.bufload(bufnr) + end + + local range = location.targetRange or location.range + local contents = vim.api.nvim_buf_get_lines( + bufnr, + range.start.line - before_context, + range["end"].line + 1 + context, + false + ) + local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") + return vim.lsp.util.open_floating_preview(contents, filetype, { border = lvim.lsp.popup_border }) +end + +function M.preview_location_callback(_, method, result) + local context = 15 + if result == nil or vim.tbl_isempty(result) then + print("No location found: " .. method) + return nil + end + if vim.tbl_islist(result) then + M.floating_buf, M.floating_win = M.preview_location(result[1], context) + else + M.floating_buf, M.floating_win = M.preview_location(result, context) + end +end + +function M.PeekDefinition() + if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then + vim.api.nvim_set_current_win(M.floating_win) + else + local params = vim.lsp.util.make_position_params() + return vim.lsp.buf_request(0, "textDocument/definition", params, M.preview_location_callback) + end +end + +function M.PeekTypeDefinition() + if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then + vim.api.nvim_set_current_win(M.floating_win) + else + local params = vim.lsp.util.make_position_params() + return vim.lsp.buf_request(0, "textDocument/typeDefinition", params, M.preview_location_callback) + end +end + +function M.PeekImplementation() + if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then + vim.api.nvim_set_current_win(M.floating_win) + else + local params = vim.lsp.util.make_position_params() + return vim.lsp.buf_request(0, "textDocument/implementation", params, M.preview_location_callback) + end +end + function M.setup() if lvim.lsp.default_keybinds then vim.cmd "nnoremap <silent> gd <cmd>lua vim.lsp.buf.definition()<CR>" @@ -13,7 +78,7 @@ function M.setup() { noremap = true, silent = true } ) - vim.cmd "nnoremap <silent> gp <cmd>lua require'lsp.service'.PeekDefinition()<CR>" + vim.cmd "nnoremap <silent> gp <cmd>lua require'lsp.keybinds'.PeekDefinition()<CR>" vim.cmd "nnoremap <silent> K :lua vim.lsp.buf.hover()<CR>" vim.cmd "nnoremap <silent> <C-p> :lua vim.lsp.diagnostic.goto_prev({popup_opts = {border = lvim.lsp.popup_border}})<CR>" vim.cmd "nnoremap <silent> <C-n> :lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<CR>" diff --git a/lua/lsp/null-ls.lua b/lua/lsp/null-ls.lua index 6a31de26..d2222602 100644 --- a/lua/lsp/null-ls.lua +++ b/lua/lsp/null-ls.lua @@ -1,76 +1,79 @@ local M = {} +local u = require "utils" +local null_ls = require "null-ls" -local _, null_ls = pcall(require, "null-ls") -local utils = require "utils" -local sources = {} +local nodejs_local_providers = { "prettier", "prettierd", "prettier_d_slim", "eslint_d", "eslint" } -local local_executables = { "prettier", "prettierd", "prettier_d_slim", "eslint_d", "eslint" } +M.requested_providers = {} -local find_local_exe = function(exe) - vim.cmd "let root_dir = FindRootDirectory()" - local root_dir = vim.api.nvim_get_var "root_dir" - local local_exe = root_dir .. "/node_modules/.bin/" .. exe - return local_exe +local function is_nodejs_provider(provider) + for _, local_provider in ipairs(nodejs_local_providers) do + if local_provider == provider.exe then + return true + end + end + return false end --- https://github.com/jose-elias-alvarez/null-ls.nvim/blob/9b8458bd1648e84169a7e8638091ba15c2f20fc0/doc/BUILTINS.md#eslint -local get_normalized_exe = function(exe, type) - if type == "diagnostics" and exe == "eslint_d" then - return "eslint" +local function is_provider_found(provider) + -- special case: fallback to "eslint" + -- https://github.com/jose-elias-alvarez/null-ls.nvim/blob/9b8458bd1648e84169a7e8638091ba15c2f20fc0/doc/BUILTINS.md#eslint + provider._opts.command = provider._opts.command == "eslint_d" and "eslint" or provider._opts.command + + local retval = { is_local = false, path = nil } + if vim.fn.executable(provider._opts.command) == 1 then + return false, provider._opts.command end - return exe + if is_nodejs_provider(provider) then + vim.cmd "let root_dir = FindRootDirectory()" + local root_dir = vim.api.nvim_get_var "root_dir" + local local_provider_command = root_dir .. "/node_modules/.bin/" .. provider._opts.command + if vim.fn.executable(local_provider_command) == 1 then + retval.is_local = true + retval.path = local_provider_command + end + end + return retval.is_local, retval.path end -local function setup_ls(exe, type) - if utils.has_value(local_executables, exe) then - local normalized_exe = get_normalized_exe(exe, type) - local smart_executable = null_ls.builtins[type][normalized_exe] - local local_executable = find_local_exe(exe) - if vim.fn.executable(local_executable) == 1 then - smart_executable._opts.command = local_executable - table.insert(sources, smart_executable) - else - if vim.fn.executable(exe) == 1 then - smart_executable._opts.command = exe - table.insert(sources, smart_executable) - end - end - else - if null_ls.builtins[type][exe] and vim.fn.executable(null_ls.builtins[type][exe]._opts.command) then - table.insert(sources, null_ls.builtins[type][exe]) - end +local function validate_provider(provider) + local is_local, provider_path = is_provider_found(provider) + if not provider_path then + u.lvim_log(string.format("Unable to find the path for: [%s]", provider)) + return false end - null_ls.register { sources = sources } + if is_local then + provider._opts.command = provider_path + end + return true end -- TODO: for linters and formatters with spaces and '-' replace with '_' -local function setup(filetype, type) - local executables = nil - if type == "diagnostics" then - executables = lvim.lang[filetype].linters +function M.setup(filetype) + for _, formatter in pairs(lvim.lang[filetype].formatters) do + local builtin_formatter = null_ls.builtins.formatting[formatter.exe] + -- FIXME: why doesn't this work? + -- builtin_formatter._opts.args = formatter.args or builtin_formatter._opts.args + -- builtin_formatter._opts.to_stdin = formatter.stdin or builtin_formatter._opts.to_stdin + table.insert(M.requested_providers, builtin_formatter) + u.lvim_log(string.format("Using format provider: [%s]", formatter.exe)) end - if type == "formatting" then - executables = lvim.lang[filetype].formatter.exe + + for _, linter in pairs(lvim.lang[filetype].linters) do + local builtin_diagnoser = null_ls.builtins.diagnostics[linter.exe] + -- FIXME: why doesn't this work? + -- builtin_diagnoser._opts.args = linter.args or builtin_diagnoser._opts.args + -- builtin_diagnoser._opts.to_stdin = linter.stdin or builtin_diagnoser._opts.to_stdin + table.insert(M.requested_providers, builtin_diagnoser) + u.lvim_log(string.format("Using linter provider: [%s]", linter.exe)) end - if utils.is_table(executables) then - for _, exe in pairs(executables) do - if exe ~= "" then - setup_ls(exe, type) - end + for idx, provider in pairs(M.requested_providers) do + if not validate_provider(provider) then + table.remove(M.requested_providers, idx) end end - if utils.is_string(executables) and executables ~= "" then - setup_ls(executables, type) - end -end - --- TODO: return the formatter if one was registered, then turn off the builtin formatter -function M.setup(filetype) - setup(filetype, "formatting") - setup(filetype, "diagnostics") - lvim.sources = sources - return sources + null_ls.register { sources = M.requested_providers } end return M diff --git a/lua/lsp/service.lua b/lua/lsp/service.lua deleted file mode 100644 index 0c49bacd..00000000 --- a/lua/lsp/service.lua +++ /dev/null @@ -1,122 +0,0 @@ -local M = {} - -local function lsp_highlight_document(client) - if lvim.lsp.document_highlight == false then - return -- we don't need further - end - -- Set autocommands conditional on server_capabilities - if client.resolved_capabilities.document_highlight then - vim.api.nvim_exec( - [[ - hi LspReferenceRead cterm=bold ctermbg=red guibg=#464646 - hi LspReferenceText cterm=bold ctermbg=red guibg=#464646 - hi LspReferenceWrite cterm=bold ctermbg=red guibg=#464646 - augroup lsp_document_highlight - autocmd! * <buffer> - autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight() - autocmd CursorMoved <buffer> lua vim.lsp.buf.clear_references() - augroup END - ]], - false - ) - end -end - -function M.lsp_highlight_document(client) - lsp_highlight_document(client) -end - --- Taken from https://www.reddit.com/r/neovim/comments/gyb077/nvimlsp_peek_defination_javascript_ttserver/ -function M.preview_location(location, context, before_context) - -- location may be LocationLink or Location (more useful for the former) - context = context or 15 - before_context = before_context or 0 - local uri = location.targetUri or location.uri - if uri == nil then - return - end - local bufnr = vim.uri_to_bufnr(uri) - if not vim.api.nvim_buf_is_loaded(bufnr) then - vim.fn.bufload(bufnr) - end - - local range = location.targetRange or location.range - local contents = vim.api.nvim_buf_get_lines( - bufnr, - range.start.line - before_context, - range["end"].line + 1 + context, - false - ) - local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") - return vim.lsp.util.open_floating_preview(contents, filetype, { border = lvim.lsp.popup_border }) -end - -function M.preview_location_callback(_, method, result) - local context = 15 - if result == nil or vim.tbl_isempty(result) then - print("No location found: " .. method) - return nil - end - if vim.tbl_islist(result) then - M.floating_buf, M.floating_win = M.preview_location(result[1], context) - else - M.floating_buf, M.floating_win = M.preview_location(result, context) - end -end - -function M.PeekDefinition() - if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then - vim.api.nvim_set_current_win(M.floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request(0, "textDocument/definition", params, M.preview_location_callback) - end -end - -function M.PeekTypeDefinition() - if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then - vim.api.nvim_set_current_win(M.floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request(0, "textDocument/typeDefinition", params, M.preview_location_callback) - end -end - -function M.PeekImplementation() - if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then - vim.api.nvim_set_current_win(M.floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request(0, "textDocument/implementation", params, M.preview_location_callback) - end -end - -function M.common_on_attach(client, bufnr) - if lvim.lsp.on_attach_callback then - lvim.lsp.on_attach_callback(client, bufnr) - end - lsp_highlight_document(client) -end - -function M.no_formatter_on_attach(client, bufnr) - if lvim.lsp.on_attach_callback then - lvim.lsp.on_attach_callback(client, bufnr) - end - lsp_highlight_document(client) - client.resolved_capabilities.document_formatting = false -end - -function M.common_capabilities() - local capabilities = vim.lsp.protocol.make_client_capabilities() - capabilities.textDocument.completion.completionItem.snippetSupport = true - capabilities.textDocument.completion.completionItem.resolveSupport = { - properties = { - "documentation", - "detail", - "additionalTextEdits", - }, - } - return capabilities -end - -return M diff --git a/lua/utils/init.lua b/lua/utils/init.lua index fe1e09aa..a41bfc10 100644 --- a/lua/utils/init.lua +++ b/lua/utils/init.lua @@ -162,6 +162,12 @@ function utils.gsub_args(args) return args end +function utils.lvim_log(msg) + if lvim.debug then + vim.notify(msg, vim.log.levels.DEBUG) + end +end + return utils -- TODO: find a new home for these autocommands diff --git a/utils/installer/lv-config.example-no-ts.lua b/utils/installer/lv-config.example-no-ts.lua index ab12309d..c0df5b8b 100644 --- a/utils/installer/lv-config.example-no-ts.lua +++ b/utils/installer/lv-config.example-no-ts.lua @@ -48,6 +48,21 @@ lvim.builtin.treesitter.highlight.enabled = true -- buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc") -- end +-- set a formatter if you want to override the default lsp one (if it exists) +-- lvim.lang.python.formatters = { +-- { +-- exe = "black", +-- args = {} +-- } +-- } +-- set an additional linter +-- lvim.lang.python.linters = { +-- { +-- exe = "flake8", +-- args = {} +-- } +-- } + -- Additional Plugins -- lvim.plugins = { -- {"folke/tokyonight.nvim"}, { diff --git a/utils/installer/lv-config.example.lua b/utils/installer/lv-config.example.lua index 681f5f65..843917a7 100644 --- a/utils/installer/lv-config.example.lua +++ b/utils/installer/lv-config.example.lua @@ -56,7 +56,20 @@ lvim.builtin.treesitter.highlight.enabled = true -- buf_set_option("omnifunc", "v:lua.vim.lsp.omnifunc") -- end --- python +-- set a formatter if you want to override the default lsp one (if it exists) +-- lvim.lang.python.formatters = { +-- { +-- exe = "black", +-- args = {} +-- } +-- } +-- set an additional linter +-- lvim.lang.python.linters = { +-- { +-- exe = "flake8", +-- args = {} +-- } +-- } -- Additional Plugins -- lvim.plugins = { |