diff options
| author | William Boman <william@redwill.se> | 2022-05-12 18:02:47 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-12 18:02:47 +0200 |
| commit | f637ef2e6dbfb03cc896143d73749f541ca18e3e (patch) | |
| tree | 2c15a25a2661d5eb424eace9267642977c58d2e9 | |
| parent | run autogen_metadata.lua (diff) | |
| download | mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.tar mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.tar.gz mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.tar.bz2 mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.tar.lz mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.tar.xz mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.tar.zst mason-f637ef2e6dbfb03cc896143d73749f541ca18e3e.zip | |
feat: patch :LspInfo's "cmd is executable" diagnostic message (#691)
| -rw-r--r-- | ftplugin/lspinfo.lua | 117 | ||||
| -rw-r--r-- | lua/nvim-lsp-installer/core/functional.lua | 25 | ||||
| -rw-r--r-- | tests/core/functional_spec.lua | 39 |
3 files changed, 181 insertions, 0 deletions
diff --git a/ftplugin/lspinfo.lua b/ftplugin/lspinfo.lua new file mode 100644 index 00000000..59303347 --- /dev/null +++ b/ftplugin/lspinfo.lua @@ -0,0 +1,117 @@ +local servers = require "nvim-lsp-installer.servers" +local functional = require "nvim-lsp-installer.core.functional" +local log = require "nvim-lsp-installer.log" + +local filter, compose = functional.filter, functional.compose + +---@class LspInfoClient +---@field name string +---@field cmd string[] +---@field cmd_diagnostics {lineno: integer}|nil + +---@param client LspInfoClient +local function is_client_managed(client) + local ok, server = servers.get_server(client.name) + return ok and server:is_installed() +end + +---@param client LspInfoClient +local function client_has_cmd_diagnostics(client) + return client.cmd_diagnostics ~= nil +end + +---@param client LspInfoClient +local function client_has_cmd(client) + return client.cmd ~= nil +end + +---@param client LspInfoClient[] +local function is_cmd_executable(client) + local cmd = client.cmd[1] + local ok, server = servers.get_server(client.name) + if not ok then + -- should not really happen + return false + end + local options = server:get_default_options() + local path = options.cmd_env and options.cmd_env.PATH + if path then + local old_path = vim.env.PATH + local is_executable = pcall(function() + vim.env.PATH = path + assert(vim.fn.executable(cmd) == 1) + end) + vim.env.PATH = old_path + return is_executable + else + return vim.fn.executable(cmd) == 1 + end +end + +local ok, err = pcall(function() + ---@type LspInfoClient[] + local clients = {} + + local lines = vim.api.nvim_buf_get_lines(0, 1, -1, false) + + local function parse_line(line) + local client_name = line:match "^%s+Client:%s+(.+)%s+%(.*$" + if client_name then + return "client_header", client_name + end + + local config_name = line:match "^%s+Config:%s+(.+)$" + if config_name then + return "client_header", config_name + end + + local cmd_diagnostics = line:match "^%s+cmd is executable:.*$" + if cmd_diagnostics then + return "cmd_diagnostics" + end + + local cmd = line:match "^%s+cmd:%s+(.+)$" + if cmd then + return "cmd", vim.split(cmd, "%s") + end + end + + local current_client + for lineno, line in ipairs(lines) do + local type, value = parse_line(line) + if type == "client_header" then + current_client = { name = value } + table.insert(clients, current_client) + elseif type == "cmd_diagnostics" then + current_client.cmd_diagnostics = { lineno = lineno } + elseif type == "cmd" then + current_client.cmd = value + end + end + + ---@type LspInfoClient[] + local executable_clients = compose( + filter(is_cmd_executable), + filter(client_has_cmd), + filter(client_has_cmd_diagnostics), + filter(is_client_managed) + )(clients) + + local override_cmd_diagnostics = functional.partial(functional.each, function(client) + vim.api.nvim_buf_set_lines( + 0, + client.cmd_diagnostics.lineno, + client.cmd_diagnostics.lineno + 1, + false, + { " cmd is executable: true (checked by nvim-lsp-installer)" } + ) + end) + + vim.api.nvim_buf_set_option(0, "modifiable", true) + override_cmd_diagnostics(executable_clients) + vim.api.nvim_buf_set_option(0, "modifiable", false) +end) + +if not ok then + log.error("Failed to patch :LspInfo window", err) +end diff --git a/lua/nvim-lsp-installer/core/functional.lua b/lua/nvim-lsp-installer/core/functional.lua index 244c3d96..8b549fb6 100644 --- a/lua/nvim-lsp-installer/core/functional.lua +++ b/lua/nvim-lsp-installer/core/functional.lua @@ -172,4 +172,29 @@ function functional.partial(fn, ...) end end +function functional.compose(...) + local functions = functional.table_pack(...) + assert(functions.n > 0, "compose requires at least one function") + return function(...) + local result = functional.table_pack(...) + for i = functions.n, 1, -1 do + result = functional.table_pack(functions[i](unpack(result, 1, result.n))) + end + return unpack(result, 1, result.n) + end +end + +---@generic T +---@param filter_fn fun(item: T): boolean +---@return fun(list: T[]): T[] +function functional.filter(filter_fn) + return functional.partial(vim.tbl_filter, filter_fn) +end + +function functional.each(fn, list) + for k, v in pairs(list) do + fn(v, k) + end +end + return functional diff --git a/tests/core/functional_spec.lua b/tests/core/functional_spec.lua index 8301d47e..734217a2 100644 --- a/tests/core/functional_spec.lua +++ b/tests/core/functional_spec.lua @@ -163,4 +163,43 @@ describe("functional", function() partially_funcy("d", nil, "f") assert.spy(funcy).was_called_with("a", nil, "c", "d", nil, "f") end) + + it("should compose functions", function() + local function add(x) + return function(y) + return y + x + end + end + local function subtract(x) + return function(y) + return y - x + end + end + local function multiply(x) + return function(y) + return y * x + end + end + + local big_maths = functional.compose(add(1), subtract(3), multiply(5)) + + assert.equals(23, big_maths(5)) + end) + + it("should not allow composing no functions", function() + local e = assert.error(function() + functional.compose() + end) + assert.equals("compose requires at least one function", e) + end) + + it("should iterate list in .each", function() + local list = { "BLUE", "YELLOW", "RED" } + local iterate_fn = spy.new() + functional.each(iterate_fn, list) + assert.spy(iterate_fn).was_called(3) + assert.spy(iterate_fn).was_called_with("BLUE", 1) + assert.spy(iterate_fn).was_called_with("YELLOW", 2) + assert.spy(iterate_fn).was_called_with("RED", 3) + end) end) |
