Subject: bug#68246: 30.0.50; Add non-TS mode as extra parent of TS modes

From: João Távora <[email-masked]>
Date: Wed, 17 Jan 2024 10:31:39 +0000

On Wed, Jan 17, 2024 at 2:06 AM Dmitry Gutov <[email-masked]> wrote:
>
> On 17/01/2024 00:00, João Távora wrote:
> > On Tue, Jan 16, 2024, 17:45 Dmitry Gutov <[email-masked]> wrote:
> >>
> >> On 16/01/2024 12:34, João Távora wrote:
> >>> I see no real categorization or classification.  I just see
> >>> a many-to-one mapping of major modes to languages.
> >>
> >> It might even be many-to-many, at least in some cases.
> >>
> >> E.g. js-ts-mode being good for both :js and :jsx.
> >
> >>
> >> Not sure how useful this -to-many relation is going to be in the above
> >> cases, but it's probably a good illustration of the possibility.
> >
> > According to https://react.dev, jsx is a "JavaScript syntax
> > extension".  So it would seem JSX is a superset of JS.  If
> > js-ts-mode parses it perfectly, it could be called
> > jsx-ts-mode instead.
>
> The grammar tree-sitter-js supports JSX. So the mode is called js-ts-mode.

OK.  In this case, I would just say js-ts-mode is for JavaScript.

A future trivial js-tsx-mode would be for JavaScriptReact.
Eglot doesn't support the "JavaScriptReact" LSP language-id
because of this, and noone has complained (they have about ts and
tsx tho).

>    tsx-ts-mode is probably okay for both :tsx, :jsx and :js but not
>    :typescript (in general, because of certain clashing syntax).

Right.  Which makes sense.  Like my-c++-mode is "probably okay"
for C, but that doesn't mean my-c++-mode isn't the mode for the C++
language (or family of languages commonly denominated as "C++")

Ergo, as I see it, tsx-ts-mode is the mode for TypeScriptReact,
a language which happens to be a superset of some other languages.

> > At the end of the day, a language is not so easy to define,
> > but it's not that problematic either, especially in the editor
> > (in the compiler, it's much more important).
> >
> > The best sources are a standard, when it exists, but each iteration,
> > sometimes  each compiler is also its own language.  There's "GNU C",
> > "ANSI C", C17, C23.  All handled by the C modes we have and the best
> > way we have to designate this is just "C".  c++-mode also handles
> > this code by the way, probably flawlessly, and yet we don't say
> > c++-mode is for C and C++.
> >
> > But if you want, I don't think there's any big problem
> > in making get-language-for-mode return a list, with
> > the most important likely language at the top.
>
> It would be a problem if we decide that the major mode function runs the
> language-specific hook, and not set-auto-mode-0 like in my patch
> (because the mmode function would like run the hooks for all supported
> languages, rather than just the current one).

I see.  Right.

> > I predict it'll be pretty rare, but I guess you could
> > have this (excuse the ugly CamelCase for demo purposes)
>
> It might indeed be rare enough for this to be a problem, and we might
> even decide to prohibit such usage, keeping the relation many-to-one.

I'd think that is fine.

> > (setq auto-mode-alist '(("\\.js$" . :JavaScript)
> >                          ("\\.jsx$" . :JavaScriptReact)))
> >
> > (setq m-m-remap-alist '((:JavaScript . js-ts-mode)
> >                          (:JavaScriptReact . js-ts-mode)))
>
> It indeed should work okay with my proposal, but might be harder to do
> if the languages are inserted as part of the existing modes hierarchy
> (e.g. as "abstract" symbols).

I don't follow.  Are you referencing the other mail?  That
(:abstract t) idea was mostly crafted for the base-mode approach.
It's not strictly needed with your patch (though I don't see how
it hurts either).

> That is assuming we do want the language
> hook to run - which seems like important goal from my POV.

Not absolutely essential to fix current problems, but yes I agree
it's natural  enough that it should be in the proposal.

> > And 'buffer-language' becomes more like:
> >
> > (or buffer-overriding-language-keyword
> >      (with-current-buffer buffer (get-language-for-mode major-mode))
> >      (let (kw)
> >         (and buffer-file-name
> >              (keywordp
> >                (setq kw
> >                      ;; yes I know this needs regexps
> >                      (alist-get buffer-file-name auto-mode-alist)))
>
> There is a bunch of variables to look up: auto-mode-alist,
> magic-mode-alist, interpreter-mode-alist, magic-fallback-mode-alist. I
> didn't want to duplicate the logic from set-auto-mode, but this of
> course could be done.

I was just illustrating the fallback logic.

João