Skip to content

Commit

Permalink
feat: add support for vim help files (#164)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevearc committed Oct 19, 2022
1 parent c248731 commit 817be1d
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 4 deletions.
56 changes: 56 additions & 0 deletions lua/aerial/backends/treesitter/extensions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,62 @@ M.markdown = {
end,
}

M.help = {
_get_level = function(node)
local level_str = node:type():match("^h(%d+)$")
if level_str then
return tonumber(level_str)
else
return 99
end
end,
get_parent = function(stack, match, node)
-- Fix the symbol nesting
local level = M.help._get_level(node)
for i = #stack, 1, -1 do
local last = stack[i]
if M.help._get_level(last.node) < level then
return last.item, last.node, i
else
table.remove(stack, i)
end
end
return nil, nil, 0
end,
postprocess = function(bufnr, item, match)
-- The name node of headers only captures the final node.
-- We need to get _all_ word nodes
local pieces = {}
local node = match.name.node
if vim.startswith(match.type.node:type(), "h") then
while node and node:type() == "word" do
local row, col = node:start()
table.insert(pieces, 1, get_node_text(node, bufnr))
node = node:prev_sibling()
item.lnum = row + 1
item.col = col
end
item.name = table.concat(pieces, " ")
end
end,
postprocess_symbols = function(bufnr, items)
-- Sometimes helpfiles have a bunch of tags at the top in the same line. Collapse them.
while #items > 1 and items[1].lnum == items[2].lnum do
table.remove(items, 2)
end
-- Remove the first tag under a header IF that tag appears on the same line
for _, item in ipairs(items) do
if item.children and item.children[1] then
local child = item.children[1]
if child.lnum == item.lnum then
table.remove(item.children, 1)
end
M.help.postprocess_symbols(bufnr, item.children)
end
end
end,
}

M.rust = {
postprocess = function(bufnr, item, match)
if item.kind == "Class" then
Expand Down
8 changes: 4 additions & 4 deletions lua/aerial/backends/treesitter/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ M.fetch_symbols_sync = function(bufnr)
local ext = extensions[lang]
local kind_map = language_kind_map[lang]
for match in query.iter_group_results(bufnr, "aerial", syntax_tree:root(), lang) do
local name_node = (utils.get_at_path(match, "name") or {}).node
local type_node = (utils.get_at_path(match, "type") or {}).node
local name_node = (match.name or {}).node
local type_node = (match.type or {}).node
-- The location capture groups are optional. We default to the
-- location of the @type capture
local start_node = (utils.get_at_path(match, "start") or {}).node or type_node
local end_node = (utils.get_at_path(match, "end") or {}).node or start_node
local start_node = (match.start or {}).node or type_node
local end_node = (match["end"] or {}).node or start_node
local parent_item, parent_node, level = ext.get_parent(stack, match, type_node)
-- Sometimes our queries will match the same node twice.
-- Detect that (type_node == parent_node), and skip dupes.
Expand Down
5 changes: 5 additions & 0 deletions lua/aerial/backends/treesitter/language_kind_map.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ return {
method_declaration = "Method",
struct_type = "Struct",
},
help = {
h1 = "Interface",
h2 = "Interface",
tag = "Interface",
},
java = {
class_declaration = "Class",
enum_declaration = "Enum",
Expand Down
13 changes: 13 additions & 0 deletions queries/help/aerial.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(h1
(word)+ @name @start
(tag)
) @type

(h2
(word)+ @name @start
(tag)
) @type

(tag
text: (word) @name
) @type
37 changes: 37 additions & 0 deletions tests/treesitter/help_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
local util = require("tests.test_util")

describe("treesitter help", function()
it("parses all symbols correctly", function()
util.test_file_symbols("treesitter", "./tests/treesitter/help_test.txt", {
{
kind = "Interface",
name = "help_test.txt",
level = 0,
lnum = 1,
col = 0,
end_lnum = 1,
end_col = 15,
},
{
kind = "Interface",
name = "TEST INTRO",
level = 0,
lnum = 3,
col = 0,
end_lnum = 3,
end_col = 10,
children = {
{
kind = "Interface",
name = ":SomeCommand",
level = 1,
lnum = 5,
col = 68,
end_lnum = 5,
end_col = 82,
},
},
},
})
end)
end)
9 changes: 9 additions & 0 deletions tests/treesitter/help_test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*help_test.txt* *help_test*
--------------------------------------------------------------------------------
TEST INTRO *test-intro*

SomeCommand *:SomeCommand*
Description of the command

================================================================================
vim:tw=80:ts=2:ft=help:norl:syntax=help:

0 comments on commit 817be1d

Please sign in to comment.