Merge branch 'master' into add_usd_support

This commit is contained in:
Colin Kennedy 2023-05-15 21:14:13 -07:00
commit 12ff8f7918
18 changed files with 174 additions and 60 deletions

View file

@ -680,6 +680,7 @@ hi AerialGuide2 guifg=Blue
- [close_all()](doc/api.md#close_all)
- [close_all_but_current()](doc/api.md#close_all_but_current)
- [open(opts)](doc/api.md#openopts)
- [open_in_win(target_win, source_win)](doc/api.md#open_in_wintarget_win-source_win)
- [open_all()](doc/api.md#open_all)
- [focus()](doc/api.md#focus)
- [toggle(opts)](doc/api.md#toggleopts)

View file

@ -447,6 +447,16 @@ open({opts}) *aerial.ope
(default true)
{direction} `"left"|"right"|"float"` Direction to open aerial window
open_in_win({target_win}, {source_win}) *aerial.open_in_win*
Open aerial in an existing window
Parameters:
{target_win} `integer` The winid to open the aerial buffer
{source_win} `integer` The winid that contains the source buffer
Note:
This can be used to create custom layouts, since you can create and position the window yourself
open_all() *aerial.open_all*
Open an aerial window for each visible window.

View file

@ -9,6 +9,7 @@
- [close_all()](#close_all)
- [close_all_but_current()](#close_all_but_current)
- [open(opts)](#openopts)
- [open_in_win(target_win, source_win)](#open_in_wintarget_win-source_win)
- [open_all()](#open_all)
- [focus()](#focus)
- [toggle(opts)](#toggleopts)
@ -94,6 +95,21 @@ Open the aerial window for the current buffer.
| | focus | `boolean` | If true, jump to aerial window if it is opened (default true) |
| | direction | `"left"\|"right"\|"float"` | Direction to open aerial window |
## open_in_win(target_win, source_win)
`open_in_win(target_win, source_win)` \
Open aerial in an existing window
| Param | Type | Desc |
| ---------- | --------- | ----------------------------------------- |
| target_win | `integer` | The winid to open the aerial buffer |
| source_win | `integer` | The winid that contains the source buffer |
**Note:**
<pre>
This can be used to create custom layouts, since you can create and position the window yourself
</pre>
## open_all()
`open_all()` \

View file

@ -22,7 +22,7 @@ local function should_close_aerial(aer_win)
-- Close the aerial window if its attached buffer is unsupported
if config.close_automatic_events.unsupported then
if not vim.api.nvim_buf_is_valid(src_buf) or not backends.get(src_buf) then
if not src_buf or not vim.api.nvim_buf_is_valid(src_buf) or not backends.get(src_buf) then
return true
end
end

View file

@ -108,7 +108,9 @@ local function attach(bufnr, backend, name)
local loading = require("aerial.loading")
local util = require("aerial.util")
local aer_bufnr = util.get_aerial_buffer(bufnr)
loading.set_loading(aer_bufnr, not data.has_received_data(bufnr))
if aer_bufnr then
loading.set_loading(aer_bufnr, not data.has_received_data(bufnr))
end
-- On first attach, fetch symbols from ALL possible backends so that they will race and the
-- fastest provider will display symbols (instead of just waiting for the prioritized backend
@ -179,7 +181,10 @@ M.set_symbols = function(bufnr, items, ctx)
end
data.set_symbols(bufnr, items)
loading.set_loading(util.get_aerial_buffer(bufnr), false)
local aer_bufnr = util.get_aerial_buffer(bufnr)
if aer_bufnr then
loading.set_loading(aer_bufnr, false)
end
render.update_aerial_buffer(bufnr)
window.update_all_positions(bufnr, 0)

View file

@ -199,6 +199,11 @@ M.on_publish_diagnostics = function(_err, result, ctx, _config)
then
return
end
-- Ignore diagnostics from other clients
local attached_client = lsp_util.get_client(bufnr)
if not attached_client or attached_client.id ~= client_id then
return
end
-- Don't update if there are diagnostics errors, unless config option is set
-- or we have no symbols for this buffer

View file

@ -32,32 +32,12 @@ local function hook_handlers(preserve_symbol_callback)
replace_handler("textDocument/publishDiagnostics", callbacks.on_publish_diagnostics, true)
end
---@param bufnr integer
---@param exclude_id nil|integer Client ID to exclude from calculation
---@return nil|table
local function get_client(bufnr, exclude_id)
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
client.id ~= exclude_id
and 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)
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) }
local client = get_client(bufnr)
local client = lsp_util.get_client(bufnr)
if not client then
vim.notify(
string.format("No LSP client found that supports symbols in buffer %d", bufnr),
@ -80,7 +60,7 @@ M.fetch_symbols_sync = function(bufnr, opts)
timeout = 4000,
})
local params = { textDocument = vim.lsp.util.make_text_document_params(bufnr) }
local client = get_client(bufnr)
local client = lsp_util.get_client(bufnr)
if not client then
vim.notify(
string.format("No LSP client found that supports symbols in buffer %d", bufnr),
@ -123,7 +103,7 @@ M.is_supported = function(bufnr)
if not bufnr or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
end
if not get_client(bufnr) then
if not lsp_util.get_client(bufnr) then
return false, "No LSP client found that supports symbols"
end
return true, nil
@ -147,7 +127,7 @@ M.on_attach = function(client, bufnr, opts)
end
M.on_detach = function(client_id, bufnr)
if not get_client(bufnr, client_id) then
if not lsp_util.get_client(bufnr, client_id) then
-- This is called from the LspDetach autocmd
-- The client isn't fully attached until just after that autocmd completes, so we need to
-- schedule the attach

View file

@ -9,4 +9,24 @@ M.client_supports_symbols = function(client)
and config.lsp.priority[client.name] ~= -1
end
---@param bufnr integer
---@param exclude_id nil|integer Client ID to exclude from calculation
---@return nil|table
M.get_client = function(bufnr, exclude_id)
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
client.id ~= exclude_id
and M.client_supports_symbols(client)
and priority > last_priority
then
ret = client
last_priority = priority
end
end
return ret
end
return M

View file

@ -17,14 +17,13 @@ local config = require("aerial.config")
---@field parent? aerial.Symbol
---@field selection_range? aerial.Range
---@field children? aerial.Symbol[]
---@field scope? string
---@class aerial.BufData
---@field bufnr integer
---@field items aerial.Symbol[]
---@field flat_items aerial.Symbol[]
---@field positions any
---@field last_win integer
---@field last_win nil|integer
---@field collapsed table<string, boolean>
---@field collapse_level integer
---@field max_level integer
@ -37,7 +36,7 @@ function BufData.new(bufnr)
items = {},
flat_items = {},
positions = {},
last_win = -1,
last_win = nil,
collapsed = {},
collapse_level = 99,
}
@ -148,7 +147,7 @@ function BufData:visit(callback)
end
end
---@param include_hidden boolean
---@param opts nil|{skip_hidden: nil|boolean}
---@return integer
function BufData:count(opts)
opts = vim.tbl_extend("keep", opts or {}, {
@ -181,6 +180,9 @@ end
function M.get_or_create(buf)
buf = buf or 0
local bufnr, _ = util.get_buffers(buf)
if not bufnr then
error("Could not find source buffer")
end
local bufdata = buf_to_symbols[bufnr]
if not bufdata then
bufdata = BufData.new(bufnr)
@ -237,7 +239,7 @@ function M.has_received_data(bufnr)
end
---Return true if the buffer has any symbols
---@param bufnr integer
---@param bufnr nil|integer
---@return boolean
function M.has_symbols(bufnr)
local bufdata = M.get(bufnr)

View file

@ -244,6 +244,18 @@ M.open = function(opts)
require("aerial.window").open(opts.focus, opts.direction)
end
---Open aerial in an existing window
---@param target_win integer The winid to open the aerial buffer
---@param source_win integer The winid that contains the source buffer
---@note
--- This can be used to create custom layouts, since you can create and position the window yourself
M.open_in_win = function(target_win, source_win)
do_setup()
was_closed = false
local source_bufnr = vim.api.nvim_win_get_buf(source_win)
require("aerial.window").open_aerial_in_win(source_bufnr, source_win, target_win)
end
---Open an aerial window for each visible window.
M.open_all = lazy("window", "open_all")

View file

@ -3,10 +3,14 @@ local M = {}
local timers = {}
---@param aer_bufnr integer
---@return boolean
M.is_loading = function(aer_bufnr)
return timers[aer_bufnr] ~= nil
end
---@param aer_bufnr integer
---@param is_loading boolean
M.set_loading = function(aer_bufnr, is_loading)
if is_loading then
if timers[aer_bufnr] == nil then

View file

@ -6,8 +6,9 @@ local window = require("aerial.window")
local M = {}
local function _get_current_lnum(winid)
---@type nil|integer
local bufnr = vim.api.nvim_get_current_buf()
if data.has_symbols(bufnr) then
if bufnr and data.has_symbols(bufnr) then
local bufdata = data.get_or_create(bufnr)
local cached_lnum = bufdata.positions[winid]
if cached_lnum then
@ -18,7 +19,7 @@ local function _get_current_lnum(winid)
if util.is_aerial_buffer(bufnr) then
bufnr = util.get_source_buffer()
end
if data.has_symbols(bufnr) then
if bufnr and data.has_symbols(bufnr) then
return window.get_position_in_win(bufnr, winid)
else
return nil
@ -197,6 +198,9 @@ M.select = function(opts)
return
end
local bufnr, _ = util.get_buffers()
if not bufnr then
error("Could not find source buffer")
end
M.select_symbol(item, winid, bufnr, opts)
end

View file

@ -78,7 +78,7 @@ M.update_aerial_buffer = function(buf)
return
end
local bufnr, aer_bufnr = util.get_buffers(buf)
if aer_bufnr == -1 or loading.is_loading(aer_bufnr) then
if not bufnr or not aer_bufnr or loading.is_loading(aer_bufnr) then
resize_all_wins(aer_bufnr)
return
end
@ -203,7 +203,7 @@ M.update_highlights = function(buf)
return
end
local bufnr, aer_bufnr = util.get_buffers(buf)
if not data.has_symbols(bufnr) or aer_bufnr == -1 then
if not bufnr or not data.has_symbols(bufnr) or not aer_bufnr then
return
end
local bufdata = data.get_or_create(bufnr)
@ -251,17 +251,19 @@ M.update_highlights = function(buf)
M.clear_highlights(bufnr)
local cursor = vim.api.nvim_win_get_cursor(0)
local item = data.get_or_create(0):item(cursor[1])
vim.api.nvim_buf_add_highlight(bufnr, ns, "AerialLine", item.lnum - 1, 0, -1)
if item then
vim.api.nvim_buf_add_highlight(bufnr, ns, "AerialLine", item.lnum - 1, 0, -1)
end
end
end
---@param bufnr integer
---@return integer
M.clear_highlights = function(bufnr)
if not vim.api.nvim_buf_is_valid(bufnr) then
return
end
local ns = vim.api.nvim_create_namespace("aerial-line")
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
if vim.api.nvim_buf_is_valid(bufnr) then
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1)
end
return ns
end

View file

@ -131,11 +131,11 @@ M.toggle = function(opts)
end
---Set the collapse level of the symbol tree
---@param bufnr integer
---@param bufnr nil|integer
---@param level integer 0 is all closed, use 99 to open all
M.set_collapse_level = function(bufnr, level)
bufnr = util.get_buffers(bufnr or 0)
if not data.has_symbols(bufnr) then
if not bufnr or not data.has_symbols(bufnr) then
return
end
local bufdata = data.get_or_create(bufnr)
@ -148,7 +148,7 @@ M.set_collapse_level = function(bufnr, level)
end, vim.api.nvim_list_wins())
else
local source_win = util.get_winids(0)
if vim.api.nvim_win_get_buf(source_win) == bufnr then
if source_win and vim.api.nvim_win_get_buf(source_win) == bufnr then
wins = { source_win }
else
wins = util.get_fixed_wins(bufnr)

View file

@ -141,6 +141,9 @@ M.get_source_win = function(winid)
return M.get_winid_from_var(winid or 0, "source_win")
end
---@param bufnr nil|integer
---@return nil|integer Source buffer
---@return nil|integer Aerial buffer
M.get_buffers = function(bufnr)
if bufnr == nil or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
@ -152,18 +155,25 @@ M.get_buffers = function(bufnr)
end
end
---@param bufnr nil|integer
---@return nil|integer
M.get_aerial_buffer = function(bufnr)
return M.get_buffer_from_var(bufnr or 0, "aerial_buffer")
end
---@param bufnr nil|integer
---@return nil|integer
M.get_source_buffer = function(bufnr)
return M.get_buffer_from_var(bufnr or 0, "source_buffer")
end
---@param bufnr integer
---@param varname string
---@return nil|integer
M.get_buffer_from_var = function(bufnr, varname)
local status, result_bufnr = pcall(vim.api.nvim_buf_get_var, bufnr, varname)
if not status or result_bufnr == nil or not vim.api.nvim_buf_is_valid(result_bufnr) then
return -1
return nil
end
return result_bufnr
end
@ -295,7 +305,8 @@ M.is_managing_folds = function(winid)
return vim.api.nvim_win_get_option(winid or 0, "foldexpr") == "v:lua.aerial_foldexpr()"
end
M.detect_split_direction = function(bufnr)
---@return "left"|"right"|"float"
M.detect_split_direction = function()
local default = config.layout.default_direction
if default ~= "prefer_left" and default ~= "prefer_right" then
return default

View file

@ -107,12 +107,17 @@ local function setup_aerial_win(src_winid, aer_winid, aer_bufnr)
end
end
---@param bufnr nil|integer
---@param aer_bufnr nil|integer
---@param direction "left"|"right"|"float"
---@param existing_win nil|integer
---@return integer
local function create_aerial_window(bufnr, aer_bufnr, direction, existing_win)
if direction ~= "left" and direction ~= "right" and direction ~= "float" then
error("Expected direction to be 'left', 'right', or 'float'")
end
if aer_bufnr == -1 then
if not aer_bufnr then
aer_bufnr = create_aerial_buffer(bufnr)
end
@ -183,7 +188,7 @@ M.open_aerial_in_win = function(src_bufnr, src_winid, aer_winid)
vim.api.nvim_win_set_var(src_winid, "aerial_win", aer_winid)
return
end
if aer_bufnr == -1 then
if not aer_bufnr then
aer_bufnr = create_aerial_buffer(src_bufnr)
end
local my_winid = vim.api.nvim_get_current_win()
@ -200,7 +205,7 @@ end
---@return integer|nil
local function get_aerial_win_for_buf(bufnr)
local aer_bufnr = util.get_aerial_buffer(bufnr)
if aer_bufnr ~= -1 then
if aer_bufnr then
return util.buf_first_win_in_tabpage(aer_bufnr)
end
end
@ -286,10 +291,9 @@ M.maybe_open_automatic = function(bufnr)
end
end
M.open = function(focus, direction, opts)
opts = vim.tbl_extend("keep", opts or {}, {
winid = nil,
})
---@param focus? boolean
---@param direction? "left"|"right"|"float"
M.open = function(focus, direction)
if util.is_aerial_buffer(0) or util.is_ignored_win() then
return
end
@ -303,7 +307,7 @@ M.open = function(focus, direction, opts)
end
direction = direction or util.detect_split_direction()
local aer_winid = create_aerial_window(bufnr, aer_bufnr, direction, opts.winid or aerial_win)
local aer_winid = create_aerial_window(bufnr, aer_bufnr, direction, aerial_win)
local backend = backends.get(0)
if backend and not data.has_symbols(bufnr) then
backend.fetch_symbols(bufnr)
@ -462,7 +466,7 @@ M.update_position = function(winids, last_focused_win)
end
local win_bufnr = vim.api.nvim_win_get_buf(winids[1])
local bufnr = util.get_buffers(win_bufnr)
if not data.has_symbols(bufnr) then
if not bufnr or not data.has_symbols(bufnr) then
return
end
if util.is_aerial_buffer(win_bufnr) then
@ -498,9 +502,10 @@ M.update_position = function(winids, last_focused_win)
end
end
---@param buffer nil|integer
M.center_symbol_in_view = function(buffer)
local bufnr, aer_bufnr = util.get_buffers(buffer)
if not data.has_symbols(bufnr) then
if not bufnr or not data.has_symbols(bufnr) or not aer_bufnr then
return
end
local bufdata = data.get_or_create(bufnr)
@ -512,9 +517,11 @@ M.center_symbol_in_view = function(buffer)
local max_topline = vim.api.nvim_buf_line_count(aer_bufnr) - height
local topline = math.max(1, math.min(max_topline, lnum - math.floor(height / 2)))
local aerial_win = util.buf_first_win_in_tabpage(aer_bufnr)
vim.api.nvim_win_call(aerial_win, function()
vim.fn.winrestview({ lnum = lnum, topline = topline })
end)
if aerial_win then
vim.api.nvim_win_call(aerial_win, function()
vim.fn.winrestview({ lnum = lnum, topline = topline })
end)
end
end
end
end

View file

@ -5,14 +5,28 @@ M.on_load = function() end
M.is_win_supported = function(winid, bufnr)
local util = require("aerial.util")
return util.is_aerial_buffer(bufnr)
if not util.is_aerial_buffer(bufnr) then
return false
end
local source_win = util.get_source_win(winid)
local source_buf = util.get_source_buffer(bufnr)
return source_win
and vim.api.nvim_win_is_valid(source_win)
and source_buf
and vim.api.nvim_buf_is_valid(source_buf)
end
M.save_win = function(winid)
local util = require("aerial.util")
local source_win = util.get_source_win(winid)
if not source_win then
error("Source winid is nil")
end
local rel_nr = vim.api.nvim_win_get_number(source_win) - vim.api.nvim_win_get_number(winid)
local bufnr = util.get_source_buffer(vim.api.nvim_win_get_buf(winid))
if not bufnr or not vim.api.nvim_buf_is_valid(bufnr) then
error("Source buffer is nil")
end
return {
rel_nr = rel_nr,
bufname = vim.api.nvim_buf_get_name(bufnr),

View file

@ -43,4 +43,25 @@ a.describe("layout", function()
assert.equals("aerial", vim.api.nvim_buf_get_option(aer_bufnr, "filetype"))
assert(require("aerial.util").is_floating_win(winid))
end)
a.it("can open aerial in a specific window (not current)", function()
local target_win = vim.api.nvim_get_current_win()
vim.cmd("edit README.md")
vim.cmd.vsplit()
aerial.open_in_win(target_win, 0)
local aer_bufnr = vim.api.nvim_win_get_buf(target_win)
assert.equals("aerial", vim.bo[aer_bufnr].filetype)
assert.truthy(vim.api.nvim_buf_get_name(0):match("README.md$"))
end)
a.it("can open aerial in a specific (current) window", function()
local source_win = vim.api.nvim_get_current_win()
vim.cmd("edit README.md")
vim.cmd.vsplit()
local target_win = vim.api.nvim_get_current_win()
aerial.open_in_win(target_win, source_win)
local source_bufnr = vim.api.nvim_win_get_buf(source_win)
assert.equals("aerial", vim.bo.filetype)
assert.truthy(vim.api.nvim_buf_get_name(source_bufnr):match("README.md$"))
end)
end)