You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdesdk/scripts/kde-emacs/dirvars.el

201 lines
6.9 KiB

;;; -*- local-enable-local-variables: nil -*-
;;; dirvars.el --- Local variables that apply to an entire directory
;; Copyright (C) 2002 Matt Armstrong
;; Author: Matt Armstrong <matt@lickey.com>
;; Location: http://www.lickey.com/env/elisp/dirvars.el
;; Keywords: files
;; Version: 1.2
;; Obscure: matt@squeaker.lickey.com|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
;; 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., 51 Franklin Steet, Fifth Floor,
;; Boston, MA 02110-1301, 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.
;;; 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:
(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."
;; 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
buffer-file-name)))
default-directory))
;; 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))
parent-dir)
(while (and (not (file-exists-p file1))
(progn (setq parent-dir
(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)
parent-dir))))
;; 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))
file1
nil)))
(defun dirvars-eat-comment ()
(while (looking-at "[ \t\n]*;")
(let ((begin (point)))
(skip-chars-forward " \t\n")
(if (looking-at ";")
(progn
(end-of-line)
(delete-region begin (point)))))))
(defun dirvars-hack-local-variables (dirvars-file)
(save-excursion
(let ((original-buffer (current-buffer))
(temp-buffer (get-buffer-create "*dirvars-temp*"))
(enable-local-variables (and ;local-enable-local-variables -- doesn't exist!
enable-local-variables
dirvars-enable-flag))
(continue t)
(parse-sexp-ignore-comments t)
(lisp-mode-hook nil)
beg)
(set-buffer temp-buffer)
(erase-buffer)
(lisp-mode)
(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"
(point))))
(skip-chars-backward " \t")
(let* ((str (buffer-substring beg (point)))
(var (read str))
val)
;; Read the variable value.
(skip-chars-forward "^:")
(forward-char 1)
(setq val (read (current-buffer)))
(save-excursion
(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)
nil)
;; Trap risky variables and such. This is the same logic
;; that files.el uses.
((or (get var 'risky-local-variable)
(and
(string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-command$\\|-predicate$"
(symbol-name var))
(not (get var 'safe-local-variable))))
(message (format "Ignoring %s in %s"
(symbol-name var) dirvars-file)))
;;check whether the var should be evaluated
((eq var 'evaluate)
(eval val))
;; 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 ".emacs-dirvars")))
(if dirvars-file
(dirvars-hack-local-variables dirvars-file))))
(defadvice hack-local-variables
(before dirvars-hack-local-variables-before)
"Process dirvars before a file's local variables are processed."
(dirvars-hack-local-variables-before))
(ad-activate 'hack-local-variables)
(provide 'dirvars)
;;; dirvars.el ends here