summaryrefslogtreecommitdiffstats
path: root/emacs.d/lisp/dir-locals.el
diff options
context:
space:
mode:
Diffstat (limited to 'emacs.d/lisp/dir-locals.el')
-rw-r--r--emacs.d/lisp/dir-locals.el183
1 files changed, 183 insertions, 0 deletions
diff --git a/emacs.d/lisp/dir-locals.el b/emacs.d/lisp/dir-locals.el
new file mode 100644
index 0000000..f88457b
--- /dev/null
+++ b/emacs.d/lisp/dir-locals.el
@@ -0,0 +1,183 @@
+;;; dir-locals.el --- Local variables for a directory tree
+
+;; Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+
+;; Author: Dave Love <fx@gnu.org>
+;; Keywords: files
+;; $Revision: 1.7 $
+;; 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 doesn't work with some versions of the Emacs 22 codebase
+;; which changed the way hack-local-variables-hook is run, but the
+;; change has been reverted.
+
+;; Another, less clean, implementation of this sort of thing was
+;; posted to gnu-emacs-sources as dirvals.el by Benjamin Rutt
+;; <rutt.4@osu.edu>, June 2006, based on work by Matt Armstrong
+;; <matt@lickey.com>. 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
+ (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