feat: Better provider info and fix LSP deprecated warnings

- Provider priorities can now be configured through `providers.priority`

- Each provider can have a get_status() function that returns a string
  for its status. For LSP it returns the client name.

- :OutlineStatus logic refactored, together with provider checking
  functions in `providers/init.lua`

- Switch from vim.lsp.buf_get_clients to vim.lsp.get_active_clients
  (former was deprecated)

- Fixed a careless mistake from symbols-outline that seems to be an
  unreachable bug (lsp)
This commit is contained in:
hedy
2023-11-16 15:41:37 +08:00
parent 22051b6555
commit 5278eb5b2b
6 changed files with 120 additions and 54 deletions

View File

@@ -71,6 +71,7 @@ M.defaults = {
up_and_jump = '<C-k>', up_and_jump = '<C-k>',
}, },
providers = { providers = {
priority = { 'lsp', 'coc', 'markdown' },
lsp = { lsp = {
blacklist_clients = {}, blacklist_clients = {},
}, },
@@ -182,14 +183,35 @@ function M.is_symbol_blacklisted(kind)
return has_value(M.o.symbols.blacklist, kind) return has_value(M.o.symbols.blacklist, kind)
end end
function M.is_client_blacklisted(client_id) ---@param client vim.lsp.client|number
local client = vim.lsp.get_client_by_id(client_id) function M.is_client_blacklisted(client)
if not client then if not client then
return false return false
end end
if type(client) == 'number' then
client = vim.lsp.get_client_by_id(client)
if not client then
return false
end
end
return has_value(M.o.providers.lsp.blacklist_clients, client.name) return has_value(M.o.providers.lsp.blacklist_clients, client.name)
end end
function M.get_providers()
if M.providers then
return M.providers
end
M.providers = {}
for _, p in ipairs(M.o.providers.priority) do
if p == 'lsp' then
p = 'nvim-lsp' -- due to legacy reasons
end
table.insert(M.providers, p)
end
return M.providers
end
function M.show_help() function M.show_help()
print 'Current keymaps:' print 'Current keymaps:'
print(vim.inspect(M.o.keymaps)) print(vim.inspect(M.o.keymaps))

View File

@@ -606,32 +606,50 @@ end
---Display outline window status in the message area. ---Display outline window status in the message area.
function M.show_status() function M.show_status()
if M.has_provider() then -- TODO: Use a floating window instead
print("Current provider:") local p = _G._outline_current_provider
print(' ' .. _G._outline_current_provider.name) if not M.is_active() then
p = providers.find_provider()
end
if p ~= nil then
print("Current provider: " .. p.name)
if p.get_status then
print(p.get_status())
print()
end
if M.view:is_open() then if M.view:is_open() then
print("Outline window is open.") print("Outline window is open.")
else else
print("Outline window is not open.") print("Outline window is not open.")
end end
if require('outline.preview').has_code_win() then if require('outline.preview').has_code_win() then
print("Code window is active.") print("Code window is active.")
else else
print("Warning: code window is either closed or invalid. Please close and reopen the outline window.") print("Code window is either closed or invalid. Please close and reopen the outline window.")
end end
else else
print("No providers") print("No providers")
end end
end end
function M.is_active()
local winid = vim.fn.win_getid()
if M.view:is_open() and winid == M.view.winnr then
return true
end
return false
end
---Whether there is currently an available provider. ---Whether there is currently an available provider.
---@return boolean has_provider ---@return boolean has_provider
function M.has_provider() function M.has_provider()
local winid = vim.fn.win_getid() if M.is_active() then
if M.view:is_open() and winid == M.view.winnr then
return _G._outline_current_provider ~= nil return _G._outline_current_provider ~= nil
end end
return providers.has_provider() and _G._outline_current_provider return providers.has_provider()
end end
local function setup_commands() local function setup_commands()

View File

@@ -1,4 +1,7 @@
local M = {} local M = {
name = 'coc',
}
function M.should_use_provider(_) function M.should_use_provider(_)
local not_coc_installed = vim.fn.exists '*CocActionAsync' == 0 local not_coc_installed = vim.fn.exists '*CocActionAsync' == 0

View File

@@ -1,44 +1,43 @@
local M = {} local cfg = require "outline.config"
-- NOTE: There is in fact a markdown LSP that can provide symbols. However on local M = {}
-- buffer open the LSP may not be attached immediately. Before the LSP is ready local import_prefix = "outline/providers/"
-- if the user opens the outline, our own markdown provider will be used. After
-- refreshing/reopening, the provider will then switch to the LSP (if the user
-- has a markdown LSP).
local providers = {
'outline/providers/nvim-lsp',
'outline/providers/coc',
'outline/providers/markdown',
}
_G._outline_current_provider = nil _G._outline_current_provider = nil
function M.has_provider()
local ret = false function M.find_provider()
for _, value in ipairs(providers) do if not M.providers then
local provider = require(value) M.providers = vim.tbl_map(function(p) return import_prefix..p end, cfg.get_providers())
end
for _, name in ipairs(M.providers) do
local provider = require(name)
if provider.should_use_provider(0) then if provider.should_use_provider(0) then
ret = true return provider, name
break
end end
end end
return ret return nil, nil
end
---@return boolean found_provider
function M.has_provider()
return M.find_provider() ~= nil
end end
---@param on_symbols function ---@param on_symbols function
---@param opts outline.OutlineOpts? ---@param opts outline.OutlineOpts?
---@return boolean found_provider ---@return boolean found_provider
function M.request_symbols(on_symbols, opts) function M.request_symbols(on_symbols, opts)
for _, value in ipairs(providers) do local provider, name = M.find_provider()
local provider = require(value) if not provider then
if provider.should_use_provider(0) then return false
_G._outline_current_provider = provider
_G._outline_current_provider.name = value
provider.request_symbols(on_symbols, opts)
return true
end
end end
return false _G._outline_current_provider = provider
if not provider.name then
_G._outline_current_provider.name = name
end
provider.request_symbols(on_symbols, opts)
return true
end end
return M return M

View File

@@ -1,9 +1,20 @@
-- NOTE
-- Our own markdown provider is used because legacy symbols-outline considered -- Our own markdown provider is used because legacy symbols-outline considered
-- the case where markdown does not have an LSP. However, it does, so as of now -- the case where markdown does not have an LSP. However, it does, so as of now
-- this module is kept for use when user opens symbols outline before the -- this module is kept for use when user opens symbols outline before the
-- markdown LSP is ready. Please also see comment in providers/init.lua -- markdown LSP is ready.
--
-- On buffer open the LSP may not be attached immediately. Before the LSP is
-- ready if the user opens the outline, our own markdown provider will be used.
-- After refreshing/reopening, the provider will then switch to the LSP (if the
-- user has a markdown LSP). That is, if the user has an applicable markdown LSP.
--
-- If they don't this provider will always work as usual.
local M = {
name = 'markdown',
}
local M = {}
---@return boolean ft_is_markdown ---@return boolean ft_is_markdown
function M.should_use_provider(bufnr) function M.should_use_provider(bufnr)

View File

@@ -2,50 +2,63 @@ local config = require 'outline.config'
local lsp_utils = require 'outline.utils.lsp_utils' local lsp_utils = require 'outline.utils.lsp_utils'
local jsx = require 'outline.utils.jsx' local jsx = require 'outline.utils.jsx'
local M = {} local M = {
name = 'lsp',
---@type vim.lsp.client
client = nil,
}
local function getParams() function M.get_status()
if not M.client then
return "No clients"
end
return "client: "..M.client.name
end
local function get_params()
return { textDocument = vim.lsp.util.make_text_document_params() } return { textDocument = vim.lsp.util.make_text_document_params() }
end end
function M.hover_info(bufnr, params, on_info) function M.hover_info(bufnr, params, on_info)
local clients = vim.lsp.buf_get_clients(bufnr) local clients = vim.lsp.get_active_clients({ bufnr = bufnr })
local used_client local use_client
for id, client in pairs(clients) do for _, client in ipairs(clients) do
if config.is_client_blacklisted(id) then if config.is_client_blacklisted(client) then
goto continue goto continue
else else
if client.server_capabilities.hoverProvider then if client.server_capabilities.hoverProvider then
used_client = client use_client = client
M.client = client
break break
end end
end end
::continue:: ::continue::
end end
if not used_client then if not use_client then
on_info(nil, { on_info(nil, {
contents = { contents = {
kind = 'markdown', kind = 'markdown',
content = { 'No extra information availaible!' }, content = { 'No extra information availaible' },
}, },
}) })
return
end end
used_client.request('textDocument/hover', params, on_info, bufnr) use_client.request('textDocument/hover', params, on_info, bufnr)
end end
-- probably change this
function M.should_use_provider(bufnr) function M.should_use_provider(bufnr)
local clients = vim.lsp.buf_get_clients(bufnr) local clients = vim.lsp.get_active_clients({ bufnr = bufnr })
local ret = false local ret = false
for id, client in pairs(clients) do for _, client in ipairs(clients) do
if config.is_client_blacklisted(id) then if config.is_client_blacklisted(client) then
goto continue goto continue
else else
if client.server_capabilities.documentSymbolProvider then if client.server_capabilities.documentSymbolProvider then
M.client = client
ret = true ret = true
break break
end end
@@ -73,7 +86,7 @@ function M.request_symbols(on_symbols, opts)
vim.lsp.buf_request_all( vim.lsp.buf_request_all(
0, 0,
'textDocument/documentSymbol', 'textDocument/documentSymbol',
getParams(), get_params(),
function (response) function (response)
response = M.postprocess_symbols(response) response = M.postprocess_symbols(response)
on_symbols(response, opts) on_symbols(response, opts)