Merge remote-tracking branch 'origin/master' into feature/android

This commit is contained in:
Po Lu 2023-07-11 08:19:32 +08:00
commit dc7ecc6e31
13 changed files with 168 additions and 45 deletions

View file

@ -1545,9 +1545,9 @@ AC_DEFUN([gt_TYPE_WINT_T],
[GNULIBHEADERS_OVERRIDE_WINT_T=0
AC_SUBST([GNULIBHEADERS_OVERRIDE_WINT_T])])
# Emacs does not need precise checks for the Solaris 10 MB_CUR_MAX bug.
AC_DEFUN([gt_LOCALE_FR_UTF8],
[LOCALE_FR_UTF8=none
AC_SUBST([LOCALE_FR_UTF8])])
AC_DEFUN_ONCE([gl_STDLIB_H],
[AC_REQUIRE([gl_STDLIB_H_DEFAULTS])
gl_NEXT_HEADERS([stdlib.h])])
# Initialize gnulib right after choosing the compiler.
dnl Amongst other things, this sets AR and ARFLAGS.
@ -7191,6 +7191,7 @@ if test "$emacs_cv_struct_alignment" = yes; then
structure to an N-byte boundary.])
fi
AC_C_RESTRICT
AC_C_TYPEOF
AC_CACHE_CHECK([for statement expressions],

View file

@ -3630,7 +3630,11 @@ be @code{root}.
If @var{connected} is non-@code{nil}, this function returns @code{nil}
even if @var{filename} is remote, if Emacs has no network connection
to its host. This is useful when you want to avoid the delay of
making connections when they don't exist.
making connections when they don't exist. If @var{connected} is
@code{never}, @emph{never} use an existing connection to return the
identification, even if one is already present (this is otherwise like
a value of @code{nil}). This lets you prevent any connection-specific
logic, such as expanding the local part of the file name.
@end defun
@defun unhandled-file-name-directory filename

View file

@ -207,6 +207,7 @@ that will be invoked, type this as the Eshell prompt:
* Built-ins::
* Variables::
* Aliases::
* Remote Access::
* History::
* Completion::
* Control Flow::
@ -266,7 +267,10 @@ As an ordinary Lisp function
@vindex eshell-prefer-lisp-functions
If you would prefer to use ordinary Lisp functions over external
programs, set the option @code{eshell-prefer-lisp-functions} to
@code{t}. This will swap the lookup order of the last two items.
@code{t}. This will swap the lookup order of the last two items. You
can also force Eshell to look for a command as an external program by
prefixing its name with @kbd{*}, like @code{*@var{command}}
(@pxref{Built-ins}).
You can also group command forms together into a subcommand with curly
braces (@code{@{@}}). This lets you use the output of a subcommand as
@ -1090,6 +1094,43 @@ create and switch to a directory called @samp{foo}.
@end table
@node Remote Access
@section Remote Access
@cmindex remote access
Since Eshell uses Emacs facilities for most of its functionality, you
can access remote hosts transparently. To connect to a remote host,
simply @code{cd} into it:
@example
~ $ cd /ssh:user@@remote:
/ssh:user@@remote:~ $
@end example
Additionally, built-in Eshell commands (@pxref{Built-ins}) and
ordinary Lisp functions accept remote file names, so you can access
them even without explicitly connecting first. For example, to print
the contents of a remote file, you could type @samp{cat
/ssh:user@@remote:~/output.log}. However, this means that when using
built-in commands or Lisp functions from a remote directory, you must
be careful about specifying absolute file names: @samp{cat
/var/output.log} will always print the contents of your @emph{local}
@file{/var/output.log}, even from a remote directory. If you find
this behavior annoying, you can enable the optional electric forward
slash module (@pxref{Electric forward slash}).
@vindex eshell-explicit-remote-commands
When running commands, you can also make them explicitly remote by
prefixing the command name with a remote identifier, e.g.@:
@samp{/ssh:user@@remote:whoami}. This runs the command @code{whoami}
over the SSH connection for @code{user@@remote}, no matter your
current directory. If you want to explicitly run a @emph{local}
command even when in a remote directory, you can prefix the command
name with @kbd{/:}, like @samp{/:whoami}. In either case, you can
also specify the absolute path to the program, e.g.@:
@samp{/ssh:user@@remote:/usr/bin/whoami}. To disable this syntax, set
the option @code{eshell-explicit-remote-commands} to @code{nil}.
@node History
@section History
@cmindex history

View file

@ -224,6 +224,15 @@ or get a sublist of elements 2 through 4 with '$my-list[2..5]'. For
more information, see the "(eshell) Dollars Expansion" node in the
Eshell manual.
+++
*** Eshell commands can now be explicitly-remote (or local).
By prefixing a command name in Eshell with a remote identifier, like
"/ssh:user@remote:whoami", you can now runs commands on a particular
host no matter your current directory. Likewise, you can run a
command on your local system no matter your current directory via
"/:whoami". For more information, see the "(eshell) Remote Access"
node in the Eshell manual.
+++
*** Eshell's '$UID' and '$GID' variables are now connection-aware.
Now, when expanding '$UID' or '$GID' in a remote directory, the value

View file

@ -1197,7 +1197,6 @@ LIB_WSOCK32 = @LIB_WSOCK32@
LIB_XATTR = @LIB_XATTR@
LIMITS_H = @LIMITS_H@
LN_S_FILEONLY = @LN_S_FILEONLY@
LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
LTLIBGMP = @LTLIBGMP@
LTLIBINTL = @LTLIBINTL@
LTLIBOBJS = @LTLIBOBJS@

View file

@ -168,11 +168,23 @@ external version."
:type 'character
:group 'eshell-ext)
(defcustom eshell-explicit-remote-commands t
"If non-nil, support explicitly-remote commands.
These are commands with a full remote file name, such as
\"/ssh:host:whoami\". If this is enabled, you can also run
explicitly-local commands by using a quoted file name, like
\"/:whoami\"."
:type 'boolean
:group 'eshell-ext)
;;; Functions:
(defun eshell-ext-initialize () ;Called from `eshell-mode' via intern-soft!
"Initialize the external command handling code."
(add-hook 'eshell-named-command-hook #'eshell-explicit-command nil t))
(add-hook 'eshell-named-command-hook #'eshell-explicit-command nil t)
(when eshell-explicit-remote-commands
(add-hook 'eshell-named-command-hook
#'eshell-handle-remote-command nil t)))
(defun eshell-explicit-command (command args)
"If a command name begins with `*', call it externally always.
@ -186,30 +198,36 @@ This bypasses all Lisp functions and aliases."
(error "%s: external command not found"
(substring command 1))))))
(defun eshell-handle-remote-command (command args)
"Handle remote (or quoted) COMMAND names, using ARGS.
This calls the appropriate function for commands that aren't on
the connection associated with `default-directory'. (See
`eshell-explicit-remote-commands'.)"
(if (file-name-quoted-p command)
(let ((default-directory (if (file-remote-p default-directory)
(expand-file-name "~")
default-directory)))
(eshell-external-command (file-name-unquote command) args))
(when (file-remote-p command)
(eshell-remote-command command args))))
(defun eshell-remote-command (command args)
"Insert output from a remote COMMAND, using ARGS.
A remote command is something that executes on a different machine.
An external command simply means external to Emacs.
Note that this function is very crude at the moment. It gathers up
all the output from the remote command, and sends it all at once,
causing the user to wonder if anything's really going on..."
(let ((outbuf (generate-new-buffer " *eshell remote output*"))
(errbuf (generate-new-buffer " *eshell remote error*"))
(command (file-local-name command))
(exitcode 1))
(unwind-protect
(progn
(setq exitcode
(shell-command
(mapconcat #'shell-quote-argument
(append (list command) args) " ")
outbuf errbuf))
(eshell-print (with-current-buffer outbuf (buffer-string)))
(eshell-error (with-current-buffer errbuf (buffer-string))))
(eshell-close-handles exitcode 'nil)
(kill-buffer outbuf)
(kill-buffer errbuf))))
An external command simply means external to Emacs."
(let* ((cwd-connection (file-remote-p default-directory))
(command-connection (file-remote-p command))
(default-directory (if (equal cwd-connection command-connection)
default-directory
command-connection))
;; Never use the remote connection here. We don't want to
;; expand the local name! Instead, we want it as the user
;; typed, so that if COMMAND is "/ssh:host:cat", we just get
;; "cat" as the result.
(command-localname (file-remote-p command 'localname 'never)))
(unless command-connection
(error "%s: not a remote command" command))
(eshell-external-command command-localname args)))
(defun eshell-external-command (command args)
"Insert output from an external COMMAND, using ARGS."

View file

@ -1270,7 +1270,9 @@ there is an existing connection.
If CONNECTED is non-nil, return an identification only if FILE is
located on a remote system and a connection is established to
that remote system.
that remote system. If CONNECTED is `never', never use an
existing connection to return the identification (this is
otherwise like a value of nil).
Tip: You can use this expansion of remote identifier components
to derive a new remote file name from an existing one. For

View file

@ -4341,13 +4341,14 @@ Let-bind it when necessary.")
(let ((tramp-verbose (min tramp-verbose 3)))
(when (tramp-tramp-file-p filename)
(let* ((o (tramp-dissect-file-name filename))
(p (tramp-get-connection-process o))
(p (and (not (eq connected 'never))
(tramp-get-connection-process o)))
(c (and (process-live-p p)
(tramp-get-connection-property p "connected"))))
;; We expand the file name only, if there is already a connection.
(with-parsed-tramp-file-name
(if c (expand-file-name filename) filename) nil
(and (or (not connected) c)
(and (or (memq connected '(nil never)) c)
(cond
((eq identification 'method) method)
;; Domain and port are appended to user and host,

View file

@ -463,7 +463,7 @@ This can be useful when using docker to run a language server.")
(eval-and-compile
(defvar eglot--lsp-interface-alist
`(
(CodeAction (:title) (:kind :diagnostics :edit :command :isPreferred))
(CodeAction (:title) (:kind :diagnostics :edit :command :isPreferred :data))
(ConfigurationItem () (:scopeUri :section))
(Command ((:title . string) (:command . string)) (:arguments))
(CompletionItem (:label)
@ -739,9 +739,12 @@ ACTION is an LSP object of either `CodeAction' or `Command' type."
(server action) "Default implementation."
(eglot--dcase action
(((Command)) (eglot--request server :workspace/executeCommand action))
(((CodeAction) edit command)
(when edit (eglot--apply-workspace-edit edit))
(when command (eglot--request server :workspace/executeCommand command))))))
(((CodeAction) edit command data)
(if (and (null edit) (null command) data
(eglot--server-capable :codeActionProvider :resolveProvider))
(eglot-execute server (eglot--request server :codeAction/resolve action))
(when edit (eglot--apply-workspace-edit edit))
(when command (eglot--request server :workspace/executeCommand command)))))))
(cl-defgeneric eglot-initialization-options (server)
"JSON object to send under `initializationOptions'."
@ -825,6 +828,7 @@ ACTION is an LSP object of either `CodeAction' or `Command' type."
:documentHighlight `(:dynamicRegistration :json-false)
:codeAction (list
:dynamicRegistration :json-false
:resolveSupport t :dataSupport t
:codeActionLiteralSupport
'(:codeActionKind
(:valueSet
@ -3197,11 +3201,25 @@ for which LSP on-type-formatting should be requested."
sig
(with-temp-buffer
(insert siglabel)
;; Ad-hoc attempt to parse label as <name>(<params>)
;; Add documentation, indented so we can distinguish multiple signatures
(when-let (doc (and (not briefp) sigdoc (eglot--format-markup sigdoc)))
(goto-char (point-max))
(insert "\n" (replace-regexp-in-string "^" " " doc)))
;; Try to highlight function name only
(let (first-parlabel)
(cond ((and (cl-plusp (length parameters))
(vectorp (setq first-parlabel
(plist-get (aref parameters 0) :label))))
(save-excursion
(goto-char (elt first-parlabel 0))
(skip-syntax-backward "^w")
(add-face-text-property (point-min) (point)
'font-lock-function-name-face)))
((save-excursion
(goto-char (point-min))
(looking-at "\\([^(]*\\)([^)]*)"))
(add-face-text-property (match-beginning 1) (match-end 1)
'font-lock-function-name-face))))
;; Now to the parameters
(cl-loop
with active-param = (or sig-active activeParameter)
@ -3210,13 +3228,8 @@ for which LSP on-type-formatting should be requested."
((:label parlabel))
((:documentation pardoc)))
parameter
(when (zerop i)
(goto-char (elt parlabel 0))
(skip-syntax-backward "^w")
(add-face-text-property (point-min) (point)
'font-lock-function-name-face))
;; ...perhaps highlight it in the formals list
(when (= i active-param)
(when (eq i active-param)
(save-excursion
(goto-char (point-min))
(pcase-let

View file

@ -1679,7 +1679,8 @@ It's also possible to enter an arbitrary directory not in the list."
ret))
;; XXX: Just using this for the category (for the substring
;; completion style).
(table (project--file-completion-table (cons dir-choice choices)))
(table (project--file-completion-table
(reverse (cons dir-choice choices))))
(pr-name ""))
(while (equal pr-name "")
;; If the user simply pressed RET, do this again until they don't.

View file

@ -5056,7 +5056,7 @@ but that should be robust in the unexpected case that an error is signaled."
;; The use without `format' is obsolete, let's warn when we bump
;; into any such remaining uses.
(macroexp-warn-and-return
(format-message "Missing format argument in `with-demote-errors'")
(format-message "Missing format argument in `with-demoted-errors'")
exp nil nil
orig-format))))

