fix(providers): Ensure working on nvim-0.7

This commit removed the ability to receive symbols from all attached
clients in the current buffer. Everything works as before when only one
client is attached to a buffer.

This also fixes outline LSP finding clients on nvim-0.7
This commit is contained in:
hedy
2023-12-29 19:17:00 +08:00
parent 5669c8aa9e
commit 8b2f412b7b
7 changed files with 91 additions and 48 deletions

View File

@@ -140,7 +140,7 @@ function M.show_status(ctx)
if p.get_status then if p.get_status then
table.insert(lines, 'Provider info:') table.insert(lines, 'Provider info:')
table.insert(lines, '') table.insert(lines, '')
for _, line in ipairs(p.get_status()) do for _, line in ipairs(p.get_status(ctx.provider_info)) do
table.insert(lines, indent .. line) table.insert(lines, indent .. line)
end end
end end

View File

@@ -252,19 +252,20 @@ end
---Open a floating window displaying debug information about outline ---Open a floating window displaying debug information about outline
function M.show_status() function M.show_status()
local sidebar = M._get_sidebar(false) local sidebar = M._get_sidebar()
local buf, win = 0, 0 local buf, win = 0, 0
local is_open, provider local is_open, provider, provider_info
if sidebar then if sidebar then
buf = sidebar.code.buf buf = sidebar.code.buf
win = sidebar.code.win win = sidebar.code.win
is_open = sidebar.view:is_open() is_open = sidebar.view:is_open()
provider = sidebar.provider provider = sidebar.provider
provider_info = sidebar.provider_info
end end
if not is_open then if not is_open then
provider = providers.find_provider() provider, provider_info = providers.find_provider()
end end
---@type outline.StatusContext ---@type outline.StatusContext
@@ -272,9 +273,10 @@ function M.show_status()
priority = cfg.o.providers.priority, priority = cfg.o.providers.priority,
outline_open = is_open, outline_open = is_open,
provider = provider, provider = provider,
provider_info = provider_info,
} }
if vim.api.nvim_buf_is_valid(buf) then if buf and vim.api.nvim_buf_is_valid(buf) then
ctx.ft = vim.api.nvim_buf_get_option(buf, 'ft') ctx.ft = vim.api.nvim_buf_get_option(buf, 'ft')
ctx.filter = cfg.o.symbols.user_config_filter[ctx.ft] ctx.filter = cfg.o.symbols.user_config_filter[ctx.ft]
-- 'else' is handled in help.lua -- 'else' is handled in help.lua

View File

@@ -1,17 +1,19 @@
local M = {} local M = {}
local import_prefix = 'outline/providers/' local import_prefix = 'outline/providers/'
---@return outline.Provider? ---@return outline.Provider?, table?
function M.find_provider() function M.find_provider()
if not M.providers then if not M.providers then
M.providers = vim.tbl_map(function(p) M.providers = vim.tbl_map(function(p)
return import_prefix .. p return import_prefix .. p
end, require('outline.config').get_providers()) end, require('outline.config').get_providers())
end end
for _, path in ipairs(M.providers) do for _, path in ipairs(M.providers) do
local provider = require(path) local provider = require(path)
if provider.supports_buffer(0) then local ok, info = provider.supports_buffer(0)
return provider if ok then
return provider, info
end end
end end
end end

View File

