meain / evil-textobj-tree-sitter

Tree-sitter powered textobjects for evil mode in Emacs
Apache License 2.0
197 stars 14 forks source link

Query to get function name from within function body #103

Closed Schievel1 closed 10 months ago

Schievel1 commented 1 year ago

Hi,

I really like this package in emacs and I use it on a daily basis. I wrote a simple custom query which does just return the identifier at point. This way I can yank function names, variable names etc. without caring about parenthesis at the end of them or underscores in them. (Compared to yanking with yiW or yiw) FWIW here's what I got:

(map! :map evil-inner-text-objects-map
      "u" (evil-textobj-tree-sitter-get-textobj "identifier"
                '((c-mode . [(identifier) @identifier ]))))

(Using doom emacs, that is where that map! macro is from. But the query itself is the same)

Now often find myself in the situation where I navigate a file looking for a function to use in may program. When I want to copy that function name to call it, it have to move point into the function name and yank it with yiu. I wondered if it is possible to yank the function name (and maybe with evil-outer-text-objects-map the whole declaration from the functions name to the end of the parameters) when point is only within the function body, not at the function name. I thought maybe to use @function.outer from this repository then get the first identifier from that. But I don't know how. Can you help me out?

Also are there any resources where this query languages is described with some examples? That would be really helpful.

meain commented 1 year ago

Well, this lib might not be the best for this usecase, but you can kinda do it something like this. I have just added it for c as that is the example you had in your original question.

(defun meain/yank-func-name ()
  (interactive)
  (save-excursion
    (evil-textobj-tree-sitter-goto-textobj
     "function.name" t nil
     '((c-ts-mode . "(function_definition (function_declarator declarator: (identifier) @function.name))")))
    (kill-new (thing-at-point 'symbol t))))

You might wanna take a look at my blog around something similar.

As of documentation around this, the tree-sitter documentation is a great place to start. They also have a playground where you can try out things.

Schievel1 commented 1 year ago

Thanks for that playground, I think it is incredibly useful.

This is what I got now thanks to you:

(map! :map evil-inner-text-objects-map
      "u" (evil-textobj-tree-sitter-get-textobj "identifier"
                '((c-mode . [(identifier) @identifier ])))
      "n" (evil-textobj-tree-sitter-get-textobj "function.name"
        '((c-mode . [(function_definition (function_declarator declarator: (identifier) @function.name))]))
)

But this gives me the next match from point. So when I am inside the function body it does not give me the function name of the function point is in but the next function further down. How can I first query for the parent? I was thinking about using the function.outer query and work my way down from there, but I can't figure it out

// oh I just realized thats what you are doing in your function.

Schievel1 commented 1 year ago

Hm I am still trying to grasp whats going on here. Maybe you can give me a notch in the right direction. When I use the query for the function.outer from here and bind it to a key like this:

      "e" (evil-textobj-tree-sitter-get-textobj "function.blubb"
        '((c-mode . [(function_definition body:  (compound_statement)) @function.blubb])))

Emacs is highlighting the the function body and its signature when I press v i e. I wanted to work down from there and try to find the declaration in the compound_statement. Yet the when I do the same query in the playground, it only marks the inner function bodies. This is what I put into the playground as a query:

(function_definition body: (compound_statement)  @function.name)

So why is that? How is the query for function.outer (or function.blubb now) mark the function body of the function point is in and the other ones search downward? Is it because point is already on something the query returns?

meain commented 1 year ago

I'm not sure I completely understand you question, but if I understood correctly, you are able to highlight function definition or the body, but when you try to look for just a name, it goes to the next one and not the one of the function that you are currently in.

Is it because point is already on something the query returns?

You are right about this. The way the plugin works is that if the start is before the cursor and end is after the cursor which would be the case for func definition, it would return the one that it is on. But when looking for names, since we are not already on one, we look for the next available option which would go to the name of the next function.

Schievel1 commented 1 year ago

My question actually is how is it that the playground and emacs return different things for the same query?

The playground highlights the inner function body, whereas emacs return the complete function for function.outer

meain commented 1 year ago

Ahh, that is the difference between where you put the capture name.

In the first one, ie (function_definition body: (compound_statement)) @function.blubb, the capture name @function.blubb is after the second ) which marks the end of function_body and in the second case (function_definition body: (compound_statement) @function.name), @function.name is right after te closing bracket for compound_statement and thus selects the body.

meain commented 10 months ago

Closing the issue, feel free to reopen if you have any more questions.