summaryrefslogtreecommitdiff
path: root/lisp/files-x.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/files-x.el')
-rw-r--r--lisp/files-x.el102
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))