diff options
author | Jim Porter <jporterbugs@gmail.com> | 2022-10-11 22:11:04 -0700 |
---|---|---|
committer | Jim Porter <jporterbugs@gmail.com> | 2022-10-17 18:48:52 -0700 |
commit | 3cc356abfef8294abcb91dc421e3c63a561a11b4 (patch) | |
tree | 79fd49b558b5880a04c41461794d380b682d93f1 /lisp | |
parent | 1beb389e472ab8132b478c9f24dd0ab6b7398670 (diff) | |
download | emacs-3cc356abfef8294abcb91dc421e3c63a561a11b4.tar.gz emacs-3cc356abfef8294abcb91dc421e3c63a561a11b4.tar.bz2 emacs-3cc356abfef8294abcb91dc421e3c63a561a11b4.zip |
Add helpers to dynamically assign connection-local values
* lisp/files-x.el (connection-local-criteria)
(connection-local-profile-name-for-setq): New variables.
(with-connection-local-variables-1): ... let-bind them here.
(connection-local-update-profile-variables)
(connection-local-profile-name-for-criteria): New functions.
(with-connection-local-application-variables, setq-connection-local):
New macros.
* test/lisp/files-x-tests.el: Require 'tramp-integration'
(files-x-test--variable5, remote-lazy-var): New variables.
(files-x-test-hack-connection-local-variables-apply): Expand checks.
(files-x-test-with-connection-local-variables): Remove
'hack-connection-local-variables-apply' check (it belongs in the above
test), and expand some other checks.
(files-x-test--get-lazy-var, files-x-test--set-lazy-var): New
functions.
(files-x-test-connection-local-update-profile-variables)
(files-x-test-setq-connection-local): New tests.
* doc/lispref/variables.texi (Connection Local Variables): Split into
two subsections and document the new features.
* etc/NEWS: Announce 'setq-connection-local'.
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/files-x.el | 103 |
1 files changed, 98 insertions, 5 deletions
diff --git a/lisp/files-x.el b/lisp/files-x.el index 0131d495f27..3516592fc3e 100644 --- a/lisp/files-x.el +++ b/lisp/files-x.el @@ -620,6 +620,18 @@ PROFILES is a list of connection profiles (symbols)." :group 'tramp :version "29.1") +(defvar connection-local-criteria nil + "The current connection-local criteria, or nil. +This is set while executing the body of +`with-connection-local-variables'.") + +(defvar connection-local-profile-name-for-setq nil + "The current connection-local profile name, or nil. +This is the name of the profile to use when setting variables via +`setq-connection-local'. Its value is derived from +`connection-local-criteria' and is set while executing the body +of `with-connection-local-variables'.") + (defsubst connection-local-normalize-criteria (criteria) "Normalize plist CRITERIA according to properties. Return a reordered plist." @@ -696,6 +708,23 @@ in order." (customize-set-variable 'connection-local-profile-alist connection-local-profile-alist)) +;;;###autoload +(defun connection-local-update-profile-variables (profile variables) + "Update the variable settings for PROFILE in-place. +VARIABLES is a list that declares connection-local variables for +the connection profile. An element in VARIABLES is an alist +whose elements are of the form (VAR . VALUE). + +Unlike `connection-local-set-profile-variables' (which see), this +function preserves the values of any existing variable +definitions that aren't listed in VARIABLES." + (when-let ((existing-variables + (nreverse (connection-local-get-profile-variables profile)))) + (dolist (var variables) + (setf (alist-get (car var) existing-variables) (cdr var))) + (setq variables (nreverse existing-variables))) + (connection-local-set-profile-variables profile variables)) + (defun hack-connection-local-variables (criteria) "Read connection-local variables according to CRITERIA. Store the connection-local variables in buffer local @@ -738,6 +767,15 @@ If APPLICATION is nil, `connection-local-default-application' is used." :user ,(file-remote-p default-directory 'user) :machine ,(file-remote-p default-directory 'host)))) +(defun connection-local-profile-name-for-criteria (criteria) + "Get a connection-local profile name based on CRITERIA." + (when criteria + (let (print-level print-length) + (intern (concat + "autogenerated-connection-local-profile/" + (prin1-to-string + (connection-local-normalize-criteria criteria))))))) + ;;;###autoload (defmacro with-connection-local-variables (&rest body) "Apply connection-local variables according to `default-directory'. @@ -746,15 +784,27 @@ Execute BODY, and unwind connection-local variables." `(with-connection-local-variables-1 (lambda () ,@body))) ;;;###autoload +(defmacro with-connection-local-application-variables (application &rest body) + "Apply connection-local variables for APPLICATION in `default-directory'. +Execute BODY, and unwind connection-local variables." + (declare (debug t) (indent 1)) + `(let ((connection-local-default-application ,application)) + (with-connection-local-variables-1 (lambda () ,@body)))) + +;;;###autoload (defun with-connection-local-variables-1 (body-fun) "Apply connection-local variables according to `default-directory'. Call BODY-FUN with no args, and then unwind connection-local variables." (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)) + (let* ((enable-connection-local-variables t) + (connection-local-criteria + (connection-local-criteria-for-default-directory)) + (connection-local-profile-name-for-setq + (connection-local-profile-name-for-criteria + connection-local-criteria)) + (old-buffer-local-variables (buffer-local-variables)) + connection-local-variables-alist) + (hack-connection-local-variables-apply connection-local-criteria) (unwind-protect (funcall body-fun) ;; Cleanup. @@ -767,6 +817,49 @@ Call BODY-FUN with no args, and then unwind connection-local variables." (funcall body-fun))) ;;;###autoload +(defmacro setq-connection-local (&rest pairs) + "Set each VARIABLE connection-locally to VALUE. + +When `connection-local-profile-name-for-setq' is set, assign each +variable's value on that connection profile, and set that profile +for `connection-local-criteria'. You can use this in combination +with `with-connection-local-variables', as in + + (with-connection-local-variables + (setq-connection-local VARIABLE VALUE)) + +If there's no connection-local profile to use, just set the +variables normally, as with `setq'. + +The variables are literal symbols and should not be quoted. The +second VALUE is not computed until after the first VARIABLE is +set, and so on; each VALUE can use the new value of variables set +earlier in the `setq-connection-local'. The return value of the +`setq-connection-local' form is the value of the last VALUE. + +\(fn [VARIABLE VALUE]...)" + (declare (debug setq)) + (unless (zerop (mod (length pairs) 2)) + (error "PAIRS must have an even number of variable/value members")) + (let ((set-expr nil) + (profile-vars nil)) + (while pairs + (unless (symbolp (car pairs)) + (error "Attempting to set a non-symbol: %s" (car pairs))) + (push `(set ',(car pairs) ,(cadr pairs)) set-expr) + (push `(cons ',(car pairs) ,(car pairs)) profile-vars) + (setq pairs (cddr pairs))) + `(prog1 + ,(macroexp-progn (nreverse set-expr)) + (when connection-local-profile-name-for-setq + (connection-local-update-profile-variables + connection-local-profile-name-for-setq + (list ,@(nreverse profile-vars))) + (connection-local-set-profiles + connection-local-criteria + connection-local-profile-name-for-setq))))) + +;;;###autoload (defun path-separator () "The connection-local value of `path-separator'." (with-connection-local-variables path-separator)) |