Commit 6f649e77 authored by Michael Albinus's avatar Michael Albinus

Implement command completion in remote shells. (Bug#31704)

* doc/lispref/files.texi (Locating Files): Describe optional
argument REMOTE of `executable-find'.
(Magic File Names): Add `exec-path'.

* doc/lispref/processes.texi (Subprocess Creation): Describe
function `exec-path'.

* doc/misc/tramp.texi (Remote programs): Explain refresh of search
paths by `tramp-cleanup-this-connection'.

* etc/NEWS: Mention 'exec-path' and 'executable-find'.

* lisp/files.el (exec-path): New defun.
(executable-find): Add optional argument REMOTE.

* lisp/shell.el (shell-completion-vars): Set `comint-file-name-prefix'.
(shell--command-completion-data): Use `(exec-path)'.  (Bug#31704)

* lisp/net/ange-ftp.el (exec-path):
* lisp/net/tramp.el (tramp-file-name-for-operation):
* lisp/net/tramp-adb.el (tramp-adb-file-name-handler-alist):
* lisp/net/tramp-archive.el (tramp-archive-file-name-handler-alist):
* lisp/net/tramp-gvfs.el (tramp-gvfs-file-name-handler-alist):
* lisp/net/tramp-sh.el (tramp-sh-file-name-handler-alist):
* lisp/net/tramp-smb.el (tramp-smb-file-name-handler-alist)
<exec-path>: Add handler.

* lisp/net/tramp-adb.el (tramp-adb-handle-exec-path): New defun.
(tramp-adb-maybe-open-connection): Do not set "remote-path"
connection property.

* lisp/net/tramp-compat.el (tramp-compat-exec-path): New defun.

* lisp/net/tramp-sh.el (tramp-sh-handle-exec-path): New defun.

* lisp/net/tramp.el (tramp-eshell-directory-change): Use it.

* test/lisp/net/tramp-archive-tests.el
(tramp-archive-test43-delay-load): Rename.

* test/lisp/net/tramp-tests.el (tramp-test34-exec-path): New test.
(tramp-test39-special-characters-with-ls, tramp-test40-utf8)
(tramp-test40-utf8-with-stat, tramp-test40-utf8-with-perl)
(tramp-test40-utf8-with-ls, tramp-test41-file-system-info)
(tramp-test42-asynchronous-requests, tramp-test43-auto-load)
(tramp-test43-delay-load, tramp-test43-recursive-load)
(tramp-test43-remote-load-path, tramp-test44-unload): Rename.
parent 3a47f392
......@@ -1567,13 +1567,16 @@ For compatibility, @var{predicate} can also be one of the symbols
a list of one or more of these symbols.
@end defun
@defun executable-find program
@defun executable-find program &optional remote
This function searches for the executable file of the named
@var{program} and returns the absolute file name of the executable,
including its file-name extensions, if any. It returns @code{nil} if
the file is not found. The functions searches in all the directories
the file is not found. The function searches in all the directories
in @code{exec-path}, and tries all the file-name extensions in
@code{exec-suffixes} (@pxref{Subprocess Creation}).
If @var{remote} is non-@code{nil}, and @code{default-directory} is a
remote directory, @var{program} is searched on the respective remote host.
@end defun
@node Changing Files
......@@ -3137,8 +3140,8 @@ first, before handlers for jobs such as remote file access.
@code{dired-compress-file}, @code{dired-uncache},@*
@code{dired-compress-file}, @code{dired-uncache},
@code{exec-path}, @code{expand-file-name},@*
......@@ -3195,7 +3198,7 @@ first, before handlers for jobs such as remote file access.
@code{dired-compress-file}, @code{dired-uncache},
@code{exec-path}, @code{expand-file-name},
......@@ -177,6 +177,14 @@ before starting Emacs. Trying to modify @code{exec-path}
independently of @env{PATH} can lead to confusing results.
@end defopt
@defun exec-path
The function @code{exec-path} is an extension of the respective
variable. If @code{default-directory} indicates a remote directory,
it returns a list of directories used for searching programs on the
respective remote host. In case of a local @code{default-directory},
the function returns just the value of the variable @code{exec-path}.
@end defun
@node Shell Arguments
@section Shell Arguments
@cindex arguments for shell commands
......@@ -1816,9 +1816,9 @@ shell supports the login argument @samp{-l}.
@end defopt
When remote search paths are changed, local @value{tramp} caches must
be recomputed. To force @value{tramp} to recompute afresh, exit
Emacs, remove the persistent file (@pxref{Connection caching}), and
restart Emacs.
be recomputed. To force @value{tramp} to recompute afresh, call
@kbd{M-x tramp-cleanup-this-connection @key{RET}} or friends
(@pxref{Cleanup remote connections}).
@node Remote shell setup
......@@ -145,6 +145,14 @@ regular expression was previously invalid, but is now accepted:
** The German prefix and postfix input methods now support Capital sharp S.
** The new function 'exec-path' returns a directory list from a remote host.
** Function 'executable-find' supports an optional argument REMOTE.
This triggers to search a program name on the remote host indicated by
* Editing Changes in Emacs 27.1
......@@ -436,7 +444,6 @@ It can be used to set any buffer as the next one to be used by
This means that pressing C-M-SPACE now selects the entire tree by
default, and not just the opening element.
** Eshell
......@@ -454,11 +461,15 @@ To restore the old behavior, use
Previously eshell/kill would fail if provided a kill signal to send to the
process. It now accepts signals specified either by name or by its number.
** Shell
*** Program name completion inside remote shells works now as expected.
** Pcomplete
*** The function 'pcomplete-uniquify-list' has been renamed from
** Auth-source
......@@ -755,7 +766,6 @@ will be chosen even if you have an entry for image/* in your
overrides all system and Emacs-provided defaults. To get the old
method back, set 'mailcap-prefer-mailcap-viewers' to nil.
** URL
*** The file: handler no longer looks for index.html in directories if
......@@ -763,14 +773,12 @@ you ask it for a file:///dir URL. Since this is a low-level library,
such decisions (if they are to be made at all) are left to
higher-level functions.
** image-mode
*** image-mode started using ImageMagick by default for all images
some years back. It now respects 'imagemagick-types-inhibit' as a way
to disable that.
** The new function 'read-answer' accepts either long or short answers
depending on the new customizable variable 'read-answer-short'.
......@@ -1024,13 +1024,33 @@ customize the variable `user-emacs-directory-warning'."
errtype user-emacs-directory)))))
(defun exec-path ()
"List of directories to search programs to run in remote subprocesses.
The remote host is identified by `default-directory'. For remote
hosts which do not support subprocesses, this returns `nil'.
If `default-directory' is a local directory, the value of the variable
`exec-path' is returned."
(let ((handler (find-file-name-handler default-directory 'exec-path)))
(if handler
(funcall handler 'exec-path)
(defun executable-find (command)
(defun executable-find (command &optional remote)
"Search for COMMAND in `exec-path' and return the absolute file name.
Return nil if COMMAND is not found anywhere in `exec-path'."
;; Use 1 rather than file-executable-p to better match the behavior of
;; call-process.
(locate-file command exec-path exec-suffixes 1))
Return nil if COMMAND is not found anywhere in `exec-path'. If
REMOTE is non-nil, search on the remote host indicated by
`default-directory' instead."
(if (and remote (file-remote-p default-directory))
(let ((res (locate-file
(lambda (x) (concat (file-remote-p default-directory) x))
exec-suffixes 'file-executable-p)))
(when (stringp res) (file-local-name res)))
;; Use 1 rather than file-executable-p to better match the
;; behavior of call-process.
(locate-file command exec-path exec-suffixes 1)))
(defun load-library (library)
"Load the Emacs Lisp library named LIBRARY.
......@@ -4439,6 +4439,7 @@ NEWNAME should be the name to give the new compressed or uncompressed file.")
(put 'process-file 'ange-ftp 'ange-ftp-process-file)
(put 'start-file-process 'ange-ftp 'ignore)
(put 'shell-command 'ange-ftp 'ange-ftp-shell-command)
(put 'exec-path 'ange-ftp 'ignore)
;;; Define ways of getting at unmodified Emacs primitives,
;;; turning off our handler.
......@@ -107,6 +107,7 @@ It is used for TCP/IP devices."
. tramp-adb-handle-directory-files-and-attributes)
(dired-compress-file . ignore)
(dired-uncache . tramp-handle-dired-uncache)
(exec-path . tramp-adb-handle-exec-path)
(expand-file-name . tramp-adb-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . ignore)
......@@ -1116,6 +1117,21 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
(tramp-flush-connection-property v "process-name")
(tramp-flush-connection-property v "process-buffer"))))))
(defun tramp-adb-handle-exec-path ()
"Like `exec-path' for Tramp files."
(with-parsed-tramp-file-name default-directory nil
(with-tramp-connection-property v "remote-path"
(tramp-adb-send-command v "echo \\\"$PATH\\\"")
(with-current-buffer (tramp-get-connection-buffer v)
;; Read the expression.
(goto-char (point-min))
(read (current-buffer)))
":" 'omit)))
;; The equivalent to `exec-directory'.
`(,(file-local-name default-directory))))
(defun tramp-adb-get-device (vec)
"Return full host name from VEC to be used in shell execution.
E.g. a host name \"\" returns \"\"
......@@ -1340,18 +1356,6 @@ connection if a previous connection has died for some reason."
vec 'file-error "Cannot switch to user `%s'" user)))
;; Set "remote-path" connection property. This is needed
;; for eshell.
(tramp-adb-send-command vec "echo \\\"$PATH\\\"")
vec "remote-path"
(with-current-buffer (tramp-get-connection-buffer vec)
;; Read the expression.
(goto-char (point-min))
(read (current-buffer)))
":" 'omit))
;; Set connection-local variables.
(tramp-set-connection-local-variables vec)
......@@ -220,6 +220,7 @@ It must be supported by libarchive(3).")
. tramp-handle-directory-files-and-attributes)
(dired-compress-file . tramp-archive-handle-not-implemented)
(dired-uncache . tramp-archive-handle-dired-uncache)
(exec-path . ignore)
;; `expand-file-name' performed by default handler.
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . ignore)
......@@ -236,6 +236,17 @@ If NAME is a remote file name, the local part of NAME is unquoted."
(defconst tramp-compat-use-url-tramp-p (fboundp 'temporary-file-directory)
"Whether to use url-tramp.el.")
;; `exec-path' is new in Emacs 27.1.
(if (fboundp 'exec-path)
(defalias 'tramp-compat-exec-path 'exec-path)
(defun tramp-compat-exec-path ()
"List of directories to search programs to run in remote subprocesses."
(let ((handler (find-file-name-handler default-directory 'exec-path)))
(if handler
(funcall handler 'exec-path)
(add-hook 'tramp-unload-hook
(lambda ()
(unload-feature 'tramp-loaddefs 'force)
......@@ -536,6 +536,7 @@ It has been changed in GVFS 1.14.")
. tramp-handle-directory-files-and-attributes)
(dired-compress-file . ignore)
(dired-uncache . tramp-handle-dired-uncache)
(exec-path . ignore)
(expand-file-name . tramp-gvfs-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . ignore)
......@@ -990,6 +990,7 @@ of command line.")
. tramp-sh-handle-directory-files-and-attributes)
(dired-compress-file . tramp-sh-handle-dired-compress-file)
(dired-uncache . tramp-handle-dired-uncache)
(exec-path . tramp-sh-handle-exec-path)
(expand-file-name . tramp-sh-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . tramp-sh-handle-file-acl)
......@@ -3083,6 +3084,13 @@ the result will be a local, non-Tramp, file name."
(defun tramp-sh-handle-exec-path ()
"Like `exec-path' for Tramp files."
(tramp-get-remote-path (tramp-dissect-file-name default-directory))
;; The equivalent to `exec-directory'.
`(,(file-local-name default-directory))))
(defun tramp-sh-handle-file-local-copy (filename)
"Like `file-local-copy' for Tramp files."
(with-parsed-tramp-file-name filename nil
......@@ -229,6 +229,7 @@ See `tramp-actions-before-shell' for more info.")
. tramp-handle-directory-files-and-attributes)
(dired-compress-file . ignore)
(dired-uncache . tramp-handle-dired-uncache)
(exec-path . ignore)
(expand-file-name . tramp-smb-handle-expand-file-name)
(file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
(file-acl . tramp-smb-handle-file-acl)
......@@ -2163,7 +2163,9 @@ ARGS are the arguments OPERATION has been called with."
((member operation
'(process-file shell-command start-file-process
;; Emacs 26+ only.
make-nearby-temp-file temporary-file-directory))
make-nearby-temp-file temporary-file-directory
;; Emacs 27+ only.
;; PROC.
((member operation
......@@ -4616,19 +4618,9 @@ Only works for Bourne-like shells."
;; when `default-directory' points to another host.
(defun tramp-eshell-directory-change ()
"Set `eshell-path-env' to $PATH of the host related to `default-directory'."
;; Remove last element of `(exec-path)', which is `exec-directory'.
(setq eshell-path-env
(if (tramp-tramp-file-p default-directory)
(with-parsed-tramp-file-name default-directory nil
;; When `tramp-own-remote-path' is in `tramp-remote-path',
;; the remote path is only set in the session cache.
(tramp-get-connection-process v) "remote-path" nil)
(tramp-get-connection-property v "remote-path" nil))
(getenv "PATH"))))
(mapconcat 'identity (butlast (tramp-compat-exec-path)) ":")))
(eval-after-load "esh-util"
......@@ -468,6 +468,8 @@ Shell buffers. It implements `shell-completion-execonly' for
(set (make-local-variable 'comint-file-name-chars) shell-file-name-chars)
(set (make-local-variable 'comint-file-name-quote-list)
(set (make-local-variable 'comint-file-name-prefix)
(file-remote-p default-directory))
(set (make-local-variable 'comint-dynamic-complete-functions)
(setq-local comint-unquote-function #'shell--unquote-argument)
......@@ -1170,9 +1172,12 @@ Returns t if successful."
(start (if (zerop (length filename)) (point) (match-beginning 0)))
(end (if (zerop (length filename)) (point) (match-end 0)))
(filenondir (file-name-nondirectory filename))
; why cdr? see `shell-dynamic-complete-command'
(path-dirs (append (cdr (reverse exec-path))
(if (memq system-type '(windows-nt ms-dos)) '("."))))
;; Ignore `exec-directory', the last entry in `exec-path'.
(append (cdr (reverse (exec-path)))
(if (and (memq system-type '(windows-nt ms-dos))
(not (file-remote-p default-directory)))
(cwd (file-name-as-directory (expand-file-name default-directory)))
(and comint-completion-fignore
......@@ -748,7 +748,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
;; The functions were introduced in Emacs 26.1.
(ert-deftest tramp-archive-test37-make-nearby-temp-file ()
(ert-deftest tramp-archive-test38-make-nearby-temp-file ()
"Check `make-nearby-temp-file' and `temporary-file-directory'."
(skip-unless tramp-archive-enabled)
;; Since Emacs 26.1.
......@@ -785,7 +785,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
(delete-directory tmp-file)
(should-not (file-exists-p tmp-file))))
(ert-deftest tramp-archive-test40-file-system-info ()
(ert-deftest tramp-archive-test41-file-system-info ()
"Check that `file-system-info' returns proper values."
(skip-unless tramp-archive-enabled)
;; Since Emacs 27.1.
......@@ -802,7 +802,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
(zerop (nth 1 fsi))
(zerop (nth 2 fsi))))))
(ert-deftest tramp-archive-test42-auto-load ()
(ert-deftest tramp-archive-test43-auto-load ()
"Check that `tramp-archive' autoloads properly."
(skip-unless tramp-archive-enabled)
;; Autoloading tramp-archive works since Emacs 27.1.
......@@ -832,7 +832,7 @@ This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
(mapconcat 'shell-quote-argument load-path " -L ")
(shell-quote-argument (format code file)))))))))
(ert-deftest tramp-archive-test42-delay-load ()
(ert-deftest tramp-archive-test43-delay-load ()
"Check that `tramp-archive' is loaded lazily, only when needed."
(skip-unless tramp-archive-enabled)
;; Autoloading tramp-archive works since Emacs 27.1.
This diff is collapsed.
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