From 59f8c56d9e71a1b61ca8cc0794a6de4aa2f240e4 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 3 Oct 2022 11:17:51 -0400 Subject: [PATCH] files.el (major-mode-remap-alist): New custom var (bug#58075) * lisp/files.el (major-mode-remap-alist): New custom var. (set-auto-mode--last): New var. (set-auto-mode-0): Obey `major-mode-remap-alist`. * doc/emacs/modes.texi (Choosing Modes): Document `major-mode-remap-alist`. * lisp/progmodes/cperl-mode.el: Recommend the use of `major-mode-remap-alist` over the crude `defalias` solution. * lisp/textmodes/tex-mode.el (tex--guess-mode): Simplify. (tex--redirect-to-submode): Obey `major-mode-remap-alist`. --- doc/emacs/modes.texi | 7 +++++ etc/NEWS | 9 ++++++ lisp/files.el | 26 +++++++++++++--- lisp/progmodes/cperl-mode.el | 2 +- lisp/textmodes/tex-mode.el | 57 +++++++++++++++++------------------- 5 files changed, 66 insertions(+), 35 deletions(-) diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi index c348130807c..56b779f8de6 100644 --- a/doc/emacs/modes.texi +++ b/doc/emacs/modes.texi @@ -454,6 +454,13 @@ only @emph{after} @code{auto-mode-alist}. By default, files, HTML/XML/SGML files, PostScript files, and Unix style Conf files. +@vindex major-mode-remap-alist + Once a major mode is found, Emacs does a final check to see if the +mode has been remapped by @code{major-mode-remap-alist}, in which case +it uses the remapped mode instead. This is used when several +different major modes can be used for the same file type, so you can +specify which mode you prefer. + @findex normal-mode If you have changed the major mode of a buffer, you can return to the major mode Emacs would have chosen automatically, by typing diff --git a/etc/NEWS b/etc/NEWS index 6e7836e3c09..9e9f9b65030 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -477,6 +477,15 @@ option) and can be set to nil to disable Just-in-time Lock mode. * Changes in Emacs 29.1 ++++ +** New variable 'major-mode-remap-alist' to specify your favorite major modes. +This variable lets you remap the default modes (e.g. 'perl-mode' or +'latex-mode') to your favorite ones (e.g. 'cperl-mode' or +'LaTeX-mode') without having to use 'defalias', which can have +undesirable side effects. +This applies to all modes specified via 'auto-mode-alist', file-local +variables, etc... + --- ** Emacs now supports Unicode Standard version 15.0. diff --git a/lisp/files.el b/lisp/files.el index 40ad11ecfc4..667e3325bb7 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3333,6 +3333,7 @@ checks if it uses an interpreter listed in `interpreter-mode-alist', matches the buffer beginning against `magic-mode-alist', compares the file name against the entries in `auto-mode-alist', then matches the buffer beginning against `magic-fallback-mode-alist'. +It also obeys `major-mode-remap-alist'. If `enable-local-variables' is nil, or if the file name matches `inhibit-local-variables-regexps', this function does not check @@ -3470,6 +3471,17 @@ we don't actually set it to the same mode the buffer already has." (unless done (set-buffer-major-mode (current-buffer))))) +(defvar-local set-auto-mode--last nil + "Remember the mode we have set via `set-auto-mode-0'.") + +(defcustom major-mode-remap-alist nil + "Alist mapping file-specified mode to actual mode. +Every entry is of the form (MODE . FUNCTION) which means that in order +to activate the major mode MODE (specified via something like +`auto-mode-alist', file-local variables, ...) we should actually call +FUNCTION instead." + :type '(alist (symbol) (function))) + ;; When `keep-mode-if-same' is set, we are working on behalf of ;; set-visited-file-name. In that case, if the major mode specified is the ;; same one we already have, don't actually reset it. We don't want to lose @@ -3480,10 +3492,15 @@ If optional arg KEEP-MODE-IF-SAME is non-nil, MODE is chased of any aliases and compared to current major mode. If they are the same, do nothing and return nil." (unless (and keep-mode-if-same - (eq (indirect-function mode) - (indirect-function major-mode))) + (or (eq (indirect-function mode) + (indirect-function major-mode)) + (and set-auto-mode--last + (eq mode (car set-auto-mode--last)) + (eq major-mode (cdr set-auto-mode--last))))) (when mode - (funcall mode) + (funcall (alist-get mode major-mode-remap-alist mode)) + (unless (eq mode major-mode) + (setq set-auto-mode--last (cons mode major-mode))) mode))) (defvar file-auto-mode-skip "^\\(#!\\|'\\\\\"\\)" @@ -3513,7 +3530,8 @@ have no effect." ;; interpreter invocation. The same holds ;; for '\" in man pages (preprocessor ;; magic for the `man' program). - (and (looking-at file-auto-mode-skip) 2)) t) + (and (looking-at file-auto-mode-skip) 2)) + t) (progn (skip-chars-forward " \t") (setq beg (point)) diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el index fa428642fa4..20a73e238e9 100644 --- a/lisp/progmodes/cperl-mode.el +++ b/lisp/progmodes/cperl-mode.el @@ -632,7 +632,7 @@ mode-compile.el. If your Emacs does not default to `cperl-mode' on Perl files, and you want it to: put the following into your .emacs file: - (defalias \\='perl-mode \\='cperl-mode) + (add-to-list \\='major-mode-remap-alist \\='(perl-mode . cperl-mode)) Get perl5-info from $CPAN/doc/manual/info/perl5-old/perl5-info.tar.gz diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el index b43537265f5..5c2dbdfe5cd 100644 --- a/lisp/textmodes/tex-mode.el +++ b/lisp/textmodes/tex-mode.el @@ -980,24 +980,23 @@ Inherits `shell-mode-map' with a few additions.") (save-excursion (beginning-of-line) (search-forward "%" search-end t)))))) - (when (and slash (not comment)) - (setq mode - (if (looking-at - (concat - (regexp-opt '("documentstyle" "documentclass" - "begin" "subsection" "section" - "part" "chapter" "newcommand" - "renewcommand" "RequirePackage") - 'words) - "\\|NeedsTeXFormat{LaTeX")) - (if (and (looking-at - "document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}") - ;; SliTeX is almost never used any more nowadays. - (tex-executable-exists-p slitex-run-command)) - #'slitex-mode - #'latex-mode) - #'plain-tex-mode)))) - mode)) + (if (not (and slash (not comment))) + mode + (if (looking-at + (concat + (regexp-opt '("documentstyle" "documentclass" + "begin" "subsection" "section" + "part" "chapter" "newcommand" + "renewcommand" "RequirePackage") + 'words) + "\\|NeedsTeXFormat{LaTeX")) + (if (and (looking-at + "document\\(style\\|class\\)\\(\\[.*\\]\\)?{slides}") + ;; SliTeX is almost never used any more nowadays. + (tex-executable-exists-p slitex-run-command)) + #'slitex-mode + #'latex-mode) + #'plain-tex-mode))))) ;; `tex-mode' plays two roles: it's the parent of several sub-modes ;; but it's also the function that chooses between those submodes. @@ -1029,20 +1028,18 @@ says which mode to use." ;; We're called from one of the children already. orig-fun (setq tex-mode--recursing t) - (tex--guess-mode))))) + (let ((mode (tex--guess-mode))) + ;; `tex--guess-mode' really tries to guess the *type* of file, + ;; so we still need to consult `major-mode-remap-alist' + ;; to see which mode to use for that type. + (funcall (alist-get mode major-mode-remap-alist mode))))))) ;; The following three autoloaded aliases appear to conflict with -;; AUCTeX. However, even though AUCTeX uses the mixed case variants -;; for all mode relevant variables and hooks, the invocation function -;; and setting of `major-mode' themselves need to be lowercase for -;; AUCTeX to provide a fully functional user-level replacement. So -;; these aliases should remain as they are, in particular since AUCTeX -;; users are likely to use them. -;; Note from Stef: I don't understand the above explanation, the only -;; justification I can find to keep those confusing aliases is for those -;; users who may have files annotated with -*- LaTeX -*- (e.g. because they -;; received them from someone using AUCTeX). - +;; AUCTeX. We keep those confusing aliases for those users who may +;; have files annotated with -*- LaTeX -*- (e.g. because they received +;; them from someone using AUCTeX). +;; FIXME: Turn them into autoloads so that AUCTeX can override them +;; with it's own autoloads? Or maybe rely on `major-mode-remap-alist'? ;;;###autoload (defalias 'TeX-mode #'tex-mode) ;;;###autoload (defalias 'plain-TeX-mode #'plain-tex-mode) ;;;###autoload (defalias 'LaTeX-mode #'latex-mode) -- 2.39.2