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

From: João Távora <[email-masked]>
Date: Sat, 6 Jan 2024 22:22:49 +0000

On Sat, Jan 6, 2024 at 3:50 PM Stefan Monnier <[email-masked]> wrote:
>
> > Personally, I think if Eglot, YASnippet and CEDET are all we
> > actually know about, I think it's very simple to fix 2 out of three (even
> > _without_ the "base mode").  And the 3 out of 3 I _think_ I can
> > fix once someone points me to what exactly it should do.
>
> I don't think embedding (repeatedly) in YASnippet, CEDET, Eglot, ffap,
> lsp-mode, (and all the others that I don't happen to know offhand) the
> knowledge that `FOO-ts-mode` is used for the same files as `FOO-mode`
> qualifies as "fixing".

Not ideal, yes.  Depends on what needs to be done for each package.  It
would be good if we knew that.  I'll only speak for Eglot, YASnippet and
possibly for lsp-mode.  These 3 packages need to know the language of
the buffer they are operating on.  That's ultimately and definitely what
they want.

They do that with major-modes, because that has very often been a
good correspondence, often a 1-to-1, but not always. The N-to-1 problem
is not new with ts modes, it has long existed (Yasnippet is turning
15!).

> Instead, I'd call it "working around the lack of info which should be
> provided by the mode".  The way my patch does it may not be The Right
> Way (tho the jury is still out on this), but at least it provides the
> info at the right place.

Yes.  If by "at the right place" you mean "nearby the major modes
definitions themselves", yes I agree.

If you want to solve this problem cleanly, or more cleanly than it is
also solved now, I'm all for it.  I just think "extra parents" is a
clumsy a abstraction, though it can be used as an implementation aid.

For simplifying the existing ways these 3 packages already
solve the problem, I propose that instead of calling 'derived-mode-add-parents'
directly near the mode definitions, we instead do something like:

   (set-language-for-mode 'foo-ts-mode 'foo)

As a first implementation, this might just as well expand to

   (derived-mode-add-parents 'foo-ts-mode 'foo-mode)

I.e. it will be 100% your solution.  `derived-mode-p` will be
affected as you want and hopefully everything will keep working
as usual (not necessarily "start working" except for packages
not aware of TS modes at all).

But of course that's not all, because with very little work it also
provides for:

   (get-language-for-mode 'foo-ts-mode) ; => 'foo

And _that's_ when Eglot, Yasnippet, very likely lsp-mode and possibly
many others will see actual simplifications.

If we like this idea, I also think supporting a :language keyword to
'define-derived-mode' is natural.  Obviously, it would just expand to
that 'set-language-for mode' and default to whatever comes before the
"-mode" in the symbol.

So in summary this is what I think -- from the perspective of these 2/3
minor modes.  Yes this introduces the concept of "language", but I think
-- in fact I'm sure given the interactions I've had with new Eglot users
-- that "language" is a much simpler concept to grasp than "extra parents".

Finally, how to give this to packages outside the tree?  The usual
route: do it in core and package it either in compat.el or in a :core
GNU Elpa package, like we did for external-completion.el.  Keep the
derived-mode-add-parents (and add a "remove" counterpart), but suggest
them as last resort options/hammers.

João