nvim-treesitter / nvim-treesitter-textobjects

Apache License 2.0
2.11k stars 190 forks source link

Question: How to write a query for comment + function #481

Open quantumfate opened 1 year ago

quantumfate commented 1 year ago

I've read through the docs on how to write TS queries but I just can't make it work. I'm trying to write a query for lua where it captures a luadoc followed by a function:

---test comment 5
---@param bool any
function M.test5(bool)
    -- oeu
    print("test5", bool)
end

These were my attempts:

(
  (comment) @comment.outer
  (function_declaration) @function.outer
    (comment) @comment.outer
    .
    (function_declaration) @function.outer) @function_context

what I kind of undestood is that by grouping comment and function within () you declare a capture group and the . means that a comment is a direct sibling to the function declaration.

Im using the query with the swap feature:

swap = {
            enable = true,
            swap_next = {
                ["<leader>spn"] = "@parameter.inner",
                ["<leader>sfn"] = {
                    query = { "@function_context" },
                    query_group = "context",
                },
            },
            swap_previous = {
                ["<leader>spp"] = "@parameter.inner",
                ["<leader>sfp"] = {
                    query = { "@function_context" },
                    query_group = "context",
                },
            },
        },

but whatever I do it just either swaps the functions without the comments or with different attempts it would swap the first function with one of the comments above the second function.

---test comment 5
---@param bool any
function M.test5(bool)
    -- oeu
    print("test5", bool)
end

---test comment 4
---@param num any
---@param str any
function M.test4(num, str)
    print("test4", num, str)
end

I did not mark this issue as a bug because there probably is a way to swap functions together with their comments. I appreciate any help or advise that I can get and maybe this could be a feature?

quantumfate commented 1 year ago

the following query should capture my code but I noticed the issue is within the swap operation as it only swaps with directly adjacent nodes and it's not fully aware of the whole context.

(
  (_) @comment.outer
  .
  (_) @function.outer
) @function_context

but when I try to swap test 5 with test 4 it only swaps test 5 with the comment of test 4

this

---@param bool any
function M.test5(bool)
    -- oeu
    print("test5", bool)
end

---@param str any
function M.test4(num, str)
    print("test4", num, str)
end

becomes this:

---@param bool any
---@param str any

function M.test5(bool)
    -- oeu
    print("test5", bool)
end
function M.test4(num, str)
    print("test4", num, str)
end
scanny commented 1 year ago

I don't believe what you're trying to do is possible in Lua, at least with the current Lua Treesitter parser.

Rationale in brief is this:

Btw, I think the query you're looking for is this:

(
  (comment) @comment.outer
  .
  (function_declaration) @function.outer
) @function_context

Trying this in Treesitter Playground (:TSPlaygroundToggle then "o" to open query editor), you can see that assigning a capture (@function_context) to the sequence of nodes is not an error, but it only returns the first node in the sequence, which is the comment in this case.

So I think what you're facing is just a limitation in the Lua language or at least the Lua treesitter parser. If you wanted this bad enough you could write a Lua script/plugin to do it. This YouTube video gives a good idea how that might look and uses Treesitter specifically: https://www.youtube.com/watch?v=IRd2zwF527M