From 5278eb5b2b0e1a87286d731ed5fa37fc7a21be67 Mon Sep 17 00:00:00 2001 From: hedy Date: Thu, 16 Nov 2023 15:41:37 +0800 Subject: [PATCH] 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) --- lua/outline/config.lua | 26 +++++++++++++-- lua/outline/init.lua | 32 ++++++++++++++---- lua/outline/providers/coc.lua | 5 ++- lua/outline/providers/init.lua | 53 +++++++++++++++--------------- lua/outline/providers/markdown.lua | 15 +++++++-- lua/outline/providers/nvim-lsp.lua | 43 +++++++++++++++--------- 6 files changed, 120 insertions(+), 54 deletions(-) diff --git a/lua/outline/config.lua b/lua/outline/config.lua index 2ead5c7..c11cbdd 100644 --- a/lua/outline/config.lua +++ b/lua/outline/config.lua @@ -71,6 +71,7 @@ M.defaults = { up_and_jump = '', }, 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)) diff --git a/lua/outline/init.lua b/lua/outline/init.lua index 23ff0bb..da72f69 100644 --- a/lua/outline/init.lua +++ b/lua/outline/init.lua @@ -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() diff --git a/lua/outline/providers/coc.lua b/lua/outline/providers/coc.lua index 900deb1..c4dade6 100644 --- a/lua/outline/providers/coc.lua +++ b/lua/outline/providers/coc.lua @@ -1,4 +1,7 @@ -local M = {} +local M = { + name = 'coc', +} + function M.should_use_provider(_) local not_coc_installed = vim.fn.exists '*CocActionAsync' == 0 diff --git a/lua/outline/providers/init.lua b/lua/outline/providers/init.lua index 5fe2cff..611df5e 100644 --- a/lua/outline/providers/init.lua +++ b/lua/outline/providers/init.lua @@ -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 diff --git a/lua/outline/providers/markdown.lua b/lua/outline/providers/markdown.lua index 3f6def2..1347c79 100644 --- a/lua/outline/providers/markdown.lua +++ b/lua/outline/providers/markdown.lua @@ -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) diff --git a/lua/outline/providers/nvim-lsp.lua b/lua/outline/providers/nvim-lsp.lua index c6ccf64..e6a18d8 100644 --- a/lua/outline/providers/nvim-lsp.lua +++ b/lua/outline/providers/nvim-lsp.lua @@ -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)