[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 683efb8de5a 1/2: Add 'server-eval-args-left' to server.el
From: |
Eli Zaretskii |
Subject: |
master 683efb8de5a 1/2: Add 'server-eval-args-left' to server.el |
Date: |
Sun, 29 Oct 2023 08:20:35 -0400 (EDT) |
branch: master
commit 683efb8de5ac3a2ba5ecc073d8c912ec6a61191d
Author: Spencer Baugh <sbaugh@catern.com>
Commit: Eli Zaretskii <eliz@gnu.org>
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)
---
doc/emacs/misc.texi | 9 +++++++++
etc/NEWS | 10 ++++++++++
etc/emacsclient-mail.desktop | 7 ++-----
lisp/server.el | 27 ++++++++++++++++++++-------
lisp/startup.el | 5 ++++-
5 files changed, 45 insertions(+), 13 deletions(-)
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index d7168fa1ca0..9c7c5dcd5da 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -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
diff --git a/etc/NEWS b/etc/NEWS
index 8ae7b89e830..84a03495798 100644
--- a/etc/NEWS
+++ b/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
diff --git a/etc/emacsclient-mail.desktop b/etc/emacsclient-mail.desktop
index 0a2420ddead..4f7f00ebefd 100644
--- a/etc/emacsclient-mail.desktop
+++ b/etc/emacsclient-mail.desktop
@@ -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
diff --git a/lisp/server.el b/lisp/server.el
index ce68e9aebc9..a2671165bfc 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -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))
diff --git a/lisp/startup.el b/lisp/startup.el
index 6329e3ea8d0..37843eab176 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -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