diff --git a/lua/outline/code_action.lua b/lua/outline/code_action.lua deleted file mode 100644 index f6910d1..0000000 --- a/lua/outline/code_action.lua +++ /dev/null @@ -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 diff --git a/lua/outline/init.lua b/lua/outline/init.lua index 0026e36..4998537 100644 --- a/lua/outline/init.lua +++ b/lua/outline/init.lua @@ -245,18 +245,24 @@ end function M.show_status() local sidebar = M._get_sidebar(false) local buf, win = 0, 0 - local is_open + local is_open, provider if sidebar then buf = sidebar.code.buf win = sidebar.code.win is_open = sidebar.view:is_open() + provider = sidebar.provider + end + + if not is_open then + provider = providers.find_provider() end ---@type outline.StatusContext local ctx = { priority = cfg.o.providers.priority, outline_open = is_open, + provider = provider, } 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 - local p = _G._outline_current_provider - if not is_open then - p = providers.find_provider() - end - - if p ~= nil then - ctx.provider = p + if provider ~= nil then -- Just show code window is active when the first outline in this tabpage -- has not yet been opened. if not sidebar then diff --git a/lua/outline/providers/coc.lua b/lua/outline/providers/coc.lua index 08538ce..1d18fe6 100644 --- a/lua/outline/providers/coc.lua +++ b/lua/outline/providers/coc.lua @@ -28,7 +28,7 @@ end ---@param result table local function convert_symbols(result) 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 for _, value in pairs(result) do value.children = {} diff --git a/lua/outline/providers/init.lua b/lua/outline/providers/init.lua index 150a03e..e18f001 100644 --- a/lua/outline/providers/init.lua +++ b/lua/outline/providers/init.lua @@ -3,19 +3,19 @@ local cfg = require('outline.config') local M = {} local import_prefix = 'outline/providers/' +---@return outline.Provider? 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) + for _, path in ipairs(M.providers) do + local provider = require(path) if provider.supports_buffer(0) then - return provider, name + return provider end end - return nil, nil end ---@return boolean found_provider @@ -23,20 +23,15 @@ 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) - local provider, name = M.find_provider() - if not provider then - return false +---Call `sidebar.provider[method]` with args. NOP if no provider or no defined `method` +---@param sidebar outline.Sidebar +---@param method string +---@param args any[] +function M.action(sidebar, method, args) + if not sidebar.provider or not sidebar.provider[method] then + return end - _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 + return sidebar.provider[method](unpack(args)) end return M diff --git a/lua/outline/providers/nvim-lsp.lua b/lua/outline/providers/nvim-lsp.lua index dec9f5a..2749da8 100644 --- a/lua/outline/providers/nvim-lsp.lua +++ b/lua/outline/providers/nvim-lsp.lua @@ -89,4 +89,20 @@ function M.request_symbols(on_symbols, opts) 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 diff --git a/lua/outline/rename.lua b/lua/outline/rename.lua deleted file mode 100644 index 55ca234..0000000 --- a/lua/outline/rename.lua +++ /dev/null @@ -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 diff --git a/lua/outline/sidebar.lua b/lua/outline/sidebar.lua index 66cb24b..22f9388 100644 --- a/lua/outline/sidebar.lua +++ b/lua/outline/sidebar.lua @@ -23,6 +23,7 @@ local Sidebar = {} ---@field original_cursor string ---@field code outline.SidebarCodeState ---@field autocmds { [integer]: integer } winnr to autocmd id +---@field provider outline.Provider? function Sidebar:new() return setmetatable({ @@ -50,6 +51,7 @@ function Sidebar:reset_state() self.items = {} self.flats = {} self.original_cursor = vim.o.guicursor + self.provider = nil self:delete_autocmds() end @@ -62,6 +64,7 @@ function Sidebar:destroy() self.items = nil self.flats = nil self.code = nil + self.provider = nil end ---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' } }, hover_symbol = { require('outline.hover').show_hover, {} }, toggle_preview = { require('outline.preview').toggle, {} }, - rename_symbol = { require('outline.rename').rename, {} }, - code_actions = { require('outline.code_action').show_code_actions, {} }, + rename_symbol = { + providers.action, { self, 'rename_symbol', { self } } + }, + code_actions = { + providers.action, { self, 'code_actions', { self } } + }, show_help = { require('outline.help').show_keymap_help, {} }, close = { function() self.view:close() end, {} }, fold_toggle = { '_toggle_fold', {} }, @@ -309,11 +316,16 @@ end ---Re-request symbols from provider function Sidebar:__refresh() local focused_outline = self.view.bufnr == vim.api.nvim_get_current_buf() - if self.view:is_open() and not focused_outline then - providers.request_symbols(function(res) - self:refresh_handler(res) - end) + if focused_outline or not self.view:is_open() then + return end + self.provider = providers.find_provider() + if not self.provider then + return + end + self.provider.request_symbols(function(res) + self:refresh_handler(res) + end) end -- stylua: ignore start @@ -365,6 +377,17 @@ function Sidebar:_goto_and_close() self:close() 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" function Sidebar:_move_and_jump(direction) local move = direction == 'down' and 1 or -1 @@ -494,12 +517,14 @@ function Sidebar:open(opts) end 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(...) end, opts) - if not found then - utils.echo('No providers found for current buffer') - end end end @@ -558,7 +583,7 @@ end ---@return boolean has_provider function Sidebar:has_provider() if self:has_focus() then - return _G._outline_current_provider ~= nil + return self.provider ~= nil end return providers.has_provider() end diff --git a/lua/outline/types/outline.lua b/lua/outline/types/outline.lua index 484c8a9..7ddb735 100644 --- a/lua/outline/types/outline.lua +++ b/lua/outline/types/outline.lua @@ -65,11 +65,13 @@ -- 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 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