mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-21 06:55:39 +00:00
Add 'server-eval-args-left' to server.el
Passing arbitrary arguments to functions through "emacsclient --eval" sometimes requires complicated escaping to avoid them being parsed as Lisp (as seen in emacsclient-mail.desktop before this change). The new variable 'server-eval-args-left' allows access to the arguments before they are parsed as Lisp. By removing arguments from the variable before they're parsed, a snippet of Lisp can consume arguments, as in emacsclient-mail.desktop. org-protocol might be able to use this as well, which might allow it to drop its current advice on server-visit-files. * etc/emacsclient-mail.desktop: Use 'server-eval-args-left'. * lisp/server.el (server-eval-args-left): New variable. (server-process-filter, server-execute): Make '-eval' arguments available through 'server-eval-args-left'. * lisp/startup.el (argv): Mention 'server-eval-args-left' in docstring. * etc/NEWS: Announce 'server-eval-args-left'. * doc/emacs/misc.texi (emacsclient Options): Document 'server-eval-args-left'. (Bug#65902)
This commit is contained in:
parent
f3a27180b7
commit
683efb8de5
@ -2078,6 +2078,15 @@ files. When this option is given, the arguments to
|
||||
@command{emacsclient} are interpreted as a list of expressions to
|
||||
evaluate, @emph{not} as a list of files to visit.
|
||||
|
||||
@vindex server-eval-args-left
|
||||
If you have arbitrary data which you want to provide as input to one
|
||||
of your expressions, you can pass the data as another argument to
|
||||
@command{emacsclient} and use @var{server-eval-args-left} in the
|
||||
expression to access the data. Be careful to have your expression
|
||||
remove the data from @var{server-eval-args-left} regardless of whether
|
||||
your code succeeds, such as by using @code{pop}, otherwise Emacs will
|
||||
attempt to evaluate the data as a Lisp expression.
|
||||
|
||||
@item -f @var{server-file}
|
||||
@itemx --server-file=@var{server-file}
|
||||
Specify a server file (@pxref{TCP Emacs server}) for connecting to an
|
||||
|
10
etc/NEWS
10
etc/NEWS
@ -233,6 +233,16 @@ to enter the file you want to modify.
|
||||
It can be used to customize the look of the appointment notification
|
||||
displayed on the mode line when 'appt-display-mode-line' is non-nil.
|
||||
|
||||
** Emacs Server and Client
|
||||
|
||||
---
|
||||
*** 'server-eval-args-left' can be used to pop subsequent eval args
|
||||
When '--eval' is passed to emacsclient and Emacs is evaluating each
|
||||
argument, this variable is set to those which have not yet been
|
||||
evaluated. It can be used to 'pop' arguments to prevent them from
|
||||
being evaluated, which is useful when those arguments contain
|
||||
arbitrary data.
|
||||
|
||||
|
||||
* Editing Changes in Emacs 30.1
|
||||
|
||||
|
@ -1,10 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Categories=Network;Email;
|
||||
Comment=GNU Emacs is an extensible, customizable text editor - and more
|
||||
# We want to pass the following commands to the shell wrapper:
|
||||
# u=$(echo "$1" | sed 's/[\"]/\\&/g'); exec emacsclient --alternate-editor= --display="$DISPLAY" --eval "(message-mailto \"$u\")"
|
||||
# Special chars '"', '$', and '\' must be escaped as '\\"', '\\$', and '\\\\'.
|
||||
Exec=sh -c "u=\\$(echo \\"\\$1\\" | sed 's/[\\\\\\"]/\\\\\\\\&/g'); exec emacsclient --alternate-editor= --display=\\"\\$DISPLAY\\" --eval \\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" sh %u
|
||||
Exec=emacsclient --alternate-editor= --eval "(message-mailto (pop server-eval-args-left))" %u
|
||||
Icon=emacs
|
||||
Name=Emacs (Mail, Client)
|
||||
MimeType=x-scheme-handler/mailto;
|
||||
@ -16,7 +13,7 @@ Actions=new-window;new-instance;
|
||||
|
||||
[Desktop Action new-window]
|
||||
Name=New Window
|
||||
Exec=sh -c "u=\\$(echo \\"\\$1\\" | sed 's/[\\\\\\"]/\\\\\\\\&/g'); exec emacsclient --alternate-editor= --create-frame --eval \\"(message-mailto \\\\\\"\\$u\\\\\\")\\"" sh %u
|
||||
Exec=emacsclient --alternate-editor= --create-frame --eval "(message-mailto (pop server-eval-args-left))" %u
|
||||
|
||||
[Desktop Action new-instance]
|
||||
Name=New Instance
|
||||
|
@ -1199,6 +1199,7 @@ The following commands are accepted by the client:
|
||||
parent-id ; Window ID for XEmbed
|
||||
dontkill ; t if client should not be killed.
|
||||
commands
|
||||
evalexprs
|
||||
dir
|
||||
use-current-frame
|
||||
frame-parameters ;parameters for newly created frame
|
||||
@ -1332,8 +1333,7 @@ The following commands are accepted by the client:
|
||||
(let ((expr (pop args-left)))
|
||||
(if coding-system
|
||||
(setq expr (decode-coding-string expr coding-system)))
|
||||
(push (lambda () (server-eval-and-print expr proc))
|
||||
commands)
|
||||
(push expr evalexprs)
|
||||
(setq filepos nil)))
|
||||
|
||||
;; -env NAME=VALUE: An environment variable.
|
||||
@ -1358,7 +1358,7 @@ The following commands are accepted by the client:
|
||||
;; arguments, use an existing frame.
|
||||
(and nowait
|
||||
(not (eq tty-name 'window-system))
|
||||
(or files commands)
|
||||
(or files commands evalexprs)
|
||||
(setq use-current-frame t))
|
||||
|
||||
(setq frame
|
||||
@ -1407,7 +1407,7 @@ The following commands are accepted by the client:
|
||||
(let ((default-directory
|
||||
(if (and dir (file-directory-p dir))
|
||||
dir default-directory)))
|
||||
(server-execute proc files nowait commands
|
||||
(server-execute proc files nowait commands evalexprs
|
||||
dontkill frame tty-name)))))
|
||||
|
||||
(when (or frame files)
|
||||
@ -1417,22 +1417,35 @@ The following commands are accepted by the client:
|
||||
;; condition-case
|
||||
(t (server-return-error proc err))))
|
||||
|
||||
(defun server-execute (proc files nowait commands dontkill frame tty-name)
|
||||
(defvar server-eval-args-left nil
|
||||
"List of eval args not yet processed.
|
||||
|
||||
Adding or removing strings from this variable while the Emacs
|
||||
server is processing a series of eval requests will affect what
|
||||
Emacs evaluates.
|
||||
|
||||
See also `argv' for a similar variable which works for
|
||||
invocations of \"emacs\".")
|
||||
|
||||
(defun server-execute (proc files nowait commands evalexprs dontkill frame tty-name)
|
||||
;; This is run from timers and process-filters, i.e. "asynchronously".
|
||||
;; But w.r.t the user, this is not really asynchronous since the timer
|
||||
;; is run after 0s and the process-filter is run in response to the
|
||||
;; user running `emacsclient'. So it is OK to override the
|
||||
;; inhibit-quit flag, which is good since `commands' (as well as
|
||||
;; inhibit-quit flag, which is good since `evalexprs' (as well as
|
||||
;; find-file-noselect via the major-mode) can run arbitrary code,
|
||||
;; including code that needs to wait.
|
||||
(with-local-quit
|
||||
(condition-case err
|
||||
(let ((buffers (server-visit-files files proc nowait)))
|
||||
(mapc 'funcall (nreverse commands))
|
||||
(let ((server-eval-args-left (nreverse evalexprs)))
|
||||
(while server-eval-args-left
|
||||
(server-eval-and-print (pop server-eval-args-left) proc)))
|
||||
;; If we were told only to open a new client, obey
|
||||
;; `initial-buffer-choice' if it specifies a file
|
||||
;; or a function.
|
||||
(unless (or files commands)
|
||||
(unless (or files commands evalexprs)
|
||||
(let ((buf
|
||||
(cond ((stringp initial-buffer-choice)
|
||||
(find-file-noselect initial-buffer-choice))
|
||||
|
@ -120,7 +120,10 @@ the remaining command-line args are in the variable `command-line-args-left'.")
|
||||
"List of command-line args not yet processed.
|
||||
This is a convenience alias, so that one can write (pop argv)
|
||||
inside of --eval command line arguments in order to access
|
||||
following arguments."))
|
||||
following arguments.
|
||||
|
||||
See also `server-eval-args-left' for a similar variable which
|
||||
works for invocations of \"emacsclient --eval\"."))
|
||||
(internal-make-var-non-special 'argv)
|
||||
|
||||
(defvar command-line-args-left nil
|
||||
|
Loading…
Reference in New Issue
Block a user