unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: storm@cua.dk (Kim F. Storm)
Cc: Dave Love <fx@gnu.org>
Subject: [gmane.emacs.sources] dir-locals.el (was: dirvars.el 1.3)
Date: Tue, 20 Jun 2006 13:13:54 +0200	[thread overview]
Message-ID: <m31wtkw03x.fsf@kfs-l.imdomain.dk> (raw)


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 <fx@gnu.org>
;; 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
;; <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
  ;; 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 <storm@cua.dk> http://www.cua.dk

             reply	other threads:[~2006-06-20 11:13 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-06-20 11:13 Kim F. Storm [this message]
2006-06-20 12:36 ` [gmane.emacs.sources] dir-locals.el Chong Yidong
2006-06-20 22:23   ` Chong Yidong
2006-08-02  8:39     ` Masatake YAMATO
2006-08-02 21:20       ` Richard Stallman
2006-06-20 22:18 ` [gmane.emacs.sources] dir-locals.el (was: dirvars.el 1.3) Richard Stallman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m31wtkw03x.fsf@kfs-l.imdomain.dk \
    --to=storm@cua.dk \
    --cc=fx@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).