diff options
Diffstat (limited to 'lisp/files-x.el')
-rw-r--r-- | lisp/files-x.el | 102 |
1 files changed, 73 insertions, 29 deletions
diff --git a/lisp/files-x.el b/lisp/files-x.el index 1e4efa01f63..6b04518fe40 100644 --- a/lisp/files-x.el +++ b/lisp/files-x.el @@ -30,6 +30,8 @@ ;;; Code: +(eval-when-compile (require 'subr-x)) ; for string-trim-right + ;;; Commands to add/delete file-local/directory-local variables. @@ -484,23 +486,49 @@ from the MODE alist ignoring the input argument VALUE." (if (memq variable '(mode eval)) (cdr mode-assoc) (assq-delete-all variable (cdr mode-assoc)))))) - (assq-delete-all mode variables))) + (assoc-delete-all mode variables))) (setq variables (cons `(,mode . ((,variable . ,value))) variables)))) + ;; Invalidate cache (may be needed if this .dir-locals.el file + ;; will be written with the same timestamp as is already present + ;; in the cache, see bug#13860). + (setq dir-locals-directory-cache + (assoc-delete-all (file-name-directory variables-file) + dir-locals-directory-cache)) + ;; Insert modified alist of directory-local variables. (insert ";;; Directory Local Variables\n") (insert ";;; For more information see (info \"(emacs) Directory Variables\")\n\n") - (pp (sort variables - (lambda (a b) - (cond - ((null (car a)) t) - ((null (car b)) nil) - ((and (symbolp (car a)) (stringp (car b))) t) - ((and (symbolp (car b)) (stringp (car a))) nil) - (t (string< (car a) (car b)))))) - (current-buffer))))) + (princ (dir-locals-to-string + (sort variables + (lambda (a b) + (cond + ((null (car a)) t) + ((null (car b)) nil) + ((and (symbolp (car a)) (stringp (car b))) t) + ((and (symbolp (car b)) (stringp (car a))) nil) + (t (string< (car a) (car b))))))) + (current-buffer)) + (goto-char (point-min)) + (indent-sexp)))) + +(defun dir-locals-to-string (variables) + "Output alists of VARIABLES to string in dotted pair notation syntax." + (format "(%s)" (mapconcat + (lambda (mode-variables) + (format "(%S . %s)" + (car mode-variables) + (format "(%s)" (mapconcat + (lambda (variable-value) + (format "(%S . %s)" + (car variable-value) + (string-trim-right + (pp-to-string + (cdr variable-value))))) + (cdr mode-variables) "\n")))) + variables "\n"))) ;;;###autoload (defun add-dir-local-variable (mode variable value) @@ -561,7 +589,7 @@ changed by the user.") (setq ignored-local-variables (cons 'connection-local-variables-alist ignored-local-variables)) -(defvar connection-local-profile-alist '() +(defvar connection-local-profile-alist nil "Alist mapping connection profiles to variable lists. Each element in this list has the form (PROFILE VARIABLES). PROFILE is the name of a connection profile (a symbol). @@ -569,7 +597,7 @@ VARIABLES is a list that declares connection-local variables for PROFILE. An element in VARIABLES is an alist whose elements are of the form (VAR . VALUE).") -(defvar connection-local-criteria-alist '() +(defvar connection-local-criteria-alist nil "Alist mapping connection criteria to connection profiles. Each element in this list has the form (CRITERIA PROFILES). CRITERIA is a plist identifying a connection and the application @@ -664,7 +692,12 @@ This does nothing if `enable-connection-local-variables' is nil." ;; Loop over variables. (dolist (variable (connection-local-get-profile-variables profile)) (unless (assq (car variable) connection-local-variables-alist) - (push variable connection-local-variables-alist)))))) + (push variable connection-local-variables-alist)))) + ;; Push them to `file-local-variables-alist'. Connection-local + ;; variables do not appear from external files. So we can regard + ;; them as safe. + (let ((enable-local-variables :all)) + (hack-local-variables-filter connection-local-variables-alist nil)))) ;;;###autoload (defun hack-connection-local-variables-apply (criteria) @@ -676,24 +709,35 @@ will not be changed." (copy-tree connection-local-variables-alist))) (hack-local-variables-apply))) +(defsubst connection-local-criteria-for-default-directory () + "Return a connection-local criteria, which represents `default-directory'." + (when (file-remote-p default-directory) + `(:application tramp + :protocol ,(file-remote-p default-directory 'method) + :user ,(file-remote-p default-directory 'user) + :machine ,(file-remote-p default-directory 'host)))) + ;;;###autoload -(defmacro with-connection-local-profiles (profiles &rest body) - "Apply connection-local variables according to PROFILES in current buffer. +(defmacro with-connection-local-variables (&rest body) + "Apply connection-local variables according to `default-directory'. Execute BODY, and unwind connection-local variables." - (declare (indent 1) (debug t)) - `(let ((enable-connection-local-variables t) - (old-buffer-local-variables (buffer-local-variables)) - connection-local-variables-alist connection-local-criteria-alist) - (apply 'connection-local-set-profiles nil ,profiles) - (hack-connection-local-variables-apply nil) - (unwind-protect - (progn ,@body) - ;; Cleanup. - (dolist (variable connection-local-variables-alist) - (let ((elt (assq (car variable) old-buffer-local-variables))) - (if elt - (set (make-local-variable (car elt)) (cdr elt)) - (kill-local-variable (car variable)))))))) + (declare (debug t)) + `(if (file-remote-p default-directory) + (let ((enable-connection-local-variables t) + (old-buffer-local-variables (buffer-local-variables)) + connection-local-variables-alist) + (hack-connection-local-variables-apply + (connection-local-criteria-for-default-directory)) + (unwind-protect + (progn ,@body) + ;; Cleanup. + (dolist (variable connection-local-variables-alist) + (let ((elt (assq (car variable) old-buffer-local-variables))) + (if elt + (set (make-local-variable (car elt)) (cdr elt)) + (kill-local-variable (car variable))))))) + ;; No connection-local variables to apply. + ,@body)) |