From mboxrd@z Thu Jan 1 00:00:00 1970 Path: main.gmane.org!not-for-mail From: Luc Teirlinck Newsgroups: gmane.emacs.devel Subject: Recent attempts at standardizing major mode definitions. Date: Sun, 1 Sep 2002 21:40:13 -0500 (CDT) Sender: emacs-devel-admin@gnu.org Message-ID: <200209020240.VAA26083@eel.dms.auburn.edu> NNTP-Posting-Host: localhost.gmane.org X-Trace: main.gmane.org 1030934416 7515 127.0.0.1 (2 Sep 2002 02:40:16 GMT) X-Complaints-To: usenet@main.gmane.org NNTP-Posting-Date: Mon, 2 Sep 2002 02:40:16 +0000 (UTC) Return-path: Original-Received: from quimby.gnus.org ([80.91.224.244]) by main.gmane.org with esmtp (Exim 3.35 #1 (Debian)) id 17lh8Q-0001x6-00 for ; Mon, 02 Sep 2002 04:40:14 +0200 Original-Received: from monty-python.gnu.org ([199.232.76.173]) by quimby.gnus.org with esmtp (Exim 3.12 #1 (Debian)) id 17lhgQ-0000Jj-00 for ; Mon, 02 Sep 2002 05:15:23 +0200 Original-Received: from localhost ([127.0.0.1] helo=monty-python.gnu.org) by monty-python.gnu.org with esmtp (Exim 4.10) id 17lh9u-0007s7-00; Sun, 01 Sep 2002 22:41:47 -0400 Original-Received: from list by monty-python.gnu.org with tmda-scanned (Exim 4.10) id 17lh8T-0007m6-00 for emacs-devel@gnu.org; Sun, 01 Sep 2002 22:40:17 -0400 Original-Received: from mail by monty-python.gnu.org with spam-scanned (Exim 4.10) id 17lh8Q-0007lZ-00 for emacs-devel@gnu.org; Sun, 01 Sep 2002 22:40:16 -0400 Original-Received: from manatee.dms.auburn.edu ([131.204.53.104]) by monty-python.gnu.org with esmtp (Exim 4.10) id 17lh8P-0007lD-00 for emacs-devel@gnu.org; Sun, 01 Sep 2002 22:40:13 -0400 Original-Received: from eel.dms.auburn.edu (eel.dms.auburn.edu [131.204.53.108]) by manatee.dms.auburn.edu (8.9.1a/8.9.1) with ESMTP id VAA24104 for ; Sun, 1 Sep 2002 21:40:12 -0500 (CDT) Original-Received: (from teirllm@localhost) by eel.dms.auburn.edu (8.9.3+Sun/8.9.3) id VAA26083; Sun, 1 Sep 2002 21:40:13 -0500 (CDT) X-Authentication-Warning: eel.dms.auburn.edu: teirllm set sender to teirllm@dms.auburn.edu using -f Original-To: emacs-devel@gnu.org Errors-To: emacs-devel-admin@gnu.org X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.0.11 Precedence: bulk List-Help: List-Post: List-Subscribe: , List-Id: Emacs development discussions. List-Unsubscribe: , List-Archive: Xref: main.gmane.org gmane.emacs.devel:7310 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:7310 Stefan Monnier wrote: PS: The elisp manual clearly says in the "major mode conventions" node to "Define a command whose name ends in `-mode'" so ibuffer-mode should be interactive. I'd of course argue that it should use `define-derived-mode' which would have made it interactive as a matter of course without the programmer having to think about it. As long as we don't use such a macro systematically, we'll have to live with all those inconsistencies. It seems to me that in the present 21.3.50 code, define-derived-mode is already used pretty systematically. As I pointed out in another message, this has lead to bugs. To avoid confusion: I am not at all opposed to "using such a macro systematically", but I am very much opposed to using define-derived-mode in its present form. One reason is that the present use of this macro has caused bugs in several modes. (See my previous message.) It is not the only reason. I believe that any macro that aims to standardize major mode definitions should under no condition prevent the writer of a major mode to do anything that is not only not "forbidden" by the guidelines in the Elisp manual, but that is even explicitly allowed by these guidelines, and is very often in the best interest of the user. Neither should the macro make this unnecessarily difficult for him or her. The ELisp manual clearly says that a major mode does not need to have its own syntax-table or abbrev-table, but may share one with related modes. Especially in the case of abbrev-tables, it is in the user's interest to share local abbrev-tables as much as possible between closely related modes. Yet, define-derived-mode makes it unnecessarily tricky to share abbrev tables or syntax tables without introducing the second type of bug I described in my previous message. The Elisp manual also says that hooks of related modes may be ran just before the mode's own hook OR that they may be ran earlier. It seems to me that define-derived-mode tries to enforce the first type of behavior. Apart from the bug-related objections and the "enforcement of unnecessary or even counterproductive rules" objections, I also do not like the way define-derived-mode amalgamates two barely related functionalities into one macro. Of course, one can always "save a function definition" by combining two different functions into a single macro that expands into the code of one or the other depending on the value of some argument. Whether it makes sense to actually do so is a different question. define-derived-mode is currently used for two barely compatible, in many respects diametrically opposite purposes: A way to make a very specialized, but common, task easy for people to do, namely defining a barely different derived mode from a parent mode. I believe define-derived-mode serves this purpose well, except for the fact that, as I pointed out in my previous message, it should make the derived mode use the parent's abbrev table instead of introducing bugs and confusion by trying to copy the parent's abbrev-table. The second, more recent purpose is as a "standard" way to define any major mode whatsoever. This is a completely different task. I believe that one should revert to the 21.2.90 behavior and no longer make the code expand into something different when the parent mode is fundamental-mode. Some modes could truly differ so little from fundamental-mode that they are "truly" derived modes of fundamental mode. I believe the current value of "nil" for PARENT should be eliminated and replaced by a separate macro `define-major-mode', which would be a true analogue of `define-minor-mode'. This would then take over as the "standard" way to define a major mode. I propose to define a macro that would be called like this: (define-major-mode mymode name syntax-table abbrev-table mode-class docstring body) (A proposed expansion is included below.) Here, syntax-table and abbrev-table could be another mode's syntax or abbrev-tables, or nil, in which case the mode gets its own syntax or abbrev table. This is one difference with the current code. Another is that now the author decides when other mode's hooks are ran. Of course, (s)he is perfectly free to choose the current solution in body, (s)he is just not forced too. Note that my code still runs run-mode-hooks instead of run-hooks, so that, if I understand things correctly, authors using `define-major-mode' would still be supporting other people's use of delay-mode-hooks, even if they would choose not to use that machinery themselves. (I have not yet read through the details of the source code of the functions involved in the "delay-mode-hooks run-mode-hooks" machinery and their documentation strings are imprecise and cryptic.) There is still one thing I am hesitating about: The Elisp manual says: Major modes usually should have their own keymap... There is a "usually" in this sentence. So maybe define-major-mode should also take a keymap argument. This is a lot less clear than it is for syntax-tables and abbrev-tables however. To give a clearer idea of what I have in mind, here is what I envision the macro (approximately) to expand into. (I have not yet even tried to debug this, because at this stage it is just a proposal.) Note that it is just an amended version of what define-derived-mode with a PARENT of nil or fundamental-mode would expand into, but it eliminates the second type of bug I reported in my previous message and it takes care of all objections I formulated above. (progn (defvar mymode-map (make-sparse-keymap)) (unless syntax-table (defvar mymode-syntax-table (make-syntax-table))) (unless abbrev-table (defvar mymode-abbrev-table (progn (define-abbrev-table 'mymode-abbrev-table nil) mymode-abbrev-table))) (if mode-class (put 'mymode 'mode-class 'special)) (put 'mymode 'derived-mode-parent 'nil) (defun mymode nil "docstring\n\nThis mode runs the hook `mymode-hook', as the final step\nduring initialization.\n\n\\{mymode-map}" (interactive) (kill-all-local-variables) (setq major-mode 'mymode) (setq mode-name name) (use-local-map mymode-map) (set-syntax-table (or syntax-table mymode-syntax-table)) (setq local-abbrev-table (or abbrev-table mymode-abbrev-table)) body (run-mode-hooks 'my-mode-hook)))