diff options
-rw-r--r-- | .github/workflows/install.yaml | 6 | ||||
-rw-r--r-- | init.lua | 2 | ||||
-rw-r--r-- | lua/lvim/bootstrap.lua | 2 | ||||
-rw-r--r-- | lua/lvim/config/init.lua | 4 | ||||
-rw-r--r-- | lua/lvim/core/autocmds.lua | 5 | ||||
-rw-r--r-- | lua/lvim/core/commands.lua | 2 | ||||
-rw-r--r-- | lua/lvim/core/info.lua | 4 | ||||
-rw-r--r-- | lua/lvim/core/which-key.lua | 4 | ||||
-rw-r--r-- | lua/lvim/lsp/config.lua | 5 | ||||
-rw-r--r-- | lua/lvim/lsp/manager.lua | 43 | ||||
-rw-r--r-- | lua/lvim/lsp/utils.lua | 17 | ||||
-rw-r--r-- | lua/lvim/plugin-loader.lua | 58 | ||||
-rw-r--r-- | lua/lvim/utils/ft.lua | 47 | ||||
-rw-r--r-- | lua/lvim/utils/hooks.lua | 3 | ||||
-rw-r--r-- | tests/bootstrap_spec.lua | 8 | ||||
-rw-r--r-- | tests/config_loader_spec.lua | 8 | ||||
-rw-r--r-- | tests/lsp_spec.lua | 36 | ||||
-rw-r--r-- | tests/minimal_lsp.lua | 25 | ||||
-rw-r--r-- | utils/bin/lvim.ps1 | 2 | ||||
-rw-r--r-- | utils/bin/test_runner.sh | 10 |
20 files changed, 145 insertions, 146 deletions
diff --git a/.github/workflows/install.yaml b/.github/workflows/install.yaml index fa1b9be8..02400ce4 100644 --- a/.github/workflows/install.yaml +++ b/.github/workflows/install.yaml @@ -33,12 +33,6 @@ jobs: run: | ./utils/installer/install.sh --local --no-install-dependencies - - name: Test LunarVim PackerCompile - run: if "$HOME"/.local/bin/lvim --headless +PackerCompile -c ':qall' 2>&1|grep -q 'Error'; then false; fi - - - name: Test LunarVim Health - run: if "$HOME"/.local/bin/lvim --headless +checkhealth -c ':qall' 2>&1|grep -q 'Error'; then false; fi - - name: Run unit-tests # NOTE: make sure to adjust the timeout if you start adding a lot of tests timeout-minutes: 4 @@ -10,7 +10,7 @@ require("lvim.bootstrap"):init(base_dir) require("lvim.config"):load() local plugins = require "lvim.plugins" -require("lvim.plugin-loader"):load { plugins, lvim.plugins } +require("lvim.plugin-loader").load { plugins, lvim.plugins } local Log = require "lvim.core.log" Log:debug "Starting LunarVim" diff --git a/lua/lvim/bootstrap.lua b/lua/lvim/bootstrap.lua index e17c79db..74a9bf45 100644 --- a/lua/lvim/bootstrap.lua +++ b/lua/lvim/bootstrap.lua @@ -87,7 +87,7 @@ function M:init(base_dir) require("lvim.config"):init() - require("lvim.plugin-loader"):init { + require("lvim.plugin-loader").init { package_root = self.pack_dir, install_path = self.packer_install_dir, } diff --git a/lua/lvim/config/init.lua b/lua/lvim/config/init.lua index e89cb260..1256e236 100644 --- a/lua/lvim/config/init.lua +++ b/lua/lvim/config/init.lua @@ -102,8 +102,8 @@ function M:reload() local plugins = require "lvim.plugins" utils.toggle_autoformat() local plugin_loader = require "lvim.plugin-loader" - plugin_loader:cache_reset() - plugin_loader:load { plugins, lvim.plugins } + plugin_loader.cache_clear() + plugin_loader.load { plugins, lvim.plugins } vim.cmd ":PackerInstall" vim.cmd ":PackerCompile" -- vim.cmd ":PackerClean" diff --git a/lua/lvim/core/autocmds.lua b/lua/lvim/core/autocmds.lua index 5d1d365e..569622be 100644 --- a/lua/lvim/core/autocmds.lua +++ b/lua/lvim/core/autocmds.lua @@ -6,11 +6,6 @@ function M.load_augroups() return { _general_settings = { - { - "Filetype", - "*", - "lua require('lvim.utils.ft').do_filetype(vim.fn.expand(\"<amatch>\"))", - }, { "FileType", "qf,help,man", "nnoremap <silent> <buffer> q :close<CR>" }, { "TextYankPost", diff --git a/lua/lvim/core/commands.lua b/lua/lvim/core/commands.lua index b750f12b..61148889 100644 --- a/lua/lvim/core/commands.lua +++ b/lua/lvim/core/commands.lua @@ -14,6 +14,8 @@ M.defaults = { [[ command! LvimInfo lua require('lvim.core.info').toggle_popup(vim.bo.filetype) ]], [[ command! LvimCacheReset lua require('lvim.utils.hooks').reset_cache() ]], [[ command! LvimUpdate lua require('lvim.bootstrap').update() ]], + [[ command! LvimSyncCorePlugins lua require('lvim.plugin-loader'):sync_core_plugins() ]], + [[ command! LvimReload lua require('lvim.config'):reload() ]], } M.load = function(commands) diff --git a/lua/lvim/core/info.lua b/lua/lvim/core/info.lua index 5707cc30..fc87691e 100644 --- a/lua/lvim/core/info.lua +++ b/lua/lvim/core/info.lua @@ -61,11 +61,13 @@ local function make_client_info(client) local client_enabled_caps = lsp_utils.get_client_capabilities(client.id) local name = client.name local id = client.id + local filetypes = lsp_utils.get_supported_filetypes(name) local document_formatting = client.resolved_capabilities.document_formatting local attached_buffers_list = table.concat(vim.lsp.get_buffers_by_client_id(client.id), ", ") local client_info = { fmt("* Name: %s", name), fmt("* Id: [%s]", tostring(id)), + fmt("* filetype(s): [%s]", table.concat(filetypes, ", ")), fmt("* Attached buffers: [%s]", tostring(attached_buffers_list)), fmt("* Supports formatting: %s", tostring(document_formatting)), } @@ -106,7 +108,7 @@ function M.toggle_popup(ft) local lsp_info = { "Language Server Protocol (LSP) info", - fmt "* Associated server(s):", + fmt "* Active server(s):", } for _, client in pairs(clients) do diff --git a/lua/lvim/core/which-key.lua b/lua/lvim/core/which-key.lua index 42e37456..b036e376 100644 --- a/lua/lvim/core/which-key.lua +++ b/lua/lvim/core/which-key.lua @@ -98,7 +98,7 @@ M.config = function() name = "Packer", c = { "<cmd>PackerCompile<cr>", "Compile" }, i = { "<cmd>PackerInstall<cr>", "Install" }, - r = { "<cmd>lua require('lvim.utils').reload_lv_config()<cr>", "Reload" }, + r = { "<cmd>lua require('lvim.plugin-loader').recompile()<cr>", "Re-compile" }, s = { "<cmd>PackerSync<cr>", "Sync" }, S = { "<cmd>PackerStatus<cr>", "Status" }, u = { "<cmd>PackerUpdate<cr>", "Update" }, @@ -220,7 +220,7 @@ M.config = function() }, P = { "<cmd>exe 'edit '.stdpath('cache').'/packer.nvim.log'<cr>", "Open the Packer logfile" }, }, - r = { "<cmd>lua require('lvim.utils').reload_lv_config()<cr>", "Reload configurations" }, + r = { "<cmd>LvimReload<cr>", "Reload LunarVim's configuration" }, u = { "<cmd>LvimUpdate<cr>", "Update LunarVim" }, }, s = { diff --git a/lua/lvim/lsp/config.lua b/lua/lvim/lsp/config.lua index 2d9104ea..ccc524ee 100644 --- a/lua/lvim/lsp/config.lua +++ b/lua/lvim/lsp/config.lua @@ -46,15 +46,20 @@ return { "ansiblels", "denols", "ember", + "emmet_ls", "eslint", "eslintls", + "graphql", "jedi_language_server", + "ltex", + "phpactor", "pylsp", "rome", "sqlls", "sqls", "stylelint_lsp", "tailwindcss", + "tflint", "volar", }, } diff --git a/lua/lvim/lsp/manager.lua b/lua/lvim/lsp/manager.lua index a8544803..dbb7b87f 100644 --- a/lua/lvim/lsp/manager.lua +++ b/lua/lvim/lsp/manager.lua @@ -39,6 +39,12 @@ local function resolve_config(name, user_config) return config end +-- manually start the server and don't wait for the usual filetype trigger from lspconfig +local function buf_try_add(server_name, bufnr) + bufnr = bufnr or vim.api.nvim_get_current_buf() + require("lspconfig")[server_name].manager.try_add_wrapper(bufnr) +end + ---Setup a language server by providing a name ---@param server_name string name of the language server ---@param user_config table [optional] when available it will take predence over any default configurations @@ -48,32 +54,37 @@ function M.setup(server_name, user_config) if lvim_lsp_utils.is_client_active(server_name) then return end + local servers = require "nvim-lsp-installer.servers" local config = resolve_config(server_name, user_config) - local server_available, requested_server = require("nvim-lsp-installer.servers").get_server(server_name) + local server_available, requested_server = servers.get_server(server_name) - local function ensure_installed(server) - if server:is_installed() then - return true - end - if not lvim.lsp.automatic_servers_installation then - Log:debug(server.name .. " is not managed by the automatic installer") - return false + if server_available then + local install_notification = false + + if not requested_server:is_installed() then + if lvim.lsp.automatic_servers_installation then + Log:debug "Automatic server installation detected" + requested_server:install() + install_notification = true + else + Log:debug(requested_server.name .. " is not managed by the automatic installer") + end end - Log:debug(string.format("Installing [%s]", server.name)) - server:install() - vim.schedule(function() - vim.cmd [[LspStart]] - end) - end - if server_available and ensure_installed(requested_server) then - requested_server:setup(config) + requested_server:on_ready(function() + if install_notification then + vim.notify(string.format("Installation complete for [%s] server", requested_server.name), vim.log.levels.INFO) + end + install_notification = false + requested_server:setup(config) + end) else -- since it may not be installed, don't attempt to configure the LSP unless there is a custom provider local has_custom_provider, _ = pcall(require, "lvim/lsp/providers/" .. server_name) if has_custom_provider then require("lspconfig")[server_name].setup(config) + buf_try_add(server_name) end end end diff --git a/lua/lvim/lsp/utils.lua b/lua/lvim/lsp/utils.lua index a34fbf44..7cc8f54f 100644 --- a/lua/lvim/lsp/utils.lua +++ b/lua/lvim/lsp/utils.lua @@ -49,14 +49,17 @@ function M.get_client_capabilities(client_id) 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 + -- temporary workaround: https://github.com/neovim/nvim-lspconfig/pull/1358 + if server_name == "dockerls" then + return { "dockerfile" } + end + local lsp_installer_servers = require "nvim-lsp-installer.servers" + local server_available, requested_server = lsp_installer_servers.get_server(server_name) + if not server_available then + return {} end + + return requested_server:get_supported_filetypes() end return M diff --git a/lua/lvim/plugin-loader.lua b/lua/lvim/plugin-loader.lua index e1ede7bc..c4bd7373 100644 --- a/lua/lvim/plugin-loader.lua +++ b/lua/lvim/plugin-loader.lua @@ -5,7 +5,9 @@ local Log = require "lvim.core.log" -- we need to reuse this outside of init() local compile_path = get_config_dir() .. "/plugin/packer_compiled.lua" -function plugin_loader:init(opts) +local _, packer = pcall(require, "packer") + +function plugin_loader.init(opts) opts = opts or {} local install_path = opts.install_path or vim.fn.stdpath "data" .. "/site/pack/packer/start/packer.nvim" @@ -16,14 +18,10 @@ function plugin_loader:init(opts) vim.cmd "packadd packer.nvim" end - local packer_ok, packer = pcall(require, "packer") - if not packer_ok then - return - end - packer.init { package_root = package_root, compile_path = compile_path, + log = { level = "warn" }, git = { clone_timeout = 300 }, display = { open_fn = function() @@ -31,36 +29,51 @@ function plugin_loader:init(opts) end, }, } +end - self.packer = packer - return self +-- packer expects a space separated list +local function pcall_packer_command(cmd, kwargs) + local status_ok, msg = pcall(function() + require("packer")[cmd](unpack(kwargs or {})) + end) + if not status_ok then + Log:warn(cmd .. " failed with: " .. vim.inspect(msg)) + Log:trace(vim.inspect(vim.fn.eval "v:errmsg")) + end end -function plugin_loader:cache_clear() +function plugin_loader.cache_clear() if vim.fn.delete(compile_path) == 0 then Log:debug "deleted packer_compiled.lua" end end -function plugin_loader:cache_reset() - self.cache_clear() - require("packer").compile() +function plugin_loader.recompile() + plugin_loader.cache_clear() + pcall_packer_command "compile" if utils.is_file(compile_path) then Log:debug "generated packer_compiled.lua" end end -function plugin_loader:load(configurations) - return self.packer.startup(function(use) - for _, plugins in ipairs(configurations) do - for _, plugin in ipairs(plugins) do - use(plugin) +function plugin_loader.load(configurations) + Log:debug "loading plugins configuration" + local status_ok, _ = xpcall(function() + packer.startup(function(use) + for _, plugins in ipairs(configurations) do + for _, plugin in ipairs(plugins) do + use(plugin) + end end - end - end) + end) + end, debug.traceback) + if not status_ok then + Log:warn "problems detected while loading plugins' configurations" + Log:trace(debug.traceback()) + end end -function plugin_loader:get_core_plugins() +function plugin_loader.get_core_plugins() local list = {} local plugins = require "lvim.plugins" for _, item in pairs(plugins) do @@ -69,9 +82,10 @@ function plugin_loader:get_core_plugins() return list end -function plugin_loader:sync_core_plugins() +function plugin_loader.sync_core_plugins() local core_plugins = plugin_loader.get_core_plugins() - vim.cmd("PackerSync " .. unpack(core_plugins)) + Log:trace(string.format("Syncing core plugins: [%q]", table.concat(core_plugins, ", "))) + pcall_packer_command("sync", core_plugins) end return plugin_loader diff --git a/lua/lvim/utils/ft.lua b/lua/lvim/utils/ft.lua deleted file mode 100644 index e9852e6f..00000000 --- a/lua/lvim/utils/ft.lua +++ /dev/null @@ -1,47 +0,0 @@ --- Here be dragons --- Opening files with telescope will not start LSP without this -local ft = {} - -ft.find_lua_ftplugins = function(filetype) - local patterns = { - string.format("ftplugin/%s.lua", filetype), - - -- Looks like we don't need this, because the first one works - -- string.format("after/ftplugin/%s.lua", filetype), - } - - local result = {} - for _, pat in ipairs(patterns) do - vim.list_extend(result, vim.api.nvim_get_runtime_file(pat, true)) - end - - return result -end - -ft.do_filetype = function(filetype) - local ftplugins = ft.find_lua_ftplugins(filetype) - - local f_env = setmetatable({ - -- Override print, so the prints still go through, otherwise it's confusing for people - print = vim.schedule_wrap(print), - }, { - -- Buf default back read/write to whatever is going on in the global landscape - __index = _G, - __newindex = _G, - }) - - for _, file in ipairs(ftplugins) do - local f = loadfile(file) - if not f then - vim.api.nvim_err_writeln("Unable to load file: " .. file) - else - local ok, msg = pcall(setfenv(f, f_env)) - - if not ok then - vim.api.nvim_err_writeln("Error while processing file: " .. file .. "\n" .. msg) - end - end - end -end - -return ft diff --git a/lua/lvim/utils/hooks.lua b/lua/lvim/utils/hooks.lua index cc884523..0fe4a7fd 100644 --- a/lua/lvim/utils/hooks.lua +++ b/lua/lvim/utils/hooks.lua @@ -15,8 +15,7 @@ end ---Tip: Useful for clearing any outdated settings function M.reset_cache() _G.__luacache.clear_cache() - - plugin_loader:cache_reset() + require("lvim.plugin-loader").recompile() package.loaded["lvim.lsp.templates"] = nil Log:debug "Re-generatring ftplugin template files" diff --git a/tests/bootstrap_spec.lua b/tests/bootstrap_spec.lua index d92e213d..c86d22d4 100644 --- a/tests/bootstrap_spec.lua +++ b/tests/bootstrap_spec.lua @@ -25,4 +25,12 @@ a.describe("initial start", function() a.it("should be able to run treesitter without errors", function() assert.truthy(vim.treesitter.highlighter.active) end) + + a.it("should be able to pass basic checkhealth without errors", function() + vim.cmd "checkhealth nvim" + local errmsg = vim.fn.eval "v:errmsg" + local exception = vim.fn.eval "v:exception" + assert.equal("", errmsg) -- v:errmsg was not updated. + assert.equal("", exception) + end) end) diff --git a/tests/config_loader_spec.lua b/tests/config_loader_spec.lua index 8e7ab339..1aef0974 100644 --- a/tests/config_loader_spec.lua +++ b/tests/config_loader_spec.lua @@ -1,5 +1,6 @@ local a = require "plenary.async_lib.tests" local config = require "lvim.config" +local utils = require "lvim.utils" a.describe("config-loader", function() local user_config_path = config:get_user_config_path() @@ -20,18 +21,19 @@ a.describe("config-loader", function() vim.opt.undodir = "/tmp" assert.equal(vim.opt.undodir:get()[1], "/tmp") config:reload() - assert.equal(vim.opt.undodir:get()[1], get_cache_dir() .. "/undo") + assert.equal(vim.opt.undodir:get()[1], utils.join_paths(get_cache_dir(), "undo")) end) a.it("should not get interrupted by errors in user-config", function() vim.opt.undodir = "/tmp" assert.equal(vim.opt.undodir:get()[1], "/tmp") - os.execute("echo bad_string_test >> " .. user_config_path) + os.execute(string.format("echo 'bad_string_test' >> %s", user_config_path)) local error_handler = function(msg) return msg end local err = xpcall(config:reload(), error_handler) assert.falsy(err) - assert.equal(vim.opt.undodir:get()[1], get_cache_dir() .. "/undo") + assert.equal(vim.opt.undodir:get()[1], utils.join_paths(get_cache_dir(), "undo")) + os.execute(string.format("echo '' > %s", user_config_path)) end) end) diff --git a/tests/lsp_spec.lua b/tests/lsp_spec.lua index 173810e0..b3bb59ab 100644 --- a/tests/lsp_spec.lua +++ b/tests/lsp_spec.lua @@ -44,29 +44,6 @@ a.describe("lsp workflow", function() end) end) - a.it("shoud retrieve supported filetypes correctly", function() - local ocaml = { - name = "ocamlls", - filetypes = { "ocaml", "reason" }, - } - local ocaml_fts = require("lvim.lsp.utils").get_supported_filetypes(ocaml.name) - assert.True(vim.deep_equal(ocaml.filetypes, ocaml_fts)) - - local tsserver = { - name = "tsserver", - filetypes = { - "javascript", - "javascriptreact", - "javascript.jsx", - "typescript", - "typescriptreact", - "typescript.tsx", - }, - } - local tsserver_fts = require("lvim.lsp.utils").get_supported_filetypes(tsserver.name) - assert.True(vim.deep_equal(tsserver.filetypes, tsserver_fts)) - end) - a.it("shoud not include blacklisted servers in the generated templates", function() assert.True(utils.is_directory(lvim.lsp.templates_dir)) require("lvim.lsp").setup() @@ -77,4 +54,17 @@ a.describe("lsp workflow", function() end end end) + + a.it("shoud only include one server per generated template", function() + assert.True(utils.is_directory(lvim.lsp.templates_dir)) + require("lvim.lsp").setup() + + for _, file in ipairs(vim.fn.glob(lvim.lsp.templates_dir .. "/*.lua", 1, 1)) do + local count = 0 + for _ in io.lines(file) do + count = count + 1 + end + assert.equal(count, 1) + end + end) end) diff --git a/tests/minimal_lsp.lua b/tests/minimal_lsp.lua index a2b9ab57..9873e5ef 100644 --- a/tests/minimal_lsp.lua +++ b/tests/minimal_lsp.lua @@ -1,8 +1,25 @@ +local on_windows = vim.loop.os_uname().version:match "Windows" + +local function join_paths(...) + local path_sep = on_windows and "\\" or "/" + local result = table.concat({ ... }, path_sep) + return result +end + vim.cmd [[set runtimepath=$VIMRUNTIME]] -vim.cmd [[set packpath=/tmp/nvim/site]] -local package_root = "/tmp/nvim/site/pack" -local install_path = package_root .. "/packer/start/packer.nvim" +local temp_dir +if on_windows then + temp_dir = vim.loop.os_getenv "TEMP" +else + temp_dir = "/tmp" +end + +vim.cmd("set packpath=" .. join_paths(temp_dir, "nvim", "site")) + +local package_root = join_paths(temp_dir, "nvim", "site", "pack") +local install_path = join_paths(package_root, "packer", "start", "packer.nvim") +local compile_path = join_paths(install_path, "plugin", "packer_compiled.lua") -- Choose whether to use the executable that's managed by lsp-installer local use_lsp_installer = true @@ -16,7 +33,7 @@ local function load_plugins() }, config = { package_root = package_root, - compile_path = install_path .. "/plugin/packer_compiled.lua", + compile_path = compile_path, }, } end diff --git a/utils/bin/lvim.ps1 b/utils/bin/lvim.ps1 index 79950365..a031c219 100644 --- a/utils/bin/lvim.ps1 +++ b/utils/bin/lvim.ps1 @@ -6,4 +6,4 @@ $env:LUNARVIM_RUNTIME_DIR = ($env:LUNARVIM_RUNTIME_DIR, "$env:XDG_DATA_HOME\luna $env:LUNARVIM_CONFIG_DIR = ($env:LUNARVIM_CONFIG_DIR, "$env:XDG_CONFIG_HOME\lvim", 1 -ne $null)[0] $env:LUNARVIM_CACHE_DIR = ($env:LUNARVIM_CACHE_DIR, "$env:XDG_CACHE_HOME\lvim", 1 -ne $null)[0] -nvim -u "$env:LUNARVIM_RUNTIME_DIR\lvim\init.lua" +nvim -u "$env:LUNARVIM_RUNTIME_DIR\lvim\init.lua" @args diff --git a/utils/bin/test_runner.sh b/utils/bin/test_runner.sh index ee138345..6fc6858b 100644 --- a/utils/bin/test_runner.sh +++ b/utils/bin/test_runner.sh @@ -1,15 +1,17 @@ #!/usr/bin/env bash set -e -export LUNARVIM_CONFIG_DIR="${LUNARVIM_CONFIG_DIR:-"$HOME/.config/lvim"}" export LUNARVIM_RUNTIME_DIR="${LUNARVIM_RUNTIME_DIR:-"$HOME/.local/share/lunarvim"}" export LVIM_TEST_ENV=true -rm -f "$LUNARVIM_CONFIG_DIR/plugin/packer_compiled.lua" +# we should start with an empty configuration +TEST_BASE_DIR="$(mktemp -d)" + +export LUNARVIM_CONFIG_DIR="$TEST_BASE_DIR" +export LUNARVIM_CACHE_DIR="$TEST_BASE_DIR" lvim() { - # TODO: allow running with a minimal_init.lua nvim -u "$LUNARVIM_RUNTIME_DIR/lvim/tests/minimal_init.lua" --cmd "set runtimepath+=$LUNARVIM_RUNTIME_DIR/lvim" "$@" } @@ -18,3 +20,5 @@ if [ -n "$1" ]; then else lvim --headless -c "PlenaryBustedDirectory tests/ { minimal_init = './tests/minimal_init.lua' }" fi + +rm -rf "$TEST_BASE_DIR" |