feat(ts): Add support for elixir

This commit is contained in:
Steven Arcangeli 2022-06-23 08:47:42 -07:00
parent 17773f8e31
commit 897d4bd852
7 changed files with 287 additions and 1 deletions

View file

@ -123,6 +123,7 @@ automatically fetch symbols from treesitter.
- c_sharp
- cpp
- dart
- elixir
- go
- java
- javascript

View file

@ -61,6 +61,40 @@ local function set_end_range(bufnr, items, last_line)
end
end
M.elixir = {
kind_map = {
callback = "Function",
def = "Function",
defguard = "Function",
defimpl = "Class",
defmacro = "Function",
defmacrop = "Function",
defmodule = "Module",
defp = "Function",
defprotocol = "Interface",
defstruct = "Struct",
module_attribute = "Field",
spec = "TypeParameter",
},
postprocess = function(bufnr, item, match)
local identifier = (utils.get_at_path(match, "identifier") or {}).node
if identifier then
local name = get_node_text(identifier, bufnr) or "<parse error>"
item.kind = M.elixir.kind_map[name] or item.kind
if name == "callback" and item.parent then
item.parent.kind = "Interface"
elseif name == "defstruct" and item.parent then
item.parent.kind = "Struct"
return false
elseif name == "defimpl" then
local protocol = (utils.get_at_path(match, "protocol") or {}).node
local protocol_name = get_node_text(protocol, bufnr) or "<parse error>"
item.name = string.format("%s > %s", item.name, protocol_name)
end
end
end,
}
M.markdown = {
get_parent = function(stack, match, node)
local level_node = (utils.get_at_path(match, "level") or {}).node

View file

@ -100,7 +100,9 @@ M.fetch_symbols_sync = function(bufnr)
col = col,
end_col = end_col,
}
ext.postprocess(bufnr, item, match)
if ext.postprocess(bufnr, item, match) == false then
goto continue
end
if item.parent then
if not item.parent.children then
item.parent.children = {}

View file

@ -28,6 +28,9 @@ return {
method_signature = "Method",
enum_declaration = "Enum",
},
elixir = {
call = "Function",
},
go = {
function_declaration = "Function",
method_declaration = "Method",

38
queries/elixir/aerial.scm Normal file
View file

@ -0,0 +1,38 @@
(call
target: (identifier) @identifier (#any-of? @identifier "defmodule" "defprotocol")
(arguments) @name) @type
(call
target: (identifier) @identifier (#eq? @identifier "defimpl")
(arguments
(alias) @protocol
(keywords (pair
key: (keyword) @kw (#match? @kw "^for:")
value: (alias) @name))
)) @type
(call
target: (identifier) @identifier (#any-of? @identifier "def" "defp" "defguard" "defmacro" "defmacrop")
(arguments [
(call target: (identifier) @name)
(binary_operator left: (call target: (identifier) @name))
])) @type
(unary_operator
operand: (call
target: (identifier) @identifier (#any-of? @identifier "callback" "spec")
(arguments [
(call target: (identifier) @name)
(binary_operator left: (call target: (identifier) @name))
])) @type) @start
(unary_operator
operand: (call
target: (identifier) @identifier (#eq? @identifier "module_attribute")
(arguments) @name
) @type
) @start
(do_block
(call
target: (identifier) @identifier (#eq? @identifier "defstruct")) @type) @start

View file

@ -0,0 +1,169 @@
local util = require("tests.test_util")
describe("treesitter elixir", function()
it("parses all symbols correctly", function()
util.test_file_symbols("treesitter", "./tests/treesitter/elixir_test.exs", {
{
kind = "Module",
name = "Example.Module",
level = 0,
lnum = 1,
col = 0,
end_lnum = 19,
end_col = 3,
children = {
{
kind = "Field",
name = ":value",
level = 1,
lnum = 2,
col = 2,
end_lnum = 2,
end_col = 26,
},
{
kind = "Function",
name = "public_function",
level = 1,
lnum = 4,
col = 2,
end_lnum = 5,
end_col = 5,
},
{
kind = "Function",
name = "private_function",
level = 1,
lnum = 7,
col = 2,
end_lnum = 8,
end_col = 5,
},
{
kind = "Function",
name = "public_guard",
level = 1,
lnum = 10,
col = 2,
end_lnum = 10,
end_col = 42,
},
{
kind = "Function",
name = "private_guard",
level = 1,
lnum = 12,
col = 2,
end_lnum = 12,
end_col = 43,
},
{
kind = "Function",
name = "public_macro",
level = 1,
lnum = 14,
col = 2,
end_lnum = 15,
end_col = 5,
},
{
kind = "Function",
name = "private_macro",
level = 1,
lnum = 17,
col = 2,
end_lnum = 18,
end_col = 5,
},
},
},
{
kind = "Interface",
name = "Example.Behaviour",
level = 0,
lnum = 21,
col = 0,
end_lnum = 23,
end_col = 3,
children = {
{
kind = "Function",
name = "example_function",
level = 1,
lnum = 22,
col = 2,
end_lnum = 22,
end_col = 46,
},
},
},
{
kind = "Struct",
name = "Example.Struct",
level = 0,
lnum = 25,
col = 0,
end_lnum = 27,
end_col = 3,
},
{
kind = "Interface",
name = "Example.Protocol",
level = 0,
lnum = 29,
col = 0,
end_lnum = 32,
end_col = 3,
children = {
{
kind = "TypeParameter",
name = "public_function_head",
level = 1,
lnum = 30,
col = 2,
end_lnum = 30,
end_col = 50,
},
{
kind = "Function",
name = "public_function_head",
level = 1,
lnum = 31,
col = 2,
end_lnum = 31,
end_col = 39,
},
},
},
{
kind = "Class",
name = "Map > Example.Protocol",
level = 0,
lnum = 34,
col = 0,
end_lnum = 39,
end_col = 3,
children = {
{
kind = "TypeParameter",
name = "public_function_head",
level = 1,
lnum = 35,
col = 2,
end_lnum = 35,
end_col = 56,
},
{
kind = "Function",
name = "public_function_head",
level = 1,
lnum = 36,
col = 2,
end_lnum = 38,
end_col = 5,
},
},
},
})
end)
end)

View file

@ -0,0 +1,39 @@
defmodule Example.Module do
@module_attribute :value
def public_function() do
end
defp private_function() do
end
defguard public_guard(x) when is_atom(x)
defguard private_guard(x) when is_atom(x)
defmacro public_macro() do
end
defmacrop private_macro() do
end
end
defmodule Example.Behaviour do
@callback example_function(atom()) :: atom()
end
defmodule Example.Struct do
defstruct name: nil, age: nil
end
defprotocol Example.Protocol do
@spec public_function_head(t, atom()) :: boolean
def public_function_head(target, opt)
end
defimpl Example.Protocol, for: Map do
@spec public_function_head(Map.t(), atom()) :: boolean
def public_function_head(target, opt) do
true
end
end