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

From: Eli Zaretskii <[email-masked]>
Date: Wed, 11 Jun 2025 16:16:14 +0300

> From: Daniel Colascione <[email-masked]>
> Cc: [email-masked],  [email-masked],  [email-masked]
> Date: Wed, 11 Jun 2025 05:59:28 -0700
> 
> Eli Zaretskii <[email-masked]> writes:
> 
> >> > We still lack some useful
> >> >functionalities that are present in CC Mode, forrea that very reason;
> >> >what was easy to implement was done long ago.
> >> 
> >> That's the opposite of reality. Alan and others have spent years
> >> building a flexible and fast backtracking syntactic analyser for CC
> >> mode. Tree sitter does the same thing but in a more general way, in
> >> native code for better performance. Its availability makes doing
> >> what cc-mode does easier, not harder.
> >
> > We expected that, yes.  The reality disappointed us to some extent.
> 
> What specific information is missing from the TS AST?

Anything that is not part of the C grammar.  I already gave one
example: the way we support DEFUN.  Handling of cpp directives is also
not entirely satisfactory (because macros are not C, so TS added them
as a semi-kludgey feature).

> > I'm not saying we should never do that.  I was responding to your much
> > more general remarks, not to this particular case.
> 
> By default, commands should do one thing.  One can rebut the presumption
> that a command should do one simple thing for certain special cases, I
> guess, but I don't see a strong argument for for beginning-of-defun
> being one of these cases when it's easy to provide commands for the
> various supported behaviors.

In this case, the different behavior is from user preference of either
preferring the nested function or the top-level one.  That preference
affects more than just beginning-of-defun.  I think Yuan explained why
we are where we are with this.

> > Once again, going the looking-at way means we bring back all the
> > ad-hoc stuff that attempts to "parse" the code using heuristic
> > regexps, with the serious disadvantage that these heuristics need to
> > be well understood by someone who has a good knowledge of the
> > underlying language, and updated as the language evolves.  So I'd like
> > to do that only when absolutely necessary, and as little as possible
> > even then.
> 
> I'm not saying c++-ts-mode should parse using regexps like cc-mode does.
> I am saying that the AST should contain all the information cc-mode
> would instead get from this parsing and can be put to the same use.
> What information is the AST missing?

See above.

As another example that I saw only recently (which is why I still
remember it): the C grammar library only now added support for
__cdecl, something that c-mode supported long ago.  So we also have
features missing from tree-sitter just because they are missing.

> > Consistency is problematic here, because "sexp" doesn't translate
> > consistently between languages, and even "defun" not always does
> > (cf. the "namespace" case).
> 
> That "sexp" and "defun" mean different things in different languages
> doesn't mean movement commands between defuns should do different things
> in different languages.  Movement _between_ defuns should work the same
> way everywhere even if the _definition_ of a defun is language-specific.

Yes, but here the definition of the defun differs.

> > There's no such mindset.  I have no disagreement with you on that
> > level.  The disagreement is on a very practical level: we did try to
> > do things that way at the beginning, two years ago.  We are where we
> > are because that didn't work well enough.
> 
> Maybe we didn't try hard enough.  If there's something missing in the
> AST, perhaps it could be added.

I certainly hope so.  Please be sure to propose improvements based on
the AST, I don't think anyone will object.  What we do (or don't do)
now is just because we didn't yet get tro implementing it or found it
hard, not because we don't want the same features as in non-TS modes.

> >> What 40 years of development and user experience holds is that if
> >> I'm four pages deep into a nasty TypeScript function and hit
> >> beginning-of-defun, I want to go to the beginning of the four page
> >> defun I am editing and not some random place two pages up that I
> >> didn't even know about in which someone scribbled out some kind of
> >> nested lambda irrelevant to my present task.
> >
> > It turns out other users have other preferences and expectations,
> > especially if we include other languages in the context.  We cannot
> > tell them to get lost.
> 
> Users really prefer go-to-sibling behavior for beginning-of-defun?

Turns out that way.

> Says who?

Users.