mirror of
https://github.com/stevearc/aerial.nvim
synced 2024-09-16 14:34:08 +02:00
refactor!: split close_behavior into two new config options
Gracefully deprecates the close_behavior option. See :help aerial-close-behavior for information on how to migrate.
This commit is contained in:
parent
b9cde181c3
commit
8e1d57562d
9 changed files with 342 additions and 172 deletions
|
@ -372,6 +372,16 @@ replicate the old behavior you could get with `open_automatic_min_lines` and
|
|||
}
|
||||
<
|
||||
|
||||
*aerial-close-behavior*
|
||||
The `close_behavior` config option has been replaced by a combination of
|
||||
`attach_mode` and `close_automatic_events`. I would recommend reading the docs
|
||||
for each of these, but a migration cheat-sheet is provided below.
|
||||
>
|
||||
close_behavior = "global" --> attach_mode = "global"
|
||||
close_behavior = "persist" --> this is the new effective default
|
||||
close_behavior = "auto" --> close_automatic_events = { "unsupported" }
|
||||
close_behavior = "close" --> close_automatic_events = { "switch_buffer" }
|
||||
<
|
||||
|
||||
*SymbolKind* *symbol*
|
||||
A quick note on SymbolKind. An authoritative list of valid SymbolKinds can be
|
||||
|
|
|
@ -9,17 +9,63 @@ local window = require("aerial.window")
|
|||
|
||||
local M = {}
|
||||
|
||||
local function is_sticky(behavior)
|
||||
return behavior == "persist" or behavior == "global"
|
||||
local maybe_open_automatic = util.throttle(function()
|
||||
window.maybe_open_automatic()
|
||||
end, { delay = 5, reset_timer_on_call = true })
|
||||
|
||||
---@param aer_win integer
|
||||
---@return boolean
|
||||
local function should_close_aerial(aer_win)
|
||||
local aer_buf = vim.api.nvim_win_get_buf(aer_win)
|
||||
local src_win = util.get_source_win(aer_win)
|
||||
-- If the aerial window has no valid source window, close it
|
||||
if not src_win then
|
||||
return true
|
||||
end
|
||||
local src_buf = util.get_source_buffer(aer_buf)
|
||||
|
||||
if config.close_automatic_events.unfocus then
|
||||
-- Close the window if the aerial source win is not the current win
|
||||
if src_win ~= vim.api.nvim_get_current_win() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- 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
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function close_orphans()
|
||||
local orphans = util.get_aerial_orphans()
|
||||
for _, winid in ipairs(orphans) do
|
||||
if is_sticky(config.close_behavior) then
|
||||
render.clear_buffer(vim.api.nvim_win_get_buf(winid))
|
||||
else
|
||||
vim.api.nvim_win_close(winid, true)
|
||||
local function update_aerial_windows()
|
||||
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
local winbuf = vim.api.nvim_win_get_buf(winid)
|
||||
if util.is_aerial_buffer(winbuf) then
|
||||
local close = false
|
||||
if config.attach_mode == "global" then
|
||||
window.open_aerial_in_win(0, 0, winid)
|
||||
elseif config.attach_mode == "window" then
|
||||
local src_win = util.get_source_win(winid)
|
||||
local src_buf = vim.api.nvim_win_get_buf(src_win)
|
||||
|
||||
-- Close the aerial window if its source window has switched buffers
|
||||
if config.close_automatic_events.switch_buffer then
|
||||
if src_buf ~= util.get_source_buffer(winbuf) then
|
||||
close = true
|
||||
end
|
||||
end
|
||||
|
||||
if util.get_source_win(winid) == vim.api.nvim_get_current_win() then
|
||||
window.open_aerial_in_win(src_buf, src_win, winid)
|
||||
end
|
||||
end
|
||||
|
||||
if close or should_close_aerial(winid) then
|
||||
vim.api.nvim_win_close(winid, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -31,47 +77,33 @@ M.on_enter_buffer = util.throttle(function()
|
|||
end
|
||||
|
||||
local mybuf = vim.api.nvim_get_current_buf()
|
||||
if not util.is_aerial_buffer(mybuf) then
|
||||
if config.close_behavior == "close" then
|
||||
close_orphans()
|
||||
end
|
||||
|
||||
-- If we're not in supported buffer
|
||||
local backend = backends.get()
|
||||
if not backend then
|
||||
fold.restore_foldmethod()
|
||||
close_orphans()
|
||||
return
|
||||
end
|
||||
|
||||
fold.maybe_set_foldmethod()
|
||||
end
|
||||
|
||||
if util.is_aerial_buffer(mybuf) then
|
||||
local source_win = util.get_source_win()
|
||||
if
|
||||
(not is_sticky(config.close_behavior) and util.is_aerial_buffer_orphaned(mybuf))
|
||||
or vim.tbl_count(vim.api.nvim_list_wins()) == 1
|
||||
(not source_win and config.attach_mode ~= "global")
|
||||
or vim.tbl_count(vim.api.nvim_tabpage_list_wins(0)) == 1
|
||||
then
|
||||
vim.cmd("quit")
|
||||
else
|
||||
-- Hack to ignore winwidth
|
||||
util.restore_width(0)
|
||||
end
|
||||
elseif window.is_open() then
|
||||
close_orphans()
|
||||
render.update_aerial_buffer()
|
||||
return
|
||||
end
|
||||
|
||||
update_aerial_windows()
|
||||
|
||||
-- If we're not in supported buffer
|
||||
local backend = backends.get()
|
||||
if not backend then
|
||||
fold.restore_foldmethod()
|
||||
else
|
||||
local orphans = util.get_aerial_orphans()
|
||||
if orphans[1] then
|
||||
-- open our symbols in that window
|
||||
vim.defer_fn(function()
|
||||
window.open(false, nil, { winid = orphans[1] })
|
||||
end, 5)
|
||||
else
|
||||
vim.defer_fn(function()
|
||||
window.maybe_open_automatic()
|
||||
end, 5)
|
||||
end
|
||||
fold.maybe_set_foldmethod()
|
||||
end
|
||||
|
||||
if not window.is_open() then
|
||||
maybe_open_automatic()
|
||||
end
|
||||
end, { delay = 10, reset_timer_on_call = true })
|
||||
|
||||
|
|
|
@ -41,6 +41,26 @@ M.is_supported = function(bufnr, name)
|
|||
end
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@return string[]
|
||||
M.get_status_lines = function(bufnr)
|
||||
local ret = {}
|
||||
for _, name in ipairs(config.backends(bufnr)) do
|
||||
local line = " " .. name
|
||||
local supported, err = M.is_supported(bufnr, name)
|
||||
if supported then
|
||||
line = line .. " (supported)"
|
||||
else
|
||||
line = line .. " (not supported) [" .. err .. "]"
|
||||
end
|
||||
if M.is_backend_attached(bufnr, name) then
|
||||
line = line .. " (attached)"
|
||||
end
|
||||
table.insert(ret, line)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param bufnr? integer
|
||||
---@return aerial.Backend?
|
||||
---@return string?
|
||||
|
@ -58,13 +78,13 @@ local function get_best_backend(bufnr)
|
|||
return nil, nil
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@param backend string
|
||||
local function set_backend(bufnr, backend)
|
||||
vim.api.nvim_buf_set_var(bufnr, "aerial_backend", backend)
|
||||
vim.api.nvim_buf_set_var(bufnr or 0, "aerial_backend", backend)
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@param backend? aerial.Backend
|
||||
---@param name? string
|
||||
---@param existing_backend_name? string
|
||||
|
@ -82,27 +102,32 @@ local function attach(bufnr, backend, name, existing_backend_name)
|
|||
else
|
||||
require("aerial.autocommands").attach_autocommands(bufnr)
|
||||
require("aerial.fold").add_fold_mappings(bufnr)
|
||||
local data = require("aerial.data")
|
||||
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))
|
||||
end
|
||||
if not existing_backend_name and config.on_attach then
|
||||
config.on_attach(bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@return aerial.Backend?
|
||||
M.get = function(bufnr)
|
||||
local existing_backend_name = M.get_attached_backend(bufnr)
|
||||
if existing_backend_name then
|
||||
return M.get_backend_by_name(existing_backend_name)
|
||||
return M.get_backend_by_name(existing_backend_name), existing_backend_name
|
||||
end
|
||||
local backend, name = get_best_backend(bufnr)
|
||||
if backend and name then
|
||||
attach(bufnr, backend, name, existing_backend_name)
|
||||
end
|
||||
return backend
|
||||
return backend, name
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@param items aerial.Symbol[]
|
||||
M.set_symbols = function(bufnr, items)
|
||||
if not bufnr or bufnr == 0 then
|
||||
|
@ -127,7 +152,12 @@ M.set_symbols = function(bufnr, items)
|
|||
if not had_symbols then
|
||||
fold.maybe_set_foldmethod(bufnr)
|
||||
if bufnr == vim.api.nvim_get_current_buf() then
|
||||
window.maybe_open_automatic(bufnr)
|
||||
-- When switching buffers, this can complete before the BufEnter autocmd since it's throttled.
|
||||
-- We need that autocmd to complete first so that it reallocates the existing aerial windows,
|
||||
-- thus the defer. It's a bit of a hack :/
|
||||
vim.defer_fn(function()
|
||||
window.maybe_open_automatic(bufnr)
|
||||
end, 15)
|
||||
end
|
||||
if config.on_first_symbols then
|
||||
config.on_first_symbols(bufnr)
|
||||
|
@ -139,7 +169,7 @@ M.log_support_err = function()
|
|||
vim.api.nvim_err_writeln("Aerial could find no supported backend")
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@param backend string
|
||||
---@return boolean?
|
||||
M.is_backend_attached = function(bufnr, backend)
|
||||
|
@ -147,14 +177,14 @@ M.is_backend_attached = function(bufnr, backend)
|
|||
return b and (b == backend or backend == nil)
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@return string?
|
||||
M.get_attached_backend = function(bufnr)
|
||||
local ok, val = pcall(vim.api.nvim_buf_get_var, bufnr or 0, "aerial_backend")
|
||||
return ok and val or nil
|
||||
end
|
||||
|
||||
---@param bufnr integer
|
||||
---@param bufnr? integer
|
||||
---@param refresh? boolean
|
||||
M.attach = function(bufnr, refresh)
|
||||
if refresh then
|
||||
|
|
|
@ -12,26 +12,29 @@ local default_options = {
|
|||
width = nil,
|
||||
min_width = 10,
|
||||
|
||||
-- Enum: prefer_right, prefer_left, right, left, float
|
||||
-- Determines the default direction to open the aerial window. The 'prefer'
|
||||
-- options will open the window in the other direction *if* there is a
|
||||
-- different buffer in the way of the preferred direction
|
||||
-- Enum: prefer_right, prefer_left, right, left, float
|
||||
default_direction = "prefer_right",
|
||||
|
||||
-- Enum: edge, group, window
|
||||
-- Determines where the aerial window will be opened
|
||||
-- edge - open aerial at the far right/left of the editor
|
||||
-- group - open aerial to the right/left of the group of windows containing the current buffer
|
||||
-- window - open aerial to the right/left of the current window
|
||||
placement = "window",
|
||||
},
|
||||
|
||||
-- Enum: persist, close, auto, global
|
||||
-- persist - aerial window will stay open until closed
|
||||
-- close - aerial window will close when original file is no longer visible
|
||||
-- auto - aerial window will stay open as long as there is a visible
|
||||
-- buffer to attach to
|
||||
-- global - same as 'persist', and will always show symbols for the current buffer
|
||||
close_behavior = "auto",
|
||||
-- Determines how the aerial window decides which buffer to display symbols for
|
||||
-- window - aerial window will display symbols for the buffer in the window from which it was opened
|
||||
-- global - aerial window will display symbols for the current window
|
||||
attach_mode = "window",
|
||||
|
||||
-- List of enum values that configure when to auto-close the aerial window
|
||||
-- unfocus - close aerial when you leave the original source window
|
||||
-- switch_buffer - close aerial when you change buffers in the source window
|
||||
-- unsupported - close aerial when attaching to a buffer that has no symbol source
|
||||
close_automatic_events = {},
|
||||
|
||||
-- Set to false to remove the default keybindings for the aerial buffer
|
||||
default_bindings = true,
|
||||
|
@ -56,7 +59,6 @@ local default_options = {
|
|||
"Struct",
|
||||
},
|
||||
|
||||
-- Enum: split_width, full_width, last, none
|
||||
-- Determines line highlighting mode when multiple splits are visible.
|
||||
-- split_width Each open window will have its cursor location marked in the
|
||||
-- aerial buffer. Each line will only be partially highlighted
|
||||
|
@ -87,7 +89,7 @@ local default_options = {
|
|||
icons = {},
|
||||
|
||||
-- Control which windows and buffers aerial should ignore.
|
||||
-- If close_behavior is "global", focusing an ignored window/buffer will
|
||||
-- If attach_mode is "global", focusing an ignored window/buffer will
|
||||
-- not cause the aerial window to update.
|
||||
-- If open_automatic is true, focusing an ignored window/buffer will not
|
||||
-- cause an aerial window to open.
|
||||
|
@ -181,7 +183,7 @@ local default_options = {
|
|||
-- Controls border appearance. Passed to nvim_open_win
|
||||
border = "rounded",
|
||||
|
||||
-- Enum: cursor, editor, win
|
||||
-- Determines location of floating window
|
||||
-- cursor - Opens float on top of the cursor
|
||||
-- editor - Opens float centered in the editor
|
||||
-- win - Opens float centered in the window
|
||||
|
@ -321,6 +323,28 @@ local function compat_move_option(opts, key, nested_key)
|
|||
end
|
||||
end
|
||||
|
||||
---@param value string
|
||||
---@param values string[]
|
||||
---@param opts? {allow_nil: boolean}
|
||||
local function assert_enum(value, values, opts)
|
||||
opts = opts or {}
|
||||
local valid
|
||||
if value == nil then
|
||||
valid = opts.allow_nil
|
||||
else
|
||||
valid = vim.tbl_contains(values, value)
|
||||
end
|
||||
if valid then
|
||||
return value
|
||||
else
|
||||
vim.notify(
|
||||
string.format("Aerial got '%s', expected one of %s", value, table.concat(values, ", ")),
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
return values[1]
|
||||
end
|
||||
end
|
||||
|
||||
M.setup = function(opts)
|
||||
opts = opts or {}
|
||||
|
||||
|
@ -336,13 +360,54 @@ M.setup = function(opts)
|
|||
end
|
||||
compat_move_option(opts, "placement_editor_edge", "layout")
|
||||
|
||||
if opts.close_behavior then
|
||||
if opts.close_behavior == "global" then
|
||||
opts.attach_mode = "global"
|
||||
elseif opts.close_behavior == "persist" then
|
||||
-- pass
|
||||
elseif opts.close_behavior == "close" then
|
||||
opts.close_automatic_events = { "switch_buffer" }
|
||||
elseif opts.close_behavior == "auto" then
|
||||
opts.close_automatic_events = { "unsupported" }
|
||||
end
|
||||
opts.close_behavior = nil
|
||||
vim.notify(
|
||||
"Deprecated[aerial]: close_behavior is deprecated. See :help aerial-close-behavior",
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
end
|
||||
|
||||
local newconf = vim.tbl_deep_extend("force", default_options, opts)
|
||||
|
||||
-- Asserts for all enum values
|
||||
newconf.layout.default_direction = assert_enum(
|
||||
newconf.layout.default_direction,
|
||||
{ "prefer_right", "prefer_left", "right", "left", "float" }
|
||||
)
|
||||
newconf.layout.placement = assert_enum(newconf.layout.placement, { "window", "edge", "group" })
|
||||
newconf.attach_mode = assert_enum(newconf.attach_mode, { "window", "global" })
|
||||
for i, v in ipairs(newconf.close_automatic_events) do
|
||||
newconf.close_automatic_events[i] =
|
||||
assert_enum(v, { "unfocus", "switch_buffer", "unsupported" })
|
||||
end
|
||||
newconf.highlight_mode =
|
||||
assert_enum(newconf.highlight_mode, { "split_width", "full_width", "last", "none" })
|
||||
|
||||
if newconf.auto_close ~= "persist" and newconf.auto_attach == "global" then
|
||||
newconf.auto_close = "persist"
|
||||
end
|
||||
|
||||
if newconf.nerd_font == "auto" then
|
||||
local has_devicons = pcall(require, "nvim-web-devicons")
|
||||
local has_lspkind = pcall(require, "lspkind")
|
||||
newconf.nerd_font = has_devicons or has_lspkind
|
||||
end
|
||||
|
||||
-- Add lookup to close_automatic_events
|
||||
for i, v in ipairs(newconf.close_automatic_events) do
|
||||
newconf.close_automatic_events[v] = i
|
||||
end
|
||||
|
||||
-- Undocumented use_lspkind option for tests. End users can simply provide
|
||||
-- their own icons
|
||||
if newconf.use_lspkind == nil then
|
||||
|
|
|
@ -20,7 +20,7 @@ M.setup = function(opts)
|
|||
vim.cmd([[
|
||||
aug AerialEnterBuffer
|
||||
au!
|
||||
au BufEnter * lua require'aerial.autocommands'.on_enter_buffer()
|
||||
au WinEnter,BufEnter * lua require'aerial.autocommands'.on_enter_buffer()
|
||||
aug END
|
||||
]])
|
||||
command.create_commands()
|
||||
|
@ -285,22 +285,13 @@ end
|
|||
|
||||
---Print out debug information for aerial
|
||||
M.info = function()
|
||||
local filetype = vim.api.nvim_buf_get_option(0, "filetype")
|
||||
local bufnr = util.get_buffers(0)
|
||||
local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype")
|
||||
print("Aerial Info")
|
||||
print("-----------")
|
||||
print(string.format("Filetype: %s", filetype))
|
||||
print("Configured backends:")
|
||||
for _, name in ipairs(config.backends(0)) do
|
||||
local line = " " .. name
|
||||
local supported, err = backends.is_supported(0, name)
|
||||
if supported then
|
||||
line = line .. " (supported)"
|
||||
else
|
||||
line = line .. " (not supported) [" .. err .. "]"
|
||||
end
|
||||
if backends.is_backend_attached(0, name) then
|
||||
line = line .. " (attached)"
|
||||
end
|
||||
for _, line in ipairs(backends.get_status_lines(bufnr)) do
|
||||
print(line)
|
||||
end
|
||||
print(string.format("Show symbols: %s", config.get_filter_kind_map()))
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
local backends = require("aerial.backends")
|
||||
local config = require("aerial.config")
|
||||
local data = require("aerial.data")
|
||||
local layout = require("aerial.layout")
|
||||
|
@ -74,8 +75,13 @@ M.update_aerial_buffer = function(buf)
|
|||
end
|
||||
if not data:has_symbols(bufnr) then
|
||||
local lines = { "No symbols" }
|
||||
if config.lsp.filter_kind ~= false then
|
||||
table.insert(lines, ":help aerial-filter")
|
||||
if backends.get(bufnr) then
|
||||
if config.lsp.filter_kind ~= false then
|
||||
table.insert(lines, ":help aerial-filter")
|
||||
end
|
||||
else
|
||||
table.insert(lines, "")
|
||||
vim.list_extend(lines, backends.get_status_lines(bufnr))
|
||||
end
|
||||
resize_all_wins(aer_bufnr)
|
||||
util.render_centered_text(aer_bufnr, lines)
|
||||
|
|
|
@ -61,17 +61,6 @@ M.go_buf_no_au = function(bufnr)
|
|||
vim.cmd(string.format("noau b %d", bufnr))
|
||||
end
|
||||
|
||||
M.get_aerial_orphans = function()
|
||||
local orphans = {}
|
||||
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
local winbuf = vim.api.nvim_win_get_buf(winid)
|
||||
if M.is_aerial_buffer(winbuf) and M.is_aerial_buffer_orphaned(winbuf) then
|
||||
table.insert(orphans, winid)
|
||||
end
|
||||
end
|
||||
return orphans
|
||||
end
|
||||
|
||||
M.buf_first_win_in_tabpage = function(bufnr)
|
||||
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
if vim.api.nvim_win_get_buf(winid) == bufnr then
|
||||
|
@ -80,24 +69,41 @@ M.buf_first_win_in_tabpage = function(bufnr)
|
|||
end
|
||||
end
|
||||
|
||||
M.is_aerial_buffer_orphaned = function(bufnr)
|
||||
local sourcebuf = M.get_source_buffer(bufnr)
|
||||
if sourcebuf == -1 then
|
||||
return true
|
||||
---@param winid? integer
|
||||
---@return integer? Source window
|
||||
---@return integer? Aerial window
|
||||
M.get_winids = function(winid)
|
||||
if winid == nil or winid == 0 then
|
||||
winid = vim.api.nvim_get_current_win()
|
||||
end
|
||||
if config.close_behavior == "global" and not M.is_aerial_buffer() then
|
||||
return sourcebuf ~= vim.api.nvim_get_current_buf()
|
||||
local bufnr = vim.api.nvim_win_get_buf(winid)
|
||||
if M.is_aerial_buffer(bufnr) then
|
||||
return M.get_source_win(winid), winid
|
||||
else
|
||||
return winid, M.get_aerial_win(winid)
|
||||
end
|
||||
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
if vim.api.nvim_win_get_buf(winid) == sourcebuf then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
M.get_aerial_buffer = function(bufnr)
|
||||
return M.get_buffer_from_var(bufnr or 0, "aerial_buffer")
|
||||
---@param winid integer
|
||||
---@param varname string
|
||||
---@return integer?
|
||||
M.get_winid_from_var = function(winid, varname)
|
||||
local status, result_winid = pcall(vim.api.nvim_win_get_var, winid, varname)
|
||||
if status and result_winid ~= nil and vim.api.nvim_win_is_valid(result_winid) then
|
||||
return result_winid
|
||||
end
|
||||
end
|
||||
|
||||
---@param winid? integer
|
||||
---@return integer?
|
||||
M.get_aerial_win = function(winid)
|
||||
return M.get_winid_from_var(winid or 0, "aerial_win")
|
||||
end
|
||||
|
||||
---@param winid? integer
|
||||
---@return integer?
|
||||
M.get_source_win = function(winid)
|
||||
return M.get_winid_from_var(winid or 0, "source_win")
|
||||
end
|
||||
|
||||
M.get_buffers = function(bufnr)
|
||||
|
@ -111,6 +117,10 @@ M.get_buffers = function(bufnr)
|
|||
end
|
||||
end
|
||||
|
||||
M.get_aerial_buffer = function(bufnr)
|
||||
return M.get_buffer_from_var(bufnr or 0, "aerial_buffer")
|
||||
end
|
||||
|
||||
M.get_source_buffer = function(bufnr)
|
||||
return M.get_buffer_from_var(bufnr or 0, "source_buffer")
|
||||
end
|
||||
|
@ -239,6 +249,8 @@ M.detect_split_direction = function(bufnr)
|
|||
if not bufnr or bufnr == 0 then
|
||||
bufnr = vim.api.nvim_get_current_buf()
|
||||
end
|
||||
-- TODO make this smarter by accounting for placement = 'group' vs placement = 'window'
|
||||
-- and also using winlayout()
|
||||
left_available = vim.api.nvim_win_get_buf(wins[1]) == bufnr
|
||||
right_available = vim.api.nvim_win_get_buf(wins[#wins]) == bufnr
|
||||
end
|
||||
|
|
|
@ -3,16 +3,16 @@ local bindings = require("aerial.bindings")
|
|||
local config = require("aerial.config")
|
||||
local data = require("aerial.data")
|
||||
local layout = require("aerial.layout")
|
||||
local loading = require("aerial.loading")
|
||||
local render = require("aerial.render")
|
||||
local util = require("aerial.util")
|
||||
|
||||
local api = vim.api
|
||||
|
||||
local M = {}
|
||||
|
||||
local function create_aerial_buffer(bufnr)
|
||||
local aer_bufnr = api.nvim_create_buf(false, true)
|
||||
if bufnr == 0 then
|
||||
bufnr = vim.api.nvim_get_current_buf()
|
||||
end
|
||||
local aer_bufnr = vim.api.nvim_create_buf(false, true)
|
||||
|
||||
if config.default_bindings then
|
||||
for _, binding in ipairs(bindings.keys) do
|
||||
|
@ -21,41 +21,62 @@ local function create_aerial_buffer(bufnr)
|
|||
keys = { keys }
|
||||
end
|
||||
for _, key in ipairs(keys) do
|
||||
api.nvim_buf_set_keymap(aer_bufnr, "n", key, command, { silent = true, noremap = true })
|
||||
vim.api.nvim_buf_set_keymap(aer_bufnr, "n", key, command, { silent = true, noremap = true })
|
||||
end
|
||||
end
|
||||
end
|
||||
api.nvim_buf_set_var(bufnr, "aerial_buffer", aer_bufnr)
|
||||
vim.api.nvim_buf_set_var(bufnr, "aerial_buffer", aer_bufnr)
|
||||
-- Set buffer options
|
||||
api.nvim_buf_set_var(aer_bufnr, "source_buffer", bufnr)
|
||||
loading.set_loading(aer_bufnr, not data:has_received_data(bufnr))
|
||||
api.nvim_buf_set_option(aer_bufnr, "buftype", "nofile")
|
||||
api.nvim_buf_set_option(aer_bufnr, "bufhidden", "wipe")
|
||||
api.nvim_buf_set_option(aer_bufnr, "buflisted", false)
|
||||
api.nvim_buf_set_option(aer_bufnr, "swapfile", false)
|
||||
api.nvim_buf_set_option(aer_bufnr, "modifiable", false)
|
||||
vim.api.nvim_buf_set_var(aer_bufnr, "source_buffer", bufnr)
|
||||
vim.api.nvim_buf_set_option(aer_bufnr, "buftype", "nofile")
|
||||
vim.api.nvim_buf_set_option(aer_bufnr, "bufhidden", "wipe")
|
||||
vim.api.nvim_buf_set_option(aer_bufnr, "buflisted", false)
|
||||
vim.api.nvim_buf_set_option(aer_bufnr, "swapfile", false)
|
||||
vim.api.nvim_buf_set_option(aer_bufnr, "modifiable", false)
|
||||
-- Set the filetype only after we enter the buffer so that ftplugins behave properly
|
||||
vim.api.nvim_buf_call(aer_bufnr, function()
|
||||
vim.api.nvim_buf_set_option(aer_bufnr, "filetype", "aerial")
|
||||
end)
|
||||
-- We create an autocmd to render the first time this buffer is displayed in a window
|
||||
vim.cmd(string.format(
|
||||
[[
|
||||
au CursorMoved <buffer=%d> lua require('aerial.autocommands').on_cursor_move(true)
|
||||
au BufLeave <buffer=%d> lua require('aerial.autocommands').on_leave_aerial_buf()
|
||||
au BufWinEnter <buffer=%d> ++nested ++once lua require('aerial.render').update_aerial_buffer(%d)
|
||||
]],
|
||||
aer_bufnr,
|
||||
aer_bufnr,
|
||||
aer_bufnr,
|
||||
aer_bufnr
|
||||
))
|
||||
return aer_bufnr
|
||||
end
|
||||
|
||||
---@param src_winid integer
|
||||
---@param aer_winid integer
|
||||
local function setup_aerial_win(src_winid, aer_winid)
|
||||
if src_winid == 0 then
|
||||
src_winid = vim.api.nvim_get_current_win()
|
||||
end
|
||||
if aer_winid == 0 then
|
||||
aer_winid = vim.api.nvim_get_current_win()
|
||||
end
|
||||
vim.api.nvim_win_set_option(aer_winid, "listchars", "tab:> ")
|
||||
vim.api.nvim_win_set_option(aer_winid, "winfixwidth", true)
|
||||
vim.api.nvim_win_set_option(aer_winid, "number", false)
|
||||
vim.api.nvim_win_set_option(aer_winid, "signcolumn", "no")
|
||||
vim.api.nvim_win_set_option(aer_winid, "foldcolumn", "0")
|
||||
vim.api.nvim_win_set_option(aer_winid, "relativenumber", false)
|
||||
vim.api.nvim_win_set_option(aer_winid, "wrap", false)
|
||||
vim.api.nvim_win_set_option(aer_winid, "spell", false)
|
||||
vim.api.nvim_win_set_var(aer_winid, "is_aerial_win", true)
|
||||
|
||||
vim.api.nvim_win_set_var(aer_winid, "source_win", src_winid)
|
||||
vim.api.nvim_win_set_var(src_winid, "aerial_win", aer_winid)
|
||||
util.restore_width(aer_winid)
|
||||
end
|
||||
|
||||
local function create_aerial_window(bufnr, aer_bufnr, direction, existing_win)
|
||||
-- We used to use < and > to indicate direction.
|
||||
-- TODO: remove these at some point
|
||||
if direction == "<" then
|
||||
direction = "left"
|
||||
vim.notify("Invalid aerial direction '<'. Use 'left'", vim.log.levels.WARN)
|
||||
end
|
||||
if direction == ">" then
|
||||
vim.notify("Invalid aerial direction '>'. Use 'right'", vim.log.levels.WARN)
|
||||
direction = "right"
|
||||
end
|
||||
if direction ~= "left" and direction ~= "right" and direction ~= "float" then
|
||||
error("Expected direction to be 'left', 'right', or 'float'")
|
||||
return
|
||||
|
@ -65,7 +86,8 @@ local function create_aerial_window(bufnr, aer_bufnr, direction, existing_win)
|
|||
aer_bufnr = create_aerial_buffer(bufnr)
|
||||
end
|
||||
|
||||
local my_winid = api.nvim_get_current_win()
|
||||
local my_winid = vim.api.nvim_get_current_win()
|
||||
local aer_winid
|
||||
if not existing_win then
|
||||
if direction == "float" then
|
||||
local rel = config.float.relative
|
||||
|
@ -87,10 +109,10 @@ local function create_aerial_window(bufnr, aer_bufnr, direction, existing_win)
|
|||
win_config.win = vim.api.nvim_get_current_win()
|
||||
end
|
||||
local new_config = config.float.override(win_config) or win_config
|
||||
local winid = vim.api.nvim_open_win(aer_bufnr, true, new_config)
|
||||
aer_winid = vim.api.nvim_open_win(aer_bufnr, false, new_config)
|
||||
-- We store this as a window variable because relative=cursor gets
|
||||
-- turned into relative=win when checking nvim_win_get_config()
|
||||
vim.api.nvim_win_set_var(winid, "relative", new_config.relative)
|
||||
vim.api.nvim_win_set_var(aer_winid, "relative", new_config.relative)
|
||||
else
|
||||
local modifier
|
||||
if config.layout.placement == "edge" then
|
||||
|
@ -111,39 +133,44 @@ local function create_aerial_window(bufnr, aer_bufnr, direction, existing_win)
|
|||
modifier = direction == "left" and "leftabove" or "rightbelow"
|
||||
end
|
||||
vim.cmd(string.format("noau vertical %s split", modifier))
|
||||
aer_winid = vim.api.nvim_get_current_win()
|
||||
util.go_win_no_au(my_winid)
|
||||
end
|
||||
else
|
||||
util.go_win_no_au(existing_win)
|
||||
aer_winid = existing_win
|
||||
end
|
||||
|
||||
util.go_buf_no_au(aer_bufnr)
|
||||
api.nvim_win_set_option(0, "listchars", "tab:> ")
|
||||
api.nvim_win_set_option(0, "winfixwidth", true)
|
||||
api.nvim_win_set_option(0, "number", false)
|
||||
api.nvim_win_set_option(0, "signcolumn", "no")
|
||||
api.nvim_win_set_option(0, "foldcolumn", "0")
|
||||
api.nvim_win_set_option(0, "relativenumber", false)
|
||||
api.nvim_win_set_option(0, "wrap", false)
|
||||
api.nvim_win_set_option(0, "spell", false)
|
||||
api.nvim_win_set_var(0, "is_aerial_win", true)
|
||||
-- Set the filetype only after we enter the buffer so that FileType autocmds
|
||||
-- behave properly
|
||||
api.nvim_buf_set_option(aer_bufnr, "filetype", "aerial")
|
||||
vim.api.nvim_win_set_buf(aer_winid, aer_bufnr)
|
||||
|
||||
local aer_winid = api.nvim_get_current_win()
|
||||
util.go_win_no_au(my_winid)
|
||||
render.update_aerial_buffer(aer_bufnr)
|
||||
setup_aerial_win(my_winid, aer_winid)
|
||||
return aer_winid
|
||||
end
|
||||
|
||||
M.is_open = function(bufnr)
|
||||
local aer_bufnr = util.get_aerial_buffer(bufnr)
|
||||
---@param src_bufnr integer source buffer
|
||||
---@param src_winid integer window containing source buffer
|
||||
---@param aer_winid integer aerial window
|
||||
M.open_aerial_in_win = function(src_bufnr, src_winid, aer_winid)
|
||||
local aer_bufnr = util.get_aerial_buffer(src_bufnr)
|
||||
if aer_bufnr == -1 then
|
||||
return false
|
||||
else
|
||||
local winid = util.buf_first_win_in_tabpage(aer_bufnr)
|
||||
return winid ~= nil
|
||||
aer_bufnr = create_aerial_buffer(src_bufnr)
|
||||
end
|
||||
vim.api.nvim_win_set_buf(aer_winid, aer_bufnr)
|
||||
setup_aerial_win(src_winid, aer_winid)
|
||||
end
|
||||
|
||||
---@param bufnr? integer
|
||||
---@return integer|nil
|
||||
M.get_aerial_win = function(bufnr)
|
||||
local aer_bufnr = util.get_aerial_buffer(bufnr)
|
||||
if aer_bufnr ~= -1 then
|
||||
return util.buf_first_win_in_tabpage(aer_bufnr)
|
||||
end
|
||||
end
|
||||
|
||||
---@param bufnr? integer
|
||||
---@return boolean
|
||||
M.is_open = function(bufnr)
|
||||
return M.get_aerial_win(bufnr) ~= nil
|
||||
end
|
||||
|
||||
M.close = function()
|
||||
|
@ -192,14 +219,11 @@ M.close_all_but_current = function()
|
|||
end
|
||||
end
|
||||
|
||||
---@param bufnr? integer
|
||||
---@return boolean
|
||||
M.maybe_open_automatic = function(bufnr)
|
||||
if config.open_automatic(bufnr or 0) then
|
||||
local opts = {}
|
||||
local orphans = util.get_aerial_orphans()
|
||||
if orphans[1] then
|
||||
opts.winid = orphans[1]
|
||||
end
|
||||
M.open(false, nil, opts)
|
||||
M.open(false)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
|
@ -216,10 +240,10 @@ M.open = function(focus, direction, opts)
|
|||
return
|
||||
end
|
||||
local bufnr, aer_bufnr = util.get_buffers()
|
||||
if M.is_open() then
|
||||
local aerial_win = M.get_aerial_win(bufnr)
|
||||
if aerial_win then
|
||||
if focus then
|
||||
local winid = util.buf_first_win_in_tabpage(aer_bufnr)
|
||||
api.nvim_set_current_win(winid)
|
||||
vim.api.nvim_set_current_win(aerial_win)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
@ -228,15 +252,15 @@ M.open = function(focus, direction, opts)
|
|||
if not data:has_symbols(bufnr) then
|
||||
backend.fetch_symbols(bufnr)
|
||||
end
|
||||
local my_winid = api.nvim_get_current_win()
|
||||
local my_winid = vim.api.nvim_get_current_win()
|
||||
M.update_position(nil, my_winid)
|
||||
if focus then
|
||||
api.nvim_set_current_win(aer_winid)
|
||||
vim.api.nvim_set_current_win(aer_winid)
|
||||
end
|
||||
end
|
||||
|
||||
M.open_all = function()
|
||||
if config.close_behavior == "global" then
|
||||
if config.attach_mode == "global" then
|
||||
return M.open()
|
||||
end
|
||||
for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do
|
||||
|
@ -252,10 +276,10 @@ M.focus = function()
|
|||
if not M.is_open() then
|
||||
return
|
||||
end
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local aer_bufnr = util.get_aerial_buffer(bufnr)
|
||||
local winid = util.buf_first_win_in_tabpage(aer_bufnr)
|
||||
api.nvim_set_current_win(winid)
|
||||
vim.api.nvim_set_current_win(winid)
|
||||
end
|
||||
|
||||
M.toggle = function(focus, direction)
|
||||
|
@ -277,7 +301,7 @@ end
|
|||
---@param winid? integer
|
||||
---@return aerial.CursorPosition
|
||||
M.get_position_in_win = function(bufnr, winid)
|
||||
local cursor = api.nvim_win_get_cursor(winid or 0)
|
||||
local cursor = vim.api.nvim_win_get_cursor(winid or 0)
|
||||
local lnum = cursor[1]
|
||||
local col = cursor[2]
|
||||
local bufdata = data:get_or_create(bufnr)
|
||||
|
@ -367,14 +391,14 @@ M.update_position = function(winids, last_focused_win)
|
|||
return
|
||||
end
|
||||
if winids == nil or winids == 0 then
|
||||
winids = { api.nvim_get_current_win() }
|
||||
winids = { vim.api.nvim_get_current_win() }
|
||||
elseif type(winids) ~= "table" then
|
||||
winids = { winids }
|
||||
end
|
||||
if #winids == 0 then
|
||||
return
|
||||
end
|
||||
local win_bufnr = api.nvim_win_get_buf(winids[1])
|
||||
local win_bufnr = vim.api.nvim_win_get_buf(winids[1])
|
||||
local bufnr, aer_bufnr = util.get_buffers(win_bufnr)
|
||||
if not data:has_symbols(bufnr) then
|
||||
return
|
||||
|
@ -399,13 +423,13 @@ M.update_position = function(winids, last_focused_win)
|
|||
local aer_winid = util.buf_first_win_in_tabpage(aer_bufnr)
|
||||
if aer_winid then
|
||||
local last_position = bufdata.positions[bufdata.last_win]
|
||||
local lines = api.nvim_buf_line_count(aer_bufnr)
|
||||
local lines = vim.api.nvim_buf_line_count(aer_bufnr)
|
||||
|
||||
-- When aerial window is global, the items can change and cursor will move
|
||||
-- before the symbols are published, which causes the line number to be
|
||||
-- invalid.
|
||||
if last_position and lines >= last_position.lnum then
|
||||
api.nvim_win_set_cursor(aer_winid, { last_position.lnum, 0 })
|
||||
vim.api.nvim_win_set_cursor(aer_winid, { last_position.lnum, 0 })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ describe("config", function()
|
|||
|
||||
it("falls back to default options", function()
|
||||
config.setup()
|
||||
assert.equals(config.close_behavior, "auto")
|
||||
assert.equals(config.attach_mode, "window")
|
||||
end)
|
||||
|
||||
-- Filetype maps
|
||||
|
|
Loading…
Reference in a new issue