From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Phil Sainty Newsgroups: gmane.emacs.bugs Subject: bug#35351: 27.0.50; Enable derived modes to run their own very-early 'change-major-mode-hook' code Date: Sun, 21 Apr 2019 14:35:35 +1200 Message-ID: <85237c18-768d-089b-221a-fe70b0ba4379@orcon.net.nz> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="157492"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.2.1 To: 35351@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun Apr 21 04:41:16 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hI2Pr-000eqv-0p for geb-bug-gnu-emacs@m.gmane.org; Sun, 21 Apr 2019 04:41:15 +0200 Original-Received: from localhost ([127.0.0.1]:47962 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hI2Pp-0004yb-UM for geb-bug-gnu-emacs@m.gmane.org; Sat, 20 Apr 2019 22:41:13 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:55976) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hI2Ph-0004se-At for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:41:08 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hI2Pf-0001xI-9S for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:41:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:33676) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hI2Pd-0001wO-VI for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:41:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hI2Pd-0004di-Ro for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:41:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Phil Sainty Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 21 Apr 2019 02:41:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 35351 X-GNU-PR-Package: emacs X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.155581442217774 (code B ref -1); Sun, 21 Apr 2019 02:41:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 21 Apr 2019 02:40:22 +0000 Original-Received: from localhost ([127.0.0.1]:47220 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hI2Oz-0004cb-Ug for submit@debbugs.gnu.org; Sat, 20 Apr 2019 22:40:22 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:41383) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hI2Ox-0004cO-Da for submit@debbugs.gnu.org; Sat, 20 Apr 2019 22:40:20 -0400 Original-Received: from lists.gnu.org ([209.51.188.17]:51208) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hI2Oo-0001Ts-SB for submit@debbugs.gnu.org; Sat, 20 Apr 2019 22:40:14 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:55723) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hI2On-0004h3-Ab for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:40:10 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hI2KU-0006zl-80 for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:35:43 -0400 Original-Received: from smtp-4.orcon.net.nz ([60.234.4.59]:59751) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hI2KT-0006xG-Tr for bug-gnu-emacs@gnu.org; Sat, 20 Apr 2019 22:35:42 -0400 Original-Received: from [150.107.172.17] (port=56784 helo=[192.168.20.103]) by smtp-4.orcon.net.nz with esmtpa (Exim 4.86_2) (envelope-from ) id 1hI2KO-0001kI-Am for bug-gnu-emacs@gnu.org; Sun, 21 Apr 2019 14:35:36 +1200 Content-Language: en-GB X-GeoIP: NZ X-Spam_score: -2.9 X-Spam_score_int: -28 X-Spam_bar: -- X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 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.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:157920 Archived-At: The library I'm working on (so-long.el) defines a major mode which needs to remember various buffer-local values as they were in the original mode, *before* my major mode takes effect. I'm currently using `change-major-mode-hook' for this, but it has occurred to me that it would be nicer if this hook code of mine only ever ran in the case where it is useful (i.e. the major mode being changed to is in fact my mode). `change-major-mode-hook' has no knowledge of the mode which has just been invoked, so it must necessarily run for *every* mode change -- which isn't relevant to my library in the vast majority of cases. I think `change-major-mode-hook' would more commonly be used by modes to handle any subsequent 'unloading' needs of that same mode in case it gets replaced later on (i.e. the mode body could set a buffer-local hook value), so my scenario of the new mode wanting to know things about the previous mode is doubtless a bit of a niche case; but I thought I'd raise it for discussion. `define-derived-mode' creates the mode function like so: (defun ,child () ,docstring (interactive) ; Run the parent. (delay-mode-hooks (,(or parent 'kill-all-local-variables)) Where PARENT must likewise `kill-all-local-variables' (which runs `change-major-mode-hook'). What would be nice is a way for the mode definition to provide code which would be evaluated before that (delay-mode-hooks...) form, and consequently acted like a `change-major-mode-hook' which only ever happened if this mode was called. (A vaguely analogous facility currently in `define-derived-mode' is the :after-hook keyword, for running code very *late* in the proceedings.) I could always define my mode without using the macro, and then do whatever I wanted before calling `kill-all-local-variables'; but I *want* to have the benefits of using the macro, so I don't want to resort to that; I just want the equivalent ability, while still using the macro. A hack which works in my case (because my mode was not already derived from another) is: (defun my-mode-parent () (do-my-custom-thing) (kill-all-local-variables)) (define-derived-mode my-mode my-mode-parent ...) This feels a little ugly, and `derived-mode-make-docstring' will point out the existence of the parent, so it's not ideal; but I'm still tempted to use this approach, and simply document it sufficiently such that the docstring reference won't cause undue confusion for those who follow it. That hack obviously can't be used in cases where a parent is already defined, but my suggested new feature could still work in those cases. Something like: (defun ,child () ,docstring (interactive) ,@before-hook ; Run the parent. (delay-mode-hooks (,(or parent 'kill-all-local-variables)) If the new child mode is used directly then things pan out almost identically to the hack version. More generally, we end up with: ,@child-before-hook (delay-mode-hooks ,@parent-before-hook (delay-mode-hooks ,@grandparent-before-hook (delay-mode-hooks (kill-all-local-variables) ;; runs change-major-mode-hook ,@grandparent-body) (run-mode-hooks 'grandparent-mode-hook) ,@parent-body) (run-mode-hooks 'parent-mode-hook) ,@child-body) (run-mode-hooks 'child-mode-hook) Which creates the following sequence of events: ,@child-before-hook ,@parent-before-hook ,@grandparent-before-hook (kill-all-local-variables) ;; runs change-major-mode-hook ,@grandparent-body ,@parent-body ,@child-body (run-hooks 'change-major-mode-after-body-hook) (run-hooks 'grandparent-mode-hook) (run-hooks 'parent-mode-hook) (run-hooks 'child-mode-hook) (run-hooks 'after-change-major-mode-hook) Obviously that sequence of 'before-hook' instances is in the reverse sequence to the 'body' and 'mode-hook' sequences. That's possibly a desirable thing, but I'm not absolutely certain. A simply way of reversing that sequence would be for each :before-hook to be added as a buffer-local change-major-mode-hook entry -- (add-hook 'change-major-mode-hook FOO nil :local) -- rather than evaluating them immediately, which would then build up a buffer-local hook sequence like: '(grandparent-before-hook parent-before-hook child-before-hook) And then `kill-all-local-variables' would run them in that order (and still ahead of any other pre-existing buffer-local values for `change-major-mode-hook'). What do people think? -Phil