@@ -6,52 +6,70 @@ local l = vim.lsp
local M = { local M = {
name = 'lsp', name = 'lsp',
---@type lsp.client
client = nil,
} }
local request_timeout = 2000 local request_timeout = 2000
function M.get_status() ---@param info table? Must be the table received from `supports_buffer`
if not M.client then function M.get_status(info)
if not info then
return { 'No clients' } return { 'No clients' }
end end
return { 'client: ' .. M.client.name } return { 'client: ' .. info.client.name }
end end
local function get_appropriate_client(bufnr, capability) ---@param client lsp.client
local clients = l.get_active_clients({ bufnr = bufnr }) ---@param capability string
local use_client ---@return boolean
local function _check_client(client, capability)
for _, client in ipairs(clients) do
if cfg.is_client_blacklisted(client) then if cfg.is_client_blacklisted(client) then
goto continue return false
else end
if client.server_capabilities[capability] then return client.server_capabilities[capability]
end
---@param bufnr integer
---@param capability string
---@return lsp.client?
local function get_appropriate_client(bufnr, capability)
local clients, use_client
if _G._outline_nvim_has[8] then
clients = l.get_active_clients({ bufnr = bufnr })
for _, client in ipairs(clients) do
if _check_client(client, capability) then
use_client = client use_client = client
M.client = client
break break
end end
end end
::continue:: else
-- Returns client_id:client pairs
---@diagnostic disable-next-line
clients = l.buf_get_clients(bufnr)
for _, client in pairs(clients) do
if _check_client(client, capability) then
use_client = client
break
end end
end
end
return use_client return use_client
end end
---@return boolean ---@return boolean, table?
function M.supports_buffer(bufnr) function M.supports_buffer(bufnr)
local client = get_appropriate_client(bufnr, 'documentSymbolProvider') local client = get_appropriate_client(bufnr, 'documentSymbolProvider')
if not client then if not client then
return false return false
end end
return true return true, { client = client }
end end
---@param response outline.ProviderSymbol[] ---Include JSX symbols if applicable, and merge it with existing symbols
---@param symbols outline.ProviderSymbol[]
---@return outline.ProviderSymbol[] ---@return outline.ProviderSymbol[]
local function postprocess_symbols(response) local function postprocess_symbols(symbols)
local symbols = lsp_utils.flatten_response(response)
local jsx_symbols = jsx.get_symbols() local jsx_symbols = jsx.get_symbols()
if #jsx_symbols > 0 then if #jsx_symbols > 0 then
@@ -61,16 +79,31 @@ local function postprocess_symbols(response)
end end
end end
-- XXX: Only one LSP client is supported here, to prevent checking blacklisting
-- over again
---@param on_symbols fun(symbols?:outline.ProviderSymbol[], opts?:table) ---@param on_symbols fun(symbols?:outline.ProviderSymbol[], opts?:table)
---@param opts table ---@param opts table?
function M.request_symbols(on_symbols, opts) ---@param info table? Must be the table received from `supports_buffer`
function M.request_symbols(on_symbols, opts, info)
if not info then
return on_symbols(nil, opts)
end
local params = { local params = {
textDocument = l.util.make_text_document_params(), textDocument = l.util.make_text_document_params(),
} }
l.buf_request_all(0, 'textDocument/documentSymbol', params, function(response) -- XXX: Is bufnr=0 ok here?
local status = info.client.request('textDocument/documentSymbol', params, function(err, response)
if err or not response then
on_symbols(response, opts)
else
response = postprocess_symbols(response) response = postprocess_symbols(response)
on_symbols(response, opts) on_symbols(response, opts)
end) end
end, 0)
if not status then
on_symbols(nil, opts)
end
end end
-- No good way to update outline when LSP action complete for now -- No good way to update outline when LSP action complete for now
@@ -97,6 +130,7 @@ end
---@see rename_symbol ---@see rename_symbol
---@param sidebar outline.Sidebar ---@param sidebar outline.Sidebar
---@param client lsp.client
---@param node outline.FlatSymbol ---@param node outline.FlatSymbol
---@return boolean success ---@return boolean success
local function legacy_rename(sidebar, client, node) local function legacy_rename(sidebar, client, node)
@@ -141,8 +175,8 @@ function M.rename_symbol(sidebar)
sidebar:wrap_goto_location(function() sidebar:wrap_goto_location(function()
-- Options table with filter key only added in nvim-0.8 -- Options table with filter key only added in nvim-0.8
-- Use vim.lsp's function because it has better support. -- Use vim.lsp's function because it has better support.
l.buf.rename(nil, { filter = function (client) l.buf.rename(nil, { filter = function (cl)
return not cfg.is_client_blacklisted(client) return not cfg.is_client_blacklisted(cl)
end }) end })
end) end)
return true return true

View File

