From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Alan Mackenzie Newsgroups: gmane.emacs.bugs Subject: bug#23407: .dir-local settings get obliterated on running a major mode function. Date: Sun, 1 May 2016 21:28:46 +0000 Message-ID: <20160501212846.GA4228@acm.fritz.box> References: <20160430102744.GA4644@acm.fritz.box> <0joa8rszhb.fsf@fencepost.gnu.org> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1462138187 19701 80.91.229.3 (1 May 2016 21:29:47 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 1 May 2016 21:29:47 +0000 (UTC) Cc: yary , 23407@debbugs.gnu.org, Stefan Monnier , Dmitry Gutov To: Glenn Morris Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Sun May 01 23:29:36 2016 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1awyvn-0006AC-OD for geb-bug-gnu-emacs@m.gmane.org; Sun, 01 May 2016 23:29:35 +0200 Original-Received: from localhost ([::1]:34381 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awyvj-0006FS-TI for geb-bug-gnu-emacs@m.gmane.org; Sun, 01 May 2016 17:29:31 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:52972) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awyvV-0005zd-LM for bug-gnu-emacs@gnu.org; Sun, 01 May 2016 17:29:24 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1awyvJ-0004EY-93 for bug-gnu-emacs@gnu.org; Sun, 01 May 2016 17:29:12 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:48777) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1awyvJ-0004D6-54 for bug-gnu-emacs@gnu.org; Sun, 01 May 2016 17:29:05 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1awyvF-0003sJ-Q8 for bug-gnu-emacs@gnu.org; Sun, 01 May 2016 17:29:01 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Alan Mackenzie Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 01 May 2016 21:29:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 23407 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 23407-submit@debbugs.gnu.org id=B23407.146213813214880 (code B ref 23407); Sun, 01 May 2016 21:29:01 +0000 Original-Received: (at 23407) by debbugs.gnu.org; 1 May 2016 21:28:52 +0000 Original-Received: from localhost ([127.0.0.1]:32881 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1awyv6-0003rw-DL for submit@debbugs.gnu.org; Sun, 01 May 2016 17:28:52 -0400 Original-Received: from mail.muc.de ([193.149.48.3]:60451) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1awyv3-0003rn-Uc for 23407@debbugs.gnu.org; Sun, 01 May 2016 17:28:50 -0400 Original-Received: (qmail 60318 invoked by uid 3782); 1 May 2016 21:28:48 -0000 Original-Received: from acm.muc.de (p579E946C.dip0.t-ipconnect.de [87.158.148.108]) by colin.muc.de (tmda-ofmipd) with ESMTP; Sun, 01 May 2016 23:28:46 +0200 Original-Received: (qmail 2291 invoked by uid 1000); 1 May 2016 21:28:46 -0000 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.24 (2015-08-30) X-Delivery-Agent: TMDA/1.1.12 (Macallan) X-Primary-Address: acm@muc.de 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: 208.118.235.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:117550 Archived-At: Hello, Glenn. On Sat, Apr 30, 2016 at 02:53:07PM -0400, Glenn Morris wrote: > PS dupe of http://debbugs.gnu.org/15577 More fully known as: Subject: bug#15577: 24.3; dir-local variables not applied when switching major-mode Date: Wed, 9 Oct 2013 16:14:00 -0400 From: yary Thanks for the reference. I'd actually searched debbugs for ".dir-locals" and found nothing. Anyhow, I've hacked a patch together. The idea is to call `hack-local-variables' from `run-mode-hooks' rather than from `normal-mode'. Of course, it's never quite that simple. The main thing is that the local variables are now set with the major mode rather than with the visiting of the file. So file/directory local variables are now not lost on setting the major mode. The following patch is based on the master branch from earlier on today. diff --git a/lisp/files.el b/lisp/files.el index 132ebce..940a9ac 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -2322,8 +2322,13 @@ normal-mode ;; s-a-m and h-l-v may parse the same regions, looking for "mode:". (with-demoted-errors "File mode specification error: %s" (set-auto-mode)) - (with-demoted-errors "File local-variables error: %s" - (hack-local-variables))) + ;; delay-mode-hooks is set when `byte-compile-file' is the caller. + ;; It is essential that we call `hack-local-variables' in order to + ;; set up `lexical-binding', since `run-mode-hooks' is prevented + ;; from doing its job. + (when delay-mode-hooks + (with-demoted-errors "File local-variables error: %s" + (hack-local-variables 'no-mode)))) ;; 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 @@ -3297,11 +3302,15 @@ hack-local-variables-filter ;; TODO? Warn once per file rather than once per session? (defvar hack-local-variables--warned-lexical nil) -(defun hack-local-variables (&optional mode-only) +(defun hack-local-variables (&optional handle-mode) "Parse and put into effect this buffer's local variables spec. Uses `hack-local-variables-apply' to apply the variables. -If MODE-ONLY is non-nil, all we do is check whether a \"mode:\" +If HANDLE-MODE is nil, we apply all the specified local +variables. If HANDLE-MODE is neither nil nor t, we do the same, +except that any settings of `mode' are ignored. + +If HANDLE-MODE is t, 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. @@ -3319,7 +3328,7 @@ hack-local-variables (let ((enable-local-variables (and local-enable-local-variables enable-local-variables)) result) - (unless mode-only + (unless (eq handle-mode t) (setq file-local-variables-alist nil) (with-demoted-errors "Directory-local variables error: %s" ;; Note this is a no-op if enable-local-variables is nil. @@ -3327,18 +3336,19 @@ hack-local-variables ;; This entire function is basically a no-op if enable-local-variables ;; is nil. All it does is set file-local-variables-alist to nil. (when enable-local-variables - ;; This part used to ignore enable-local-variables when mode-only - ;; was non-nil. That was inappropriate, eg consider the + ;; This part used to ignore enable-local-variables when handle-mode + ;; was t. That was inappropriate, eg consider the ;; (artificial) example of: ;; (setq local-enable-local-variables nil) ;; Open a file foo.txt that contains "mode: sh". ;; It correctly opens in text-mode. ;; M-x set-visited-file name foo.c, and it incorrectly stays in text-mode. (unless (or (inhibit-local-variables-p) - ;; If MODE-ONLY is non-nil, and the prop line specifies a + ;; If HANDLE-MODE is t, and the prop line specifies a ;; mode, then we're done, and have no need to scan further. - (and (setq result (hack-local-variables-prop-line mode-only)) - mode-only)) + (and (setq result (hack-local-variables-prop-line + (eq handle-mode t))) + (eq handle-mode t))) ;; Look for "Local variables:" line in last page. (save-excursion (goto-char (point-max)) @@ -3393,7 +3403,7 @@ hack-local-variables (goto-char (point-min)) (while (not (or (eobp) - (and mode-only result))) + (and (eq handle-mode t) result))) ;; Find the variable name; (unless (looking-at hack-local-variable-regexp) (error "Malformed local variable line: %S" @@ -3410,7 +3420,7 @@ hack-local-variables (forward-char 1) (let ((read-circle nil)) (setq val (read (current-buffer)))) - (if mode-only + (if (eq handle-mode t) (and (eq var 'mode) ;; Specifying minor-modes via mode: is ;; deprecated, but try to reject them anyway. @@ -3432,6 +3442,7 @@ hack-local-variables ;; to use 'thisbuf's name in the ;; warning message. (or (buffer-file-name thisbuf) "")))))) + ((and (eq var 'mode) handle-mode)) (t (ignore-errors (push (cons (if (eq var 'eval) @@ -3440,8 +3451,8 @@ hack-local-variables val) result)))))) (forward-line 1)))))))) ;; Now we've read all the local variables. - ;; If MODE-ONLY is non-nil, return whether the mode was specified. - (if mode-only result + ;; If HANDLE-MODE is t, return whether the mode was specified. + (if (eq handle-mode t) result ;; Otherwise, set the variables. (hack-local-variables-filter result nil) (hack-local-variables-apply))))) diff --git a/lisp/subr.el b/lisp/subr.el index 5f8d830..162ac21 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1732,10 +1732,14 @@ after-change-major-mode-hook (defun run-mode-hooks (&rest hooks) "Run mode hooks `delayed-mode-hooks' and HOOKS, or delay HOOKS. -If the variable `delay-mode-hooks' is non-nil, does not run any hooks, +Call `hack-local-variables' to set up file local and directory local +variables. + +If the variable `delay-mode-hooks' is non-nil, does not do anything, just adds the HOOKS to the list `delayed-mode-hooks'. Otherwise, runs hooks in the sequence: `change-major-mode-after-body-hook', -`delayed-mode-hooks' (in reverse order), HOOKS, and finally +`delayed-mode-hooks' (in reverse order), HOOKS, then runs +`hack-local-variables' and finally runs the hook `after-change-major-mode-hook'. Major mode functions should use this instead of `run-hooks' when running their FOO-mode-hook." (if delay-mode-hooks @@ -1746,6 +1750,9 @@ run-mode-hooks (setq hooks (nconc (nreverse delayed-mode-hooks) hooks)) (setq delayed-mode-hooks nil) (apply 'run-hooks (cons 'change-major-mode-after-body-hook hooks)) + (if (buffer-file-name) + (with-demoted-errors "File local-variables error: %s" + (hack-local-variables 'no-mode))) (run-hooks 'after-change-major-mode-hook))) (defmacro delay-mode-hooks (&rest body) -- Alan Mackenzie (Nuremberg, Germany).