From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: sbaugh@catern.com Newsgroups: gmane.emacs.bugs Subject: bug#65902: 29.0.92; emacsclient-mail.desktop fails due to complicated escaping Date: Sun, 24 Sep 2023 14:20:16 +0000 (UTC) Message-ID: <87wmwfps9s.fsf@catern.com> References: <80d8aeb0-c9f1-410f-b83d-60f83ca5b3af@email.android.com> <83led8ls3z.fsf@gnu.org> <835y4ckkzu.fsf@gnu.org> <874jjnvvip.fsf@catern.com> <835y4290kf.fsf@gnu.org> <87zg1cprix.fsf@catern.com> <83a5tc4096.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="15038"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: jporterbugs@gmail.com, sbaugh@janestreet.com, 65902@debbugs.gnu.org To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Sun Sep 24 16:21:14 2023 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1qkPyy-0003fo-WC for geb-bug-gnu-emacs@m.gmane-mx.org; Sun, 24 Sep 2023 16:21:13 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qkPyf-0006mB-5N; Sun, 24 Sep 2023 10:20:53 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1qkPyd-0006m1-1x for bug-gnu-emacs@gnu.org; Sun, 24 Sep 2023 10:20:51 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1qkPyc-0007RW-Pv for bug-gnu-emacs@gnu.org; Sun, 24 Sep 2023 10:20:50 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qkPyo-0002pF-75 for bug-gnu-emacs@gnu.org; Sun, 24 Sep 2023 10:21:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: sbaugh@catern.com Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 24 Sep 2023 14:21:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 65902 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch Original-Received: via spool by 65902-submit@debbugs.gnu.org id=B65902.169556524410824 (code B ref 65902); Sun, 24 Sep 2023 14:21:02 +0000 Original-Received: (at 65902) by debbugs.gnu.org; 24 Sep 2023 14:20:44 +0000 Original-Received: from localhost ([127.0.0.1]:43388 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qkPyS-0002oR-Lb for submit@debbugs.gnu.org; Sun, 24 Sep 2023 10:20:44 -0400 Original-Received: from s.wfbtzhsv.outbound-mail.sendgrid.net ([159.183.224.104]:44368) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qkPyN-0002o5-Hh for 65902@debbugs.gnu.org; Sun, 24 Sep 2023 10:20:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=catern.com; h=from:subject:in-reply-to:references:mime-version:to:cc:content-type: cc:content-type:from:subject:to; s=s1; bh=2gZjm7zpgvjHkvVnoniLdM5KdtNzGlv/czRBkKcZh64=; b=kn39f1SzVa4J3ljQdx+D8i1pFx8uEzhtOTbb3ehyV+jSwIX4t9VFBTZlcy4YlZgWIsCi MRdgW/B8UwOPXhedrbf/A/VCWTcyFe3GTU9gq35IowexR7M2ptCE4ppUGuySc3VrSZzXBq OFj23HbHgkrzlIqAEBr2BlkayGUhMnVarDTWtr6zHs+U9QnWhDCw4z3MXRnsYoYSurQgoi lD0w2tfABRYCFOpQyXaKNoBDhiJiWE10wsWTIgs57tpZe2sv7NzNNX0nhGaNxNbLSbWOVX Bw9UkQJjbQnq4VlaXmq1asdQEHrMCa80SU2a5esP7jvcb5Dnle1jHmfe2RQVdq5Q== Original-Received: by filterdrecv-84b96456cb-vm9rv with SMTP id filterdrecv-84b96456cb-vm9rv-1-651045A0-19 2023-09-24 14:20:16.640783476 +0000 UTC m=+11803291.394807526 Original-Received: from earth.catern.com (unknown) by geopod-ismtpd-4 (SG) with ESMTP id Kj0zs797SWu0wHI6_UKTvg Sun, 24 Sep 2023 14:20:16.393 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=::1; helo=localhost; envelope-from=sbaugh@catern.com; receiver=gnu.org Original-Received: from localhost (localhost [IPv6:::1]) by earth.catern.com (Postfix) with ESMTPSA id E94DA62523; Sun, 24 Sep 2023 10:20:15 -0400 (EDT) In-Reply-To: <83a5tc4096.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 24 Sep 2023 08:18:45 +0300") X-SG-EID: ZgbRq7gjGrt0q/Pjvxk7wM0yQFRdOkTJAtEbkjCkHbLC3WoWB5tg9x0+m6oYKRVDWrjV2LdH6ULrE2KTahezJtcW51fC6aUaKxNkHHTUsx8rh+TqvTCynNw+GgGtLB+aIigHvXyKachOSx4f9/b7iEHccMh82al/BYPpG9HJpYGU1UsHw36WoDtFwpBdKGtK+jQmHWfhJO37ElqcNPsk4Q== X-Entity-ID: d/0VcHixlS0t7iB1YKCv4Q== X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:271247 Archived-At: --=-=-= Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Eli Zaretskii writes: >> From: sbaugh@catern.com >> Date: Sat, 23 Sep 2023 20:24:07 +0000 (UTC) >> Cc: 65902@debbugs.gnu.org, sbaugh@janestreet.com, jporterbugs@gmail.com >> >> > IIUC, this kind of solution is fine by me, but the protocol of >> > accessing and using server-eval-args-left in the Lisp expressions >> > specified on the emacsclient command line should be well-documented to >> > avoid any confusion and UB. >> >> Added a docstring and included it in NEWS. I would have put it in the >> manual, but it seems rather niche to put in the Emacs manual and I >> didn't see a natural place to put it in the Emacs Lisp manual. > > The natural place is in the Emacs user manual, in "emacsclient > Options", where --eval is described. Where else? Ah true, obvious, I added it there. >> Passing arbitrary arguments to functions through emacsclient --eval >> requires complicated escaping to avoid them being parsed as Lisp (as >> seen in emacsclient-mail.desktop before this change). >> >> This 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. > > The right place to keep this information is in the manual and the doc > strings, not just in the Git commit log message. Done. >> +(defvar server-eval-args-left nil >> + "List of eval args not yet processed. >> + >> +When the server receives a request to eval one or more strings, >> +it stores them in this variable. Then, until this variable is >> +nil, it `pop's a string from this variable and evaluates it with >> +`server-eval-and-print'. Adding or removing strings from this >> +variable during this process will affect what is evaluated. > > This describes the implementation rather than the intended usage. Fixed. >> +This allows an expression passed to \"emacsclient --eval\" to >> +consume one or more subsequent arguments before they're parsed or >> +evaluated, with (pop server-eval-args-left). This is useful if >> +those arguments are arbitrary strings which should not be >> +evaluated. > > This describes a way of using this, but without the important part: > that any processed argument _must_ be popped, or it will be evaluated > again. See the doc string of command-line-functions for what I have > in mind. > > All in all, I think this should be rewritten in terms of how to use > this, and the result moved to the Emacs manual, leaving just the > minimum here. Done. >> +See also `command-line-args-left' for a similar variable which >> +works for command line invocations of \"emacs\".") > > This "see also" is not useful, because the doc string of > command-line-args-left is minimal and doesn't add any information > (which is okay, since that variable is basically meant for internal > Emacs handling of command-line arguments, unlike this one). Okay, fair, probably that should point at `argv' instead. >> --- a/lisp/startup.el >> +++ b/lisp/startup.el >> @@ -120,7 +120,10 @@ command-switch-alist >> "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\".")) > > And neither is this, because the use cases of the two variables are > almost completely unrelated. The docstring of argv says: This is a convenience alias, so that one can write (pop argv) inside of --eval command line arguments in order to access following arguments. That is exactly the same way this new variable is used. And in fact it's used for the exact same purpose in message-mailto. The reason "emacs" doesn't require complicated escaping is because message-mailto does (pop command-line-args-left) internally. I agree that argv/command-line-args-left has other use cases besides this one. But one of argv's use cases is the exact same use case of server-eval-args-left. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Add-server-eval-args-left-to-server.el.patch >From bd49b918e57363593660f605c3e0efc3d0155c2b Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Thu, 21 Sep 2023 21:35:50 -0400 Subject: [PATCH] Add server-eval-args-left to server.el Passing arbitrary arguments to functions through emacsclient --eval requires complicated escaping to avoid them being parsed as Lisp (as seen in emacsclient-mail.desktop before this change). This 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. (bug#65902) * lisp/server.el (server-eval-args-left): Add. (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. --- 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 7a88b7ef5e0..1ce1713b01c 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2078,6 +2078,15 @@ emacsclient Options @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 cd4c414a64c..de1d79fcb98 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -121,6 +121,16 @@ Anything following the symbol 'mode-line-format-right-align' in right-aligned to is controlled by the new user option 'mode-line-right-align-edge'. +** 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..5962fa1764c 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 c3325e5a24c..3970d7a7e81 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -1189,6 +1189,7 @@ server-process-filter 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 @@ -1319,8 +1320,7 @@ server-process-filter (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. @@ -1345,7 +1345,7 @@ server-process-filter ;; 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 @@ -1394,7 +1394,7 @@ server-process-filter (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) @@ -1404,22 +1404,35 @@ server-process-filter ;; 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 7f601668369..f2c84751211 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -120,7 +120,10 @@ command-switch-alist "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 -- 2.41.0 --=-=-=--