Subject: Re: bug#8586: 23.3.50; Directory-local variable ignored when file-local variables set mode

From: Glenn Morris <[email-masked]>
Date: Sat, 21 May 2011 21:35:49 -0400

I think this area is a bit of mess, but here is an attempt at a fix.

In the longer term, since they do a lot of the same thing, unifying
set-auto-mode and set-auto-coding might make sense (eg to solve bug#7169).

*** lisp/files.el	2011-05-22 01:18:49 +0000
--- lisp/files.el	2011-05-22 01:28:30 +0000
***************
*** 2244,2250 ****
      (report-errors "File mode specification error: %s"
        (set-auto-mode))
      (report-errors "File local-variables error: %s"
!       (hack-local-variables)))
    ;; Turn font lock off and on, to make sure it takes account of
    ;; whatever file local variables are relevant to it.
    (when (and font-lock-mode
--- 2244,2250 ----
      (report-errors "File mode specification error: %s"
        (set-auto-mode))
      (report-errors "File local-variables error: %s"
!       (hack-local-variables nil t)))
    ;; Turn font lock off and on, to make sure it takes account of
    ;; whatever file local variables are relevant to it.
    (when (and font-lock-mode
***************
*** 2616,2631 ****
    "Select major mode appropriate for current buffer.
  
  To find the right major mode, this function checks for a -*- mode tag,
  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 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
--- 2616,2629 ----
    "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'.
  
! If `enable-local-variables' is nil, this function does not check for
! any mode: tag.
  
  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
***************
*** 2667,2672 ****
--- 2665,2677 ----
  	      (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)
+ 	 (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.
***************
*** 3144,3155 ****
  		   (assq-delete-all (car elt) file-local-variables-alist)))
  	   (push elt file-local-variables-alist)))))
  
! (defun hack-local-variables (&optional mode-only)
    "Parse and put into effect this buffer's local variables spec.
  If MODE-ONLY is non-nil, all we do is check whether a \"mode:\"
  is specified, and return the corresponding mode symbol, or nil.
  In this case, we try to ignore minor-modes, and only return a
! major-mode."
    (let ((enable-local-variables
  	 (and local-enable-local-variables enable-local-variables))
  	result)
--- 3149,3164 ----
  		   (assq-delete-all (car elt) file-local-variables-alist)))
  	   (push elt file-local-variables-alist)))))
  
! (defun hack-local-variables (&optional mode-only keep-mode-if-same)
    "Parse and put into effect this buffer's local variables spec.
  If MODE-ONLY is non-nil, all we do is check whether a \"mode:\"
  is specified, and return the corresponding mode symbol, or nil.
  In this case, we try to ignore minor-modes, and only return a
! major-mode.
! 
! If the optional argument KEEP-MODE-IF-SAME is non-nil, then we
! ignore a mode: entry if it specifies the same major-mode as the
! buffer already has."
    (let ((enable-local-variables
  	 (and local-enable-local-variables enable-local-variables))
  	result)
***************
*** 3186,3192 ****
  	      (forward-line 1)
  	      (let ((startpos (point))
  		    endpos
! 		    (thisbuf (current-buffer)))
  		(save-excursion
  		  (unless (let ((case-fold-search t))
  			    (re-search-forward
--- 3195,3202 ----
  	      (forward-line 1)
  	      (let ((startpos (point))
  		    endpos
! 		    (thisbuf (current-buffer))
! 		    (thismajor major-mode))
  		(save-excursion
  		  (unless (let ((case-fold-search t))
  			    (re-search-forward
***************
*** 3242,3248 ****
  				     "-minor\\'"
  				     (setq val2 (symbol-name val))))
  			       (setq result (intern (concat val2 "-mode"))))
! 			(unless (eq var 'coding)
  			  (condition-case nil
  			      (push (cons (if (eq var 'eval)
  					      'eval
--- 3252,3266 ----
  				     "-minor\\'"
  				     (setq val2 (symbol-name val))))
  			       (setq result (intern (concat val2 "-mode"))))
! 			(or (eq var 'coding)
! 			    (and keep-mode-if-same
! 				 (eq var 'mode)
! 				 (functionp
! 				  (setq val2
! 					(intern
! 					 (concat (symbol-name val) "-mode"))))
! 				 (eq (indirect-function thismajor)
! 				     (indirect-function val2)))
  			    (condition-case nil
  				(push (cons (if (eq var 'eval)
  						'eval