all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Yuan Fu <casouri@gmail.com>
To: Stefan Monnier <monnier@iro.umontreal.ca>
Cc: Eli Zaretskii <eliz@gnu.org>,
	emacs-devel@gnu.org, mickey@masteringemacs.org,
	theo@thornhill.no, dgutov@yandex.ru
Subject: Re: Extending define-derived-mode
Date: Wed, 31 May 2023 14:31:06 -0700	[thread overview]
Message-ID: <F869BB44-F62A-4FE4-BC05-C7CB7E8E9A41@gmail.com> (raw)
In-Reply-To: <jwv8rd62al1.fsf-monnier+emacs@gnu.org>



> On May 30, 2023, at 7:16 AM, Stefan Monnier <monnier@iro.umontreal.ca> wrote:
> 
>> You are basically talking about different modes that support the same
>> programming language or file format.  We never had this in Emacs, with
>> (AFAIK) the single exception of perl-mode vs cperl-mode, which never
>> played well.
> 
> Not quite: within Emacs there's at least pascal.el vs opascal.el and
> sgml-mode vs nxml-mode, and depending on how you define it there's also
> postscript-mode vs doc-view-mode, as well as c-mode vs image-mode (for
> XPM files).
> 
> And if we consider packages not bundled with Emacs, there are many more
> case:s such as latex-mode vs LaTeX-mode, python.el vs python-mode.el,
> js.el vs js2.el vs js3.el, octave-mode vs matlab-mode.
> 
>> I think some thought was invested in trying to reconcile
>> them (Stefan, am I right?), but we never came up with a good solution.
>> Not sure if that is a general problem or not.
> 
> We don't really have a good answer yet, no.
> `major-mode-remap-alist` is aimed at this problem, but brand new so it's
> not clear how useful it will be for that and it's definitely not
> a complete solution.
> 
>>> 1. Fallback modes: user enables xxx-ts-mode, but there’s no
>>>   tree-sitter grammar for xxx, so Emacs falls back to xxx-mode
>>>   instead. This feature is also desirable for some non-tree-sitter
>>>   modes, like TeX modes. Ideally the dispatch should happen before
>>>   major mode does anything.
>> 
>> This fallback must be user-controlled.
> 
> I don't see this as a big problem, actually (there are already several
> mechanisms that can do that).  The question of how "user enables
> xxx-ts-mode" is probably harder.

Couldn’t they use major-mode-remap-alist?

There are mechanisms to do that, yes, if you are talking about the advices for latex-mode and bash-ts-mode. But I’d love to see a standard, cleaner way to do it.

