diff options
| author | kylo252 <[email protected]> | 2021-10-03 16:13:46 +0200 | 
|---|---|---|
| committer | GitHub <[email protected]> | 2021-10-03 16:13:46 +0200 | 
| commit | d01ba08eaec1640ac2d038893525b3ba0af25813 (patch) | |
| tree | 5edf2f5a12cedacb32f0c5d45ec2d999dacb99cd /lua | |
| parent | 3e1cd1ec235404ae96ed2d0756729cf44ae48f3e (diff) | |
refactor: auto-generate language configuration (#1584)
Refactor the monolithic `lvim.lang` design into a more modular approach.
IMPORTANT: run `:LvimUpdate` in order to generate the new ftplugin template files.
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/bootstrap.lua | 4 | ||||
| -rw-r--r-- | lua/config/defaults.lua | 1164 | ||||
| -rw-r--r-- | lua/config/init.lua | 100 | ||||
| -rw-r--r-- | lua/core/builtins/init.lua | 1 | ||||
| -rw-r--r-- | lua/core/cmp.lua | 30 | ||||
| -rw-r--r-- | lua/core/info.lua | 87 | ||||
| -rw-r--r-- | lua/core/log.lua | 1 | ||||
| -rw-r--r-- | lua/core/lspinstall.lua | 19 | ||||
| -rw-r--r-- | lua/core/lualine/components.lua | 3 | ||||
| -rw-r--r-- | lua/core/which-key.lua | 2 | ||||
| -rw-r--r-- | lua/lsp/config.lua | 27 | ||||
| -rw-r--r-- | lua/lsp/init.lua | 102 | ||||
| -rw-r--r-- | lua/lsp/kind.lua | 31 | ||||
| -rw-r--r-- | lua/lsp/manager.lua | 82 | ||||
| -rw-r--r-- | lua/lsp/null-ls/formatters.lua | 30 | ||||
| -rw-r--r-- | lua/lsp/null-ls/init.lua | 54 | ||||
| -rw-r--r-- | lua/lsp/null-ls/linters.lua | 30 | ||||
| -rw-r--r-- | lua/lsp/null-ls/services.lua | 15 | ||||
| -rw-r--r-- | lua/lsp/providers/jsonls.lua | 30 | ||||
| -rw-r--r-- | lua/lsp/providers/sumneko_lua.lua | 19 | ||||
| -rw-r--r-- | lua/lsp/providers/vuels.lua | 26 | ||||
| -rw-r--r-- | lua/lsp/templates.lua | 98 | ||||
| -rw-r--r-- | lua/lsp/utils.lua | 57 | ||||
| -rw-r--r-- | lua/plugins.lua | 7 | ||||
| -rw-r--r-- | lua/utils/init.lua | 100 | 
25 files changed, 673 insertions, 1446 deletions
| diff --git a/lua/bootstrap.lua b/lua/bootstrap.lua index 7f8f97ed..fb2099ce 100644 --- a/lua/bootstrap.lua +++ b/lua/bootstrap.lua @@ -85,9 +85,10 @@ function M:init()      vim.cmd("set spellfile=" .. join_paths(self.config_dir, "spell", "en.utf-8.add"))    end +  vim.fn.mkdir(vim.fn.stdpath "cache", "p") +    -- FIXME: currently unreliable in unit-tests    if not os.getenv "LVIM_TEST_ENV" then -    vim.fn.mkdir(vim.fn.stdpath "cache", "p")      require("impatient").setup {        path = vim.fn.stdpath "cache" .. "/lvim_cache",        enable_profiling = true, @@ -112,6 +113,7 @@ end  function M:update()    M:update_repo()    M:reset_cache() +  require("lsp.templates").generate_templates()    vim.schedule(function()      -- TODO: add a changelog      vim.notify("Update complete", vim.log.levels.INFO) diff --git a/lua/config/defaults.lua b/lua/config/defaults.lua index a67a9c53..f030234d 100644 --- a/lua/config/defaults.lua +++ b/lua/config/defaults.lua @@ -1,7 +1,5 @@  local home_dir = vim.loop.os_homedir()  local utils = require "utils" --- FIXME: stop using hard-coded paths for LspInstall -local ls_install_prefix = vim.fn.stdpath "data" .. "/lspinstall"  lvim = {    leader = "space", @@ -30,1170 +28,10 @@ lvim = {        },      },    }, - -  lsp = { -    completion = { -      item_kind = { -        " īž  (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)", -      }, -    }, -    diagnostics = { -      signs = { -        active = true, -        values = { -          { name = "LspDiagnosticsSignError", text = "ī" }, -          { name = "LspDiagnosticsSignWarning", text = "īŠ" }, -          { name = "LspDiagnosticsSignHint", text = "ī ĩ" }, -          { name = "LspDiagnosticsSignInformation", text = "ī" }, -        }, -      }, -      virtual_text = { -        prefix = "ī", -        spacing = 0, -      }, -      update_in_insert = false, -      underline = true, -      severity_sort = true, -    }, -    override = {}, -    document_highlight = true, -    popup_border = "single", -    on_attach_callback = nil, -    on_init_callback = nil, -    null_ls = { -      setup = {}, -    }, -  }, -    plugins = {      -- use config.lua for this not put here    },    autocommands = {}, -} - -local schemas = nil -local status_ok, jsonls_settings = pcall(require, "nlspsettings.jsonls") -if status_ok then -  schemas = jsonls_settings.get_default_schemas() -end - --- TODO move all of this into lang specific files, only require when using -lvim.lang = { -  asm = { -    formatters = { -      -- { -      --   exe = "asmfmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "", -      setup = {}, -    }, -  }, -  beancount = { -    formatters = { -      -- { -      --   exe = "bean_format", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "beancount", -      setup = { -        cmd = { "beancount-langserver" }, -      }, -    }, -  }, -  bicep = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "bicep", -      setup = { -        cmd = { -          "dotnet", -          ls_install_prefix .. "/bicep/Bicep.LangServer.dll", -        }, -        filetypes = { "bicep" }, -      }, -    }, -  }, -  c = { -    formatters = { -      -- { -      --   exe = "clang_format", -      --   args = {}, -      -- }, -      -- { -      --   exe = "uncrustify", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "clangd", -      setup = { -        cmd = { -          ls_install_prefix .. "/cpp/clangd/bin/clangd", -          "--background-index", -          "--header-insertion=never", -          "--cross-file-rename", -          "--clang-tidy", -          "--clang-tidy-checks=-*,llvm-*,clang-analyzer-*", -        }, -      }, -    }, -  }, -  cpp = { -    formatters = { -      -- { -      --   exe = "clang_format", -      --   args = {}, -      -- }, -      -- { -      --   exe = "uncrustify", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "clangd", -      setup = { -        cmd = { -          ls_install_prefix .. "/cpp/clangd/bin/clangd", -          "--background-index", -          "--header-insertion=never", -          "--cross-file-rename", -          "--clang-tidy", -          "--clang-tidy-checks=-*,llvm-*,clang-analyzer-*", -        }, -      }, -    }, -  }, -  crystal = { -    formatters = { -      -- { -      --   exe = "crystal_format", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "crystalline", -      setup = { -        cmd = { "crystalline" }, -      }, -    }, -  }, -  cs = { -    formatters = { -      -- { -      --   exe = "clang_format ", -      --   args = {}, -      -- }, -      -- { -      --   exe = "uncrustify", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "omnisharp", -      setup = { -        cmd = { -          ls_install_prefix .. "/csharp/omnisharp/run", -          "--languageserver", -          "--hostPID", -          tostring(vim.fn.getpid()), -        }, -      }, -    }, -  }, -  cmake = { -    formatters = { -      -- { -      --   exe = "cmake_format", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "cmake", -      setup = { -        cmd = { -          ls_install_prefix .. "/cmake/venv/bin/cmake-language-server", -        }, -      }, -    }, -  }, -  clojure = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "clojure_lsp", -      setup = { -        cmd = { -          ls_install_prefix .. "/clojure/clojure-lsp", -        }, -      }, -    }, -  }, -  css = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "cssls", -      setup = { -        cmd = { -          "node", -          ls_install_prefix .. "/css/vscode-css/css-language-features/server/dist/node/cssServerMain.js", -          "--stdio", -        }, -      }, -    }, -  }, -  less = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "cssls", -      setup = { -        cmd = { -          "node", -          ls_install_prefix .. "/css/vscode-css/css-language-features/server/dist/node/cssServerMain.js", -          "--stdio", -        }, -      }, -    }, -  }, -  d = { -    formatters = { -      -- { -      --   exe = "dfmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "serve_d", -      setup = { -        cmd = { "serve-d" }, -      }, -    }, -  }, -  dart = { -    formatters = { -      -- { -      --   exe = "dart_format", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "dartls", -      setup = { -        cmd = { -          "dart", -          "/usr/lib/dart/bin/snapshots/analysis_server.dart.snapshot", -          "--lsp", -        }, -      }, -    }, -  }, -  dockerfile = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "dockerls", -      setup = { -        cmd = { -          ls_install_prefix .. "/dockerfile/node_modules/.bin/docker-langserver", -          "--stdio", -        }, -      }, -    }, -  }, -  elixir = { -    formatters = { -      -- { -      --   exe = "mix", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "elixirls", -      setup = { -        cmd = { -          ls_install_prefix .. "/elixir/elixir-ls/language_server.sh", -        }, -      }, -    }, -  }, -  elm = { -    formatters = { -      -- { -      --   exe = "elm_format", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "elmls", -      setup = { -        cmd = { -          ls_install_prefix .. "/elm/node_modules/.bin/elm-language-server", -        }, -        -- init_options = { -        -- elmAnalyseTrigger = "change", -        -- elmFormatPath = ls_install_prefix .. "/elm/node_modules/.bin/elm-format", -        -- elmPath = ls_install_prefix .. "/elm/node_modules/.bin/", -        -- elmTestPath = ls_install_prefix .. "/elm/node_modules/.bin/elm-test", -        -- }, -      }, -    }, -  }, -  erlang = { -    formatters = { -      -- { -      --   exe = "erlfmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "erlangls", -      setup = { -        cmd = { -          "erlang_ls", -        }, -      }, -    }, -  }, -  emmet = { active = false }, -  fish = { -    formatters = { -      -- { -      --   exe = "fish_indent", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "", -      setup = {}, -    }, -  }, -  fortran = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "fortls", -      setup = { -        cmd = { -          ls_install_prefix .. "/fortran/venv/bin/fortls", -        }, -      }, -    }, -  }, -  go = { -    formatters = { -      -- { -      --   exe = "gofmt", -      --   args = {}, -      -- }, -      -- { -      --   exe = "goimports", -      --   args = {}, -      -- }, -      -- { -      --   exe = "gofumpt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "gopls", -      setup = { -        cmd = { -          ls_install_prefix .. "/go/gopls", -        }, -      }, -    }, -  }, -  graphql = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "graphql", -      setup = { -        cmd = { -          "graphql-lsp", -          "server", -          "-m", -          "stream", -        }, -      }, -    }, -  }, -  haskell = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "hls", -      setup = { -        cmd = { ls_install_prefix .. "/haskell/hls" }, -      }, -    }, -  }, -  html = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "html", -      setup = { -        cmd = { -          "node", -          ls_install_prefix .. "/html/vscode-html/html-language-features/server/dist/node/htmlServerMain.js", -          "--stdio", -        }, -      }, -    }, -  }, -  java = { -    formatters = { -      -- { -      --   exe = "clang_format", -      --   args = {}, -      -- }, -      -- { -      --   exe = "uncrustify", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "jdtls", -      setup = { -        cmd = { ls_install_prefix .. "/java/jdtls.sh" }, -      }, -    }, -  }, -  json = { -    formatters = { -      -- { -      --   exe = "json_tool", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "jsonls", -      setup = { -        cmd = { -          "node", -          ls_install_prefix .. "/json/vscode-json/json-language-features/server/dist/node/jsonServerMain.js", -          "--stdio", -        }, -        settings = { -          json = { -            schemas = schemas, -            --   = { -            --   { -            --     fileMatch = { "package.json" }, -            --     url = "https://json.schemastore.org/package.json", -            --   }, -            -- }, -          }, -        }, -        commands = { -          Format = { -            function() -              vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 }) -            end, -          }, -        }, -      }, -    }, -  }, -  julia = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "julials", -      setup = { -        { -          "julia", -          "--startup-file=no", -          "--history-file=no", -          -- self.runtime_dir .. "lvim/utils/julia/run.jl", -        }, -      }, -    }, -  }, -  kotlin = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "kotlin_language_server", -      setup = { -        cmd = { -          ls_install_prefix .. "/kotlin/server/bin/kotlin-language-server", -        }, -        root_dir = function(fname) -          local util = require "lspconfig/util" - -          local root_files = { -            "settings.gradle", -- Gradle (multi-project) -            "settings.gradle.kts", -- Gradle (multi-project) -            "build.xml", -- Ant -            "pom.xml", -- Maven -          } - -          local fallback_root_files = { -            "build.gradle", -- Gradle -            "build.gradle.kts", -- Gradle -          } -          return util.root_pattern(unpack(root_files))(fname) or util.root_pattern(unpack(fallback_root_files))(fname) -        end, -      }, -    }, -  }, -  lua = { -    formatters = { -      -- { -      --   exe = "stylua", -      --   args = {}, -      -- }, -      -- { -      --   exe = "lua_format", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "sumneko_lua", -      setup = { -        cmd = { -          ls_install_prefix .. "/lua/sumneko-lua-language-server", -          "-E", -          ls_install_prefix .. "/lua/main.lua", -        }, -        settings = { -          Lua = { -            diagnostics = { -              -- Get the language server to recognize the `vim` global -              globals = { "vim", "lvim" }, -            }, -            workspace = { -              -- Make the server aware of Neovim runtime files -              library = { -                [require("utils").join_paths(get_runtime_dir(), "lvim", "lua")] = true, -                [vim.fn.expand "$VIMRUNTIME/lua"] = true, -                [vim.fn.expand "$VIMRUNTIME/lua/vim/lsp"] = true, -              }, -              maxPreload = 100000, -              preloadFileSize = 10000, -            }, -          }, -        }, -      }, -    }, -  }, -  nginx = { -    formatters = { -      -- { -      --   exe = "nginx_beautifier", -      --   args = { -      --     provider = "", -      --     setup = {}, -      --   }, -      -- }, -    }, -    linters = {}, -    lsp = {}, -  }, -  perl = { -    formatters = { -      -- { -      --   exe = "perltidy", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "", -      setup = {}, -    }, -  }, -  solidity = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "solang", -      setup = { -        cmd = { "solang", "--language-server" }, -      }, -    }, -  }, -  sql = { -    formatters = { -      -- { -      --   exe = "sqlformat", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "sqls", -      setup = { -        cmd = { "sqls" }, -      }, -    }, -  }, -  php = { -    formatters = { -      -- { -      --   exe = "phpcbf", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "intelephense", -      setup = { -        cmd = { -          ls_install_prefix .. "/php/node_modules/.bin/intelephense", -          "--stdio", -        }, -        filetypes = { "php", "phtml" }, -        settings = { -          intelephense = { -            environment = { -              phpVersion = "7.4", -            }, -          }, -        }, -      }, -    }, -  }, -  puppet = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "puppet", -      setup = { -        cmd = { -          ls_install_prefix .. "/puppet/puppet-editor-services/puppet-languageserver", -          "--stdio", -        }, -      }, -    }, -  }, -  javascript = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettier_d_slim", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    -- @usage can be {"eslint"} or {"eslint_d"} -    linters = {}, -    lsp = { -      provider = "tsserver", -      setup = { -        cmd = { -          -- TODO: -          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  javascriptreact = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettier_d_slim", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "tsserver", -      setup = { -        cmd = { -          -- TODO: -          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  python = { -    formatters = { -      -- { -      --   exe = "yapf", -      --   args = {}, -      -- }, -      -- { -      --   exe = "isort", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "pyright", -      setup = { -        cmd = { -          ls_install_prefix .. "/python/node_modules/.bin/pyright-langserver", -          "--stdio", -        }, -      }, -    }, -  }, -  -- 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 = { -    formatters = { -      -- { -      --   exe = "format_r", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "r_language_server", -      setup = { -        cmd = { -          "R", -          "--slave", -          "-e", -          "languageserver::run()", -        }, -      }, -    }, -  }, -  ruby = { -    formatters = { -      -- { -      --   exe = "rufo", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "solargraph", -      setup = { -        cmd = { -          ls_install_prefix .. "/ruby/solargraph/solargraph", -          "stdio", -        }, -        filetypes = { "ruby" }, -        init_options = { -          formatting = true, -        }, -        root_dir = function(fname) -          local util = require("lspconfig").util -          return util.root_pattern("Gemfile", ".git")(fname) -        end, -        settings = { -          solargraph = { -            diagnostics = true, -          }, -        }, -      }, -    }, -  }, -  rust = { -    formatters = { -      -- { -      --   exe = "rustfmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "rust_analyzer", -      setup = { -        cmd = { -          ls_install_prefix .. "/rust/rust-analyzer", -        }, -      }, -    }, -  }, -  scala = { -    formatters = { -      -- { -      --   exe = "scalafmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "metals", -      setup = {}, -    }, -  }, -  sh = { -    formatters = { -      -- { -      --   exe = "shfmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "bashls", -      setup = { -        cmd = { -          ls_install_prefix .. "/bash/node_modules/.bin/bash-language-server", -          "start", -        }, -      }, -    }, -  }, -  svelte = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "svelte", -      setup = { -        cmd = { -          ls_install_prefix .. "/svelte/node_modules/.bin/svelteserver", -          "--stdio", -        }, -      }, -    }, -  }, -  swift = { -    formatters = { -      -- { -      --   exe = "swiftformat", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "sourcekit", -      setup = { -        cmd = { -          "xcrun", -          "sourcekit-lsp", -        }, -      }, -    }, -  }, -  tailwindcss = { -    lsp = { -      active = false, -      provider = "tailwindcss", -      setup = { -        cmd = { -          ls_install_prefix .. "/tailwindcss/node_modules/.bin/tailwindcss-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  terraform = { -    formatters = { -      -- { -      --   exe = "terraform_fmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "terraformls", -      setup = { -        cmd = { -          ls_install_prefix .. "/terraform/terraform-ls", -          "serve", -        }, -      }, -    }, -  }, -  tex = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "texlab", -      setup = { -        cmd = { ls_install_prefix .. "/latex/texlab" }, -      }, -    }, -  }, -  typescript = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettier_d_slim", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "tsserver", -      setup = { -        cmd = { -          -- TODO: -          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  typescriptreact = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettier_d_slim", -      --   args = {}, -      -- }, -    }, -    -- @usage can be {"eslint"} or {"eslint_d"} -    linters = {}, -    lsp = { -      provider = "tsserver", -      setup = { -        cmd = { -          -- TODO: -          ls_install_prefix .. "/typescript/node_modules/.bin/typescript-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  vim = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "vimls", -      setup = { -        cmd = { -          ls_install_prefix .. "/vim/node_modules/.bin/vim-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  vue = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettier_d_slim", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "vuels", -      setup = { -        cmd = { -          ls_install_prefix .. "/vue/node_modules/.bin/vls", -        }, -        root_dir = function(fname) -          local util = require "lspconfig/util" -          return util.root_pattern "package.json"(fname) or util.root_pattern "vue.config.js"(fname) or vim.fn.getcwd() -        end, -        init_options = { -          config = { -            vetur = { -              completion = { -                autoImport = true, -                tagCasing = "kebab", -                useScaffoldSnippets = true, -              }, -              useWorkspaceDependencies = true, -              validation = { -                script = true, -                style = true, -                template = true, -              }, -            }, -          }, -        }, -      }, -    }, -  }, -  yaml = { -    formatters = { -      -- { -      --   exe = "prettier", -      --   args = {}, -      -- }, -      -- { -      --   exe = "prettierd", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "yamlls", -      setup = { -        cmd = { -          ls_install_prefix .. "/yaml/node_modules/.bin/yaml-language-server", -          "--stdio", -        }, -      }, -    }, -  }, -  zig = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "zls", -      setup = { -        cmd = { -          "zls", -        }, -      }, -    }, -  }, -  gdscript = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "gdscript", -      setup = { -        cmd = { -          "nc", -          "localhost", -          "6008", -        }, -      }, -    }, -  }, -  ps1 = { -    formatters = {}, -    linters = {}, -    lsp = { -      provider = "powershell_es", -      setup = { -        bundle_path = "", -      }, -    }, -  }, -  nix = { -    formatters = { -      -- { -      --   exe = "nixfmt", -      --   args = {}, -      -- }, -    }, -    linters = {}, -    lsp = { -      provider = "rnix", -      setup = { -        cmd = { "rnix-lsp" }, -        filetypes = { "nix" }, -        init_options = {}, -        settings = {}, -        root_dir = function(fname) -          local util = require "lspconfig/util" -          return util.root_pattern ".git"(fname) or vim.fn.getcwd() -        end, -      }, -    }, -  }, +  lang = {},  } diff --git a/lua/config/init.lua b/lua/config/init.lua index c09617bc..f0062560 100644 --- a/lua/config/init.lua +++ b/lua/config/init.lua @@ -22,6 +22,106 @@ function M:init(opts)    local settings = require "config.settings"    settings.load_options() + +  local lvim_lsp_config = require "lsp.config" +  lvim.lsp = vim.deepcopy(lvim_lsp_config) + +  local supported_languages = { +    "asm", +    "bash", +    "beancount", +    "bibtex", +    "bicep", +    "c", +    "c_sharp", +    "clojure", +    "cmake", +    "comment", +    "commonlisp", +    "cpp", +    "crystal", +    "cs", +    "css", +    "cuda", +    "d", +    "dart", +    "dockerfile", +    "dot", +    "elixir", +    "elm", +    "emmet", +    "erlang", +    "fennel", +    "fish", +    "fortran", +    "gdscript", +    "glimmer", +    "go", +    "gomod", +    "graphql", +    "haskell", +    "hcl", +    "heex", +    "html", +    "java", +    "javascript", +    "javascriptreact", +    "jsdoc", +    "json", +    "json5", +    "jsonc", +    "julia", +    "kotlin", +    "latex", +    "ledger", +    "less", +    "lua", +    "markdown", +    "nginx", +    "nix", +    "ocaml", +    "ocaml_interface", +    "perl", +    "php", +    "pioasm", +    "ps1", +    "puppet", +    "python", +    "ql", +    "query", +    "r", +    "regex", +    "rst", +    "ruby", +    "rust", +    "scala", +    "scss", +    "sh", +    "solidity", +    "sparql", +    "sql", +    "supercollider", +    "surface", +    "svelte", +    "swift", +    "tailwindcss", +    "terraform", +    "tex", +    "tlaplus", +    "toml", +    "tsx", +    "turtle", +    "typescript", +    "typescriptreact", +    "verilog", +    "vim", +    "vue", +    "yaml", +    "yang", +    "zig", +  } + +  require("lsp.manager").init_defaults(supported_languages)  end  --- Override the configuration with a user provided one diff --git a/lua/core/builtins/init.lua b/lua/core/builtins/init.lua index dc9b5ff5..c3b3618f 100644 --- a/lua/core/builtins/init.lua +++ b/lua/core/builtins/init.lua @@ -15,7 +15,6 @@ local builtins = {    "core.bufferline",    "core.autopairs",    "core.comment", -  "core.lspinstall",    "core.lualine",  } diff --git a/lua/core/cmp.lua b/lua/core/cmp.lua index 2bc724fb..965285c7 100644 --- a/lua/core/cmp.lua +++ b/lua/core/cmp.lua @@ -35,9 +35,35 @@ M.config = function()        select = true,      },      formatting = { +      kind_icons = { +        Class = "ī  ", +        Color = "îĢ ", +        Constant = "ī˛ ", +        Constructor = "īĨ ", +        Enum = "īŠ", +        EnumMember = "ī
 ", +        Event = "ī§ ", +        Field = "î ", +        File = "ī", +        Folder = "ī ", +        Function = "ī ", +        Interface = "ī°Ž ", +        Keyword = "ī  ", +        Method = "î ", +        Module = "ī¨ ", +        Operator = "ī", +        Property = "î¤ ", +        Reference = "ī ", +        Snippet = "ī ", +        Struct = "ī ", +        Text = "īž ", +        TypeParameter = "ī ", +        Unit = "īĨŦ", +        Value = "īĸ ", +        Variable = "īĻ ", +      },        format = function(entry, vim_item) -        local icons = require("lsp.kind").icons -        vim_item.kind = icons[vim_item.kind] +        vim_item.kind = lvim.builtin.cmp.formatting.kind_icons[vim_item.kind]          vim_item.menu = ({            nvim_lsp = "(LSP)",            emoji = "(Emoji)", diff --git a/lua/core/info.lua b/lua/core/info.lua index b8d51a8c..ff024fa5 100644 --- a/lua/core/info.lua +++ b/lua/core/info.lua @@ -10,6 +10,7 @@ local M = {  }  local fmt = string.format +local text = require "interface.text"  local function str_list(list)    return fmt("[ %s ]", table.concat(list, ", ")) @@ -65,44 +66,55 @@ local function tbl_set_highlight(terms, highlight_group)    end  end +local function make_client_info(client) +  local client_enabled_caps = require("lsp.utils").get_ls_capabilities(client.id) +  local name = client.name +  local id = client.id +  local document_formatting = client.resolved_capabilities.document_formatting +  local client_info = { +    fmt("* Name:                 %s", name), +    fmt("* Id:                   %s", tostring(id)), +    fmt("* Supports formatting:  %s", tostring(document_formatting)), +  } +  if not vim.tbl_isempty(client_enabled_caps) then +    local caps_text = "* Capabilities list:    " +    local caps_text_len = caps_text:len() +    local enabled_caps = text.format_table(client_enabled_caps, 3, " | ") +    enabled_caps = text.shift_right(enabled_caps, caps_text_len) +    enabled_caps[1] = fmt("%s%s", caps_text, enabled_caps[1]:sub(caps_text_len + 1)) +    vim.list_extend(client_info, enabled_caps) +  end + +  return client_info +end +  function M.toggle_popup(ft)    local lsp_utils = require "lsp.utils" -  local client = lsp_utils.get_active_client_by_ft(ft) -  local is_client_active = false -  local client_enabled_caps = {} -  local client_name = "" -  local client_id = 0 -  local document_formatting = false -  if client ~= nil then -    is_client_active = not client.is_stopped() -    client_enabled_caps = require("lsp").get_ls_capabilities(client.id) -    client_name = client.name -    client_id = client.id -    document_formatting = client.resolved_capabilities.document_formatting -  end +  local clients = lsp_utils.get_active_client_by_ft(ft) +  local client_names = {}    local header = {      fmt("Detected filetype:      %s", ft),      fmt("Treesitter active:      %s", tostring(next(vim.treesitter.highlighter.active) ~= nil)),    } -  local text = require "interface.text"    local lsp_info = {      "Language Server Protocol (LSP) info", -    fmt("* Associated server:    %s", client_name), -    fmt("* Active:               %s (id: %d)", tostring(is_client_active), client_id), -    fmt("* Supports formatting:  %s", tostring(document_formatting)), +    fmt "* Associated server(s):",    } -  if not vim.tbl_isempty(client_enabled_caps) then -    local caps_text = "* Capabilities list:    " -    local caps_text_len = caps_text:len() -    local enabled_caps = text.format_table(client_enabled_caps, 3, " | ") -    enabled_caps = text.shift_right(enabled_caps, caps_text_len) -    enabled_caps[1] = fmt("%s%s", caps_text, enabled_caps[1]:sub(caps_text_len + 1)) -    vim.list_extend(lsp_info, enabled_caps) + +  for _, client in pairs(clients) do +    vim.list_extend(lsp_info, make_client_info(client)) +    table.insert(client_names, client.name)    end -  local null_ls = require "lsp.null-ls" -  local registered_providers = null_ls.list_supported_provider_names(ft) + +  local null_formatters = require "lsp.null-ls.formatters" +  local null_linters = require "lsp.null-ls.linters" +  local registered_formatters = null_formatters.list_supported_names(ft) +  local registered_linters = null_linters.list_supported_names(ft) +  local registered_providers = {} +  vim.list_extend(registered_providers, registered_formatters) +  vim.list_extend(registered_providers, registered_linters)    local registered_count = vim.tbl_count(registered_providers)    local null_ls_info = {      "Formatters and linters", @@ -113,24 +125,6 @@ function M.toggle_popup(ft)      ),    } -  local null_formatters = require "lsp.null-ls.formatters" -  local missing_formatters = null_formatters.list_unsupported_names(ft) -  local missing_formatters_status = {} -  if not vim.tbl_isempty(missing_formatters) then -    missing_formatters_status = { -      fmt("* Missing formatters:   %s", table.concat(missing_formatters, " ī , ") .. " ī "), -    } -  end - -  local null_linters = require "lsp.null-ls.linters" -  local missing_linters = null_linters.list_unsupported_names(ft) -  local missing_linters_status = {} -  if not vim.tbl_isempty(missing_linters) then -    missing_linters_status = { -      fmt("* Missing linters:      %s", table.concat(missing_linters, " ī , ") .. " ī "), -    } -  end -    local content_provider = function(popup)      local content = {} @@ -143,8 +137,6 @@ function M.toggle_popup(ft)        lsp_info,        { "" },        null_ls_info, -      missing_formatters_status, -      missing_linters_status,        { "" },        { "" },        get_formatter_suggestion_msg(ft), @@ -167,11 +159,8 @@ function M.toggle_popup(ft)      vim.cmd 'let m=matchadd("string", "true")'      vim.cmd 'let m=matchadd("error", "false")'      tbl_set_highlight(registered_providers, "LvimInfoIdentifier") -    tbl_set_highlight(missing_formatters, "LvimInfoIdentifier") -    tbl_set_highlight(missing_linters, "LvimInfoIdentifier")      -- tbl_set_highlight(require("lsp.null-ls.formatters").list_available(ft), "LvimInfoIdentifier")      -- tbl_set_highlight(require("lsp.null-ls.linters").list_available(ft), "LvimInfoIdentifier") -    vim.cmd('let m=matchadd("LvimInfoIdentifier", "' .. client_name .. '")')    end    local Popup = require("interface.popup"):new { diff --git a/lua/core/log.lua b/lua/core/log.lua index 1eb786ba..fca1fcb4 100644 --- a/lua/core/log.lua +++ b/lua/core/log.lua @@ -8,6 +8,7 @@ function Log:add_entry(msg, level)    if self.__handle then      -- plenary uses lower-case log levels      self.__handle[level:lower()](msg) +    return    end    local status_ok, plenary = pcall(require, "plenary")    if status_ok then diff --git a/lua/core/lspinstall.lua b/lua/core/lspinstall.lua deleted file mode 100644 index 0bb59e0e..00000000 --- a/lua/core/lspinstall.lua +++ /dev/null @@ -1,19 +0,0 @@ -local M = {} - -M.config = function() -  lvim.builtin.lspinstall = { -    active = true, -    on_config_done = nil, -  } -end - -M.setup = function() -  local lspinstall = require "lspinstall" -  lspinstall.setup() - -  if lvim.builtin.lspinstall.on_config_done then -    lvim.builtin.lspinstall.on_config_done(lspinstall) -  end -end - -return M diff --git a/lua/core/lualine/components.lua b/lua/core/lualine/components.lua index 21e25585..3ee2fdf8 100644 --- a/lua/core/lualine/components.lua +++ b/lua/core/lualine/components.lua @@ -96,14 +96,11 @@ return {        local buf_client_names = {}        -- add client -      local utils = require "lsp.utils" -      local active_client = utils.get_active_client_by_ft(buf_ft)        for _, client in pairs(buf_clients) do          if client.name ~= "null-ls" then            table.insert(buf_client_names, client.name)          end        end -      vim.list_extend(buf_client_names, active_client or {})        -- add formatter        local formatters = require "lsp.null-ls.formatters" diff --git a/lua/core/which-key.lua b/lua/core/which-key.lua index 27cec37c..a115bcc5 100644 --- a/lua/core/which-key.lua +++ b/lua/core/which-key.lua @@ -148,9 +148,9 @@ M.config = function()            "<cmd>Telescope lsp_workspace_diagnostics<cr>",            "Workspace Diagnostics",          }, -        -- f = { "<cmd>silent FormatWrite<cr>", "Format" },          f = { "<cmd>lua vim.lsp.buf.formatting()<cr>", "Format" },          i = { "<cmd>LspInfo<cr>", "Info" }, +        I = { "<cmd>LspInstallInfo<cr>", "Installer Info" },          j = {            "<cmd>lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<cr>",            "Next Diagnostic", diff --git a/lua/lsp/config.lua b/lua/lsp/config.lua new file mode 100644 index 00000000..146301c9 --- /dev/null +++ b/lua/lsp/config.lua @@ -0,0 +1,27 @@ +return { +  templates_dir = join_paths(get_runtime_dir(), "site", "after", "ftplugin"), +  diagnostics = { +    signs = { +      active = true, +      values = { +        { name = "LspDiagnosticsSignError", text = "ī" }, +        { name = "LspDiagnosticsSignWarning", text = "īŠ" }, +        { name = "LspDiagnosticsSignHint", text = "ī ĩ" }, +        { name = "LspDiagnosticsSignInformation", text = "ī" }, +      }, +    }, +    virtual_text = { +      prefix = "ī", +      spacing = 0, +    }, +    update_in_insert = false, +    underline = true, +    severity_sort = true, +  }, +  override = {}, +  document_highlight = true, +  popup_border = "single", +  on_attach_callback = nil, +  on_init_callback = nil, +  automatic_servers_installation = true, +} diff --git a/lua/lsp/init.lua b/lua/lsp/init.lua index 386be075..7f20a39d 100644 --- a/lua/lsp/init.lua +++ b/lua/lsp/init.lua @@ -1,5 +1,6 @@  local M = {}  local Log = require "core.log" +local utils = require "utils"  local function lsp_highlight_document(client)    if lvim.lsp.document_highlight == false then @@ -61,48 +62,12 @@ function M.common_capabilities()    return capabilities  end -function M.get_ls_capabilities(client_id) -  local client -  if not client_id then -    local buf_clients = vim.lsp.buf_get_clients() -    for _, buf_client in ipairs(buf_clients) do -      if buf_client.name ~= "null-ls" then -        client_id = buf_client.id -        break -      end -    end -  end -  if not client_id then -    error "Unable to determine client_id" -  end - -  client = vim.lsp.get_client_by_id(tonumber(client_id)) - -  local enabled_caps = {} - -  for k, v in pairs(client.resolved_capabilities) do -    if v == true then -      table.insert(enabled_caps, k) -    end -  end - -  return enabled_caps -end -  function M.common_on_init(client, bufnr)    if lvim.lsp.on_init_callback then      lvim.lsp.on_init_callback(client, bufnr)      Log:debug "Called lsp.on_init_callback"      return    end - -  local formatters = lvim.lang[vim.bo.filetype].formatters -  if not vim.tbl_isempty(formatters) and formatters[1]["exe"] ~= nil and formatters[1].exe ~= "" then -    client.resolved_capabilities.document_formatting = false -    Log:debug( -      string.format("Overriding language server [%s] with format provider [%s]", client.name, formatters[1].exe) -    ) -  end  end  function M.common_on_attach(client, bufnr) @@ -112,63 +77,46 @@ function M.common_on_attach(client, bufnr)    end    lsp_highlight_document(client)    add_lsp_buffer_keybindings(bufnr) -  require("lsp.null-ls").setup(vim.bo.filetype)  end -function M.setup(lang) -  local lsp_utils = require "lsp.utils" -  local lsp = lvim.lang[lang].lsp -  if (lsp.active ~= nil and not lsp.active) or lsp_utils.is_client_active(lsp.provider) then -    return -  end - -  local overrides = lvim.lsp.override -  if type(overrides) == "table" then -    if vim.tbl_contains(overrides, lang) then -      return -    end +local function bootstrap_nlsp(opts) +  opts = opts or {} +  local lsp_settings_status_ok, lsp_settings = pcall(require, "nlspsettings") +  if lsp_settings_status_ok then +    lsp_settings.setup(opts)    end +end -  if lsp.provider ~= nil and lsp.provider ~= "" then -    local lspconfig = require "lspconfig" +function M.get_common_opts() +  return { +    on_attach = M.common_on_attach, +    on_init = M.common_on_init, +    capabilities = M.common_capabilities(), +  } +end -    if not lsp.setup.on_attach then -      lsp.setup.on_attach = M.common_on_attach -    end -    if not lsp.setup.on_init then -      lsp.setup.on_init = M.common_on_init -    end -    if not lsp.setup.capabilities then -      lsp.setup.capabilities = M.common_capabilities() -    end +function M.setup() +  Log:debug "Setting up LSP support" -    lspconfig[lsp.provider].setup(lsp.setup) +  local lsp_status_ok, _ = pcall(require, "lspconfig") +  if not lsp_status_ok then +    return    end -end - -function M.global_setup() -  vim.lsp.protocol.CompletionItemKind = lvim.lsp.completion.item_kind    for _, sign in ipairs(lvim.lsp.diagnostics.signs.values) do      vim.fn.sign_define(sign.name, { texthl = sign.name, text = sign.text, numhl = sign.name })    end -    require("lsp.handlers").setup() -  local null_status_ok, null_ls = pcall(require, "null-ls") -  if null_status_ok then -    null_ls.config() -    require("lspconfig")["null-ls"].setup(lvim.lsp.null_ls.setup) +  if not utils.is_directory(lvim.lsp.templates_dir) then +    require("lsp.templates").generate_templates()    end -  local utils = require "utils" +  bootstrap_nlsp { config_home = utils.join_paths(get_config_dir(), "lsp-settings") } -  local lsp_settings_status_ok, lsp_settings = pcall(require, "nlspsettings") -  if lsp_settings_status_ok then -    lsp_settings.setup { -      config_home = utils.join_paths(get_config_dir(), "lsp-settings"), -    } -  end +  require("lsp.null-ls").setup() + +  require("utils").toggle_autoformat()  end  return M diff --git a/lua/lsp/kind.lua b/lua/lsp/kind.lua deleted file mode 100644 index b78fd318..00000000 --- a/lua/lsp/kind.lua +++ /dev/null @@ -1,31 +0,0 @@ -local M = {} - -M.icons = { -  Class = "ī  ", -  Color = "îĢ ", -  Constant = "ī˛ ", -  Constructor = "īĨ ", -  Enum = "īŠ", -  EnumMember = "ī
 ", -  Event = "ī§ ", -  Field = "î ", -  File = "ī", -  Folder = "ī ", -  Function = "ī ", -  Interface = "ī°Ž ", -  Keyword = "ī  ", -  Method = "î ", -  Module = "ī¨ ", -  Operator = "ī", -  Property = "î¤ ", -  Reference = "ī ", -  Snippet = "ī ", -  Struct = "ī ", -  Text = "īž ", -  TypeParameter = "ī ", -  Unit = "īĨŦ", -  Value = "īĸ ", -  Variable = "īĻ ", -} - -return M diff --git a/lua/lsp/manager.lua b/lua/lsp/manager.lua new file mode 100644 index 00000000..24d462ad --- /dev/null +++ b/lua/lsp/manager.lua @@ -0,0 +1,82 @@ +local M = {} + +local Log = require "core.log" +local lsp_utils = require "lsp.utils" + +function M.init_defaults(languages) +  for _, entry in ipairs(languages) do +    if not lvim.lang[entry] then +      lvim.lang[entry] = { +        formatters = {}, +        linters = {}, +      } +    end +  end +end + +local function is_overridden(server) +  local overrides = lvim.lsp.override +  if type(overrides) == "table" then +    if vim.tbl_contains(overrides, server) then +      return +    end +  end +end + +function M.setup_server(server_name) +  vim.validate { +    name = { server_name, "string" }, +  } + +  if lsp_utils.is_client_active(server_name) or is_overridden(server_name) then +    return +  end + +  local lsp_installer_servers = require "nvim-lsp-installer.servers" +  local server_available, requested_server = lsp_installer_servers.get_server(server_name) +  if server_available then +    if not requested_server:is_installed() then +      Log:debug(string.format("[%s] is not installed", server_name)) +      if lvim.lsp.automatic_servers_installation then +        Log:debug(string.format("Installing [%s]", server_name)) +        requested_server:install() +      else +        return +      end +    end +  end + +  local default_config = { +    on_attach = require("lsp").common_on_attach, +    on_init = require("lsp").common_on_init, +    capabilities = require("lsp").common_capabilities(), +  } + +  local status_ok, custom_config = pcall(require, "lsp/providers/" .. requested_server.name) +  if status_ok then +    local new_config = vim.tbl_deep_extend("force", default_config, custom_config) +    Log:debug("Using custom configuration for requested server: " .. requested_server.name) +    requested_server:setup(new_config) +  else +    Log:debug("Using the default configuration for requested server: " .. requested_server.name) +    requested_server:setup(default_config) +  end +end + +function M.setup(servers) +  local status_ok, _ = pcall(require, "nvim-lsp-installer") +  if not status_ok then +    return +  end + +  --- allow using a single value +  if type(servers) == "string" then +    servers = { servers } +  end + +  for _, server in ipairs(servers) do +    M.setup_server(server) +  end +end + +return M diff --git a/lua/lsp/null-ls/formatters.lua b/lua/lsp/null-ls/formatters.lua index 2c2a4f06..8199aca0 100644 --- a/lua/lsp/null-ls/formatters.lua +++ b/lua/lsp/null-ls/formatters.lua @@ -1,29 +1,14 @@  local M = {} -local formatters_by_ft = {}  local null_ls = require "null-ls"  local services = require "lsp.null-ls.services"  local Log = require "core.log" -local function list_names(formatters, options) -  options = options or {} -  local filter = options.filter or "supported" - -  return vim.tbl_keys(formatters[filter]) -end -  function M.list_supported_names(filetype) -  if not formatters_by_ft[filetype] then -    return {} -  end -  return list_names(formatters_by_ft[filetype], { filter = "supported" }) -end - -function M.list_unsupported_names(filetype) -  if not formatters_by_ft[filetype] then -    return {} -  end -  return list_names(formatters_by_ft[filetype], { filter = "unsupported" }) +  local null_ls_methods = require "null-ls.methods" +  local formatter_method = null_ls_methods.internal["FORMATTING"] +  local registered_providers = services.list_registered_providers_names(filetype) +  return registered_providers[formatter_method] or {}  end  function M.list_available(filetype) @@ -62,12 +47,13 @@ function M.list_configured(formatter_configs)    return { supported = formatters, unsupported = errors }  end -function M.setup(filetype, options) -  if not lvim.lang[filetype] or (formatters_by_ft[filetype] and not options.force_reload) then +function M.setup(formatter_configs, filetype) +  if vim.tbl_isempty(formatter_configs) then      return    end -  formatters_by_ft[filetype] = M.list_configured(lvim.lang[filetype].formatters) +  local formatters_by_ft = {} +  formatters_by_ft[filetype] = M.list_configured(formatter_configs)    null_ls.register { sources = formatters_by_ft[filetype].supported }  end diff --git a/lua/lsp/null-ls/init.lua b/lua/lsp/null-ls/init.lua index ce4c07d9..0540fb48 100644 --- a/lua/lsp/null-ls/init.lua +++ b/lua/lsp/null-ls/init.lua @@ -1,44 +1,26 @@  local M = {} -function M.list_supported_provider_names(filetype) -  local names = {} - -  local formatters = require "lsp.null-ls.formatters" -  local linters = require "lsp.null-ls.linters" - -  vim.list_extend(names, formatters.list_supported_names(filetype)) -  vim.list_extend(names, linters.list_supported_names(filetype)) - -  return names -end - -function M.list_unsupported_provider_names(filetype) -  local names = {} - -  local formatters = require "lsp.null-ls.formatters" -  local linters = require "lsp.null-ls.linters" - -  vim.list_extend(names, formatters.list_unsupported_names(filetype)) -  vim.list_extend(names, linters.list_unsupported_names(filetype)) - -  return names -end - --- TODO: for linters and formatters with spaces and '-' replace with '_' -function M.setup(filetype, options) -  options = options or {} - -  local ok, _ = pcall(require, "null-ls") -  if not ok then -    require("core.log"):error "Missing null-ls dependency" +local Log = require "core.log" +local formatters = require "lsp.null-ls.formatters" +local linters = require "lsp.null-ls.linters" + +function M:setup() +  local status_ok, null_ls = pcall(require, "null-ls") +  if not status_ok then +    Log:error "Missing null-ls dependency"      return    end -  local formatters = require "lsp.null-ls.formatters" -  local linters = require "lsp.null-ls.linters" - -  formatters.setup(filetype, options) -  linters.setup(filetype, options) +  null_ls.config() +  require("lspconfig")["null-ls"].setup {} +  for _, filetype in pairs(lvim.lang) do +    if filetype.formatters then +      formatters.setup(filetype.formatters, filetype) +    end +    if filetype.linters then +      linters.setup(filetype.linters, filetype) +    end +  end  end  return M diff --git a/lua/lsp/null-ls/linters.lua b/lua/lsp/null-ls/linters.lua index d88a8b83..ea45fa87 100644 --- a/lua/lsp/null-ls/linters.lua +++ b/lua/lsp/null-ls/linters.lua @@ -1,29 +1,14 @@  local M = {} -local linters_by_ft = {}  local null_ls = require "null-ls"  local services = require "lsp.null-ls.services"  local Log = require "core.log" -local function list_names(linters, options) -  options = options or {} -  local filter = options.filter or "supported" - -  return vim.tbl_keys(linters[filter]) -end -  function M.list_supported_names(filetype) -  if not linters_by_ft[filetype] then -    return {} -  end -  return list_names(linters_by_ft[filetype], { filter = "supported" }) -end - -function M.list_unsupported_names(filetype) -  if not linters_by_ft[filetype] then -    return {} -  end -  return list_names(linters_by_ft[filetype], { filter = "unsupported" }) +  local null_ls_methods = require "null-ls.methods" +  local linter_method = null_ls_methods.internal["DIAGNOSTICS"] +  local registered_providers = services.list_registered_providers_names(filetype) +  return registered_providers[linter_method] or {}  end  function M.list_available(filetype) @@ -62,12 +47,13 @@ function M.list_configured(linter_configs)    return { supported = linters, unsupported = errors }  end -function M.setup(filetype, options) -  if not lvim.lang[filetype] or (linters_by_ft[filetype] and not options.force_reload) then +function M.setup(linter_configs, filetype) +  if vim.tbl_isempty(linter_configs) then      return    end -  linters_by_ft[filetype] = M.list_configured(lvim.lang[filetype].linters) +  local linters_by_ft = {} +  linters_by_ft[filetype] = M.list_configured(linter_configs)    null_ls.register { sources = linters_by_ft[filetype].supported }  end diff --git a/lua/lsp/null-ls/services.lua b/lua/lsp/null-ls/services.lua index 1e76b40a..c62fc709 100644 --- a/lua/lsp/null-ls/services.lua +++ b/lua/lsp/null-ls/services.lua @@ -45,4 +45,19 @@ function M.find_command(command)    return nil  end +function M.list_registered_providers_names(filetype) +  local u = require "null-ls.utils" +  local c = require "null-ls.config" +  local registered = {} +  for method, source in pairs(c.get()._methods) do +    for name, filetypes in pairs(source) do +      if u.filetype_matches(filetypes, filetype) then +        registered[method] = registered[method] or {} +        table.insert(registered[method], name) +      end +    end +  end +  return registered +end +  return M diff --git a/lua/lsp/providers/jsonls.lua b/lua/lsp/providers/jsonls.lua new file mode 100644 index 00000000..55bc1ea2 --- /dev/null +++ b/lua/lsp/providers/jsonls.lua @@ -0,0 +1,30 @@ +local schemas = nil +local status_ok, jsonls_settings = pcall(require, "nlspsettings.jsonls") +if status_ok then +  schemas = jsonls_settings.get_default_schemas() +end + +local opts = { +  setup = { +    settings = { +      json = { +        schemas = schemas, +        --   = { +        --   { +        --     fileMatch = { "package.json" }, +        --     url = "https://json.schemastore.org/package.json", +        --   }, +        -- }, +      }, +    }, +    commands = { +      Format = { +        function() +          vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 }) +        end, +      }, +    }, +  }, +} + +return opts diff --git a/lua/lsp/providers/sumneko_lua.lua b/lua/lsp/providers/sumneko_lua.lua new file mode 100644 index 00000000..4fee1fd1 --- /dev/null +++ b/lua/lsp/providers/sumneko_lua.lua @@ -0,0 +1,19 @@ +local opts = { +  settings = { +    Lua = { +      diagnostics = { +        globals = { "vim", "lvim" }, +      }, +      workspace = { +        library = { +          [require("utils").join_paths(get_runtime_dir(), "lvim", "lua")] = true, +          [vim.fn.expand "$VIMRUNTIME/lua"] = true, +          [vim.fn.expand "$VIMRUNTIME/lua/vim/lsp"] = true, +        }, +        maxPreload = 100000, +        preloadFileSize = 10000, +      }, +    }, +  }, +} +return opts diff --git a/lua/lsp/providers/vuels.lua b/lua/lsp/providers/vuels.lua new file mode 100644 index 00000000..3f44275d --- /dev/null +++ b/lua/lsp/providers/vuels.lua @@ -0,0 +1,26 @@ +local opts = { +  setup = { +    root_dir = function(fname) +      local util = require "lspconfig/util" +      return util.root_pattern "package.json"(fname) or util.root_pattern "vue.config.js"(fname) or vim.fn.getcwd() +    end, +    init_options = { +      config = { +        vetur = { +          completion = { +            autoImport = true, +            tagCasing = "kebab", +            useScaffoldSnippets = true, +          }, +          useWorkspaceDependencies = true, +          validation = { +            script = true, +            style = true, +            template = true, +          }, +        }, +      }, +    }, +  }, +} +return opts diff --git a/lua/lsp/templates.lua b/lua/lsp/templates.lua new file mode 100644 index 00000000..6ded636d --- /dev/null +++ b/lua/lsp/templates.lua @@ -0,0 +1,98 @@ +local M = {} + +local Log = require "core.log" +local utils = require "utils" +local get_supported_filetypes = require("lsp.utils").get_supported_filetypes + +local ftplugin_dir = lvim.lsp.templates_dir + +local join_paths = _G.join_paths + +function M.remove_template_files() +  -- remove any outdated files +  for _, file in ipairs(vim.fn.glob(ftplugin_dir .. "/*.lua", 1, 1)) do +    vim.fn.delete(file) +  end +end + +---Checks if a server is ignored by default because of a conflict +---Only TSServer is enabled by default for the javascript-family +---@param server_name string +function M.is_ignored(server_name, filetypes) +  --TODO: this is easy to be made configurable once stable +  filetypes = filetypes or get_supported_filetypes(server_name) + +  if vim.tbl_contains(filetypes, "javascript") then +    if server_name == "tsserver" or server_name == "tailwindcss" then +      return false +    else +      return true +    end +  end + +  local blacklist = { +    "jedi_language_server", +    "pylsp", +    "sqlls", +    "sqls", +    "angularls", +    "ansiblels", +  } +  return vim.tbl_contains(blacklist, server_name) +end + +---Generates an ftplugin file based on the server_name in the selected directory +---@param server_name string name of a valid language server, e.g. pyright, gopls, tsserver, etc. +---@param dir string the full path to the desired directory +function M.generate_ftplugin(server_name, dir) +  -- we need to go through lspconfig to get the corresponding filetypes currently +  local filetypes = get_supported_filetypes(server_name) or {} +  if not filetypes then +    return +  end + +  if M.is_ignored(server_name, filetypes) then +    return +  end + +  -- print("got associated filetypes: " .. vim.inspect(filetypes)) + +  for _, filetype in ipairs(filetypes) do +    local filename = join_paths(dir, filetype .. ".lua") +    local setup_cmd = string.format([[require("lsp.manager").setup(%q)]], server_name) +    -- print("using setup_cmd: " .. setup_cmd) +    -- overwrite the file completely +    utils.write_file(filename, setup_cmd .. "\n", "a") +  end +end + +---Generates ftplugin files based on a list of server_names +---The files are generated to a runtimepath: "$LUNARVIM_RUNTIME_DIR/site/after/ftplugin/template.lua" +---@param servers_names table list of servers to be enabled. Will add all by default +function M.generate_templates(servers_names) +  servers_names = servers_names or {} + +  Log:debug "Templates installation in progress" + +  M.remove_template_files() + +  if vim.tbl_isempty(servers_names) then +    local available_servers = require("nvim-lsp-installer.servers").get_available_servers() + +    for _, server in pairs(available_servers) do +      table.insert(servers_names, server.name) +    end +  end + +  -- create the directory if it didn't exist +  if not utils.is_directory(lvim.lsp.templates_dir) then +    vim.fn.mkdir(ftplugin_dir, "p") +  end + +  for _, server in ipairs(servers_names) do +    M.generate_ftplugin(server, ftplugin_dir) +  end +  Log:debug "Templates installation is complete" +end + +return M diff --git a/lua/lsp/utils.lua b/lua/lsp/utils.lua index 17b9c3bc..1a5dd79d 100644 --- a/lua/lsp/utils.lua +++ b/lua/lsp/utils.lua @@ -10,19 +10,60 @@ function M.is_client_active(name)    return false  end --- FIXME: this should return a list instead -function M.get_active_client_by_ft(filetype) -  if not lvim.lang[filetype] or not lvim.lang[filetype].lsp then -    return nil -  end +function M.disable_formatting_capability(client) +  -- FIXME: figure out a reasonable way to do this +  client.resolved_capabilities.document_formatting = false +  require("core.log"):debug(string.format("Turning off formatting capability for language server [%s] ", client.name)) +end +function M.get_active_client_by_ft(filetype) +  local matches = {}    local clients = vim.lsp.get_active_clients()    for _, client in pairs(clients) do -    if client.name == lvim.lang[filetype].lsp.provider then -      return client +    local supported_filetypes = client.config.filetypes or {} +    if client.name ~= "null-ls" and vim.tbl_contains(supported_filetypes, filetype) then +      table.insert(matches, client) +    end +  end +  return matches +end + +function M.get_ls_capabilities(client_id) +  if not client_id then +    local buf_clients = vim.lsp.buf_get_clients() +    for _, buf_client in ipairs(buf_clients) do +      if buf_client.name ~= "null-ls" then +        client_id = buf_client.id +        break +      end +    end +  end +  if not client_id then +    error "Unable to determine client_id" +    return +  end + +  local client = vim.lsp.get_client_by_id(tonumber(client_id)) + +  local enabled_caps = {} +  for capability, status in pairs(client.resolved_capabilities) do +    if status == true then +      table.insert(enabled_caps, capability) +    end +  end + +  return enabled_caps +end + +function M.get_supported_filetypes(server_name) +  -- print("got filetypes query request for: " .. server_name) +  local configs = require "lspconfig/configs" +  pcall(require, ("lspconfig/" .. server_name)) +  for _, config in pairs(configs) do +    if config.name == server_name then +      return config.document_config.default_config.filetypes or {}      end    end -  return nil  end  return M diff --git a/lua/plugins.lua b/lua/plugins.lua index 178fb99e..d7f47fcb 100644 --- a/lua/plugins.lua +++ b/lua/plugins.lua @@ -6,12 +6,7 @@ return {    { "jose-elias-alvarez/null-ls.nvim" },    { "antoinemadec/FixCursorHold.nvim" }, -- Needed while issue https://github.com/neovim/neovim/issues/12587 is still open    { -    "kabouzeid/nvim-lspinstall", -    event = "VimEnter", -    config = function() -      local lspinstall = require "core.lspinstall" -      lspinstall.setup() -    end, +    "williamboman/nvim-lsp-installer",    },    { "nvim-lua/popup.nvim" }, diff --git a/lua/utils/init.lua b/lua/utils/init.lua index 7f8e1f77..eaac54f4 100644 --- a/lua/utils/init.lua +++ b/lua/utils/init.lua @@ -99,8 +99,7 @@ function utils.reload_lv_config()    vim.cmd ":PackerInstall"    vim.cmd ":PackerCompile"    -- vim.cmd ":PackerClean" -  local null_ls = require "lsp.null-ls" -  null_ls.setup(vim.bo.filetype, { force_reload = true }) +  require("lsp").setup()    Log:info "Reloaded configuration"  end @@ -133,15 +132,106 @@ function utils.apply_defaults(config, default_config)  end  --- Checks whether a given path exists and is a file. ---@param filename (string) path to check +--@param path (string) path to check  --@returns (bool) -function utils.is_file(filename) -  local stat = uv.fs_stat(filename) +function utils.is_file(path) +  local stat = uv.fs_stat(path)    return stat and stat.type == "file" or false  end +--- Checks whether a given path exists and is a directory +--@param path (string) path to check +--@returns (bool) +function utils.is_directory(path) +  local stat = uv.fs_stat(path) +  return stat and stat.type == "directory" or false +end + +function utils.write_file(path, txt, flag) +  uv.fs_open(path, flag, 438, function(open_err, fd) +    assert(not open_err, open_err) +    uv.fs_write(fd, txt, -1, function(write_err) +      assert(not write_err, write_err) +      uv.fs_close(fd, function(close_err) +        assert(not close_err, close_err) +      end) +    end) +  end) +end +  utils.join_paths = _G.join_paths +function utils.write_file(path, txt, flag) +  uv.fs_open(path, flag, 438, function(open_err, fd) +    assert(not open_err, open_err) +    uv.fs_write(fd, txt, -1, function(write_err) +      assert(not write_err, write_err) +      uv.fs_close(fd, function(close_err) +        assert(not close_err, close_err) +      end) +    end) +  end) +end + +function utils.debounce(ms, fn) +  local timer = vim.loop.new_timer() +  return function(...) +    local argv = { ... } +    timer:start(ms, 0, function() +      timer:stop() +      vim.schedule_wrap(fn)(unpack(argv)) +    end) +  end +end + +function utils.search_file(file, args) +  local Job = require "plenary.job" +  local stderr = {} +  local stdout, ret = Job +    :new({ +      command = "grep", +      args = { args, file }, +      cwd = get_cache_dir(), +      on_stderr = function(_, data) +        table.insert(stderr, data) +      end, +    }) +    :sync() +  return stdout, ret, stderr +end + +function utils.file_contains(file, query) +  local stdout, ret, stderr = utils.search_file(file, query) +  if ret == 0 then +    return true +  end +  if not vim.tbl_isempty(stderr) then +    error(vim.inspect(stderr)) +  end +  if not vim.tbl_isempty(stdout) then +    error(vim.inspect(stdout)) +  end +  return false +end + +function utils.log_contains(query) +  local logfile = require("core.log"):get_path() +  local stdout, ret, stderr = utils.search_file(logfile, query) +  if ret == 0 then +    return true +  end +  if not vim.tbl_isempty(stderr) then +    error(vim.inspect(stderr)) +  end +  if not vim.tbl_isempty(stdout) then +    error(vim.inspect(stdout)) +  end +  if not vim.tbl_isempty(stderr) then +    error(vim.inspect(stderr)) +  end +  return false +end +  return utils  -- TODO: find a new home for these autocommands | 
