[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gmane.emacs.sources] dir-locals.el (was: dirvars.el 1.3)
Kim F. Storm
[gmane.emacs.sources] dir-locals.el (was: dirvars.el 1.3)
Tue, 20 Jun 2006 13:13:54 +0200
Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)
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
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 <address@hidden>
;; 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.
;; 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"
;; (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
;; <address@hidden>, June 2006, based on work by Matt Armstrong
;; <address@hidden>. It uses a different format for the equivalent
;; of .emacs-locals.
(defgroup dir-locals ()
"Directory-wide file-local variables"
:link '(emacs-commentary-link "dir-locals")
(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'."
: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
"Toggle use of directory-wide file-local variables.
;; 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)
(add-hook 'find-file-hook 'dir-locals-hack-local-variables)
(remove-hook 'find-file-hook 'dir-locals-hack-local-variables))
(add-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
FILE may be a string or a nullary function returning one on the basis
(unless (and (not dir-locals-chase-remote)
(fboundp 'file-remote-p) ; not in Emacs 21
;; 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)))
(file (if (functionp 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
;; 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)
(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
(let* ((file (dir-locals-tree-find dir-locals-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)))
;; Make queries from `hack-local-variables' clearer.
(rename-buffer (file-name-nondirectory file) t)
(let* ((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)))
(dolist (v vars)
(let ((sym (car v)))
(unless (local-variable-p sym) ; file-locals take precedence
(if (and (string-match "-mode\\'" (symbol-name sym))
(set (make-local-variable sym) (cdr v))))))))
;;; dir-locals.el ends here
Kim F. Storm <address@hidden> http://www.cua.dk
- [gmane.emacs.sources] dir-locals.el (was: dirvars.el 1.3),
Kim F. Storm <=