View file

@ -23,6 +23,7 @@
;;; Code:
(require 'tramp)
(require 'ert)
(require 'esh-mode)
(require 'esh-ext)
@ -73,4 +74,35 @@
(eshell-match-command-output "echo $PATH"
(concat original-path "\n")))))
(ert-deftest esh-ext-test/explicitly-remote-command ()
"Test that an explicitly-remote command is remote no matter the current dir."
(skip-unless (and (eshell-tests-remote-accessible-p)
(executable-find "sh")))
(dolist (default-directory (list default-directory
ert-remote-temporary-file-directory))
(dolist (cmd (list "sh" (executable-find "sh")))
(ert-info ((format "Directory: %s; executable: %s" default-directory cmd))
(with-temp-eshell
;; Check the value of $INSIDE_EMACS using `sh' in order to
;; delay variable expansion.
(eshell-match-command-output
(format "%s%s -c 'echo $INSIDE_EMACS'"
(file-remote-p ert-remote-temporary-file-directory) cmd)
"eshell,tramp"))))))
(ert-deftest esh-ext-test/explicitly-local-command ()
"Test that an explicitly-local command is local no matter the current dir."
(skip-unless (and (eshell-tests-remote-accessible-p)
(executable-find "sh")))
(dolist (default-directory (list default-directory
ert-remote-temporary-file-directory))
(dolist (cmd (list "sh" (executable-find "sh")))
(ert-info ((format "In directory: %s" default-directory))
(with-temp-eshell
;; Check the value of $INSIDE_EMACS using `sh' in order to
;; delay variable expansion.
(eshell-match-command-output
(format "/:%s -c 'echo $INSIDE_EMACS'" cmd)
"eshell\n"))))))
;; esh-ext-tests.el ends here

View file

@ -6073,7 +6073,9 @@ INPUT, if non-nil, is a string sent to the process."
;; Unset the variable.
(let ((tramp-remote-process-environment
(cons (concat envvar "=foo") tramp-remote-process-environment)))
;; Set the initial value, we want to unset below.
;; Refill the cache; we don't want to run into timeouts.
(file-truename default-directory)
;; Check the initial value, we want to unset below.
(should
(string-match-p
"foo"