# HG changeset patch # User Juri Linkov # Date 1227380515 0 # Node ID 8b9f58a19020811e21f7903db8425f8440c13b11 # Parent d82ed85d2a2e0e9c8f1cafdc8e2c0c8bbebd7e72 (hack-local-variables-confirm): Rename arg `project' to `dir-name'. Move `(or dir-name name)' to let-binding of `name'. (hack-local-variables-filter): Rename arg `project' to `dir-name'. (hack-local-variables): Rename call of `hack-project-variables' to `hack-dir-local-variables'. Change error text to "Directory-local variables error". (dir-locals-class-alist): Rename from `project-class-alist'. (dir-locals-directory-alist): Rename from `project-directory-alist'. (dir-locals-get-class-variables): Rename from `project-get-alist'. (dir-locals-collect-mode-variables): Rename from `project-collect-bindings-from-alist'. Rename arg `mode-alist' to `mode-variables', and arg `settings' to `variables'. (dir-locals-collect-variables): Rename from `project-collect-binding-list'. Rename arg `binding-list' to `class-variables', and arg `settings' to `variables'. (dir-locals-set-directory-class): Rename from `set-directory-project'. (dir-locals-set-class-variables): Rename from `define-project-bindings'. Rename arg `settings' to `variables'. (dir-locals-file): New defconst. (dir-locals-find-file): Rename from `project-find-settings-file'. Use `dir-locals-file'. Rename let-bound `settings' to `locals-file', and `pda' to `dir-elt'. (dir-locals-read-from-file): Rename from `project-define-from-project-file'. Rename arg `settings-file' to `file'. Rename let-bound `list' to `variables'. (hack-dir-local-variables): Rename from `hack-project-variables'. Rename let-bound `settings' to `variables-file', `root-dir' to `dir-name', and `bindings' to `variables'. diff -r d82ed85d2a2e -r 8b9f58a19020 lisp/files.el --- a/lisp/files.el Sat Nov 22 18:31:15 2008 +0000 +++ b/lisp/files.el Sat Nov 22 19:01:55 2008 +0000 @@ -2708,18 +2708,19 @@ 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 @@ -2728,16 +2729,15 @@ (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.") @@ -2859,15 +2859,15 @@ 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))) @@ -2905,7 +2905,7 @@ (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))))))) @@ -2918,8 +2918,8 @@ 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. @@ -3121,39 +3121,39 @@ (set-text-properties 0 (length val) nil val)) (set (make-local-variable var) val)))) -;;; Handling directory local variables, aka project settings. - -(defvar project-class-alist '() - "Alist mapping project class names (symbols) to project variable lists.") - -(defvar project-directory-alist '() - "Alist mapping project directory roots to project classes.") - -(defsubst project-get-alist (class) - "Return the project variable list for project CLASS." - (cdr (assq class project-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. +;;; Handling directory-local variables, aka project settings. + +(defvar dir-locals-class-alist '() + "Alist mapping class names (symbols) to variable lists.") + +(defvar dir-locals-directory-alist '() + "Alist mapping directory roots to variable classes.") + +(defsubst dir-locals-get-class-variables (class) + "Return the variable list for CLASS." + (cdr (assq class dir-locals-class-alist))) + +(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))))) - -(defun project-collect-binding-list (binding-list root settings) - "Collect entries from BINDING-LIST into SETTINGS. + (push (cons variable value) variables))))) + +(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) @@ -3162,31 +3162,31 @@ (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)))))))) - -(defun set-directory-project (directory class) - "Declare that the project rooted at DIRECTORY is an instance of CLASS. + (setq variables (dir-locals-collect-mode-variables + (cdr entry) variables)))))))) + +(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) @@ -3198,13 +3198,13 @@ 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. @@ -3212,77 +3212,83 @@ * 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)))) - -(defun project-find-settings-file (file) - "Find the settings file for FILE. + (setcdr elt variables) + (push (cons class variables) dir-locals-class-alist)))) + +(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))))))) (defcustom change-major-mode-with-file-name t