refactor: Provider symbol actions
It makes sense to store the provider each sidebar is using with own
self.provider fields, no way that did not occur to me before this.
The old `_G._outline_current_provider` ironically, can now be replaced
by `require('outline').current.provider`.
This commit is contained in:
@@ -1,14 +0,0 @@
|
|||||||
local outline = require('outline')
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
function M.show_code_actions()
|
|
||||||
-- keep the cursor info in outline and jump back (or not jump back?)
|
|
||||||
local winnr, pos = vim.api.nvim_get_current_win(), vim.api.nvim_win_get_cursor(0)
|
|
||||||
outline.current:_goto_location(true)
|
|
||||||
vim.lsp.buf.code_action()
|
|
||||||
vim.fn.win_gotoid(winnr)
|
|
||||||
vim.api.nvim_win_set_cursor(winnr, pos)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -245,18 +245,24 @@ end
|
|||||||
function M.show_status()
|
function M.show_status()
|
||||||
local sidebar = M._get_sidebar(false)
|
local sidebar = M._get_sidebar(false)
|
||||||
local buf, win = 0, 0
|
local buf, win = 0, 0
|
||||||
local is_open
|
local is_open, provider
|
||||||
|
|
||||||
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
|
||||||
|
end
|
||||||
|
|
||||||
|
if not is_open then
|
||||||
|
provider = providers.find_provider()
|
||||||
end
|
end
|
||||||
|
|
||||||
---@type outline.StatusContext
|
---@type outline.StatusContext
|
||||||
local ctx = {
|
local ctx = {
|
||||||
priority = cfg.o.providers.priority,
|
priority = cfg.o.providers.priority,
|
||||||
outline_open = is_open,
|
outline_open = is_open,
|
||||||
|
provider = provider,
|
||||||
}
|
}
|
||||||
|
|
||||||
if vim.api.nvim_buf_is_valid(buf) then
|
if vim.api.nvim_buf_is_valid(buf) then
|
||||||
@@ -267,13 +273,7 @@ function M.show_status()
|
|||||||
|
|
||||||
ctx.default_filter = cfg.o.symbols.user_config_filter.default
|
ctx.default_filter = cfg.o.symbols.user_config_filter.default
|
||||||
|
|
||||||
local p = _G._outline_current_provider
|
if provider ~= nil then
|
||||||
if not is_open then
|
|
||||||
p = providers.find_provider()
|
|
||||||
end
|
|
||||||
|
|
||||||
if p ~= nil then
|
|
||||||
ctx.provider = p
|
|
||||||
-- Just show code window is active when the first outline in this tabpage
|
-- Just show code window is active when the first outline in this tabpage
|
||||||
-- has not yet been opened.
|
-- has not yet been opened.
|
||||||
if not sidebar then
|
if not sidebar then
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ end
|
|||||||
---@param result table
|
---@param result table
|
||||||
local function convert_symbols(result)
|
local function convert_symbols(result)
|
||||||
local s = {}
|
local s = {}
|
||||||
local kinds_index = require('outline.symbol').str_to_kind
|
local kinds_index = require('outline.symbols').str_to_kind
|
||||||
-- rebuild coc.nvim symbol list hierarchy according to the 'level' key
|
-- rebuild coc.nvim symbol list hierarchy according to the 'level' key
|
||||||
for _, value in pairs(result) do
|
for _, value in pairs(result) do
|
||||||
value.children = {}
|
value.children = {}
|
||||||
|
|||||||
@@ -3,19 +3,19 @@ local cfg = require('outline.config')
|
|||||||
local M = {}
|
local M = {}
|
||||||
local import_prefix = 'outline/providers/'
|
local import_prefix = 'outline/providers/'
|
||||||
|
|
||||||
|
---@return outline.Provider?
|
||||||
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, cfg.get_providers())
|
end, cfg.get_providers())
|
||||||
end
|
end
|
||||||
for _, name in ipairs(M.providers) do
|
for _, path in ipairs(M.providers) do
|
||||||
local provider = require(name)
|
local provider = require(path)
|
||||||
if provider.supports_buffer(0) then
|
if provider.supports_buffer(0) then
|
||||||
return provider, name
|
return provider
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return nil, nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
---@return boolean found_provider
|
---@return boolean found_provider
|
||||||
@@ -23,20 +23,15 @@ function M.has_provider()
|
|||||||
return M.find_provider() ~= nil
|
return M.find_provider() ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param on_symbols function
|
---Call `sidebar.provider[method]` with args. NOP if no provider or no defined `method`
|
||||||
---@param opts outline.OutlineOpts?
|
---@param sidebar outline.Sidebar
|
||||||
---@return boolean found_provider
|
---@param method string
|
||||||
function M.request_symbols(on_symbols, opts)
|
---@param args any[]
|
||||||
local provider, name = M.find_provider()
|
function M.action(sidebar, method, args)
|
||||||
if not provider then
|
if not sidebar.provider or not sidebar.provider[method] then
|
||||||
return false
|
return
|
||||||
end
|
end
|
||||||
_G._outline_current_provider = provider
|
return sidebar.provider[method](unpack(args))
|
||||||
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
|
||||||
|
|||||||
@@ -89,4 +89,20 @@ function M.request_symbols(on_symbols, opts)
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- No good way to update outline when LSP action complete for now
|
||||||
|
|
||||||
|
---@param sidebar outline.Sidebar
|
||||||
|
function M.code_actions(sidebar)
|
||||||
|
sidebar:wrap_goto_location(function()
|
||||||
|
vim.lsp.buf.code_action()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param sidebar outline.Sidebar
|
||||||
|
function M.rename_symbol(sidebar)
|
||||||
|
sidebar:wrap_goto_location(function()
|
||||||
|
vim.lsp.buf.rename()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
local outline = require('outline')
|
|
||||||
|
|
||||||
local M = {}
|
|
||||||
|
|
||||||
local function get_rename_params(node, winnr)
|
|
||||||
local bufnr = vim.api.nvim_win_get_buf(winnr)
|
|
||||||
local fn = 'file://' .. vim.api.nvim_buf_get_name(bufnr)
|
|
||||||
|
|
||||||
return {
|
|
||||||
textDocument = { uri = fn },
|
|
||||||
position = { line = node.line, character = node.character },
|
|
||||||
bufnr = bufnr,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function M.rename()
|
|
||||||
local current_line = vim.api.nvim_win_get_cursor(outline.current.view.winnr)[1]
|
|
||||||
local node = outline.current.flats[current_line]
|
|
||||||
|
|
||||||
local params = get_rename_params(node, outline.current.code.win)
|
|
||||||
|
|
||||||
local new_name = vim.fn.input({ prompt = 'New Name: ', default = node.name })
|
|
||||||
if not new_name or new_name == '' or new_name == node.name then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
params.newName = new_name
|
|
||||||
|
|
||||||
vim.lsp.buf_request(params.bufnr, 'textDocument/rename', params, function(_, result, ctx)
|
|
||||||
if result ~= nil then
|
|
||||||
local client = vim.lsp.get_client_by_id(ctx.client_id)
|
|
||||||
vim.lsp.util.apply_workspace_edit(result, client.offset_encoding)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
return M
|
|
||||||
@@ -23,6 +23,7 @@ local Sidebar = {}
|
|||||||
---@field original_cursor string
|
---@field original_cursor string
|
||||||
---@field code outline.SidebarCodeState
|
---@field code outline.SidebarCodeState
|
||||||
---@field autocmds { [integer]: integer } winnr to autocmd id
|
---@field autocmds { [integer]: integer } winnr to autocmd id
|
||||||
|
---@field provider outline.Provider?
|
||||||
|
|
||||||
function Sidebar:new()
|
function Sidebar:new()
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
@@ -50,6 +51,7 @@ function Sidebar:reset_state()
|
|||||||
self.items = {}
|
self.items = {}
|
||||||
self.flats = {}
|
self.flats = {}
|
||||||
self.original_cursor = vim.o.guicursor
|
self.original_cursor = vim.o.guicursor
|
||||||
|
self.provider = nil
|
||||||
self:delete_autocmds()
|
self:delete_autocmds()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -62,6 +64,7 @@ function Sidebar:destroy()
|
|||||||
self.items = nil
|
self.items = nil
|
||||||
self.flats = nil
|
self.flats = nil
|
||||||
self.code = nil
|
self.code = nil
|
||||||
|
self.provider = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
---Handler for provider request_symbols when outline is opened for the first time.
|
---Handler for provider request_symbols when outline is opened for the first time.
|
||||||
@@ -135,8 +138,12 @@ function Sidebar:setup_keymaps()
|
|||||||
up_and_jump = { '_move_and_jump', { 'up' } },
|
up_and_jump = { '_move_and_jump', { 'up' } },
|
||||||
hover_symbol = { require('outline.hover').show_hover, {} },
|
hover_symbol = { require('outline.hover').show_hover, {} },
|
||||||
toggle_preview = { require('outline.preview').toggle, {} },
|
toggle_preview = { require('outline.preview').toggle, {} },
|
||||||
rename_symbol = { require('outline.rename').rename, {} },
|
rename_symbol = {
|
||||||
code_actions = { require('outline.code_action').show_code_actions, {} },
|
providers.action, { self, 'rename_symbol', { self } }
|
||||||
|
},
|
||||||
|
code_actions = {
|
||||||
|
providers.action, { self, 'code_actions', { self } }
|
||||||
|
},
|
||||||
show_help = { require('outline.help').show_keymap_help, {} },
|
show_help = { require('outline.help').show_keymap_help, {} },
|
||||||
close = { function() self.view:close() end, {} },
|
close = { function() self.view:close() end, {} },
|
||||||
fold_toggle = { '_toggle_fold', {} },
|
fold_toggle = { '_toggle_fold', {} },
|
||||||
@@ -309,11 +316,16 @@ end
|
|||||||
---Re-request symbols from provider
|
---Re-request symbols from provider
|
||||||
function Sidebar:__refresh()
|
function Sidebar:__refresh()
|
||||||
local focused_outline = self.view.bufnr == vim.api.nvim_get_current_buf()
|
local focused_outline = self.view.bufnr == vim.api.nvim_get_current_buf()
|
||||||
if self.view:is_open() and not focused_outline then
|
if focused_outline or not self.view:is_open() then
|
||||||
providers.request_symbols(function(res)
|
return
|
||||||
|
end
|
||||||
|
self.provider = providers.find_provider()
|
||||||
|
if not self.provider then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.provider.request_symbols(function(res)
|
||||||
self:refresh_handler(res)
|
self:refresh_handler(res)
|
||||||
end)
|
end)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- stylua: ignore start
|
-- stylua: ignore start
|
||||||
@@ -365,6 +377,17 @@ function Sidebar:_goto_and_close()
|
|||||||
self:close()
|
self:close()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---Goto location in code, run fn() then go back to outline.
|
||||||
|
---Like emacs save-excursion but here it's explicitly goto_location.
|
||||||
|
---@param fn function
|
||||||
|
function Sidebar:wrap_goto_location(fn)
|
||||||
|
local pos = vim.api.nvim_win_get_cursor(0)
|
||||||
|
self:__goto_location(true)
|
||||||
|
fn()
|
||||||
|
vim.fn.win_gotoid(self.view.winnr)
|
||||||
|
vim.api.nvim_win_set_cursor(self.view.winnr, pos)
|
||||||
|
end
|
||||||
|
|
||||||
---@param direction "up"|"down"
|
---@param direction "up"|"down"
|
||||||
function Sidebar:_move_and_jump(direction)
|
function Sidebar:_move_and_jump(direction)
|
||||||
local move = direction == 'down' and 1 or -1
|
local move = direction == 'down' and 1 or -1
|
||||||
@@ -494,12 +517,14 @@ function Sidebar:open(opts)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not self.view:is_open() then
|
if not self.view:is_open() then
|
||||||
local found = providers.request_symbols(function(...)
|
self.provider = providers.find_provider()
|
||||||
|
if not self.provider then
|
||||||
|
utils.echo('No providers found for current buffer')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self.provider.request_symbols(function(...)
|
||||||
self:initial_handler(...)
|
self:initial_handler(...)
|
||||||
end, opts)
|
end, opts)
|
||||||
if not found then
|
|
||||||
utils.echo('No providers found for current buffer')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -558,7 +583,7 @@ end
|
|||||||
---@return boolean has_provider
|
---@return boolean has_provider
|
||||||
function Sidebar:has_provider()
|
function Sidebar:has_provider()
|
||||||
if self:has_focus() then
|
if self:has_focus() then
|
||||||
return _G._outline_current_provider ~= nil
|
return self.provider ~= nil
|
||||||
end
|
end
|
||||||
return providers.has_provider()
|
return providers.has_provider()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -65,11 +65,13 @@
|
|||||||
-- PROVIDER
|
-- PROVIDER
|
||||||
|
|
||||||
---@class outline.Provider
|
---@class outline.Provider
|
||||||
---@field should_use_provider fun(bufnr:integer):boolean
|
|
||||||
---@field hover_info fun(bufnr:integer, params:table, on_info:function)
|
|
||||||
---@field request_symbols fun(on_symbols:function, opts:table)
|
|
||||||
---@field name string
|
---@field name string
|
||||||
---@field get_status? fun():string[]
|
---@field get_status? fun():string[]
|
||||||
|
---@field supports_buffer fun(bufnr:integer):boolean
|
||||||
|
---@field request_symbols fun(on_symbols:function, opts:table?)
|
||||||
|
---@field hover_info? fun(bufnr:integer, params:table, on_info:function)
|
||||||
|
---@field rename_symbol? fun(sidebar:outline.Sidebar)
|
||||||
|
---@field code_actions? fun(sidebar:outline.Sidebar)
|
||||||
|
|
||||||
-- HELP
|
-- HELP
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user