Subject: Re: bug#78703: beginning-of-defun and friends still wrong in typescript-ts-mode

From: Yuan Fu <[email-masked]>
Date: Fri, 6 Jun 2025 23:08:57 -0700

> On Jun 6, 2025, at 10:00 AM, Troy Brown <[email-masked]> wrote:
> 
> Daniel Colascione <[email-masked]> writes:
> 
>> On June 6, 2025 12:23:23 AM PDT, Yuan Fu <[email-masked]> wrote:
>>> 
>>> 
>>>> On Jun 6, 2025, at 12:01 AM, Eli Zaretskii <[email-masked]> wrote:
>>>> 
>>>>> From: Daniel Colascione <[email-masked]>
>>>>> Date: Thu, 05 Jun 2025 16:40:03 -0700
>>>>> 
>>>>> Right now, C-M-a runs treesit-beginning-of-defun which goes to the
>>>>> start of the previous defun in buffer text, not the enclosing defun.
>>>>> 
>>>>> If we have this program:
>>>>> 
>>>>>   1 function foo() {
>>>>>   2   function bar() {
>>>>>   3     return 5
>>>>>   4   }
>>>>>   5   return 7
>>>>>   6 }
>>>>> 
>>>>> 
>>>>> and point is on line 5, then if we hit C-M-a, point goes to line 2, not
>>>>> line 1.  In every single situation, when I use beginning-of-defun, I
>>>>> intend to go to the start of my enclosing defun not the one that happens
>>>>> to be previous in buffer linearization.
>>>> 
>>>> I think you want to set treesit-defun-tactic to 'top-level’.
>>> 
>>> Yes. Most likely top-level is what you want.
>>> 
>>> Yuan
>>> 
>>> 
>> 
>> I don't think that's right either --- if I'm on line 3, I should go to
>> line 2, not 1. Go to beginning of defun should mean go to the
>> beginning of *my* defun. That's the traditional behavior from cc-mode,
>> js-mode, etc. and the one that makes most sense. I can see top-level
>> being an option, but I don't think the way nested works right now is
>> useful and it's confusing and inconsistent as a default.
> 
> I agree.  This behavior is not intuitive at all.  I reported this in
> detail in Bug#68664, but it never seemed to go anywhere.  Furthermore,
> using a `treesit-defun-tactic` of `top-level` doesn't work when you
> are arbitrarily nested and just want to go to the beginning of the
> function containing point.
> 
> This behavior not only impacts interactive use of
> `treesit-beginning-of-defun` (via "C-M-a"), but other functionality
> which builds upon `beginning-of-defun`, most notably
> `prog-fill-reindent-defun`.  For the Tree-sitter modes that I
> maintain, I had to create a mode-specific version of
> `prog-fill-reindent-defun` instead.  That's because, as written,
> `prog-fill-reindent-defun` uses `beginning-of-defun`, and since in
> cases like this, `treesit-beginning-of-defun' goes to the previous
> nested function, rather than the function containing point, you end up
> re-indenting the previous nested function rather than the function
> containing point.  The mode-specific version that I created, instead
> uses `treesit-defun-at-point` to locate the containing function.

So for this tactic, point should move out of the enclosing defun if it is inside a defun; and if point isn’t inside any defun it should move to the previous defund-beginning?

Any suggestions for a good name for this tactic? Right now we have `nested` and `top-level`.

Yuan