From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Dmitry Gutov Newsgroups: gmane.emacs.bugs Subject: bug#68246: 30.0.50; Add non-TS mode as extra parent of TS modes Date: Thu, 18 Jan 2024 07:05:55 +0200 Message-ID: <8e6935bc-2a60-4a14-8e63-d6057a7e2af7@gutov.dev> References: <831qavvcbo.fsf@gnu.org> <83a5phskd5.fsf@gnu.org> <83h6joqz0t.fsf@gnu.org> <834jfoq86m.fsf@gnu.org> <831qarrbjx.fsf@gnu.org> <87a5p84nlh.fsf@gmail.com> <83edekfldq.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="9379"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla Thunderbird Cc: 68246@debbugs.gnu.org, Eli Zaretskii , casouri@gmail.com, =?UTF-8?Q?Jo=C3=A3o_?= =?UTF-8?Q?T=C3=A1vora?= , Stefan Kangas To: Stefan Monnier Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Thu Jan 18 06:07:19 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rQKcW-0002Dw-9s for geb-bug-gnu-emacs@m.gmane-mx.org; Thu, 18 Jan 2024 06:07:17 +0100 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rQKcJ-0000gJ-Tj; Thu, 18 Jan 2024 00:07:03 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rQKcH-0000g6-Re for bug-gnu-emacs@gnu.org; Thu, 18 Jan 2024 00:07:01 -0500 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rQKcH-0006Ly-Iv for bug-gnu-emacs@gnu.org; Thu, 18 Jan 2024 00:07:01 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1rQKcI-0007S7-JF for bug-gnu-emacs@gnu.org; Thu, 18 Jan 2024 00:07:02 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Dmitry Gutov Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 18 Jan 2024 05:07:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 68246 X-GNU-PR-Package: emacs Original-Received: via spool by 68246-submit@debbugs.gnu.org id=B68246.170555437328586 (code B ref 68246); Thu, 18 Jan 2024 05:07:02 +0000 Original-Received: (at 68246) by debbugs.gnu.org; 18 Jan 2024 05:06:13 +0000 Original-Received: from localhost ([127.0.0.1]:54141 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rQKbV-0007Qz-1W for submit@debbugs.gnu.org; Thu, 18 Jan 2024 00:06:13 -0500 Original-Received: from out3-smtp.messagingengine.com ([66.111.4.27]:39459) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1rQKbP-0007QS-9q for 68246@debbugs.gnu.org; Thu, 18 Jan 2024 00:06:11 -0500 Original-Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailout.nyi.internal (Postfix) with ESMTP id 79B2C5C008F; Thu, 18 Jan 2024 00:06:00 -0500 (EST) Original-Received: from mailfrontend1 ([10.202.2.162]) by compute4.internal (MEProxy); Thu, 18 Jan 2024 00:06:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gutov.dev; h=cc :cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to; s=fm1; t=1705554360; x=1705640760; bh=eqEoiVaxRMzqlEgewSc5MeTZ940IF/ix07oysZknEBY=; b= qD6qI6P/qQEJvBrv3SUxaZIsVo2LKA5zDkvAl6HTiTL/WEFzha/m5R9oy8D0DMZf dxxktVnPIbXorAfvvQe9UljvMjEh4UTNTVzjQGa1/mU6m6C1R7kVpkeEUzk5ijGn QDhDZ81n89CvDmDkdOfkwTbNczyJQqfaN8q+PZq6xGQ109qujTNq2HjNrY+1kBJz j18RFUlGGoFI2EmVm4eAUDGmPMpEgQyxYQxMmvm/7+WL486J2wFZQN5dbox8LqHZ J13BYh3pqMzHUIkLXn6euSB+EFb+oNnIXOMsQ6WVXxBsdUE1QZfgoCqRgil3hDbJ ZiywSx+f2pUN2nvjRZi2Xw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:in-reply-to:message-id:mime-version :references:reply-to:subject:subject:to:to:x-me-proxy:x-me-proxy :x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t=1705554360; x= 1705640760; bh=eqEoiVaxRMzqlEgewSc5MeTZ940IF/ix07oysZknEBY=; b=f 13KQA/DjxjYtSw3w2Ovbif0EzICQKHqxvq7aj1wEr2slMkWOEgZM2fY4o0jB6G61 h+8xQIDu5n22q7EEVHt/djb9eu0CEqPg3OxMTQgiW/JLfa9HVhjI4hCFLogqa3rk BGyLOhhilrwKSSPag2VQX0I7q9kNcLIaTX57v4VbJUNdHLR3IDcAENMwOA2NhRor 0NSlq6AnW7DCCWvdkXY/ioSTG7wD9C4E2PeHJaeYSUlB+D6n0o/ohhZqXRMr/qNt Yu8rUJDOWWSq/8bxY4kfk+1sxVjMzFzO9qu7WkY7+XFNmd9ygUo6/9gwWjPnCF2c 179STqRwH49TTAh5K9Xhg== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedvkedrvdejiedgjeejucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepkfffgggfuffvvehfhfgjtgfgsehtjeertddtvdejnecuhfhrohhmpeffmhhi thhrhicuifhuthhovhcuoegumhhithhrhiesghhuthhovhdruggvvheqnecuggftrfgrth htvghrnhepteduleejgeehtefgheegjeekueehvdevieekueeftddvtdevfefhvdevgedu jeehnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepug hmihhtrhihsehguhhtohhvrdguvghv X-ME-Proxy: Feedback-ID: i0e71465a:Fastmail Original-Received: by mail.messagingengine.com (Postfix) with ESMTPA; Thu, 18 Jan 2024 00:05:58 -0500 (EST) Content-Language: en-US In-Reply-To: X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:278419 Archived-At: On 17/01/2024 19:08, Stefan Monnier wrote: >> @@ -3150,6 +3150,9 @@ auto-mode-alist >> Visiting a file whose name matches REGEXP specifies FUNCTION as the >> mode function to use. FUNCTION will be called, unless it is nil. >> >> +FUNCTION can also be a keyword denoting a language, to be looked >> +up in `major-mode-remap-alist'. > > Side note: the intention is OK but `major-mode-remap-alist' is > a defcustom and should remain nil by default. It's there for the users > to express which major modes they prefer. So if we want a mapping > between some new language/type concept and major modes, it should be > stored elsewhere (could be a plain alist that's handled as a kind of > "implicit tail of `major-mode-remap-alist`"). Good point. The user can customize it and lose the non-default modes configured for a language. The way I introduced languages as keywords was an experiment, really. Mostly to save on typing - because the first plan was to have a parallel set of alists (since we can't right away deprecate the file -> mmode mappings right away). The language-specific version of major-mode-remap-alist looks necessary after all. >> @@ -3206,10 +3209,10 @@ interpreter-mode-alist >> ("emacs" . emacs-lisp-mode))) >> "Alist mapping interpreter names to major modes. >> This is used for files whose first lines match `auto-mode-interpreter-regexp'. >> -Each element looks like (REGEXP . MODE). >> +Each element looks like (REGEXP . MODE-OR-LANGUAGE). >> If REGEXP matches the entire name (minus any directory part) of >> the interpreter specified in the first line of a script, enable >> -major mode MODE. >> +MODE-OR-LANGUAGE. > > There's a similar need for "content type" rather than "language". If we > want to mention "language" we should also take the opportunity to > mention other related categorizations like "content type". Are "content type" and "language" going to be different things? They seem the same to me. >> - (funcall (alist-get mode major-mode-remap-alist mode)) >> + ;; XXX: When there's no mapping for `:', we could also >> + ;; look for a function called `-mode'. >> + (funcall (alist-get mode major-mode-remap-alist (if (keywordp mode) >> + #'fundamental-mode >> + mode))) >> + (when (keywordp mode) ;Perhaps do that unconditionally. >> + (run-hooks (intern (format "%s-language-hook" (buffer-language))))) > > That seems wrong: > - Why should this hook run when `auto-mode-alist` says `:js` but not > when doing `M-x javascript-mode` (or other ways to enable this mode)? > - Why run this hook *after* the mode's `:after-hook` and after > things like `after-change-major-mode-hook`? > > I think it should remain the major mode's responsibility to decide which > hooks it runs. On one hand, this is an artefact of not implementing the language-classification inside define-derived-mode. OTOH, the major mode can only run the language hook, I think, if any major mode can correspond only to one language. Though I suppose if set-auto-mode-0 saves the currently "detected" language somewhere, the major mode definitions could pick it up and call the corresponding hook. Hmm, perhaps in that case the major modes won't need any special attribute in their definitions (to specify their language): any major mode would run -language-hook where is the language detected for the buffer or assigned explicitly. >> +(defun buffer-language () >> + "Return the language of the current buffer. >> +A language is a lowercase keyword with the name of the language." >> + ;; Alternatively, we could go through all the matchers in >> + ;; auto-mode-alist, interpreter-mode-alist, >> + ;; magic-fallback-mode-alist here, possibly using a cache keyed on >> + ;; buffer-file-name. But that's probably an overkill: if the user >> + ;; changes the settings, they can call `M-x revert-buffer' at the end. >> + (if (keywordp (car set-auto-mode--last)) >> + (car set-auto-mode--last) >> + ;; Backward compatibility. >> + (intern (format ":%s" (replace-regexp-in-string "\\(?:-ts\\)?-mode\\'" "" >> + (symbol-name major-mode)))))) > > I'm not comfortable enshrining the "-ts-mode" convention here. We can still go the "strict" approach, where when no language is assigned, we don't try to guess it. > Also I think if we want a `buffer-language` function, it should not rely > on how the mode was installed (e.g. `set-auto-mode--last`) but only on > the major mode itself, i.e. something like > > (defun buffer-language () > (or buffer-language Where would the buffer-language variable be set, if not inside set-auto-mode-*? > (some heuristic based on major-mode and/or derived-modes))) If we're sure we don't want several languages to be able to refer to the same major mode... > [ Of course, I already mentioned that I also suspect that there can/will > be sometimes several languages (or none). ] I'm not clear on this. You mentioned complex cases - like an xml inside an archive? But depending on the usage, only one of the languages might be "active" at a given time. Or a combination of languages would simply be another language, basically. A more specific scenario might clarify this better. >> +(defun set-buffer-language (language) >> + "Set the language of the current buffer. >> +And switch the major mode appropriately." >> + (interactive >> + (list (let* ((ct (mapcan >> + (lambda (pair) (and (keywordp (car pair)) >> + (list (symbol-name (car pair))))) >> + major-mode-remap-alist)) >> + (lang (completing-read "Language: " ct))) >> + (and lang (intern lang))))) >> + (set-auto-mode-0 language)) > > I see several issues with this function (name and implementation), but > I wonder when we'd ever need such a thing. It seemed like a missed opportunity not to provide a more high-level command to switch to a specific language for the buffer. E.g. how we sometimes use 'M-x foo-major-mode' when a file type's been misdetected, or the buffer is non-file-visiting (perhaps very temporary). A command which does this with exhaustive completion across the configured languages seems handy. At least that's my impression from briefly testing it out. Also, get-current-mode-for-language can be implemented in terms of set-buffer-language (see my earlier email to Joao). >> ;;;###autoload >> (dolist (name (list "node" "nodejs" "gjs" "rhino")) >> - (add-to-list 'interpreter-mode-alist (cons (purecopy name) 'js-mode))) >> + (add-to-list 'interpreter-mode-alist (cons (purecopy name) :js))) > > BTW, my suggested patch basically proposes to use `-mode` instead > of `:LANG>` which saves us from those changes since that matches our > historical conventions. -mode is lexically indistinguishable from -mode. If we used the names like -lang, at least one could tell whether one of the parents of a given -mode is a language. > Another issue I see if we don't use something like > `derived-mode-add-parents` is that all the various places where we use > mode-indexing, such as `.dir-locals.el`, `ffap`, YASnippet, etc... will > need to be extended with a way to use "languages" as well, and then we > also need to define a sane precedence between settings that apply to > a given mode and settings that apply to a given language (setting for > `js-ts-mode` should presumably take precedence over settings for > `:js` which should take precedence over settings for `prog-mode`). That's a good point: if "languages" as a separate notion gets added, it would make sense to use them in more places (not 100% necessary, but good for consistency). With the associated complexity that you mention.