From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: storm@cua.dk (Kim F. Storm) Newsgroups: gmane.emacs.devel Subject: [gmane.emacs.sources] dir-locals.el (was: dirvars.el 1.3) Date: Tue, 20 Jun 2006 13:13:54 +0200 Message-ID: NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1150802185 22521 80.91.229.2 (20 Jun 2006 11:16:25 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Tue, 20 Jun 2006 11:16:25 +0000 (UTC) Cc: Dave Love Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Jun 20 13:16:22 2006 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1FseDV-0004xZ-Ju for ged-emacs-devel@m.gmane.org; Tue, 20 Jun 2006 13:16:22 +0200 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1FseDU-0007HI-TM for ged-emacs-devel@m.gmane.org; Tue, 20 Jun 2006 07:16:21 -0400 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1FseDC-0007DX-MT for emacs-devel@gnu.org; Tue, 20 Jun 2006 07:16:02 -0400 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1FseDB-0007D2-NX for emacs-devel@gnu.org; Tue, 20 Jun 2006 07:16:02 -0400 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1FseDB-0007Cu-Fh for emacs-devel@gnu.org; Tue, 20 Jun 2006 07:16:01 -0400 Original-Received: from [195.41.46.236] (helo=pfepb.post.tele.dk) by monty-python.gnu.org with esmtp (Exim 4.52) id 1FseNe-0007gC-Nu; Tue, 20 Jun 2006 07:26:51 -0400 Original-Received: from kfs-l.imdomain.dk.cua.dk (unknown [80.165.4.124]) by pfepb.post.tele.dk (Postfix) with SMTP id 04B0DA50031; Tue, 20 Jun 2006 13:15:56 +0200 (CEST) Original-To: emacs-devel@gnu.org User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:56027 Archived-At: Dave Love has written a clean alternative to the "dirvars" package posted recently, but recent (major) changes to hack-local-variables broke his code. Before, hack-local-variables-hook was run unconditionally at the end of hack-local-variables, but now it is only run if the file has local variables. Is that change intentional or just an oversight? Here is Dave's code: ;;; dir-locals.el --- Local variables for a directory tree ;; Copyright (C) 2005, 2006 Free Software Foundation, Inc. ;; Author: Dave Love ;; Keywords: files ;; $Revision: 1.6 $ ;; URL: http://www.loveshack.ukfsn.org/emacs ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; It can be useful to specify local variables directory-wide, e.g. to ;; define CC mode styles consistently. This library implements such a ;; scheme, controlled by the global minor mode `dir-locals-mode'. ;; Place a file named `.emacs-locals' (or the value of ;; `dir-locals-file-name') in the directory root. This should specify ;; local variables in the usual way. The values it sets are inherited ;; when a file in the directory tree is found. Local variables ;; specified in the found file override the directory-wide ones. ;; However, `eval' pseudo-variables specified in the file are ;; evaluated (assuming `enable-local-eval' is true) _before_ any ;; directory-wide processing, and they are evaluated in a scratch ;; buffer, so that they are only useful for side effects on local ;; variables. `mode' pseudo-variables which specify minor modes ;; toggle those modes for files within the directory. If ;; .emacs-locals specifies a major mode, it doesn't propagate, but any ;; local variables and minor modes its hook sets will; thus it should ;; normally not specify a major mode. The `coding' pseudo-variable ;; will not propagate from .emacs-locals. ;; For example, with dir-locals mode on, placing this in .emacs-locals ;; at the top-level of the Linux source tree would set the C ;; indentation style appropriately for files within the tree: ;; ;; Local variables: ;; c-file-style: "linux" ;; End: ;; ;; (and ignore the stupid remarks in Documentation/CodingStyle). ;; Another possible use is, say, setting change-log parameters in ;; different trees for which the Emacs 22 development source broke use ;; of change-log-mode-hook. ;; NB: this no longer works properly with the Emacs 22 codebase since ;; that changed the way hack-local-variables-hook is run; sigh. In ;; that case it falls back to using `find-file-hook', which doesn't ;; really do the right thing, but should mostly work OK. ;; Another, less clean, implementation of this sort of thing was ;; posted to gnu-emacs-sources as dirvals.el by Benjamin Rutt ;; , June 2006, based on work by Matt Armstrong ;; . It uses a different format for the equivalent ;; of .emacs-locals. ;;; Code: (defgroup dir-locals () "Directory-wide file-local variables" :link '(emacs-commentary-link "dir-locals") :group 'files) (defcustom dir-locals-file-name ".emacs-locals" "File name used by Dir-Locals mode to specify local variables. This should specify local variables in the normal way. When Dir-Locals minor mode is active, these will be inherited by files found in a directory tree containing such a file at its root. This may also be a function of no arguments which returns the name to use, allowing arbitrary per-directory customization of the per-directory customization file on the basis of `default-directory'." :group 'dir-locals :type '(choice file function)) ;; Adapted from dirvals.el. (defcustom dir-locals-chase-remote nil "Non-nil means search upwards for `dir-locals-file-name' in remote filesystem." :group 'dir-locals :type 'boolean) (define-minor-mode dir-locals-mode "Toggle use of directory-wide file-local variables. See `dir-locals-file-name'." :global t ;; Emacs 22 doesn't run `hack-local-variables-hook' if the file has ;; no local variables; sigh. Using this new hook at least doesn't ;; catch the case of just changing the major mode, but mostly works. (if (boundp 'find-file-hook) (if dir-locals-mode (add-hook 'find-file-hook 'dir-locals-hack-local-variables) (remove-hook 'find-file-hook 'dir-locals-hack-local-variables)) (if dir-locals-mode (add-hook 'hack-local-variables-hook 'dir-locals-hack-local-variables) (remove-hook 'hack-local-variables-hook 'dir-locals-hack-local-variables)))) ;; Following find-change-log. Fixme: Should be abstracted from there. (defun dir-locals-tree-find (file) "Find FILE in the current directory or one of its parents. If one is found, return its fully-qualified name, otherwise return nil. FILE may be a string or a nullary function returning one on the basis of `default-directory'." (unless (and (not dir-locals-chase-remote) (fboundp 'file-remote-p) ; not in Emacs 21 (file-remote-p default-directory)) (let* ((dir-name ;; Chase links in the source file and start searching in ;; the dir where it resides. (or (if buffer-file-name (file-name-directory (file-chase-links buffer-file-name))) default-directory)) (file (if (functionp file) (funcall file) file)) (file1 (if (file-directory-p dir-name) (expand-file-name file dir-name)))) ;; Chase links before visiting the file. This makes it easier ;; to use a file for several related directories. (setq file1 (expand-file-name (file-chase-links file1))) ;; Move up in the dir hierarchy till we find a suitable file. (while (and (not (file-exists-p file1)) (setq dir-name (file-name-directory (directory-file-name (file-name-directory file1)))) ;; Give up if we are already at the root dir. (not (string= (file-name-directory file1) dir-name))) ;; Move up to the parent dir and try again. (setq file1 (expand-file-name (file-name-nondirectory file) dir-name))) (if (file-exists-p file1) file1)))) (defun dir-locals-hack-local-variables () "Set local variables from directory-wide values. Inherit the local variables set in `dir-locals-file-name' if that is found by `dir-locals-tree-find'. Ignore everything ignored by `hack-local-variables'." (let* ((file (dir-locals-tree-find dir-locals-file-name)) (hack-local-variables-hook nil) (buffer-file (if buffer-file-name (expand-file-name (file-chase-links buffer-file-name)))) ;; Fixme: Probably condition-case this and ensure any error ;; messages indicate the directory file. (vars (when (and file ;; Don't do it twice, so as to avoid ;; repeating possible interactive queries. (not (equal file buffer-file))) (with-temp-buffer ;; Make queries from `hack-local-variables' clearer. (rename-buffer (file-name-nondirectory file) t) (insert-file-contents file) (let* ((locals (buffer-local-variables)) (_ (hack-local-variables)) (new-locals (buffer-local-variables))) ;; Derive the list of new pairs. (dolist (l locals) (setq new-locals (delete l new-locals))) ;; And some internals which get updated. (dolist (l '(buffer-display-time buffer-display-count)) (setq new-locals (assq-delete-all l new-locals))) new-locals))))) (dolist (v vars) (let ((sym (car v))) (unless (local-variable-p sym) ; file-locals take precedence (if (and (string-match "-mode\\'" (symbol-name sym)) (fboundp sym)) (funcall sym) (set (make-local-variable sym) (cdr v)))))))) (provide 'dir-locals) ;;; dir-locals.el ends here -- Kim F. Storm http://www.cua.dk