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

From: Dmitry Gutov <[email-masked]>
Date: Thu, 18 Jan 2024 01:37:16 +0200

On 17/01/2024 12:31, João Távora wrote:
> 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).

This is indeed an approach that would work for all such cases, at the 
cost of extra typing and additional file organization (e.g. each major 
mode needs to be sorted into some file - it's no problem for 
js-jsx-ts-mode, but somewhat different for a potential new obscure 
language without close relatives).

>>     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.

What we couldn't do in this model, is create one small major mode called 
c-like-mode (which sets up a minimal syntax table), and use it for a 
bunch of languages like C, C++, JS, etc, delegating the major features 
such as syntax highlighting, indentation, imenu and completion to the 
LSP protocol (e.g. via Eglot). With no extra files required for many 
additional languages, just new entries in eglot-server-programs.

Of course it's not critical that we'd be able to do this, but seems 
interesting as a concept.

>>> (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).

Yep.

If we're referencing my patch, then many-to-many should work with it, of 
course.

>> 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.

Not 100% clear where 'buffer-overriding-language-keyword' would come 
from. If set-buffer-language was the main entry point for overriding a 
buffer's language, however, its approach of overriding the cached info 
(currently set by set-auto-mode-0) seems the easiest.