summaryrefslogtreecommitdiff
path: root/lisp/files-x.el
diff options
context:
space:
mode:
authorMichael Albinus <michael.albinus@gmx.de>2016-11-14 13:56:58 +0100
committerMichael Albinus <michael.albinus@gmx.de>2016-11-14 13:56:58 +0100
commit6647e05174ade1132a957e7e27f9ef6e96f3f9d7 (patch)
treedc94c02f1da132fcdd15af167da56605b172d808 /lisp/files-x.el
parentdb43613307bb05d0f43d2d5649b5bb2f29876cee (diff)
downloademacs-6647e05174ade1132a957e7e27f9ef6e96f3f9d7.tar.gz
Implement connection-local variables
* doc/lispref/variables.texi (Connection Local Variables): New section. * etc/NEWS: Mention connection-local variables. * lisp/files-x.el (enable-connection-local-variables) (connection-local-variables-alist, connection-local-class-alist) (connection-local-criteria-alist): New defvars. (connection-local-get-classes) (connection-local-get-class-variables): New defsubst. (connection-local-set-classes) (connection-local-set-class-variables) (hack-connection-local-variables) (hack-connection-local-variables-apply): New defuns. (with-connection-local-classes): New defmacro. * lisp/net/tramp.el (tramp-set-connection-local-variables): New defun. * lisp/net/tramp-adb.el (tramp-adb-maybe-open-connection): * lisp/net/tramp-gvfs.el (tramp-gvfs-maybe-open-connection): * lisp/net/lisp/net/tramp-sh.el (tramp-maybe-open-connection): * lisp/net/tramp-smb.el (tramp-smb-maybe-open-connection): Use it. * test/lisp/files-x-tests.el: New file.
Diffstat (limited to 'lisp/files-x.el')
-rw-r--r--lisp/files-x.el139
1 files changed, 139 insertions, 0 deletions
diff --git a/lisp/files-x.el b/lisp/files-x.el
index 05ad7f57c57..212c936414f 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -543,6 +543,145 @@ from the MODE alist ignoring the input argument VALUE."
(add-file-local-variable-prop-line (car elt) (cdr elt))))
+;;; connection-local variables.
+
+;;;###autoload
+(defvar enable-connection-local-variables t
+ "Non-nil means enable use of connection-local variables.")
+
+(defvar connection-local-variables-alist nil
+ "Alist of connection-local variable settings in the current buffer.
+Each element in this list has the form (VAR . VALUE), where VAR
+is a connection-local variable (a symbol) and VALUE is its value.
+The actual value in the buffer may differ from VALUE, if it is
+changed by the user.")
+(make-variable-buffer-local 'connection-local-variables-alist)
+(setq ignored-local-variables
+ (cons 'connection-local-variables-alist ignored-local-variables))
+
+(defvar connection-local-class-alist '()
+ "Alist mapping connection-local variable classes (symbols) to variable lists.
+Each element in this list has the form (CLASS VARIABLES).
+CLASS is the name of a variable class (a symbol).
+VARIABLES is a list that declares connection-local variables for
+CLASS. An element in VARIABLES is an alist whose elements are of
+the form (VAR . VALUE).")
+
+(defvar connection-local-criteria-alist '()
+ "Alist mapping criteria to connection-local variable classes (symbols).
+Each element in this list has the form (CRITERIA CLASSES).
+CRITERIA is either a regular expression identifying a remote
+server, or a function with one argument IDENTIFICATION, which
+returns non-nil when a remote server shall apply CLASS'es
+variables. If CRITERIA is nil, it always applies.
+CLASSES is a list of variable classes (symbols).")
+
+(defsubst connection-local-get-classes (criteria &optional identification)
+ "Return the connection-local classes list for CRITERIA.
+CRITERIA is either a regular expression identifying a remote
+server, or a function with one argument IDENTIFICATION, which
+returns non-nil when a remote server shall apply CLASS'es
+variables. If CRITERIA is nil, it always applies.
+If IDENTIFICATION is non-nil, CRITERIA must be nil, or match
+IDENTIFICATION accordingly."
+ (and (cond ((null identification))
+ ((not (stringp identification))
+ (error "Wrong identification `%s'" identification))
+ ((null criteria))
+ ((stringp criteria) (string-match criteria identification))
+ ((functionp criteria) (funcall criteria identification))
+ (t "Wrong criteria `%s'" criteria))
+ (cdr (assoc criteria connection-local-criteria-alist))))
+
+;;;###autoload
+(defun connection-local-set-classes (criteria &rest classes)
+ "Add CLASSES for remote servers.
+CRITERIA is either a regular expression identifying a remote
+server, or a function with one argument IDENTIFICATION, which
+returns non-nil when a remote server shall apply CLASS'es
+variables. If CRITERIA is nil, it always applies.
+CLASSES are the names of a variable class (a symbol).
+
+When a connection to a remote server is opened and CRITERIA
+matches to that server, the connection-local variables from CLASSES
+are applied to the corresponding process buffer. The variables
+for a class are defined using `connection-local-set-class-variables'."
+ (unless (or (null criteria) (stringp criteria) (functionp criteria))
+ (error "Wrong criteria `%s'" criteria))
+ (dolist (class classes)
+ (unless (assq class connection-local-class-alist)
+ (error "No such class `%s'" (symbol-name class))))
+ (let ((slot (assoc criteria connection-local-criteria-alist)))
+ (if slot
+ (setcdr slot (delete-dups (append (cdr slot) classes)))
+ (setq connection-local-criteria-alist
+ (cons (cons criteria (delete-dups classes))
+ connection-local-criteria-alist)))))
+
+(defsubst connection-local-get-class-variables (class)
+ "Return the connection-local variable list for CLASS."
+ (cdr (assq class connection-local-class-alist)))
+
+;;;###autoload
+(defun connection-local-set-class-variables (class variables)
+ "Map the symbol CLASS to a list of variable settings.
+VARIABLES is a list that declares connection-local variables for
+the class. An element in VARIABLES is an alist whose elements
+are of the form (VAR . VALUE).
+
+When a connection to a remote server is opened, the server's
+classes are found. A server may be assigned a class using
+`connection-local-set-class'. Then variables are set in the
+server's process buffer according to the VARIABLES list of the
+class. The list is processed in order."
+ (setf (alist-get class connection-local-class-alist) variables))
+
+(defun hack-connection-local-variables ()
+ "Read per-connection local variables for the current buffer.
+Store the connection-local variables in `connection-local-variables-alist'.
+
+This does nothing if `enable-connection-local-variables' is nil."
+ (let ((identification (file-remote-p default-directory)))
+ (when (and enable-connection-local-variables identification)
+ ;; Loop over criteria.
+ (dolist (criteria (mapcar 'car connection-local-criteria-alist))
+ ;; Filter classes which map identification.
+ (dolist (class (connection-local-get-classes criteria identification))
+ ;; Loop over variables.
+ (dolist (variable (connection-local-get-class-variables class))
+ (unless (assq (car variable) connection-local-variables-alist)
+ (push variable connection-local-variables-alist))))))))
+
+;;;###autoload
+(defun hack-connection-local-variables-apply ()
+ "Apply connection-local variables identified by `default-directory'.
+Other local variables, like file-local and dir-local variables,
+will not be changed."
+ (hack-connection-local-variables)
+ (let ((file-local-variables-alist
+ (copy-tree connection-local-variables-alist)))
+ (hack-local-variables-apply)))
+
+;;;###autoload
+(defmacro with-connection-local-classes (classes &rest body)
+ "Apply connection-local variables according to CLASSES in current buffer.
+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-classes "" ,classes)
+ (hack-connection-local-variables-apply)
+ (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))))))))
+
+
(provide 'files-x)