@@ -26,6 +26,7 @@ local Sidebar = {}
---@field code outline.SidebarCodeState ---@field code outline.SidebarCodeState
---@field augroup integer ---@field augroup integer
---@field provider outline.Provider? ---@field provider outline.Provider?
---@field provider_info table?
---@field preview outline.Preview|outline.LivePreview ---@field preview outline.Preview|outline.LivePreview
function Sidebar:new(id) function Sidebar:new(id)
@@ -92,6 +93,7 @@ end
---@param opts outline.OutlineOpts? ---@param opts outline.OutlineOpts?
function Sidebar:initial_handler(response, opts) function Sidebar:initial_handler(response, opts)
if response == nil or type(response) ~= 'table' or self.view:is_open() then if response == nil or type(response) ~= 'table' or self.view:is_open() then
utils.echo("No response from provider when requesting symbols!")
return return
end end
@@ -311,6 +313,7 @@ end
---@param response outline.ProviderSymbol[] ---@param response outline.ProviderSymbol[]
function Sidebar:refresh_handler(response) function Sidebar:refresh_handler(response)
if response == nil or type(response) ~= 'table' then if response == nil or type(response) ~= 'table' then
utils.echo("No response from provider when requesting symbols!")
return return
end end
@@ -340,11 +343,11 @@ function Sidebar:__refresh()
if ft == 'OutlineHelp' or not listed then if ft == 'OutlineHelp' or not listed then
return return
end end
self.provider = providers.find_provider() self.provider, self.provider_info = providers.find_provider()
if self.provider then if self.provider then
self.provider.request_symbols(function(res) self.provider.request_symbols(function(res)
self:refresh_handler(res) self:refresh_handler(res)
end) end, nil, self.provider_info)
return return
end end
-- No provider -- No provider
@@ -583,11 +586,11 @@ function Sidebar:open(opts)
if not self.view:is_open() then if not self.view:is_open() then
self.preview.s = self self.preview.s = self
self.provider = providers.find_provider() self.provider, self.provider_info = providers.find_provider()
if self.provider then if self.provider then
self.provider.request_symbols(function(...) self.provider.request_symbols(function(...)
self:initial_handler(...) self:initial_handler(...)
end, opts) end, opts, self.provider_info)
return return
else else
-- No provider -- No provider

View File

@@ -63,9 +63,9 @@
---@class outline.Provider ---@class outline.Provider
---@field name string ---@field name string
---@field get_status? fun():string[] ---@field get_status? fun(info:table?):string[]
---@field supports_buffer fun(bufnr:integer):boolean ---@field supports_buffer fun(bufnr:integer):boolean,table?
---@field request_symbols fun(on_symbols:fun(symbols?:outline.ProviderSymbol[], opts:table?), opts:table?) ---@field request_symbols fun(on_symbols:fun(symbols?:outline.ProviderSymbol[], opts:table?, provider_info:table?), opts:table?)
---@field show_hover? fun(sidebar:outline.Sidebar):boolean ---@field show_hover? fun(sidebar:outline.Sidebar):boolean
---@field rename_symbol? fun(sidebar:outline.Sidebar):boolean ---@field rename_symbol? fun(sidebar:outline.Sidebar):boolean
---@field code_actions? fun(sidebar:outline.Sidebar):boolean ---@field code_actions? fun(sidebar:outline.Sidebar):boolean
@@ -80,6 +80,7 @@
---@class outline.StatusContext ---@class outline.StatusContext
---@field provider outline.Provider? ---@field provider outline.Provider?
---@field provider_info table?
---@field outline_open boolean? ---@field outline_open boolean?
---@field code_win_active boolean? ---@field code_win_active boolean?
---@field ft string? ---@field ft string?

View File

@@ -12,13 +12,14 @@ function M.is_buf_markdown(bufnr)
end end
--- Merge all client token lists in an LSP response --- Merge all client token lists in an LSP response
function M.flatten_response(response) -- Currentlhy unused because we are only supporting receiving symbols
-- from 1 LSP client.
function M.merge_responses(responses)
local all_results = {} local all_results = {}
-- flatten results to one giant table of symbols -- flatten results to one giant table of symbols
for client_id, client_response in pairs(response) do for client_id, client_response in pairs(responses) do
if config.is_client_blacklisted(client_id) then if config.is_client_blacklisted(client_id) then
print('skipping client ' .. client_id)
goto continue goto continue
end end