From e145f1881a460f77190b02968657d58b73ab8f56 Mon Sep 17 00:00:00 2001 From: Glenn Morris Date: Thu, 26 May 2011 21:00:53 -0400 Subject: [PATCH] Make set-auto-mode respect mode: entries at the end of the file (bug#8586) * lisp/files.el (set-auto-mode): Also respect mode: entries at the end of the file. * doc/lispref/modes.texi (Auto Major Mode): Update for set-auto-mode changes. * doc/emacs/custom.texi (Specifying File Variables): Major modes no longer need come first. * etc/NEWS: Mention this. --- doc/emacs/ChangeLog | 5 +++++ doc/emacs/custom.texi | 10 ++++------ doc/lispref/ChangeLog | 4 ++++ doc/lispref/modes.texi | 19 ++++++++----------- etc/NEWS | 4 ++++ lisp/ChangeLog | 5 +++++ lisp/files.el | 23 +++++++++++++++++------ 7 files changed, 47 insertions(+), 23 deletions(-) diff --git a/doc/emacs/ChangeLog b/doc/emacs/ChangeLog index 2bf07904172..d2f2c23ee3d 100644 --- a/doc/emacs/ChangeLog +++ b/doc/emacs/ChangeLog @@ -1,3 +1,8 @@ +2011-05-27 Glenn Morris + + * custom.texi (Specifying File Variables): + Major modes no longer need come first. + 2011-05-22 Chong Yidong * mule.texi (Specify Coding, Text Coding, Communication Coding): diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi index d9fdff138ac..9add95a5b48 100644 --- a/doc/emacs/custom.texi +++ b/doc/emacs/custom.texi @@ -1130,7 +1130,10 @@ the file is divided into pages. If a file has both a local variables list and a @samp{-*-} line, Emacs processes @emph{everything} in the @samp{-*-} line first, and -@emph{everything} in the local variables list afterward. +@emph{everything} in the local variables list afterward. The exception +to this is a major mode specification. Emacs applies this first, +wherever it appears, since most major modes kill all local variables as +part of their initialization. A local variables list starts with a line containing the string @samp{Local Variables:}, and ends with a line containing the string @@ -1205,11 +1208,6 @@ value is @code{t}. @xref{Enabling Multibyte}. These four ``variables'' are not really variables; setting them in any other context has no special meaning. - @emph{If @code{mode} is used to set a major mode, it should be the -first ``variable'' in the list.} Otherwise, the entries that precede -it will usually have no effect, since most major modes kill all local -variables as part of their initialization. - You can use the @code{mode} ``variable'' to enable minor modes as well as the major modes; in fact, you can use it more than once, first to set the major mode and then to enable minor modes which are diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index c23073e4254..90818486e21 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,7 @@ +2011-05-27 Glenn Morris + + * modes.texi (Auto Major Mode): Update for set-auto-mode changes. + 2011-05-26 Glenn Morris * variables.texi (File Local Variables): diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 609c713194a..29041151e52 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -583,12 +583,9 @@ If you run @code{normal-mode} interactively, the argument @var{find-file} is normally @code{nil}. In this case, @code{normal-mode} unconditionally processes any file local variables. -If @code{normal-mode} processes the local variables list and this list -specifies a major mode, that mode overrides any mode chosen by -@code{set-auto-mode}. If neither @code{set-auto-mode} nor -@code{hack-local-variables} specify a major mode, the buffer stays in -the major mode determined by the default value of @code{major-mode} -(see below). +The function calls @code{set-auto-mode} to choose a major mode. If it +does not specify a mode, the buffer stays in the major mode determined +by the default value of @code{major-mode} (see below). @cindex file mode specification error @code{normal-mode} uses @code{condition-case} around the call to the @@ -600,15 +597,15 @@ mode specification error}, followed by the original error message. @cindex visited file mode This function selects the major mode that is appropriate for the current buffer. It bases its decision (in order of precedence) on -the @w{@samp{-*-}} line, on the @w{@samp{#!}} line (using +the @w{@samp{-*-}} line, on any @samp{mode:} local variable near the +end of a file, on the @w{@samp{#!}} line (using @code{interpreter-mode-alist}), on the text at the beginning of the buffer (using @code{magic-mode-alist}), and finally on the visited file name (using @code{auto-mode-alist}). @xref{Choosing Modes, , How -Major Modes are Chosen, emacs, The GNU Emacs Manual}. However, this -function does not look for the @samp{mode:} local variable near the -end of a file; the @code{hack-local-variables} function does that. +Major Modes are Chosen, emacs, The GNU Emacs Manual}. If @code{enable-local-variables} is @code{nil}, @code{set-auto-mode} -does not check the @w{@samp{-*-}} line for a mode tag either. +does not check the @w{@samp{-*-}} line, or near the end of the file, +for any mode tag. If @var{keep-mode-if-same} is non-@code{nil}, this function does not call the mode command if the buffer is already in the proper major diff --git a/etc/NEWS b/etc/NEWS index a4ca2961aed..d6fa4117c4c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -993,6 +993,10 @@ being reverted, even if the buffer has a local `revert-buffer-function'. ** New variables `delayed-warnings-list' and `delayed-warnings-hook' allow deferring warnings until the main command loop is executed. ++++ +** `set-auto-mode' now respects mode: local variables at the end of files, +as well as those in the -*- line. + * Changes in Emacs 24.1 on non-free operating systems diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 4750040bd75..acde2b246c8 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2011-05-27 Glenn Morris + + * files.el (set-auto-mode): + Also respect mode: entries at the end of the file. (Bug#8586) + 2011-05-26 Glenn Morris * files.el (hack-local-variables-prop-line, hack-local-variables): diff --git a/lisp/files.el b/lisp/files.el index 4f037c2a997..7102e0880ab 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -2241,6 +2241,8 @@ in that case, this function acts as if `enable-local-variables' were t." (interactive) (funcall (or (default-value 'major-mode) 'fundamental-mode)) (let ((enable-local-variables (or (not find-file) enable-local-variables))) + ;; FIXME this is less efficient than it could be, since both + ;; s-a-m and h-l-v may parse the same regions, looking for "mode:". (report-errors "File mode specification error: %s" (set-auto-mode)) (report-errors "File local-variables error: %s" @@ -2616,23 +2618,24 @@ Also applies to `magic-fallback-mode-alist'.") "Select major mode appropriate for current buffer. To find the right major mode, this function checks for a -*- mode tag, +checks for a `mode:' entry in the Local Variables section of the file, checks if it uses an interpreter listed in `interpreter-mode-alist', matches the buffer beginning against `magic-mode-alist', compares the filename against the entries in `auto-mode-alist', then matches the buffer beginning against `magic-fallback-mode-alist'. -It does not check for the `mode:' local variable in the -Local Variables section of the file; for that, use `hack-local-variables'. - -If `enable-local-variables' is nil, this function does not check for a --*- mode tag. +If `enable-local-variables' is nil, this function does not check for +any mode: tag anywhere in the file. If the optional argument KEEP-MODE-IF-SAME is non-nil, then we set the major mode only if that would change it. In other words we don't actually set it to the same mode the buffer already has." ;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*- (let (end done mode modes) - ;; Find a -*- mode tag + ;; Once we drop the deprecated feature where mode: is also allowed to + ;; specify minor-modes (ie, there can be more than one "mode:), we can + ;; remove this section and just let (hack-local-variables t) handle it. + ;; Find a -*- mode tag. (save-excursion (goto-char (point-min)) (skip-chars-forward " \t\n") @@ -2667,6 +2670,14 @@ we don't actually set it to the same mode the buffer already has." (or (set-auto-mode-0 mode keep-mode-if-same) ;; continuing would call minor modes again, toggling them off (throw 'nop nil)))))) + (and (not done) + enable-local-variables + (setq mode (hack-local-variables t)) + (not (memq mode modes)) ; already tried and failed + (if (not (functionp mode)) + (message "Ignoring unknown mode `%s'" mode) + (setq done t) + (set-auto-mode-0 mode keep-mode-if-same))) ;; If we didn't, look for an interpreter specified in the first line. ;; As a special case, allow for things like "#!/bin/env perl", which ;; finds the interpreter anywhere in $PATH.