diff options
| author | Ashkan Kiani <ashkan.k.kiani@gmail.com> | 2019-11-14 17:14:53 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-11-14 17:14:53 -0800 |
| commit | 0ccd248ef958a8d27e752952a880d004078b4ae9 (patch) | |
| tree | 67f4afbe9bf69322c0481f00aaff171214487c05 | |
| parent | Add github actions for docgen (#7) (diff) | |
| download | nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.tar nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.tar.gz nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.tar.bz2 nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.tar.lz nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.tar.xz nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.tar.zst nvim-lspconfig-0ccd248ef958a8d27e752952a880d004078b4ae9.zip | |
Add ElmLS (#9)
- Initial add of elmLS support
- Removes unnecessary vim.schedule_wrap fn calls in elmls & clangd impls
- Add automatic installation for elmls and update docs.
- Sort server output in the README.
- Add commands for elmls for buffer and globally.
- [bugfix] Skeleton could've tried to attach even if root_dir was nil
TODO: check for updates and warn the user if there are updates when an elm server is started.
Co-authored-by: Seth Messer <seth.messer@gmail.com>
| -rw-r--r-- | README.md | 84 | ||||
| -rw-r--r-- | README_preamble.md | 2 | ||||
| -rw-r--r-- | lua/nvim_lsp.lua | 5 | ||||
| -rw-r--r-- | lua/nvim_lsp/clangd.lua | 5 | ||||
| -rw-r--r-- | lua/nvim_lsp/elmls.lua | 141 | ||||
| -rw-r--r-- | lua/nvim_lsp/skeleton.lua | 6 | ||||
| -rw-r--r-- | lua/nvim_lsp/util.lua | 10 | ||||
| -rw-r--r-- | scripts/docgen.lua | 7 |
8 files changed, 229 insertions, 31 deletions
@@ -32,6 +32,7 @@ them are good references. Implemented: - [clangd](https://github.com/neovim/nvim-lsp#clangd) +- [elmls](https://github.com/neovim/nvim-lsp#elmls) - [gopls](https://github.com/neovim/nvim-lsp#gopls) (has some errors) - [pyls](https://github.com/neovim/nvim-lsp#pyls) - [texlab](https://github.com/neovim/nvim-lsp#texlab) @@ -151,7 +152,6 @@ nvim_lsp.SERVER.setup({config}) ``` # LSP Implementations - ## clangd https://clang.llvm.org/extra/clangd/Installation.html @@ -159,7 +159,7 @@ https://clang.llvm.org/extra/clangd/Installation.html clangd relies on a [JSON compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) specified as compile_commands.json or, for simpler projects, a compile_flags.txt. -``` +```vim nvim_lsp.clangd.setup({config}) nvim_lsp#setup("clangd", {config}) @@ -172,6 +172,65 @@ nvim_lsp#setup("clangd", {config}) root_dir = root_pattern("compile_commands.json", "compile_flags.txt", ".git") settings = {} ``` +## elmls + +https://github.com/elm-tooling/elm-language-server#installation + +You can install elmls automatically to the path at + `stdpath("cache")/nvim_lsp/elmls` +by using the function `nvim_lsp.elmls.install()` or the command `:ElmlsInstall`. + +This will only install if it can't find `elm-language-server` and if it hasn't +been installed before by neovim. + +You can see installation info via `:ElmlsInstallInfo` or via +`nvim_lsp.elmls.get_install_info()`. This will let you know if it is installed. + +If you don't want to use neovim to install it, then you can use: +```sh +npm install -g elm elm-test elm-format @elm-tooling/elm-language-server +``` + +```vim +nvim_lsp.elmls.setup({config}) +nvim_lsp#setup("elmls", {config}) + + Commands: + - ElmlsInstall: Install elmls and its dependencies to stdpath("cache")/nvim_lsp/elmls + - ElmlsInstallInfo: Print installation info for `elmls` + + Default Values: + capabilities = default capabilities, with offsetEncoding utf-8 + cmd = { "elm-language-server" } + filetypes = { "elm" } + init_options = { + elmAnalyseTrigger = "change", + elmFormatPath = "elm-format", + elmPath = "elm", + elmTestPath = "elm-test" + } + log_level = 2 + on_init = function to handle changing offsetEncoding + root_dir = root_pattern("elm.json") + settings = {} +``` +## gopls + +https://github.com/golang/tools/tree/master/gopls + +Google's lsp server for golang. + +```vim +nvim_lsp.gopls.setup({config}) +nvim_lsp#setup("gopls", {config}) + + Default Values: + cmd = { "gopls" } + filetypes = { "go" } + log_level = 2 + root_dir = root_pattern("go.mod", ".git") + settings = {} +``` ## pyls https://github.com/palantir/python-language-server @@ -214,7 +273,7 @@ settings = { }; ``` -``` +```vim nvim_lsp.pyls.setup({config}) nvim_lsp#setup("pyls", {config}) @@ -231,7 +290,7 @@ https://texlab.netlify.com/ A completion engine built from scratch for (la)tex. -``` +```vim nvim_lsp.texlab.setup({config}) nvim_lsp#setup("texlab", {config}) @@ -253,20 +312,3 @@ nvim_lsp#setup("texlab", {config}) } } ``` -## gopls - -https://github.com/golang/tools/tree/master/gopls - -Google's lsp server for golang. - -``` -nvim_lsp.gopls.setup({config}) -nvim_lsp#setup("gopls", {config}) - - Default Values: - cmd = { "gopls" } - filetypes = { "go" } - log_level = 2 - root_dir = root_pattern("go.mod", ".git") - settings = {} -``` diff --git a/README_preamble.md b/README_preamble.md index 365eb5ae..33c7dd55 100644 --- a/README_preamble.md +++ b/README_preamble.md @@ -32,6 +32,7 @@ them are good references. Implemented: - [clangd](https://github.com/neovim/nvim-lsp#clangd) +- [elmls](https://github.com/neovim/nvim-lsp#elmls) - [gopls](https://github.com/neovim/nvim-lsp#gopls) (has some errors) - [pyls](https://github.com/neovim/nvim-lsp#pyls) - [texlab](https://github.com/neovim/nvim-lsp#texlab) @@ -151,4 +152,3 @@ nvim_lsp.SERVER.setup({config}) ``` # LSP Implementations - diff --git a/lua/nvim_lsp.lua b/lua/nvim_lsp.lua index a28bc4d5..4a6518f2 100644 --- a/lua/nvim_lsp.lua +++ b/lua/nvim_lsp.lua @@ -1,8 +1,9 @@ local skeleton = require 'nvim_lsp/skeleton' -require 'nvim_lsp/gopls' -require 'nvim_lsp/texlab' require 'nvim_lsp/clangd' +require 'nvim_lsp/elmls' +require 'nvim_lsp/gopls' require 'nvim_lsp/pyls' +require 'nvim_lsp/texlab' local M = { util = require 'nvim_lsp/util'; diff --git a/lua/nvim_lsp/clangd.lua b/lua/nvim_lsp/clangd.lua index b0d4ec25..8abe8ea2 100644 --- a/lua/nvim_lsp/clangd.lua +++ b/lua/nvim_lsp/clangd.lua @@ -13,11 +13,11 @@ skeleton.clangd = { log_level = lsp.protocol.MessageType.Warning; settings = {}; capabilities = default_capabilities; - on_init = vim.schedule_wrap(function(client, result) + on_init = function(client, result) if result.offsetEncoding then client.offset_encoding = result.offsetEncoding end - end) + end }; -- commands = {}; -- on_new_config = function(new_config) end; @@ -37,4 +37,3 @@ as compile_commands.json or, for simpler projects, a compile_flags.txt. }; } -- vim:et ts=2 sw=2 - diff --git a/lua/nvim_lsp/elmls.lua b/lua/nvim_lsp/elmls.lua new file mode 100644 index 00000000..08a28c45 --- /dev/null +++ b/lua/nvim_lsp/elmls.lua @@ -0,0 +1,141 @@ +local skeleton = require 'nvim_lsp/skeleton' +local util = require 'nvim_lsp/util' +local lsp = vim.lsp +local fn = vim.fn +local api = vim.api +local need_bins = util.need_bins + +local default_capabilities = lsp.protocol.make_client_capabilities() +default_capabilities.offsetEncoding = {"utf-8", "utf-16"} + +local bin_name = "elm-language-server" + +local install_dir = util.path.join(fn.stdpath("cache"), "nvim_lsp", "elmls") +local function get_install_info() + local bin_dir = util.path.join(install_dir, "node_modules", ".bin") + local bins = { bin_dir = bin_dir; install_dir = install_dir; } + bins.elmls = util.path.join(bin_dir, bin_name) + bins.elm = util.path.join(bin_dir, "elm") + bins.elm_format = util.path.join(bin_dir, "elm-format") + bins.elm_test = util.path.join(bin_dir, "elm-test") + bins.is_installed = need_bins(bins.elmls, bins.elm, bins.elm_format, bins.elm_test) + return bins +end + +local global_commands = { + ElmlsInstall = { + function() + if get_install_info().is_installed then + return print("ElmLS is already installed") + end + skeleton.elmls.install() + end; + description = 'Install elmls and its dependencies to stdpath("cache")/nvim_lsp/elmls'; + }; + ElmlsInstallInfo = { + function() + local install_info = get_install_info() + if not install_info.is_installed then + return print("ElmLS is not installed") + end + print(vim.inspect(install_info)) + end; + description = 'Print installation info for `elmls`'; + }; +}; + +util.create_module_commands("elmls", global_commands) + +local elm_root_pattern = util.root_pattern("elm.json") + +skeleton.elmls = { + default_config = { + cmd = {bin_name}; + -- TODO(ashkan) if we comment this out, it will allow elmls to operate on elm.json. It seems like it could do that, but no other editor allows it right now. + filetypes = {"elm"}; + root_dir = function(fname, bufnr) + local filetype = api.nvim_buf_get_option(0, 'filetype') + if filetype == 'elm' or (filetype == 'json' and fname:match("elm%.json$")) then + return elm_root_pattern(fname) + end + end; + log_level = lsp.protocol.MessageType.Warning; + settings = {}; + init_options = { + elmPath = "elm", + elmFormatPath = "elm-format", + elmTestPath = "elm-test", + elmAnalyseTrigger = "change", + }; + capabilities = default_capabilities; + on_init = function(client, result) + if result.offsetEncoding then + client.offset_encoding = result.offsetEncoding + end + end + }; + commands = global_commands; + on_new_config = function(new_config) + local install_info = get_install_info() + if install_info.is_installed then + new_config.cmd = {install_info.elmls} + util.tbl_deep_extend(new_config.init_options, { + elmPath = install_info.elm; + elmFormatPath = install_info.elm_format; + elmTestPath = install_info.elm_test; + }) + end + print(vim.inspect(new_config)) + end; + docs = { + description = [[ +https://github.com/elm-tooling/elm-language-server#installation + +You can install elmls automatically to the path at + `stdpath("cache")/nvim_lsp/elmls` +by using the function `nvim_lsp.elmls.install()` or the command `:ElmlsInstall`. + +This will only install if it can't find `elm-language-server` and if it hasn't +been installed before by neovim. + +You can see installation info via `:ElmlsInstallInfo` or via +`nvim_lsp.elmls.get_install_info()`. This will let you know if it is installed. + +If you don't want to use neovim to install it, then you can use: +```sh +npm install -g elm elm-test elm-format @elm-tooling/elm-language-server +``` +]]; + default_config = { + root_dir = [[root_pattern("elm.json")]]; + on_init = [[function to handle changing offsetEncoding]]; + capabilities = [[default capabilities, with offsetEncoding utf-8]]; + }; + }; +} + +function skeleton.elmls.install() + if not need_bins(bin_name) then return end + if not need_bins("sh", "npm", "mkdir", "cd") then + vim.api.nvim_err_writeln('Installation requires "sh", "npm", "mkdir", "cd"') + return + end + local install_info = get_install_info() + if install_info.is_installed then + return + end + local cmd = io.popen("sh", "w") + local install_script = ([[ +set -eo pipefail +mkdir -p "{{install_dir}}" +cd "{{install_dir}}" +npm install elm elm-test elm-format @elm-tooling/elm-language-server +]]):gsub("{{(%S+)}}", install_info) + print(install_script) + cmd:write(install_script) + cmd:close() +end + +skeleton.elmls.get_install_info = get_install_info +-- vim:et ts=2 sw=2 + diff --git a/lua/nvim_lsp/skeleton.lua b/lua/nvim_lsp/skeleton.lua index 9fa6f835..0d69fed0 100644 --- a/lua/nvim_lsp/skeleton.lua +++ b/lua/nvim_lsp/skeleton.lua @@ -130,9 +130,11 @@ function skeleton.__newindex(t, template_name, template) function manager.try_add() local root_dir = get_root_dir(api.nvim_buf_get_name(0), api.nvim_get_current_buf()) - print(api.nvim_get_current_buf(), root_dir) + if not root_dir then return end local id = manager.add(root_dir) - lsp.buf_attach_client(0, id) + if id then + lsp.buf_attach_client(0, id) + end end M.manager = manager diff --git a/lua/nvim_lsp/util.lua b/lua/nvim_lsp/util.lua index 190869e6..2b13d227 100644 --- a/lua/nvim_lsp/util.lua +++ b/lua/nvim_lsp/util.lua @@ -2,6 +2,7 @@ local validate = vim.validate local api = vim.api local lsp = vim.lsp local uv = vim.loop +local fn = vim.fn local M = {} @@ -89,6 +90,15 @@ function M.create_module_commands(module_name, commands) end end +function M.need_bins(...) + for i = 1, select("#", ...) do + if 0 == fn.executable((select(i, ...))) then + return false + end + end + return true +end + -- Some path utilities M.path = (function() local function exists(filename) diff --git a/scripts/docgen.lua b/scripts/docgen.lua index 3b02949e..036a5226 100644 --- a/scripts/docgen.lua +++ b/scripts/docgen.lua @@ -41,7 +41,10 @@ end local writer = io.popen("cat README_preamble.md - > README.md", "w") -for k, v in pairs(skeleton) do +local skeleton_keys = vim.tbl_keys(skeleton) +table.sort(skeleton_keys) +for _, k in ipairs(skeleton_keys) do + local v = skeleton[k] local tconf = v.template_config local params = {} @@ -94,7 +97,7 @@ for k, v in pairs(skeleton) do ## {{template_name}} {{preamble}} -``` +```vim nvim_lsp.{{template_name}}.setup({config}) nvim_lsp#setup("{{template_name}}", {config}) |
