symbol post process APIs

APIs to allow the user to post-process the symbols detected by aerial.
This commit is contained in:
Emmanuel Touzery 2023-02-14 21:31:52 +01:00
parent 89031be806
commit f5b3619e4b
7 changed files with 176 additions and 20 deletions

View file

@ -372,6 +372,37 @@ require("aerial").setup({
-- Run this command after jumping to a symbol (false will disable)
post_jump_cmd = "normal! zz",
-- Invoked after each symbol is parsed, can be used to modify the parsed item,
-- or to filter it by returning false.
--
-- bufnr: a neovim buffer number
-- item: of type aerial.Symbol
-- ctx: a record containing the following fields:
-- * backend_name: treesitter, lsp, man...
-- * lang: info about the language
-- * symbols?: specific to the lsp backend
-- * symbol?: specific to the lsp backend
-- * syntax_tree?: specific to the treesitter backend
-- * match?: specific to the treesitter backend, TS query match
post_parse_symbol = function(bufnr, item, ctx)
return true
end,
-- Invoked after all symbols have been parsed and post-processed,
-- allows to modify the symbol structure before final display
--
-- bufnr: a neovim buffer number
-- items: a collection of aerial.Symbol items, organized in a tree,
-- with 'parent' and 'children' fields
-- ctx: a record containing the following fields:
-- * backend_name: treesitter, lsp, man...
-- * lang: info about the language
-- * symbols?: specific to the lsp backend
-- * syntax_tree?: specific to the treesitter backend
post_add_all_symbols = function(bufnr, items, ctx)
return items
end,
-- When true, aerial will automatically close after jumping to a symbol
close_on_select = false,
@ -455,6 +486,21 @@ spec](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.
These are the values used for configuring icons, highlight groups, and
filtering.
The `aerial.Symbol` type used in some optional callbacks is:
```typescript
{
kind: SymbolKind,
name: string,
level: number,
parent: aerial.Symbol,
lnum: number,
end_lnum: number,
col: number,
end_col: number
}
```
## Third-party integrations
### Telescope

View file

@ -210,6 +210,37 @@ OPTIONS *aerial-option
-- Run this command after jumping to a symbol (false will disable)
post_jump_cmd = "normal! zz",
-- Invoked after each symbol is parsed, can be used to modify the parsed item,
-- or to filter it by returning false.
--
-- bufnr: a neovim buffer number
-- item: of type aerial.Symbol
-- ctx: a record containing the following fields:
-- * backend_name: treesitter, lsp, man...
-- * lang: info about the language
-- * symbols?: specific to the lsp backend
-- * symbol?: specific to the lsp backend
-- * syntax_tree?: specific to the treesitter backend
-- * match?: specific to the treesitter backend, TS query match
post_parse_symbol = function(bufnr, item, ctx)
return true
end,
-- Invoked after all symbols have been parsed and post-processed,
-- allows to modify the symbol structure before final display
--
-- bufnr: a neovim buffer number
-- items: a collection of aerial.Symbol items, organized in a tree,
-- with 'parent' and 'children' fields
-- ctx: a record containing the following fields:
-- * backend_name: treesitter, lsp, man...
-- * lang: info about the language
-- * symbols?: specific to the lsp backend
-- * syntax_tree?: specific to the treesitter backend
post_add_all_symbols = function(bufnr, items, ctx)
return items
end,
-- When true, aerial will automatically close after jumping to a symbol
close_on_select = false,
@ -616,5 +647,18 @@ Struct
TypeParameter
Variable
The `aerial.Symbol` type used in some optional callbacks is:
{
kind: SymbolKind,
name: string,
level: number,
parent: aerial.Symbol,
lnum: number,
end_lnum: number,
col: number,
end_col: number
}
================================================================================
vim:tw=80:ts=2:ft=help:norl:syntax=help:

View file

@ -144,10 +144,10 @@ M.get = function(bufnr)
return backend, name
end
---@param backend_name string
---@param bufnr? integer
---@param items aerial.Symbol[]
M.set_symbols = function(backend_name, bufnr, items)
---@param context {backend_name: string, lang: string}
M.set_symbols = function(bufnr, items, ctx)
if not bufnr or bufnr == 0 then
bufnr = vim.api.nvim_get_current_buf()
end
@ -161,9 +161,13 @@ M.set_symbols = function(backend_name, bufnr, items)
local util = require("aerial.util")
local window = require("aerial.window")
if config.post_add_all_symbols then
items = config.post_add_all_symbols(bufnr, items, ctx)
end
local had_symbols = data.has_symbols(bufnr)
-- Ignore symbols from non-attached backend IFF we already have symbols
if had_symbols and not M.is_backend_attached(bufnr, backend_name) then
if had_symbols and not M.is_backend_attached(bufnr, ctx.backend_name) then
return
end

View file

@ -39,7 +39,8 @@ end
---@param symbols table
---@param bufnr integer
---@param fix_start_col boolean
local function process_symbols(symbols, bufnr, fix_start_col)
---@param client_name LSP client name
local function process_symbols(symbols, bufnr, fix_start_col, client_name)
local include_kind = config.get_filter_kind_map(bufnr)
local max_line = vim.api.nvim_buf_line_count(bufnr)
local function _process_symbols(symbols_, parent, list, level)
@ -88,7 +89,18 @@ local function process_symbols(symbols, bufnr, fix_start_col)
if symbol.children then
item.children = _process_symbols(symbol.children, item, {}, level + 1)
end
table.insert(list, item)
if
config.post_parse_symbol == nil
or config.post_parse_symbol(bufnr, item, {
backend_name = "lsp",
lang = client_name,
symbols = symbols,
symbol = symbol,
})
~= false
then
table.insert(list, item)
end
elseif symbol.children then
-- If this duplicate symbol has children (unlikely), make sure those get
-- merged into the previous symbol's children
@ -120,8 +132,12 @@ end
M.handle_symbols = function(result, bufnr, client_name)
-- Volar produces some symbols that start off the end of a line. We have to correct that or it
-- causes navigation problems.
local symbols = process_symbols(result, bufnr, client_name == "volar")
backends.set_symbols("lsp", bufnr, symbols)
local symbols = process_symbols(result, bufnr, client_name == "volar", client_name)
backends.set_symbols(
bufnr,
symbols,
{ backend_name = "lsp", symbols = symbols, lang = client_name }
)
end
local function get_error_count(bufnr, client_id)

View file

@ -1,6 +1,7 @@
local backends = require("aerial.backends")
local backend_util = require("aerial.backends.util")
local util = require("aerial.util")
local config = require("aerial.config")
local M = {}
@ -36,8 +37,17 @@ M.fetch_symbols_sync = function(bufnr)
lnum = lnum,
col = 0,
}
last_header = item
table.insert(items, item)
if
config.post_parse_symbol == nil
or config.post_parse_symbol(bufnr, item, {
backend_name = "man",
lang = "man",
})
~= false
then
last_header = item
table.insert(items, item)
end
elseif arg then
local item = {
kind = "Interface",
@ -49,18 +59,27 @@ M.fetch_symbols_sync = function(bufnr)
end_lnum = lnum,
end_col = line:len(),
}
if last_header then
last_header.children = last_header.children or {}
table.insert(last_header.children, item)
else
table.insert(items, item)
if
config.post_parse_symbol == nil
or config.post_parse_symbol(bufnr, item, {
backend_name = "man",
lang = "man",
})
~= false
then
if last_header then
last_header.children = last_header.children or {}
table.insert(last_header.children, item)
else
table.insert(items, item)
end
end
end
prev_lnum = lnum
prev_line = line
end
finalize_header()
backends.set_symbols("man", bufnr, items)
backends.set_symbols(bufnr, items, { backend_name = "man", lang = "man" })
end
M.fetch_symbols = M.fetch_symbols_sync

View file

@ -1,6 +1,7 @@
local backends = require("aerial.backends")
local backend_util = require("aerial.backends.util")
local util = require("aerial.util")
local config = require("aerial.config")
local M = {}
@ -37,7 +38,16 @@ M.fetch_symbols_sync = function(bufnr)
end
table.insert(parent.children, item)
else
table.insert(items, item)
if
config.post_parse_symbol == nil
or config.post_parse_symbol(bufnr, item, {
backend_name = "markdown",
lang = "markdown",
})
~= false
then
table.insert(items, item)
end
end
while #stack > level and #stack > 0 do
table.remove(stack, #stack)
@ -49,7 +59,7 @@ M.fetch_symbols_sync = function(bufnr)
end
-- This sets the proper end_lnum and end_col
extensions.markdown.postprocess_symbols(bufnr, items)
backends.set_symbols("markdown", bufnr, items)
backends.set_symbols(bufnr, items, { backend_name = "markdown", lang = "markdown" })
end
M.fetch_symbols = M.fetch_symbols_sync

View file

@ -45,13 +45,17 @@ M.fetch_symbols_sync = function(bufnr)
local parser = parsers.get_parser(bufnr)
local items = {}
if not parser then
backends.set_symbols("treesitter", bufnr, items)
backends.set_symbols(bufnr, items, { backend_name = "treesitter", lang = "unknown" })
return
end
local lang = parser:lang()
local syntax_tree = parser:parse()[1]
if not query.has_query_files(lang, "aerial") or not syntax_tree then
backends.set_symbols("treesitter", bufnr, items)
backends.set_symbols(
bufnr,
items,
{ backend_name = "treesitter", lang = lang, syntax_tree = syntax_tree }
)
return
end
-- This will track a loose hierarchy of recent node+items.
@ -105,6 +109,15 @@ M.fetch_symbols_sync = function(bufnr)
if ext.postprocess(bufnr, item, match) == false or not include_kind[item.kind] then
goto continue
end
local ctx = {
backend_name = "treesitter",
lang = lang,
syntax_tree = syntax_tree,
match = match,
}
if config.post_parse_symbol and config.post_parse_symbol(bufnr, item, ctx) == false then
goto continue
end
if item.parent then
if not item.parent.children then
item.parent.children = {}
@ -118,7 +131,11 @@ M.fetch_symbols_sync = function(bufnr)
::continue::
end
ext.postprocess_symbols(bufnr, items)
backends.set_symbols("treesitter", bufnr, items)
backends.set_symbols(
bufnr,
items,
{ backend_name = "treesitter", lang = lang, syntax_tree = syntax_tree }
)
end
M.fetch_symbols = M.fetch_symbols_sync