Commit 5e8d477d authored by Michael Albinus's avatar Michael Albinus

Optimize host name completion in Tramp

* lisp/net/tramp-adb.el (tramp-adb-maybe-open-connection):
* lisp/net/tramp-gvfs.el (tramp-gvfs-maybe-open-connection):
* lisp/net/tramp-rclone.el (tramp-rclone-maybe-open-connection):
* lisp/net/tramp-sh.el (tramp-maybe-open-connection):
* lisp/net/tramp-smb.el (tramp-smb-maybe-open-connection):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-maybe-open-connection):
Throw `non-essential' at the beginning of the function.

* lisp/net/tramp.el (tramp-handle-file-exists-p):
* lisp/net/tramp-sh.el (tramp-sh-handle-file-exists-p):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-file-exists-p):
Run only when host is connectable.  This is due to host name
completion, which shall be optimized.

* lisp/net/tramp-smb.el (tramp-smb-do-file-attributes-with-stat)
(tramp-smb-get-file-entries): Access connection buffer only after
sending the command.

* lisp/net/tramp.el (tramp-get-buffer, tramp-get-connection-buffer):
New argument DONT-CREATE.
(tramp-message): Use it.
(tramp-get-mutex): Check, whether host is connectable.
(tramp-file-name-handler): Set thread only when host is connectable.
(tramp-connectable-p): Allow also VEC as argument.
(tramp-completion-handle-file-name-completion): Do not expand directory.
parent 99741550
Pipeline #3107 passed with stage
in 59 minutes and 14 seconds
......@@ -1191,6 +1191,10 @@ FMT and ARGS are passed to `error'."
"Maybe open a connection VEC.
Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason."
;; During completion, don't reopen a new connection.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
(let* ((buf (tramp-get-connection-buffer vec))
(p (get-buffer-process buf))
(host (tramp-file-name-host vec))
......@@ -1204,14 +1208,6 @@ connection if a previous connection has died for some reason."
(tramp-error vec 'file-error "Cannot switch to user `%s'" user))
(unless (process-live-p p)
;; During completion, don't reopen a new connection. We check
;; this for the process related to `tramp-buffer-name';
;; otherwise `start-file-process' wouldn't run ever when
;; `non-essential' is non-nil.
(when (and (tramp-completion-mode-p)
(null (get-process (tramp-buffer-name vec))))
(throw 'non-essential 'non-essential))
(save-match-data
(when (and p (processp p)) (delete-process p))
(if (zerop (length device))
......
......@@ -1787,6 +1787,10 @@ This is relevant for GNOME Online Accounts."
"Maybe open a connection VEC.
Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason."
;; During completion, don't reopen a new connection.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
;; We set the file name, in case there are incoming D-Bus signals or
;; D-Bus errors.
(setq tramp-gvfs-dbus-event-vector vec)
......
......@@ -520,19 +520,14 @@ file names."
"Maybe open a connection VEC.
Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason."
;; During completion, don't reopen a new connection.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
(let ((host (tramp-file-name-host vec)))
(when (rassoc `(,host) (tramp-rclone-parse-device-names nil))
(if (zerop (length host))
(tramp-error vec 'file-error "Storage %s not connected" host))
;; During completion, don't reopen a new connection. We check
;; this for the process related to `tramp-buffer-name';
;; otherwise `start-file-process' wouldn't run ever when
;; `non-essential' is non-nil.
(when (and (tramp-completion-mode-p)
(null (get-process (tramp-buffer-name vec))))
(throw 'non-essential 'non-essential))
;; We need a process bound to the connection buffer. Therefore,
;; we create a dummy process. Maybe there is a better solution?
(unless (get-buffer-process (tramp-get-connection-buffer vec))
......
......@@ -1198,18 +1198,22 @@ component is used as the target of the symlink."
(defun tramp-sh-handle-file-exists-p (filename)
"Like `file-exists-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-exists-p"
(or (not (null (tramp-get-file-property
v localname "file-attributes-integer" nil)))
(not (null (tramp-get-file-property
v localname "file-attributes-string" nil)))
(tramp-send-command-and-check
v
(format
"%s %s"
(tramp-get-file-exists-command v)
(tramp-shell-quote-argument localname)))))))
;; `file-exists-p' is used as predicate in file name completion.
;; We don't want to run it when `non-essential' is t, or there is
;; no connection process yet.
(when (tramp-connectable-p filename)
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-exists-p"
(or (not (null (tramp-get-file-property
v localname "file-attributes-integer" nil)))
(not (null (tramp-get-file-property
v localname "file-attributes-string" nil)))
(tramp-send-command-and-check
v
(format
"%s %s"
(tramp-get-file-exists-command v)
(tramp-shell-quote-argument localname))))))))
(defun tramp-sh-handle-file-attributes (filename &optional id-format)
"Like `file-attributes' for Tramp files."
......@@ -4762,6 +4766,10 @@ If there is just some editing, retry it after 5 seconds."
"Maybe open a connection VEC.
Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason."
;; During completion, don't reopen a new connection.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
(let ((p (tramp-get-connection-process vec))
(process-name (tramp-get-connection-property vec "process-name" nil))
(process-environment (copy-sequence process-environment))
......@@ -4806,15 +4814,6 @@ connection if a previous connection has died for some reason."
;; New connection must be opened.
(condition-case err
(unless (process-live-p p)
;; During completion, don't reopen a new connection. We
;; check this for the process related to
;; `tramp-buffer-name'; otherwise `start-file-process'
;; wouldn't run ever when `non-essential' is non-nil.
(when (and (tramp-completion-mode-p)
(null (get-process (tramp-buffer-name vec))))
(throw 'non-essential 'non-essential))
(with-tramp-progress-reporter
vec 3
(if (zerop (length (tramp-file-name-user vec)))
......
......@@ -832,12 +832,12 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
"Implement `file-attributes' for Tramp files using stat command."
(tramp-message
vec 5 "file attributes with stat: %s" (tramp-file-name-localname vec))
(with-current-buffer (tramp-get-connection-buffer vec)
(let* (size id link uid gid atime mtime ctime mode inode)
(when (tramp-smb-send-command
vec (format "stat \"%s\"" (tramp-smb-get-localname vec)))
(let* (size id link uid gid atime mtime ctime mode inode)
(when (tramp-smb-send-command
vec (format "stat \"%s\"" (tramp-smb-get-localname vec)))
;; Loop the listing.
;; Loop the listing.
(with-current-buffer (tramp-get-connection-buffer vec)
(goto-char (point-min))
(unless (re-search-forward tramp-smb-errors nil t)
(while (not (eobp))
......@@ -1628,40 +1628,40 @@ Result is a list of (LOCALNAME MODE SIZE MONTH DAY TIME YEAR)."
(with-parsed-tramp-file-name (file-name-as-directory directory) nil
(setq localname (or localname "/"))
(with-tramp-file-property v localname "file-entries"
(with-current-buffer (tramp-get-connection-buffer v)
(let* ((share (tramp-smb-get-share v))
(cache (tramp-get-connection-property v "share-cache" nil))
res entry)
(if (and (not share) cache)
;; Return cached shares.
(setq res cache)
;; Read entries.
(if share
(tramp-smb-send-command
v (format "dir \"%s*\"" (tramp-smb-get-localname v)))
;; `tramp-smb-maybe-open-connection' lists also the share names.
(tramp-smb-maybe-open-connection v))
;; Loop the listing.
(let* ((share (tramp-smb-get-share v))
(cache (tramp-get-connection-property v "share-cache" nil))
res entry)
(if (and (not share) cache)
;; Return cached shares.
(setq res cache)
;; Read entries.
(if share
(tramp-smb-send-command
v (format "dir \"%s*\"" (tramp-smb-get-localname v)))
;; `tramp-smb-maybe-open-connection' lists also the share names.
(tramp-smb-maybe-open-connection v))
;; Loop the listing.
(with-current-buffer (tramp-get-connection-buffer v)
(goto-char (point-min))
(if (re-search-forward tramp-smb-errors nil t)
(tramp-error v 'file-error "%s `%s'" (match-string 0) directory)
(while (not (eobp))
(setq entry (tramp-smb-read-file-entry share))
(forward-line)
(when entry (push entry res))))
(when entry (push entry res)))))
;; Cache share entries.
(unless share
(tramp-set-connection-property v "share-cache" res)))
;; Cache share entries.
(unless share
(tramp-set-connection-property v "share-cache" res)))
;; Add directory itself.
(push '("" "drwxrwxrwx" 0 (0 0)) res)
;; Add directory itself.
(push '("" "drwxrwxrwx" 0 (0 0)) res)
;; Return entries.
(delq nil res))))))
;; Return entries.
(delq nil res)))))
;; Return either a share name (if SHARE is nil), or a file name.
;;
......@@ -1855,6 +1855,10 @@ Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason.
If ARGUMENT is non-nil, use it as argument for
`tramp-smb-winexe-program', and suppress any checks."
;; During completion, don't reopen a new connection.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
(let* ((share (tramp-smb-get-share vec))
(buf (tramp-get-connection-buffer vec))
(p (get-buffer-process buf)))
......@@ -1909,15 +1913,6 @@ If ARGUMENT is non-nil, use it as argument for
(string-equal
share
(tramp-get-connection-property p "smb-share" ""))))
;; During completion, don't reopen a new connection. We
;; check this for the process related to
;; `tramp-buffer-name'; otherwise `start-file-process'
;; wouldn't run ever when `non-essential' is non-nil.
(when (and (tramp-completion-mode-p)
(null (get-process (tramp-buffer-name vec))))
(throw 'non-essential 'non-essential))
(save-match-data
;; There might be unread output from checking for share names.
(when buf (with-current-buffer buf (erase-buffer)))
......
......@@ -424,10 +424,14 @@ the result will be a local, non-Tramp, file name."
(defun tramp-sudoedit-handle-file-exists-p (filename)
"Like `file-exists-p' for Tramp files."
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-exists-p"
(tramp-sudoedit-send-command
v "test" "-e" (tramp-compat-file-name-unquote localname)))))
;; `file-exists-p' is used as predicate in file name completion.
;; We don't want to run it when `non-essential' is t, or there is
;; no connection process yet.
(when (tramp-connectable-p filename)
(with-parsed-tramp-file-name filename nil
(with-tramp-file-property v localname "file-exists-p"
(tramp-sudoedit-send-command
v "test" "-e" (tramp-compat-file-name-unquote localname))))))
(defun tramp-sudoedit-handle-file-name-all-completions (filename directory)
"Like `file-name-all-completions' for Tramp files."
......@@ -760,18 +764,13 @@ Remove unneeded output."
"Maybe open a connection VEC.
Does not do anything if a connection is already open, but re-opens the
connection if a previous connection has died for some reason."
;; During completion, don't reopen a new connection.
(unless (tramp-connectable-p vec)
(throw 'non-essential 'non-essential))
;; We need a process bound to the connection buffer. Therefore, we
;; create a dummy process. Maybe there is a better solution?
(unless (tramp-get-connection-process vec)
;; During completion, don't reopen a new connection. We check
;; this for the process related to `tramp-buffer-name'; otherwise
;; `start-file-process' wouldn't run ever when `non-essential' is
;; non-nil.
(when (and (tramp-completion-mode-p)
(null (get-process (tramp-buffer-name vec))))
(throw 'non-essential 'non-essential))
(let ((p (make-network-process
:name (tramp-get-connection-name vec)
:buffer (tramp-get-connection-buffer vec)
......
......@@ -1566,25 +1566,27 @@ necessary only. This function will be used in file name completion."
tramp-postfix-host-format))
(when localname localname)))
(defun tramp-get-buffer (vec)
(defun tramp-get-buffer (vec &optional dont-create)
"Get the connection buffer to be used for VEC."
(or (get-buffer (tramp-buffer-name vec))
(with-current-buffer (get-buffer-create (tramp-buffer-name vec))
;; We use the existence of connection property "process-buffer"
;; as indication, whether a connection is active.
(tramp-set-connection-property
vec "process-buffer"
(tramp-get-connection-property vec "process-buffer" nil))
(setq buffer-undo-list t
default-directory (tramp-make-tramp-file-name vec 'noloc 'nohop))
(current-buffer))))
(defun tramp-get-connection-buffer (vec)
(unless dont-create
(with-current-buffer (get-buffer-create (tramp-buffer-name vec))
;; We use the existence of connection property "process-buffer"
;; as indication, whether a connection is active.
(tramp-set-connection-property
vec "process-buffer"
(tramp-get-connection-property vec "process-buffer" nil))
(setq buffer-undo-list t
default-directory
(tramp-make-tramp-file-name vec 'noloc 'nohop))
(current-buffer)))))
(defun tramp-get-connection-buffer (vec &optional dont-create)
"Get the connection buffer to be used for VEC.
In case a second asynchronous communication has been started, it is different
from `tramp-get-buffer'."
(or (tramp-get-connection-property vec "process-buffer" nil)
(tramp-get-buffer vec)))
(tramp-get-buffer vec dont-create)))
(defun tramp-get-connection-name (vec)
"Get the connection name to be used for VEC.
......@@ -1770,14 +1772,15 @@ applicable)."
;; Log only when there is a minimum level.
(when (>= tramp-verbose 4)
(let ((tramp-verbose 0))
;; Append connection buffer for error messages.
;; Append connection buffer for error messages, if exists.
(when (= level 1)
(with-current-buffer
(if (processp vec-or-proc)
(process-buffer vec-or-proc)
(tramp-get-connection-buffer vec-or-proc))
(setq fmt-string (concat fmt-string "\n%s")
arguments (append arguments (list (buffer-string))))))
(ignore-errors
(with-current-buffer
(if (processp vec-or-proc)
(process-buffer vec-or-proc)
(tramp-get-connection-buffer vec-or-proc 'dont-create))
(setq fmt-string (concat fmt-string "\n%s")
arguments (append arguments (list (buffer-string)))))))
;; Translate proc to vec.
(when (processp vec-or-proc)
(setq vec-or-proc (process-get vec-or-proc 'vector))))
......@@ -2517,16 +2520,22 @@ Add operations defined in `HANDLER-alist' to `tramp-file-name-handler'."
;; This variable has been obsoleted in Emacs 26.
tramp-completion-mode))
(defun tramp-connectable-p (filename)
(defun tramp-connectable-p (vec-or-filename)
"Check, whether it is possible to connect the remote host w/o side-effects.
This is true, if either the remote host is already connected, or if we are
not in completion mode."
(let (tramp-verbose)
(and (tramp-tramp-file-p filename)
(or (not (tramp-completion-mode-p))
(process-live-p
(tramp-get-connection-process
(tramp-dissect-file-name filename)))))))
(let (tramp-verbose
(vec
(cond
((tramp-file-name-p vec-or-filename) vec-or-filename)
((tramp-tramp-file-p vec-or-filename)
(tramp-dissect-file-name vec-or-filename)))))
(when vec
(or ;; We check this for the process related to
;; `tramp-buffer-name'; otherwise `start-file-process'
;; wouldn't run ever when `non-essential' is non-nil.
(process-live-p (get-process (tramp-buffer-name vec)))
(not (tramp-completion-mode-p))))))
;; Method, host name and user name completion.
;; `tramp-completion-dissect-file-name' returns a list of
......@@ -2606,8 +2615,7 @@ not in completion mode."
(try-completion
filename
(mapcar #'list (file-name-all-completions filename directory))
(when (and predicate
(tramp-connectable-p (expand-file-name filename directory)))
(when (and predicate (tramp-connectable-p directory))
(lambda (x) (funcall predicate (expand-file-name (car x) directory))))))
;; I misuse a little bit the `tramp-file-name' structure in order to
......@@ -3096,7 +3104,11 @@ User is always nil."
(defun tramp-handle-file-exists-p (filename)
"Like `file-exists-p' for Tramp files."
(not (null (file-attributes filename))))
;; `file-exists-p' is used as predicate in file name completion.
;; We don't want to run it when `non-essential' is t, or there is
;; no connection process yet.
(when (tramp-connectable-p filename)
(not (null (file-attributes filename)))))
(defun tramp-handle-file-in-directory-p (filename directory)
"Like `file-in-directory-p' for Tramp files."
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment