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

From: Dmitry Gutov <[email-masked]>
Date: Sat, 20 Jan 2024 07:43:38 +0200

On 19/01/2024 14:43, Stefan Monnier wrote:
>> That might mean that a content-type corresponds to a number of languages,
>> just like a language corresponds to a number (open set) of major modes. But
>> I don't see how. Please enlighten.
> 
> All three are taxonomies that are related to the content of the buffer.
> They are almost identical in general, but differ in details because
> taxonomies are not an exact science and those three have each been
> defined separately, so the arbitrary decisions that are involved in
> making a taxonomy have not been the same.

All right. But we'll probably only add one, if any. Adding two more (in 
addition to major modes) seems like too much.

>> The side-effect of this approach is that we basically declare a mode's
>> language twice: once in the attribute above, and once in the
>> major-mode-remap-alist which is put into autoloads. But it's probably
>> minor enough.
> 
> Again: not necessarily.  You're making assumptions about what the source
> code will look like, but we get to decide what the source code looks
> like by defining functions/macros.  Even if the information is stored in
> a redundant way, that doesn't mean the surce of that information can't
> be the same.
> 
> So if/when such a duplication proves to be a problem, I can't see why it
> would be difficult to fix it.

Okay.

>>> Cue the patch I submitted when I open this bug report 🙂
>>> Now `<LANG>-mode` is again included in `derived-mode-all-parents` for
>>> those new modes.
>>
>> If the language is called <LANG>-lang instead (of without suffix), then the
>> major mode could also run the language-specific hook, which in your patch it
>> cannot do.
> 
> I don't follow: why would the name of the mode (and hence hook) make it
> harder/easier/possible to run the hook?

So that it can be set up that for every such major mode the language 
hook does run, and the user could depend on that fact without looking up 
the mode's definition or its docstring.

You said that the choice not to do that (leaving that up to individual 
modes, IIUC) is because the new parents are existing modes, and so (I 
imagine) those hooks can existing have configurations that might not 
work with the new "child". A new name would change that.

IIUC your original design decision for `derived-mode-add-parents' is for 
the MODE not to run any of EXTRA-PARENTS hook, but I think the invariant 
that when a mode is "derived", it runs the hooks, was pretty sensible.

>>>> The major-mode could be fundamental-mode. If the language were to be
>>>> specifiable through settings external to major modes, we could still do
>>>> useful things while in fundamental-mode (e.g. do some useful editing with
>>>> Eglot, provided it supports indentation and completion), or suggest which
>>>> major modes to install from ELPA.
>>> I don't see the interest of using specifically `fundamental-mode` for
>>> that.  In any case, this seems too hypothetical at this stage to have
>>> a good idea of what we'd need in such circumstances.
>> The latter feature (suggest which major modes to install) has come up
>> recently. It's not that difficult to implement (with a whitelist of
>> packages),
> 
> I'm with you so far (my `gnu-elpa` package intended to provide
> a possible solution for that).

Hmm, that implementation is more clever than I was thinking of. Without 
getting into the details of its UI, your point is very well made that 
the major mode symbol can serve as the point of indirection as well.

To sum up, I've been looking for some sort of middle ground between your 
patch and my more radical proposal. I might look like this:

- auto-mode-alist and major-mode-remap-alist stay the same (no 
"language" entries), although it would make sense to use 
major-mode-remap-alist more prominently rather than copy the regexps, 
irrespective of this change.
- The added extra parents have new names, not of existing modes, but 
something with "-lang" or just the name of the language, but without 
"-mode".
- The child mode runs the hooks of the extra parents as well.

I think Joao has been thinking in the same direction, except his choice 
was to extend the <lang>-base-mode scheme to all languages. Which mostly 
satisfies the same constraints, if we agree that the "-base-mode" naming 
should only extend to modes such as these (with the language in the 
name), so that (get-mode-language mode) could search for that name.

*OR*, alternatively, we don't add new parents. But add the :language 
keyword (or :content-type, or something similar) to define-derived-mode 
which would basically set a property. But when such property is set, 
(get-mode-language mode) would evaluate that property's value. And the 
mode would run the hook automatically when a language is set.

I suppose the second approach is technically compatible with your patch 
as well, and since it by itself doesn't help with the generalization of 
major modes in dir-locals.el, it might make sense to do both. But I'd be 
sorry to lose the invariant mentioned above, and specifying both the 
extra parent *and* the language, for ts modes, would feel like 
unfortunate duplication.