[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

dirvars.el 1.3

From: Benjamin Rutt
Subject: dirvars.el 1.3
Date: Thu, 15 Jun 2006 14:13:43 GMT
User-agent: Gnus/5.110002 (No Gnus v0.2) Emacs/22.0.50 (gnu/linux)

I'm finally releasing my dirvars.el changes based on Matt Armstrong's
work.  The only new feature is that you can customize whether it will
look upwards for .emacs-dirvars files if on a remote (tramp/ange-ftp)
filesystem, and it defaults to off, since it can slow down remote
filesystem access.  I use .emacs-dirvars for many things and recommend
others to try it.

;;; -*- local-enable-local-variables: nil -*-
;;; dirvars.el --- Local variables that apply to an entire directory

;; Copyright (C) 2002  Matt Armstrong

;; Author: Matt Armstrong <address@hidden>
;; Location:
;; Keywords: files
;; Version: 1.3
;; Obscure: address@hidden|elisp/dirvars.el|20021213043855|48166

;; 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
;; 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:

;; Emacs allows you to specify local variable values for use when
;; editing a file either in the first line or in a local variables
;; list.
;; This file provides similar functionality, but for an entire
;; directory tree.
;; You simply place an .emacs-dirvars file in the root of your
;; project's tree, and you can then set emacs variables like you would
;; in a Local Variables: section at the end of a file.  E.g. the
;; contents of a typical dirvars file might look like this:
;;    ;; -*- emacs-lisp -*-
;;    ;;
;;    ;; This file is processed by the dirvars emacs package.  Each variable
;;    ;; setting below is performed when this dirvars file is loaded.
;;    ;;
;;    indent-tabs-mode: nil
;;    tab-width: 8
;;    show-trailing-whitespace: t
;;    indicate-empty-lines: t
;; Much of this code is stolen and modified from the standard Emacs
;; files.el
;; This code refuses to set any symbol that meets any of these
;; criteria (this criteria is stolen from files.el):
;;   - the symbol is in the ignored-local-variables list
;;   - the symbol has the risky-local-variable property.
;;   - the symbol name ends in -hook(s), -function(s), -form(s),
;;     -program, -command, or -predicate.
;; change by Benjamin Rutt:  don't look upwards by default in a
;; remote filesystem

;;; Todo:

;; Implement the following changes to keep in line with elisp coding
;; conventions: When a package provides a modification of ordinary
;; Emacs behavior, it is good to include a command to enable and
;; disable the feature, Provide a command named `WHATEVER-mode' which
;; turns the feature on or off, and make it autoload (*note
;; Autoload::).  Design the package so that simply loading it has no
;; visible effect--that should not enable the feature.(2) Users will
;; request the feature by invoking the command.
;; Support customize?

;;; Code:

(defcustom dirvars-file-name ".emacs-dirvars"
  "File base name that is loaded by dirvars."
  :type 'string) 

(defcustom dirvars-chase-remote nil
  "Whether dirvars looks upward if in a remote filesystem."
  :type 'boolean)

(defvar dirvars-enable-flag t
  "*Control use of directory variables in files you visit.
The meaningful values are nil and non-nil.")

(defun dirvars-find-upwards (file-name)
  "Find a file in the current directory or one of its parents.

Returns the fully qualified file name, or nil if it isn't found.

The FILE-NAME specifies the file name to search for."
  (if (and (not dirvars-chase-remote) (file-remote-p default-directory))
    ;; Chase links in the source file and search in the dir where it
    ;; points.
    (setq dir-name (or (and buffer-file-name
                            (file-name-directory (file-chase-links
    ;; Chase links before visiting the file.  This makes it easier to
    ;; use a single file for several related directories.
    (setq dir-name (file-chase-links dir-name))
    (setq dir-name (expand-file-name dir-name))
    ;; Move up in the dir hierarchy till we find a change log file.
    (let ((file1 (concat dir-name file-name))
      (while (and (not (file-exists-p file1))
                  (progn (setq parent-dir
                                 (file-name-directory file1))))
                         ;; Give up if we are already at the root dir.
                         (not (string= (file-name-directory file1)
        ;; Move up to the parent dir and try again.
        (setq file1 (expand-file-name file-name parent-dir)))
      ;; If we found the file in a parent dir, use that.  Otherwise,
      ;; return nil
      (if (or (get-file-buffer file1) (file-exists-p file1))

(defun dirvars-eat-comment ()
  (while (looking-at "[ \t\n]*;")
    (let ((begin (point)))
      (skip-chars-forward " \t\n")
      (if (looking-at ";")
            (delete-region begin (point)))))))

(defun dirvars-hack-local-variables (dirvars-file)
    (let ((original-buffer (current-buffer))
          (temp-buffer (get-buffer-create "*dirvars-temp*"))
          (enable-local-variables (and local-enable-local-variables
          (continue t)
          (parse-sexp-ignore-comments t)
          (lisp-mode-hook nil)
      (set-buffer temp-buffer)
      (insert-file dirvars-file)
      (goto-char (point-min))
      (catch 'done
        (while continue
          (if (null (scan-sexps (point) 1))
              (throw 'done nil))
          (goto-char (scan-sexps (point) 1))
          (goto-char (scan-sexps (point) -1))
          (if (eobp)
              (throw 'done nil))
          (setq beg (point))
          (skip-chars-forward "^:\n")
          (if (not (looking-at ":"))
              (error (format "Missing colon in directory variables entry at %d"
          (skip-chars-backward " \t")
          (let* ((str (buffer-substring beg (point)))
                 (var (read str))
            ;; Read the variable value.
            (skip-chars-forward "^:")
            (forward-char 1)
            (setq val (read (current-buffer)))
              (set-buffer original-buffer)
              (dirvars-hack-one-local-variable dirvars-file
                                               var val))))))))

(defun dirvars-hack-one-local-variable (dirvars-file var val)
  "\"Set\" one variable in a local variables spec.
A few variable names are treated specially."
  (cond ((memq var ignored-local-variables)
        ;; Trap risky variables and such.  This is the same logic
        ;; that files.el uses.
        ((or (get var 'risky-local-variable)
                            (symbol-name var))
              (not (get var 'safe-local-variable))))
         (message (format "Ignoring %s in %s"
                          (symbol-name var) dirvars-file)))
        ;; Ordinary variable, really set it.
        (t (make-local-variable var)
           (set var val))))

(defun dirvars-hack-local-variables-before ()
  (let ((dirvars-file (dirvars-find-upwards dirvars-file-name)))
    (if dirvars-file
        (dirvars-hack-local-variables dirvars-file))))

(defadvice hack-local-variables
  (before dirvars-hack-local-variables-before activate)
  "Process dirvars before a file's local variables are processed."

(provide 'dirvars)
;;; dirvars.el ends here

Benjamin Rutt

reply via email to

[Prev in Thread] Current Thread [Next in Thread]