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>',
},
providers = {
priority = { 'lsp', 'coc', 'markdown' },
lsp = {
blacklist_clients = {},
},
@@ -182,14 +183,35 @@ function M.is_symbol_blacklisted(kind)
return has_value(M.o.symbols.blacklist, kind)
end
function M.is_client_blacklisted(client_id)
local client = vim.lsp.get_client_by_id(client_id)
---@param client vim.lsp.client|number
function M.is_client_blacklisted(client)
if not client then
return false
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)
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()
print 'Current keymaps:'
print(vim.inspect(M.o.keymaps))

View File

@@ -606,32 +606,50 @@ end
---Display outline window status in the message area.
function M.show_status()
if M.has_provider() then
print("Current provider:")
print(' ' .. _G._outline_current_provider.name)
-- TODO: Use a floating window instead
local p = _G._outline_current_provider
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
print("Outline window is open.")
else
print("Outline window is not open.")
end
if require('outline.preview').has_code_win() then
print("Code window is active.")
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
else
print("No providers")
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.
---@return boolean has_provider
function M.has_provider()
local winid = vim.fn.win_getid()
if M.view:is_open() and winid == M.view.winnr then
if M.is_active() then
return _G._outline_current_provider ~= nil
end
return providers.has_provider() and _G._outline_current_provider
return providers.has_provider()
end
local function setup_commands()

View File

@@ -1,4 +1,7 @@
local M = {}
local M = {
name = 'coc',
}
function M.should_use_provider(_)
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
-- 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).
local providers = {
'outline/providers/nvim-lsp',
'outline/providers/coc',
'outline/providers/markdown',
}
local M = {}
local import_prefix = "outline/providers/"
_G._outline_current_provider = nil
function M.has_provider()
local ret = false
for _, value in ipairs(providers) do
local provider = require(value)
function M.find_provider()
if not M.providers then
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
ret = true
break
return provider, name
end
end
return ret
return nil, nil
end
---@return boolean found_provider
function M.has_provider()
return M.find_provider() ~= nil
end
---@param on_symbols function
---@param opts outline.OutlineOpts?
---@return boolean found_provider
function M.request_symbols(on_symbols, opts)
for _, value in ipairs(providers) do
local provider = require(value)
if provider.should_use_provider(0) then
_G._outline_current_provider = provider
_G._outline_current_provider.name = value
provider.request_symbols(on_symbols, opts)
return true
end
local provider, name = M.find_provider()
if not provider then
return false
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
return M

View File

@@ -1,9 +1,20 @@
-- NOTE
-- 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
-- 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
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 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() }
end
function M.hover_info(bufnr, params, on_info)
local clients = vim.lsp.buf_get_clients(bufnr)
local used_client
local clients = vim.lsp.get_active_clients({ bufnr = bufnr })
local use_client
for id, client in pairs(clients) do
if config.is_client_blacklisted(id) then
for _, client in ipairs(clients) do
if config.is_client_blacklisted(client) then
goto continue
else
if client.server_capabilities.hoverProvider then
used_client = client
use_client = client
M.client = client
break
end
end
::continue::
end
if not used_client then
if not use_client then
on_info(nil, {
contents = {
kind = 'markdown',
content = { 'No extra information availaible!' },
content = { 'No extra information availaible' },
},
})
return
end
used_client.request('textDocument/hover', params, on_info, bufnr)
use_client.request('textDocument/hover', params, on_info, bufnr)
end
-- probably change this
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
for id, client in pairs(clients) do
if config.is_client_blacklisted(id) then
for _, client in ipairs(clients) do
if config.is_client_blacklisted(client) then
goto continue
else
if client.server_capabilities.documentSymbolProvider then
M.client = client
ret = true
break
end
@@ -73,7 +86,7 @@ function M.request_symbols(on_symbols, opts)
vim.lsp.buf_request_all(
0,
'textDocument/documentSymbol',
getParams(),
get_params(),
function (response)
response = M.postprocess_symbols(response)
on_symbols(response, opts)