This hook is called only if there is at least one file-local
variable to set.")
-(defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars project)
+(defun hack-local-variables-confirm (all-vars unsafe-vars risky-vars dir-name)
"Get confirmation before setting up local variable values.
ALL-VARS is the list of all variables to be set up.
UNSAFE-VARS is the list of those that aren't marked as safe or risky.
RISKY-VARS is the list of those that are marked as risky.
-PROJECT is a directory name if these settings come from directory-local
-settings, or nil otherwise."
+DIR-NAME is a directory name if these settings come from
+directory-local variables, or nil otherwise."
(if noninteractive
nil
- (let ((name (if buffer-file-name
- (file-name-nondirectory buffer-file-name)
- (concat "buffer " (buffer-name))))
+ (let ((name (or dir-name
+ (if buffer-file-name
+ (file-name-nondirectory buffer-file-name)
+ (concat "buffer " (buffer-name)))))
(offer-save (and (eq enable-local-variables t) unsafe-vars))
prompt char)
(save-window-excursion
(set (make-local-variable 'cursor-type) nil)
(erase-buffer)
(if unsafe-vars
- (insert "The local variables list in " (or project name)
+ (insert "The local variables list in " name
"\ncontains values that may not be safe (*)"
(if risky-vars
", and variables that are risky (**)."
"."))
(if risky-vars
- (insert "The local variables list in " (or project name)
+ (insert "The local variables list in " name
"\ncontains variables that are risky (**).")
- (insert "A local variables list is specified in "
- (or project name) ".")))
+ (insert "A local variables list is specified in " name ".")))
(insert "\n\nDo you want to apply it? You can type
y -- to apply the local variables list.
n -- to ignore the local variables list.")
mode-specified
result))))
-(defun hack-local-variables-filter (variables project)
+(defun hack-local-variables-filter (variables dir-name)
"Filter local variable settings, querying the user if necessary.
VARIABLES is the alist of variable-value settings. This alist is
filtered based on the values of `ignored-local-variables',
`enable-local-eval', `enable-local-variables', and (if necessary)
user interaction. The results are added to
`file-local-variables-alist', without applying them.
-PROJECT is a directory name if these settings come from
- directory-local settings, or nil otherwise."
+DIR-NAME is a directory name if these settings come from
+ directory-local variables, or nil otherwise."
;; Strip any variables that are in `ignored-local-variables'.
(dolist (ignored ignored-local-variables)
(setq variables (assq-delete-all ignored variables)))
(null risky-vars))
(eq enable-local-variables :all)
(hack-local-variables-confirm
- variables unsafe-vars risky-vars project))
+ variables unsafe-vars risky-vars dir-name))
(dolist (elt variables)
(push elt file-local-variables-alist)))))))
result)
(unless mode-only
(setq file-local-variables-alist nil)
- (report-errors "Project local-variables error: %s"
- (hack-project-variables)))
+ (report-errors "Directory-local variables error: %s"
+ (hack-dir-local-variables)))
(when (or mode-only enable-local-variables)
(setq result (hack-local-variables-prop-line mode-only))
;; Look for "Local variables:" line in last page.
(set-text-properties 0 (length val) nil val))
(set (make-local-variable var) val))))
\f
-;;; Handling directory local variables, aka project settings.
+;;; Handling directory-local variables, aka project settings.
-(defvar project-class-alist '()
- "Alist mapping project class names (symbols) to project variable lists.")
+(defvar dir-locals-class-alist '()
+ "Alist mapping class names (symbols) to variable lists.")
-(defvar project-directory-alist '()
- "Alist mapping project directory roots to project classes.")
+(defvar dir-locals-directory-alist '()
+ "Alist mapping directory roots to variable classes.")
-(defsubst project-get-alist (class)
- "Return the project variable list for project CLASS."
- (cdr (assq class project-class-alist)))
+(defsubst dir-locals-get-class-variables (class)
+ "Return the variable list for CLASS."
+ (cdr (assq class dir-locals-class-alist)))
-(defun project-collect-bindings-from-alist (mode-alist settings)
- "Collect local variable settings from MODE-ALIST.
-SETTINGS is the initial list of bindings.
+(defun dir-locals-collect-mode-variables (mode-variables variables)
+ "Collect directory-local variables from MODE-VARIABLES.
+VARIABLES is the initial list of variables.
Returns the new list."
- (dolist (pair mode-alist settings)
+ (dolist (pair mode-variables variables)
(let* ((variable (car pair))
(value (cdr pair))
- (slot (assq variable settings)))
+ (slot (assq variable variables)))
(if slot
(setcdr slot value)
;; Need a new cons in case we setcdr later.
- (push (cons variable value) settings)))))
+ (push (cons variable value) variables)))))
-(defun project-collect-binding-list (binding-list root settings)
- "Collect entries from BINDING-LIST into SETTINGS.
+(defun dir-locals-collect-variables (class-variables root variables)
+ "Collect entries from CLASS-VARIABLES into VARIABLES.
ROOT is the root directory of the project.
-Return the new settings list."
+Return the new variables list."
(let* ((file-name (buffer-file-name))
(sub-file-name (if file-name
(substring file-name (length root)))))
- (dolist (entry binding-list settings)
+ (dolist (entry class-variables variables)
(let ((key (car entry)))
(cond
((stringp key)
(when (and sub-file-name
(>= (length sub-file-name) (length key))
(string= key (substring sub-file-name 0 (length key))))
- (setq settings (project-collect-binding-list (cdr entry)
- root settings))))
+ (setq variables (dir-locals-collect-variables
+ (cdr entry) root variables))))
((or (not key)
(derived-mode-p key))
- (setq settings (project-collect-bindings-from-alist (cdr entry)
- settings))))))))
+ (setq variables (dir-locals-collect-mode-variables
+ (cdr entry) variables))))))))
-(defun set-directory-project (directory class)
- "Declare that the project rooted at DIRECTORY is an instance of CLASS.
+(defun dir-locals-set-directory-class (directory class)
+ "Declare that the DIRECTORY root is an instance of CLASS.
DIRECTORY is the name of a directory, a string.
CLASS is the name of a project class, a symbol.
When a file beneath DIRECTORY is visited, the mode-specific
-settings from CLASS will be applied to the buffer. The settings
-for a class are defined using `define-project-bindings'."
+variables from CLASS will be applied to the buffer. The variables
+for a class are defined using `dir-locals-set-class-variables'."
(setq directory (file-name-as-directory (expand-file-name directory)))
- (unless (assq class project-class-alist)
- (error "No such project class `%s'" (symbol-name class)))
- (push (cons directory class) project-directory-alist))
-
-(defun define-project-bindings (class settings)
- "Map the project type CLASS to a list of variable settings.
-CLASS is the project class, a symbol.
-SETTINGS is a list that declares variable settings for the class.
-An element in SETTINGS is either of the form:
+ (unless (assq class dir-locals-class-alist)
+ (error "No such class `%s'" (symbol-name class)))
+ (push (cons directory class) dir-locals-directory-alist))
+
+(defun dir-locals-set-class-variables (class variables)
+ "Map the type CLASS to a list of variable settings.
+CLASS is the project class, a symbol. VARIABLES is a list
+that declares directory-local variables for the class.
+An element in VARIABLES is either of the form:
(MAJOR-MODE . ALIST)
or
(DIRECTORY . LIST)
LIST is a list of the form accepted by the function.
When a file is visited, the file's class is found. A directory
-may be assigned a class using `set-directory-project'. Then
-variables are set in the file's buffer according to the class'
-LIST. The list is processed in order.
+may be assigned a class using `dir-locals-set-directory-class'.
+Then variables are set in the file's buffer according to the
+class' LIST. The list is processed in order.
* If the element is of the form (MAJOR-MODE . ALIST), and the
buffer's major mode is derived from MAJOR-MODE (as determined
- by `derived-mode-p'), then all the settings in ALIST are
+ by `derived-mode-p'), then all the variables in ALIST are
applied. A MAJOR-MODE of nil may be used to match any buffer.
`make-local-variable' is called for each variable before it is
set.
* If the element is of the form (DIRECTORY . LIST), and DIRECTORY
is an initial substring of the file's directory, then LIST is
applied by recursively following these rules."
- (let ((elt (assq class project-class-alist)))
+ (let ((elt (assq class dir-locals-class-alist)))
(if elt
- (setcdr elt settings)
- (push (cons class settings) project-class-alist))))
+ (setcdr elt variables)
+ (push (cons class variables) dir-locals-class-alist))))
-(defun project-find-settings-file (file)
- "Find the settings file for FILE.
+(defconst dir-locals-file ".dir-locals.el"
+ "File that contains directory-local variables.
+It has to be constant to enforce uniform values
+across different environments and users.")
+
+(defun dir-locals-find-file (file)
+ "Find the directory-local variables FILE.
This searches upward in the directory tree.
-If a settings file is found, the file name is returned.
-If the file is in a registered project, a cons from
-`project-directory-alist' is returned.
+If a local variables file is found, the file name is returned.
+If the file is already registered, a cons from
+`dir-locals-directory-alist' is returned.
Otherwise this returns nil."
(setq file (expand-file-name file))
- (let ((settings (locate-dominating-file file ".dir-settings.el"))
- (pda nil))
+ (let ((locals-file (locate-dominating-file file dir-locals-file))
+ (dir-elt nil))
;; `locate-dominating-file' may have abbreviated the name.
- (when settings
- (setq settings (expand-file-name ".dir-settings.el" settings)))
- (dolist (x project-directory-alist)
- (when (and (eq t (compare-strings file nil (length (car x))
- (car x) nil nil))
- (> (length (car x)) (length (car pda))))
- (setq pda x)))
- (if (and settings pda)
- (if (> (length (file-name-directory settings))
- (length (car pda)))
- settings pda)
- (or settings pda))))
-
-(defun project-define-from-project-file (settings-file)
- "Load a settings file and register a new project class and instance.
-SETTINGS-FILE is the name of the file holding the settings to apply.
-The new class name is the same as the directory in which SETTINGS-FILE
+ (when locals-file
+ (setq locals-file (expand-file-name dir-locals-file locals-file)))
+ (dolist (elt dir-locals-directory-alist)
+ (when (and (eq t (compare-strings file nil (length (car elt))
+ (car elt) nil nil))
+ (> (length (car elt)) (length (car dir-elt))))
+ (setq dir-elt elt)))
+ (if (and locals-file dir-elt)
+ (if (> (length (file-name-directory locals-file))
+ (length (car dir-elt)))
+ locals-file
+ dir-elt)
+ (or locals-file dir-elt))))
+
+(defun dir-locals-read-from-file (file)
+ "Load a variables FILE and register a new class and instance.
+FILE is the name of the file holding the variables to apply.
+The new class name is the same as the directory in which FILE
is found. Returns the new class name."
(with-temp-buffer
- ;; We should probably store the modtime of SETTINGS-FILE and then
+ ;; We should probably store the modtime of FILE and then
;; reload it whenever it changes.
- (insert-file-contents settings-file)
- (let* ((dir-name (file-name-directory settings-file))
+ (insert-file-contents file)
+ (let* ((dir-name (file-name-directory file))
(class-name (intern dir-name))
- (list (read (current-buffer))))
- (define-project-bindings class-name list)
- (set-directory-project dir-name class-name)
+ (variables (read (current-buffer))))
+ (dir-locals-set-class-variables class-name variables)
+ (dir-locals-set-directory-class dir-name class-name)
class-name)))
(declare-function c-postprocess-file-styles "cc-mode" ())
-(defun hack-project-variables ()
- "Read local variables for the current buffer based on project settings.
-Store the project variables in `file-local-variables-alist',
+(defun hack-dir-local-variables ()
+ "Read per-directory local variables for the current buffer.
+Store the directory-local variables in `file-local-variables-alist',
without applying them."
(when (and enable-local-variables
(buffer-file-name)
(not (file-remote-p (buffer-file-name))))
- ;; Find the settings file.
- (let ((settings (project-find-settings-file (buffer-file-name)))
+ ;; Find the variables file.
+ (let ((variables-file (dir-locals-find-file (buffer-file-name)))
(class nil)
- (root-dir nil))
+ (dir-name nil))
(cond
- ((stringp settings)
- (setq root-dir (file-name-directory (buffer-file-name)))
- (setq class (project-define-from-project-file settings)))
- ((consp settings)
- (setq root-dir (car settings))
- (setq class (cdr settings))))
+ ((stringp variables-file)
+ (setq dir-name (file-name-directory (buffer-file-name)))
+ (setq class (dir-locals-read-from-file variables-file)))
+ ((consp variables-file)
+ (setq dir-name (car variables-file))
+ (setq class (cdr variables-file))))
(when class
- (let ((bindings
- (project-collect-binding-list (project-get-alist class)
- root-dir nil)))
- (when bindings
- (hack-local-variables-filter bindings root-dir)))))))
+ (let ((variables
+ (dir-locals-collect-variables
+ (dir-locals-get-class-variables class) dir-name nil)))
+ (when variables
+ (hack-local-variables-filter variables dir-name)))))))
\f
(defcustom change-major-mode-with-file-name t