feat: priority ranking for LSP clients (#222)

This commit is contained in:
Steven Arcangeli 2023-02-22 10:05:45 -08:00
parent 8e2cbd32d1
commit 7af6f812e4
7 changed files with 107 additions and 16 deletions

View file

@ -461,6 +461,13 @@ require("aerial").setup({
-- How long to wait (in ms) after a buffer change before updating
-- Only used when diagnostics_trigger_update = false
update_delay = 300,
-- Map of LSP client name to priority. Default value is 10.
-- Clients with higher (larger) priority will be used before those with lower priority.
-- Set to -1 to never use the client.
priority = {
-- pyright = 10,
},
},
treesitter = {

View file

@ -299,6 +299,13 @@ OPTIONS *aerial-option
-- How long to wait (in ms) after a buffer change before updating
-- Only used when diagnostics_trigger_update = false
update_delay = 300,
-- Map of LSP client name to priority. Default value is 10.
-- Clients with higher (larger) priority will be used before those with lower priority.
-- Set to -1 to never use the client.
priority = {
-- pyright = 10,
},
},
treesitter = {

View file

@ -3,8 +3,8 @@ local M = {}
---@class aerial.Backend
---@field is_supported fun(bufnr: integer): boolean, string?
---@field fetch_symbols_sync fun(bufnr: integer, timeout?: integer)
---@field fetch_symbols fun(bufnr: integer)
---@field fetch_symbols_sync fun(bufnr?: integer, opts?: {timeout?: integer})
---@field fetch_symbols fun(bufnr?: integer)
---@field attach fun(bufnr: integer)
---@field detach fun(bufnr: integer)
@ -146,7 +146,7 @@ end
---@param bufnr? integer
---@param items aerial.Symbol[]
---@param context {backend_name: string, lang: string}
---@param ctx {backend_name: string, lang: string}
M.set_symbols = function(bufnr, items, ctx)
if not bufnr or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
@ -164,10 +164,11 @@ M.set_symbols = function(bufnr, items, ctx)
if config.post_add_all_symbols then
items = config.post_add_all_symbols(bufnr, items, ctx)
if items == nil then
vim.notify_once(
vim.notify(
"aerial.config.post_add_all_symbols should return the symbols to display, but you returned nil or didn't return anything.",
vim.log.levels.WARN
)
return
end
end

View file

@ -1,6 +1,7 @@
local backends = require("aerial.backends")
local config = require("aerial.config")
local data = require("aerial.data")
local lsp_util = require("aerial.backends.lsp.util")
local M = {}
@ -191,7 +192,7 @@ M.on_publish_diagnostics = function(_err, result, ctx, _config)
not bufnr
or not backends.is_backend_attached(bufnr, "lsp")
or not config.lsp.diagnostics_trigger_update
or not client.server_capabilities.documentSymbolProvider
or not lsp_util.client_supports_symbols(client)
then
return
end

View file

@ -1,7 +1,9 @@
local backends = require("aerial.backends")
local callbacks = require("aerial.backends.lsp.callbacks")
local config = require("aerial.config")
local lsp_util = require("aerial.backends.lsp.util")
local util = require("aerial.backends.util")
local M = {}
local function replace_handler(name, callback, preserve_callback)
@ -30,25 +32,79 @@ local function hook_handlers(preserve_symbol_callback)
replace_handler("textDocument/publishDiagnostics", callbacks.on_publish_diagnostics, true)
end
---@param bufnr integer
---@return nil|table
local function get_client(bufnr)
local ret
local last_priority = -1
for _, client in ipairs(vim.lsp.get_active_clients({ bufnr = bufnr })) do
local priority = config.lsp.priority[client.name] or 10
if lsp_util.client_supports_symbols(client) and priority > last_priority then
ret = client
last_priority = priority
end
end
return ret
end
M.fetch_symbols = function(bufnr)
bufnr = bufnr or 0
if not bufnr or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
end
local params = { textDocument = vim.lsp.util.make_text_document_params(bufnr) }
vim.lsp.buf_request(bufnr, "textDocument/documentSymbol", params, callbacks.symbol_callback)
local client = get_client(bufnr)
if not client then
vim.notify("No LSP client found that supports symbols", vim.log.levels.WARN)
return
end
local request_success =
client.request("textDocument/documentSymbol", params, callbacks.symbol_callback, bufnr)
if not request_success then
vim.notify("Error requesting document symbols", vim.log.levels.WARN)
end
end
M.fetch_symbols_sync = function(bufnr, opts)
bufnr = bufnr or 0
if not bufnr or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
end
opts = vim.tbl_extend("keep", opts or {}, {
timeout = 4000,
})
local params = { textDocument = vim.lsp.util.make_text_document_params(bufnr) }
local response_map, err =
vim.lsp.buf_request_sync(bufnr, "textDocument/documentSymbol", params, opts.timeout)
if err or vim.tbl_isempty(response_map) then
vim.notify(string.format("Error fetching document symbols: %s", err), vim.log.levels.ERROR)
local client = get_client(bufnr)
if not client then
vim.notify("No LSP client found that supports symbols", vim.log.levels.WARN)
return
end
local response
local request_success = client.request(
"textDocument/documentSymbol",
params,
function(err, result)
response = { err = err, result = result }
end,
bufnr
)
if not request_success then
vim.notify("Error requesting document symbols", vim.log.levels.WARN)
end
local wait_result = vim.wait(opts.timeout, function()
return response ~= nil
end, 10)
if wait_result then
if response.err then
vim.notify(
string.format("Error requesting document symbols: %s", response.err),
vim.log.levels.WARN
)
else
callbacks.handle_symbols(response.result, bufnr)
end
else
local _, response = next(response_map)
callbacks.handle_symbols(response.result, bufnr)
vim.notify("Timeout when requesting document symbols", vim.log.levels.WARN)
end
end
@ -57,7 +113,7 @@ end
---@return boolean
local function is_lsp_attached(bufnr, exclude_id)
for _, client in pairs(vim.lsp.get_active_clients({ bufnr = bufnr })) do
if client.id ~= exclude_id and client.server_capabilities.documentSymbolProvider then
if client.id ~= exclude_id and lsp_util.client_supports_symbols(client) then
return true
end
end
@ -82,7 +138,7 @@ M.on_attach = function(client, bufnr, opts)
bufnr = 0
end
opts = opts or {}
if client.server_capabilities.documentSymbolProvider then
if lsp_util.client_supports_symbols(client) then
hook_handlers(opts.preserve_callback)
-- This is called from the LspAttach autocmd
-- The client isn't fully attached until just after that autocmd completes, so we need to

View file

@ -0,0 +1,12 @@
local config = require("aerial.config")
local M = {}
---@param client table
---@return boolean
M.client_supports_symbols = function(client)
return client.server_capabilities.documentSymbolProvider
and config.lsp.priority[client.name] ~= -1
end
return M

View file

@ -285,6 +285,13 @@ local default_options = {
-- How long to wait (in ms) after a buffer change before updating
-- Only used when diagnostics_trigger_update = false
update_delay = 300,
-- Map of LSP client name to priority. Default value is 10.
-- Clients with higher (larger) priority will be used before those with lower priority.
-- Set to -1 to never use the client.
priority = {
-- pyright = 10,
},
},
treesitter = {