mirror of
https://github.com/LunarVim/LunarVim.git
synced 2025-08-29 14:28:18 +02:00
Add LunarVim info panel (Experimental) (#1241)
* feat: lunarvim info (Experimental) * Add missing providers info * Use nvim api directly to create the popup * width tweaks
This commit is contained in:
parent
c8d1b95712
commit
47ebd70817
5 changed files with 268 additions and 0 deletions
180
lua/core/info.lua
Normal file
180
lua/core/info.lua
Normal file
|
@ -0,0 +1,180 @@
|
|||
local M = {}
|
||||
local u = require "utils"
|
||||
local null_ls_handler = require "lsp.null-ls"
|
||||
local indent = " "
|
||||
|
||||
M.banner = {
|
||||
"",
|
||||
"",
|
||||
"⠀⣿⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀ ⠀⠀⠀ ⠀⠀ ⣺⡿⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀",
|
||||
"⠀⣿⠇⠀⠀⠀⠀⠀⣤⡄⠀⠀⢠⣤⡄⠀.⣠⣤⣤⣤⡀⠀⠀⢀⣤⣤⣤⣤⡄⠀⠀⠀⣤⣄⣤⣤⣤⠀⠀ ⣿⣯ ⣿⡟⠀ ⣤⣤⠀⠀⠀⠀⣠⣤⣤⣤⣄⣤⣤",
|
||||
"⢠⣿⠀⠀⠀⠀⠀⠀⣿⠃⠀⠀⣸⣿⠁⠀⣿⣿⠉⠀⠈⣿⡇⠀⠀⠛⠋⠀⠀⢹⣿⠀⠀⠀⣿⠏⠀⠸⠿⠃⠀⣿⣿⠀⣰⡟⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⠀⣿⡟⢸⣿⡇⢀⣿",
|
||||
"⣸⡇⠀⠀⠀⠀⠀⢸⣿⠀⠀⠀⣿⡟⠀⢠⣿⡇⠀⠀⢰⣿⡇⠀⣰⣾⠟⠛⠛⣻⡇⠀⠀⢸⡿⠀⠀⠀⠀⠀⠀⢻⣿⢰⣿⠀⠀⠀⠀⠀⠀⣾⡇⠀⠀⠀⢸⣿⠇⢸⣿⠀⢸⡏",
|
||||
"⣿⣧⣤⣤⣤⡄⠀⠘⣿⣤⣤⡤⣿⠇⠀⢸⣿⠁⠀⠀⣼⣿⠀⠀⢿⣿⣤⣤⠔⣿⠃⠀⠀⣾⡇⠀⠀⠀⠀⠀⠀⢸⣿⣿⠋⠀⠀⠀⢠⣤⣤⣿⣥⣤⡄⠀⣼⣿⠀⣸⡏⠀⣿⠃",
|
||||
"⠉⠉⠉⠉⠉⠁⠀⠀⠈⠉⠉⠀⠉⠀⠀⠈⠉⠀⠀⠀⠉⠉⠀⠀⠀⠉⠉⠁⠈⠉⠀⠀⠀⠉⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠀⠀⠀⠀⠈⠉⠉⠉⠉⠉⠁⠀⠉⠁⠀⠉⠁⠀⠉⠀",
|
||||
"",
|
||||
"",
|
||||
}
|
||||
|
||||
local function str_list(list)
|
||||
return "[ " .. table.concat(list, ", ") .. " ]"
|
||||
end
|
||||
|
||||
local function get_formatter_suggestion_msg(ft)
|
||||
local supported_formatters = u.get_supported_formatters_by_filetype(ft)
|
||||
return {
|
||||
"-------------------------------------------------------------------",
|
||||
"",
|
||||
" HINT ",
|
||||
"",
|
||||
indent .. "* List of supported formatters: " .. str_list(supported_formatters),
|
||||
"",
|
||||
indent .. "You can enable a supported formatter by adding this to your config.lua",
|
||||
"",
|
||||
indent
|
||||
.. "lvim.lang."
|
||||
.. tostring(ft)
|
||||
.. [[.formatting = { { exe = ']]
|
||||
.. table.concat(supported_formatters, "|")
|
||||
.. [[' } }]],
|
||||
"",
|
||||
"-------------------------------------------------------------------",
|
||||
}
|
||||
end
|
||||
|
||||
local function get_linter_suggestion_msg(ft)
|
||||
local supported_linters = u.get_supported_linters_by_filetype(ft)
|
||||
return {
|
||||
"-------------------------------------------------------------------",
|
||||
"",
|
||||
" HINT ",
|
||||
"",
|
||||
indent .. "* List of supported linters: " .. str_list(supported_linters),
|
||||
"",
|
||||
indent .. "You can enable a supported linter by adding this to your config.lua",
|
||||
"",
|
||||
indent
|
||||
.. "lvim.lang."
|
||||
.. tostring(ft)
|
||||
.. [[.linters = { { exe = ']]
|
||||
.. table.concat(supported_linters, "|")
|
||||
.. [[' } }]],
|
||||
"",
|
||||
"-------------------------------------------------------------------",
|
||||
}
|
||||
end
|
||||
|
||||
---creates an average size popup
|
||||
---@param buf_lines a list of lines to print
|
||||
---@param callback could be used to set syntax highlighting rules for example
|
||||
---@return bufnr buffer number of the created buffer
|
||||
---@return win_id window ID of the created popup
|
||||
function M.create_simple_popup(buf_lines, callback)
|
||||
-- runtime/lua/vim/lsp/util.lua
|
||||
local bufnr = vim.api.nvim_create_buf(false, true)
|
||||
local height_percentage = 0.7
|
||||
local width_percentage = 0.8
|
||||
local row_start_percentage = (1 - height_percentage) / 2
|
||||
local col_start_percentage = (1 - width_percentage) / 2
|
||||
local opts = {}
|
||||
opts.relative = "editor"
|
||||
opts.height = math.ceil(vim.o.lines * height_percentage)
|
||||
opts.row = math.ceil(vim.o.lines * row_start_percentage)
|
||||
opts.col = math.floor(vim.o.columns * col_start_percentage)
|
||||
opts.width = math.floor(vim.o.columns * width_percentage)
|
||||
opts.border = {
|
||||
"┌",
|
||||
"-",
|
||||
"┐",
|
||||
"|",
|
||||
"┘",
|
||||
"-",
|
||||
"└",
|
||||
"|",
|
||||
}
|
||||
|
||||
local win_id = vim.api.nvim_open_win(bufnr, true, opts)
|
||||
|
||||
vim.api.nvim_win_set_buf(win_id, bufnr)
|
||||
-- this needs to be window option!
|
||||
vim.api.nvim_win_set_option(win_id, "number", false)
|
||||
vim.cmd "setlocal nocursorcolumn"
|
||||
vim.cmd "setlocal wrap"
|
||||
-- set buffer options
|
||||
vim.api.nvim_buf_set_option(bufnr, "filetype", "lspinfo")
|
||||
vim.lsp.util.close_preview_autocmd({ "BufHidden", "BufLeave" }, win_id)
|
||||
buf_lines = vim.lsp.util._trim(buf_lines, {})
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, buf_lines)
|
||||
vim.api.nvim_buf_set_option(bufnr, "modifiable", false)
|
||||
if type(callback) == "function" then
|
||||
callback()
|
||||
end
|
||||
return bufnr, win_id
|
||||
end
|
||||
|
||||
function M.toggle_popup(ft)
|
||||
local client = u.get_active_client_by_ft(ft)
|
||||
local is_client_active = not client.is_stopped()
|
||||
local client_enabled_caps = require("lsp").get_ls_capabilities(client.id)
|
||||
local num_caps = vim.tbl_count(client_enabled_caps)
|
||||
local null_ls_providers = null_ls_handler.get_registered_providers_by_filetype(ft)
|
||||
|
||||
local missing_linters = lvim.lang[ft].linters._failed_requests or {}
|
||||
local missing_formatters = lvim.lang[ft].formatters._failed_requests or {}
|
||||
|
||||
local buf_lines = {}
|
||||
vim.list_extend(buf_lines, M.banner)
|
||||
|
||||
local header = {
|
||||
"Detected filetype is: " .. tostring(ft),
|
||||
"",
|
||||
"Treesitter active: " .. tostring(next(vim.treesitter.highlighter.active) ~= nil),
|
||||
"",
|
||||
"",
|
||||
}
|
||||
vim.list_extend(buf_lines, header)
|
||||
|
||||
local lsp_info = {
|
||||
"Associated language-server: " .. client.name,
|
||||
indent .. "* Active: " .. tostring(is_client_active) .. ", id: " .. tostring(client.id),
|
||||
indent .. "* Formatting support: " .. tostring(client.resolved_capabilities.document_formatting),
|
||||
indent .. "* Capabilities list: " .. table.concat(vim.list_slice(client_enabled_caps, 1, num_caps / 2), ", "),
|
||||
indent .. indent .. indent .. table.concat(vim.list_slice(client_enabled_caps, ((num_caps / 2) + 1)), ", "),
|
||||
"",
|
||||
}
|
||||
vim.list_extend(buf_lines, lsp_info)
|
||||
|
||||
local null_ls_info = {
|
||||
"Configured providers: " .. table.concat(null_ls_providers, " , ") .. " ",
|
||||
"",
|
||||
}
|
||||
vim.list_extend(buf_lines, null_ls_info)
|
||||
|
||||
local missing_formatters_status
|
||||
if vim.tbl_count(missing_formatters) > 0 then
|
||||
missing_formatters_status = { "Missing formatters: " .. table.concat(missing_formatters, " , ") .. " ", "" }
|
||||
vim.list_extend(buf_lines, missing_formatters_status)
|
||||
end
|
||||
|
||||
local missing_linters_status
|
||||
if vim.tbl_count(missing_linters) > 0 then
|
||||
missing_linters_status = { "Missing linters: " .. table.concat(missing_linters, " , ") .. " ", "" }
|
||||
vim.list_extend(buf_lines, missing_linters_status)
|
||||
end
|
||||
|
||||
vim.list_extend(buf_lines, get_formatter_suggestion_msg(ft))
|
||||
|
||||
vim.list_extend(buf_lines, get_linter_suggestion_msg(ft))
|
||||
|
||||
local function set_syntax_hl()
|
||||
--TODO: highlighting is either inconsistent or not working :\
|
||||
vim.cmd("syntax match Identifier /filetype is: .*\\zs\\<" .. ft .. "\\>/")
|
||||
vim.cmd("syntax match Identifier /server: .*\\zs\\<" .. client.name .. "\\>/")
|
||||
vim.cmd("syntax match Identifier /providers: .*\\zs\\<" .. table.concat(null_ls_providers, ", ") .. "\\>/")
|
||||
vim.cmd("syntax match Identifier /formatters: .*\\zs\\<" .. table.concat(missing_formatters, ", ") .. "\\>/")
|
||||
vim.cmd("syntax match Identifier /linters: .*\\zs\\<" .. table.concat(missing_linters, ", ") .. "\\>/")
|
||||
end
|
||||
|
||||
return M.create_simple_popup(buf_lines, set_syntax_hl)
|
||||
end
|
||||
return M
|
|
@ -169,6 +169,10 @@ M.config = function()
|
|||
L = {
|
||||
name = "+LunarVim",
|
||||
k = { "<cmd>lua require('keymappings').print()<cr>", "View LunarVim's default keymappings" },
|
||||
i = {
|
||||
"<cmd>lua require('core.info').toggle_popup(vim.bo.filetype)<cr>",
|
||||
"Toggle LunarVim Info",
|
||||
},
|
||||
},
|
||||
|
||||
s = {
|
||||
|
|
|
@ -64,6 +64,36 @@ 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
|
||||
-- print("got cap: ", vim.inspect(caps))
|
||||
table.insert(enabled_caps, k)
|
||||
-- vim.list_extend(enabled_caps, cap)
|
||||
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)
|
||||
|
|
|
@ -23,6 +23,26 @@ function M.get_registered_providers_by_filetype(ft)
|
|||
return matches
|
||||
end
|
||||
|
||||
function M.get_missing_providers_by_filetype(ft)
|
||||
local matches = {}
|
||||
for _, provider in pairs(M.requested_providers) do
|
||||
if vim.tbl_contains(provider.filetypes, ft) then
|
||||
local provider_name = provider.name
|
||||
|
||||
table.insert(matches, provider_name)
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
local function register_failed_request(ft, provider, operation)
|
||||
if not lvim.lang[ft][operation]._failed_requests then
|
||||
lvim.lang[ft][operation]._failed_requests = {}
|
||||
end
|
||||
table.insert(lvim.lang[ft][operation]._failed_requests, provider)
|
||||
end
|
||||
|
||||
local function validate_nodejs_provider(provider)
|
||||
local command_path
|
||||
local root_dir
|
||||
|
@ -80,6 +100,9 @@ function M.setup(filetype)
|
|||
builtin_formatter._opts.command = resolved_path
|
||||
table.insert(M.requested_providers, builtin_formatter)
|
||||
u.lvim_log(string.format("Using format provider: [%s]", builtin_formatter.name))
|
||||
else
|
||||
-- mark it here to avoid re-doing the lookup again
|
||||
register_failed_request(filetype, formatter.exe, "formatters")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -101,6 +124,9 @@ function M.setup(filetype)
|
|||
builtin_diagnoser._opts.command = resolved_path
|
||||
table.insert(M.requested_providers, builtin_diagnoser)
|
||||
u.lvim_log(string.format("Using linter provider: [%s]", builtin_diagnoser.name))
|
||||
else
|
||||
-- mark it here to avoid re-doing the lookup again
|
||||
register_failed_request(filetype, linter.exe, "linters")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -113,6 +113,34 @@ function utils.get_active_client_by_ft(filetype)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- TODO: consider porting this logic to null-ls instead
|
||||
function utils.get_supported_linters_by_filetype(filetype)
|
||||
local null_ls = require "null-ls"
|
||||
local matches = {}
|
||||
for _, provider in pairs(null_ls.builtins.diagnostics) do
|
||||
if vim.tbl_contains(provider.filetypes, filetype) then
|
||||
local provider_name = provider.name
|
||||
|
||||
table.insert(matches, provider_name)
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
function utils.get_supported_formatters_by_filetype(filetype)
|
||||
local null_ls = require "null-ls"
|
||||
local matches = {}
|
||||
for _, provider in pairs(null_ls.builtins.formatting) do
|
||||
if provider.filetypes and vim.tbl_contains(provider.filetypes, filetype) then
|
||||
-- table.insert(matches, { provider.name, ft })
|
||||
table.insert(matches, provider.name)
|
||||
end
|
||||
end
|
||||
|
||||
return matches
|
||||
end
|
||||
|
||||
function utils.unrequire(m)
|
||||
package.loaded[m] = nil
|
||||
_G[m] = nil
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue