diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 1eed1acd964..7c1f0007dfb 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -4783,13 +4783,13 @@ proxy definitions (@pxref{Ad-hoc multi-hops}). @deffn Command tramp-cleanup-all-buffers Just as for @code{tramp-cleanup-all-connections}, all remote -connections and ad-hoc proxy definition are cleaned up in addition to +connections and ad-hoc proxy definitions are cleaned up in addition to killing all buffers related to remote connections. @end deffn @deffn Command tramp-cleanup-some-buffers Similar to @code{tramp-cleanup-all-buffers}, where all remote -connections and ad-hoc proxy definition are cleaned up. However, +connections and ad-hoc proxy definitions are cleaned up. However, additional buffers are killed only if one of the functions in @code{tramp-cleanup-some-buffers-hook} returns @code{t}. @end deffn @@ -4801,6 +4801,19 @@ remote buffers which are linked to a remote file, remote @code{dired} buffers, and buffers related to a remote process are cleaned up. @end defopt +@deffn Command tramp-cleanup-bufferless-connections + +Similar to @code{tramp-cleanup-all-connections}, remote connections and +ad-hoc proxy definitions are flushed, but limited to those connections +for which no associated buffers exist (except for Tramp internal +buffers). + +This command is helpful to prune connections after you close remote-file +buffers without having to either cherry pick via +@code{tramp-cleanup-connection} or clear them all via +@code{tramp-cleanup-all-connections}. +@end deffn + @node Renaming remote files @section Renaming remote files diff --git a/etc/NEWS b/etc/NEWS index a86c2ca2409..7a5b96b5eae 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -950,6 +950,14 @@ we invite Flyspell users to enable this new option and report issues. ** Tramp ++++ +*** New command 'tramp-cleanup-bufferless-connections'. +Connection-related objects for which no associated buffers exist, except +for Tramp internal buffers, are flushed. This is helpful to prune +connections after you close remote-file buffers without having to either +cherry pick via 'tramp-cleanup-connection' or clear them all via +'tramp-cleanup-all-connections'. + +++ *** Connection method "kubernetes" supports now optional namespace. The host name for Kubernetes connections can be of kind diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el index 71829e81093..5e7bface07b 100644 --- a/lisp/net/tramp-cmds.el +++ b/lisp/net/tramp-cmds.el @@ -101,12 +101,35 @@ SYNTAX can be one of the symbols `default' (default), ;; Use `match-buffers' starting with Emacs 29.1. ;;;###tramp-autoload (defun tramp-list-remote-buffers () - "Return a list of all buffers with remote `default-directory'." + "Return a list of remote buffers, excluding internal tramp buffers. +A buffer is considered remote if either its `default-directory' or its +buffer file name is a remote file name." (tramp-compat-seq-keep - (lambda (x) - (when (tramp-tramp-file-p (tramp-get-default-directory x)) x)) + (lambda (buffer) + (when (tramp-tramp-file-p + (or (buffer-file-name buffer) + (tramp-get-default-directory buffer))) + buffer)) (buffer-list))) +;;;###tramp-autoload +(defun tramp-list-remote-buffer-connections () + "Return a list of all remote buffer connections. +A buffer is considered remote if either its `default-directory' or the +function `buffer-file-name' is a remote file name." + (seq-uniq + (mapcar (lambda (buffer) + (or + (when (buffer-file-name buffer) + (file-remote-p (buffer-file-name buffer))) + (when (tramp-get-default-directory buffer) + (file-remote-p (tramp-get-default-directory buffer))))) + ;; Eliminate false positives from internal tramp buffers + (seq-remove + (lambda (buffer) + (member (buffer-name buffer) (tramp-list-tramp-buffers))) + (tramp-list-remote-buffers))))) + ;;; Cleanup ;;;###tramp-autoload @@ -321,6 +344,22 @@ non-nil." (let ((tramp-cleanup-some-buffers-hook '(always))) (tramp-cleanup-some-buffers))) +;;;###tramp-autoload +(defun tramp-cleanup-bufferless-connections () + "Flush connection-related objects for which no buffer exists. +A bufferless connection is one for which no live buffer's +`buffer-file-name' or `default-directory' is associated with that +connection, except for Tramp internal buffers. +Display a message of cleaned-up connections." + (interactive) + (when-let* ((bufferless-connections + (seq-difference + (mapcar #'tramp-make-tramp-file-name (tramp-list-connections)) + (tramp-list-remote-buffer-connections)))) + (message "Cleaning up %s" (mapconcat #'identity bufferless-connections ", ")) + (dolist (connection bufferless-connections) + (tramp-cleanup-connection (tramp-dissect-file-name connection 'noexpand))))) + ;;; Rename (defcustom tramp-default-rename-alist nil