> 
>>> 2.1 For xxx-mode and xxx-ts-mode, there should be shared hook. More
>>>    generally, we want to be able to have a shared hook for similar
>>>    modes (same language, similar language, etc).
> 
> As Eli explains, this is not always desirable.  And at other times it
> *is* desirable: the users's hook function can set/use features that are
> specific to one of the alternative, but they can also set/use features
> that are shared between the alternatives :-(

For sure, those that aren’t sharable should go into the not-shared hooks. I’m mainly saying that there should be a shared hook, so users _can_ share some of the configs.

> 
> Most users use only one of the alternatives, tho, so it's usually not
> a big problem (other than introducing incompatibilities when Emacs's
> defaults change from one alternative to another).

Keep in mind that when people try out tree-sitter modes, they are unlikely to just throw away their config for the old mode; also since tree-sitter and grammars aren’t the easiest to install, people working on multiple machines probably want both tree-sitter and no-tree-sitter modes configured and ready to go. So I think we’ll see a lot of people having config for both modes (me included).

> 
> It can be more annoying for `.dir-locals.el` per-mode settings.

And in general, any configuration that takes a major-mode symbol as the key. There are quite a few of them in Emacs. I think this is a big motivation for having multiple inheritance for derived-mode-p, and sharing a base mode.

> 
>>>    More generally, if there is a language X and a derived language Y,
>>>    and we have x-mode, x-ts-mode, y-mode, y-ts-mode, how should
>>>    inheritance of code and hooks works among them? y-mode probably
>>>    wants to inherit from x-mode, and y-ts-mode probably wants to
>>>    inherit hook (but not necessarily code [1]) from x-ts-mode.
> 
> `y-ts-mode` can explicitly run `y-mode-hook` (or `x-ts-mode-hook`).
> 
> We may more generally want to extend our notion of "derived" mode to
> allow "multiple inheritance".  For the actual activation code part,
> multiple inheritance is a hard problem that we probably don't want to
> tackle, but we can easily run several parent hooks, setup multiple
> keymap karents, and make `derived-mode-p` support multiple parents.

I agree that we don’t want multiple-inheritance for activation code. Also, as Juri pointed out, we can encapsulate code into functions and call functions in major mode body. Multiple-inheritance for hooks and maps has the potential disadvantage of being confusing. Right now it’s clear what hooks are run when a major mode turns on, but with multiple-inheritance it may not be. (I know I brought up the multiple-inheritance thing in the first place, I’m just writing whatever comes to my mind :-)

How do you setup multiple keymap parents? I thought a keymap can only have one parent?

Here’s another wild idea: we keep single-inheritance for define-derived-mode; major modes for the same language inherits from the same base mode; add a feature where xxx-base-mode is automatically defined when someone defines a major mode with xxx-base-mode as parent, so we don’t need to pre-define base-modes for every possible language; separate to major modes, we add a tag/category system, where modes can adopt multiple tags/categories, and a function like mode-has-category-p can work similarly to derived-mode-p.

> 
>>> 3. Unrelated to tree-sitter, here’s something I personally want:
>>>   it would be nice if every major mode can
>>>   have a hook that’s not run by its derived modes. Use case:
>>>   sage-mode inherits python-mode. I have eglot-ensure in
>>>   python-mode-hook but don’t want it when using sage-mode. Right now
>>>   I have to wrap eglot-ensure with a lambda function so that it only
>>>   runs when major-mode = python-mode.
>> 
>> What is wrong with that solution?  Except for the maybe minor
>> inconvenience of having to use a lambda-function, what different way
>> of doing this would you envision except telling define-derived-mode to
>> run some hook only under this-and-that condition?
> 
> While I tend to agree that it's not a big deal, I also agree that it's
> arguably cleaner if parent modes are kept "abstract", so rather than
> have `c++-mode` inherit from `c-mode`, you make them both inherit from
> a `c-base-mode`.  It tends to smell of overkill, tho.

Maybe defien-derived-mode can additionally define a function that only runs the major mode body but doesn’t setup anything that are autogenerated (eg, keymap, hooks, etc). This way another major mode is free to reuse other mode’s setup while not inheriting from that mode.

Yuan


  reply	other threads:[~2023-05-31 21:31 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-30  5:16 Extending define-derived-mode Yuan Fu
2023-05-30  5:51 ` Theodor Thornhill
2023-05-31 20:35   ` Yuan Fu
2023-06-01  5:43     ` Theodor Thornhill
2023-05-30 10:48 ` Eli Zaretskii
2023-05-30 14:16   ` Stefan Monnier
2023-05-31 21:31     ` Yuan Fu [this message]
2023-06-01  4:06       ` Stefan Monnier
2023-06-01  6:39         ` Eli Zaretskii
2023-06-02  7:50           ` Yuan Fu
2023-06-02 11:54             ` Eli Zaretskii
2023-06-05  7:31               ` Yuan Fu
2023-06-05 11:33                 ` Eli Zaretskii
2023-06-08  7:25                   ` Yuan Fu
2023-06-02  7:44         ` Yuan Fu
2023-06-02 16:46           ` Stefan Monnier
2023-06-05  7:39             ` Yuan Fu
2023-06-05 15:17               ` Stefan Monnier
2023-05-31 20:48   ` Yuan Fu
2023-06-01  5:47     ` Eli Zaretskii
2023-06-02  7:45       ` Yuan Fu
2023-06-02 11:51         ` Eli Zaretskii
2023-05-30 17:24 ` Juri Linkov
2023-06-05  8:30 ` Philip Kaludercic

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=F869BB44-F62A-4FE4-BC05-C7CB7E8E9A41@gmail.com \
    --to=casouri@gmail.com \
    --cc=dgutov@yandex.ru \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=mickey@masteringemacs.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=theo@thornhill.no \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.