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: Wed, 13 Sep 2023 12:57:40 +0000 (UTC) Message-ID: <87r0n2tem4.fsf@catern.com> References: <871qf2vmi4.fsf@catern.com> <87v8ceu7o0.fsf@catern.com> 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="19836"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Cc: 65902@debbugs.gnu.org To: Jim Porter Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Wed Sep 13 14:58:10 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 1qgPRY-0004tn-LY for geb-bug-gnu-emacs@m.gmane-mx.org; Wed, 13 Sep 2023 14:58:09 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1qgPRS-0004dG-QQ; Wed, 13 Sep 2023 08:58:02 -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 1qgPRM-0004a6-Sa for bug-gnu-emacs@gnu.org; Wed, 13 Sep 2023 08:57:58 -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 1qgPRM-0005Fm-K4 for bug-gnu-emacs@gnu.org; Wed, 13 Sep 2023 08:57:56 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1qgPRR-0001dY-Pe for bug-gnu-emacs@gnu.org; Wed, 13 Sep 2023 08:58:01 -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: Wed, 13 Sep 2023 12:58:01 +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.16946098766280 (code B ref 65902); Wed, 13 Sep 2023 12:58:01 +0000 Original-Received: (at 65902) by debbugs.gnu.org; 13 Sep 2023 12:57:56 +0000 Original-Received: from localhost ([127.0.0.1]:32887 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qgPRL-0001dD-3T for submit@debbugs.gnu.org; Wed, 13 Sep 2023 08:57:55 -0400 Original-Received: from s.wrqvwxzv.outbound-mail.sendgrid.net ([149.72.154.232]:42678) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1qgPRH-0001cw-Jq for 65902@debbugs.gnu.org; Wed, 13 Sep 2023 08:57:54 -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=IA/8zE8M8Z2Zq3Pn4wYU+nXEB9exsXj3Rl57w1CSpK0=; b=GDnambABtWZTPZ9e3eNGsazAV7y64tMwI9cHD5PfNgNa6O4gBvEiKYdpwvpqPLYeo/eH L5V/qqIUmF87OElxJZozd/3t/p1vPlhQw+7c5hyAKUcseB0vF45xzaNyp3pTCegrwnDtYz bJpX5R8SupspdDUPgzyAr11OvomQhLWHXZaeomhMJUM0+rpyAAStoIBXGuWMBH758e+ymG 2NB7do9K47Mmrl/O4FCLGPOf/RT6lgZUoa5TrMudcJ1t5SHPmy1Q58Daz6wrWeZ1er08bV lhqnfa3AY8KCJvEq87f7XgPqynE7CiAdgdMuETUxokgnLtVgxTSYrkPggogBlQUw== Original-Received: by filterdrecv-8684c58db7-9pkkz with SMTP id filterdrecv-8684c58db7-9pkkz-1-6501B1C3-29 2023-09-13 12:57:39.95744995 +0000 UTC m=+10847949.848089376 Original-Received: from earth.catern.com (unknown) by geopod-ismtpd-1 (SG) with ESMTP id 3uFHoXEbQjiCQb4LueyrPw Wed, 13 Sep 2023 12:57:39.685 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=::1; helo=localhost; envelope-from=sbaugh@catern.com; receiver=gmail.com Original-Received: from localhost (localhost [IPv6:::1]) by earth.catern.com (Postfix) with ESMTPSA id 3734F6566A; Wed, 13 Sep 2023 08:57:39 -0400 (EDT) In-Reply-To: (Jim Porter's message of "Tue, 12 Sep 2023 20:46:54 -0700") X-SG-EID: ZgbRq7gjGrt0q/Pjvxk7wM0yQFRdOkTJAtEbkjCkHbK05RQBjAcJRehj6j96atM0kLr7M+281RHp84Glohm29SWM2NtXD28eQ5+QHKBJi/ZCUFAj5htdyG8uwo2Zb+elErYm+hCJZra9UDgxwDp8P0YBp1QaTR1/jcV2l44wKvqgRDzUxmhpNZ4cIo2KQJ8cLSlYeHbpTuVbXaWT+Z/vKA== 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:270270 Archived-At: --=-=-= Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Jim Porter writes: > On 9/12/2023 7:30 PM, sbaugh@catern.com wrote: >> tags 65902 + patch >> quit >> This patch avoids the complicated scripting needed for >> emacsclient-mail.desktop by adding a new flag to emacsclient, --funcall, >> which mirrors emacs --funcall and allows emacsclient-mail.desktop to be >> basically the same as emacs-mail.desktop. > > I think this is actually the same as the (very long) bug#57752, so > thanks for working on this. (It was on my list of things to get to, > but I just haven't had time.) > > Over there, we agreed that something like your patch is wanted, albeit > with two caveats: > > 1. Since "--funcall" for the regular "emacs" binary doesn't pass > arguments to the function, how about we call this option "--apply" > instead? Ah, for some reason I thought --funcall passed arguments. Done in attached patch. > 2. It would be great if we could get "--apply" for the regular "emacs" > binary too, so that both programs work the same way (at least in this > regard). Done. Although the behavior is slightly different: emacs --apply calls the function with subsequent FILE arguments, and emacsclient --apply calls the function with all FILE arguments. The "subsequent FILE arguments" behavior is probably better, but I don't know a way to do that with getopt (which emacsclient uses). > Even better, if you could forward "--apply" from > "emacsclient" to the alternate editor (which would be "emacs" 99% of > the time) automatically. That works, in a roundabout way, for the > Emacs daemon, but not if the alternate editor is "emacs". This happens automatically anyway: When emacsclient starts the daemon, it sends the --apply request. I think that's exactly what you'd want. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=0001-Add-apply-argument-to-avoid-escaping-arguments.patch >From 4881017055ea6831ee7fe2d722eb79856946d907 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Tue, 12 Sep 2023 22:20:15 -0400 Subject: [PATCH] Add --apply argument to avoid escaping arguments Passing arguments to functions through emacs --eval or emacsclient --eval requires complicated escaping (as seen in emacsclient-mail.desktop before this change). The new --apply argument for both emacs and emacsclient passes command line arguments as uninterpreted strings to the specified function. This simplifies use cases where arbitrary input needs to be passed to Emacs. Note that there's a minor difference in behavior between emacs --apply and emacsclient --apply: emacs --apply func calls func with only command line arguments occuring after --apply, emacsclient --apply func calls func with all command line arguments, even those which occurred before --apply. This is hard to avoid since emacsclient uses getopt instead of fancier custom Lisp argument parsing in Emacs. * etc/emacsclient-mail.desktop: Use --apply. (bug#65902) * lib-src/emacsclient.c (longopts, decode_options, main): Add support for --apply. * lisp/server.el (server-apply-and-print): Add. (server-process-filter): Add support for -apply and -applyargs * lisp/startup.el (command-line-1): Add support for --apply. * src/emacs.c (usage_message, standard_args): Add support for --apply. --- etc/emacsclient-mail.desktop | 9 +++------ lib-src/emacsclient.c | 36 ++++++++++++++++++++++++++++++++++-- lisp/server.el | 34 ++++++++++++++++++++++++++++++++++ lisp/startup.el | 18 +++++++++++++++--- src/emacs.c | 3 +++ 5 files changed, 89 insertions(+), 11 deletions(-) diff --git a/etc/emacsclient-mail.desktop b/etc/emacsclient-mail.desktop index 0a2420ddead..750fcddacdc 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= --apply message-mailto -- %u Icon=emacs Name=Emacs (Mail, Client) MimeType=x-scheme-handler/mailto; @@ -16,8 +13,8 @@ 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 --apply message-mailto -- %u [Desktop Action new-instance] Name=New Instance -Exec=emacs -f message-mailto %u +Exec=emacs --apply message-mailto -- %u diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 698bf9b50ae..159c22d1ae9 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -116,6 +116,9 @@ #define DEFAULT_TIMEOUT (30) /* True means args are expressions to be evaluated. --eval. */ static bool eval; +/* The function to call. Other arguments are passed as strings. --apply. */ +static char *apply; + /* True means open a new frame. --create-frame etc. */ static bool create_frame; @@ -169,6 +172,7 @@ #define DEFAULT_TIMEOUT (30) { "quiet", no_argument, NULL, 'q' }, { "suppress-output", no_argument, NULL, 'u' }, { "eval", no_argument, NULL, 'e' }, + { "apply", required_argument, NULL, 'y' }, { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, { "tty", no_argument, NULL, 't' }, @@ -552,6 +556,10 @@ decode_options (int argc, char **argv) eval = true; break; + case 'y': + apply = optarg; + break; + case 'q': quiet = true; break; @@ -690,6 +698,7 @@ print_help_and_exit (void) -F ALIST, --frame-parameters=ALIST\n\ Set the parameters of a new frame\n\ -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ +-y, --apply FUNC Call ELisp FUNC, passing all FILE arguments as strings\n\ -n, --no-wait Don't wait for the server to return\n\ -w, --timeout=SECONDS Seconds to wait before timing out\n\ -q, --quiet Don't display messages on success\n\ @@ -1953,7 +1962,7 @@ main (int argc, char **argv) /* Process options. */ decode_options (argc, argv); - if (! (optind < argc || eval || create_frame)) + if (! (optind < argc || eval || apply || create_frame)) { message (true, ("%s: file name or argument required\n" "Try '%s --help' for more information\n"), @@ -1961,6 +1970,14 @@ main (int argc, char **argv) exit (EXIT_FAILURE); } + if (eval && apply) + { + message (true, ("%s: can't pass both --eval and --apply\n" + "Try '%s --help' for more information\n"), + progname, progname); + exit (EXIT_FAILURE); + } + #ifdef SOCKETS_IN_FILE_SYSTEM if (tty) { @@ -2080,6 +2097,13 @@ main (int argc, char **argv) send_to_emacs (emacs_socket, " "); continue; } + else if (apply) + { + send_to_emacs (emacs_socket, "-applyarg "); + quote_argument (emacs_socket, argv[i]); + send_to_emacs (emacs_socket, " "); + continue; + } char *p = argv[i]; if (*p == '+') @@ -2136,10 +2160,18 @@ main (int argc, char **argv) send_to_emacs (emacs_socket, " "); } + if (apply) + { + send_to_emacs (emacs_socket, "-apply "); + quote_argument (emacs_socket, apply); + send_to_emacs (emacs_socket, " "); + } + + send_to_emacs (emacs_socket, "\n"); /* Wait for an answer. */ - if (!eval && !tty && !nowait && !quiet && 0 <= process_grouping ()) + if (!eval && !apply && !tty && !nowait && !quiet && 0 <= process_grouping ()) { printf ("Waiting for Emacs..."); skiplf = false; diff --git a/lisp/server.el b/lisp/server.el index c3325e5a24c..5981e90625d 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -873,6 +873,17 @@ server-eval-and-print (point-min) (point-max)))) (server-reply-print (server-quote-arg text) proc))))))) +(defun server-apply-and-print (func args proc) + "Call FUNC on ARGS and send the result back to client PROC." + (let ((v (with-local-quit (eval (apply (intern func) args) t)))) + (when proc + (with-temp-buffer + (let ((standard-output (current-buffer))) + (pp v) + (let ((text (buffer-substring-no-properties + (point-min) (point-max)))) + (server-reply-print (server-quote-arg text) proc))))))) + (defconst server-msg-size 1024 "Maximum size of a message sent to a client.") @@ -1196,6 +1207,7 @@ server-process-filter tty-type ; string. files filepos + applyargs args-left) ;; Remove this line from STRING. (setq string (substring string (match-end 0))) @@ -1323,6 +1335,28 @@ server-process-filter commands) (setq filepos nil))) + ;; -apply FUNC: Call a function on arguments. + ("-apply" + (if use-current-frame + (setq use-current-frame 'always)) + (let ((func (pop args-left))) + (if coding-system + (setq func (decode-coding-string func coding-system))) + (push (lambda () (server-apply-and-print func applyargs proc)) + commands) + (setq applyargs nil) + (setq filepos nil))) + + ;; -applyarg ARG: Add an argument for later -apply. + ("-applyarg" + (if use-current-frame + (setq use-current-frame 'always)) + (let ((arg (pop args-left))) + (if coding-system + (setq arg (decode-coding-string arg coding-system))) + (push arg applyargs) + (setq filepos nil))) + ;; -env NAME=VALUE: An environment variable. ("-env" (let ((var (pop args-left))) diff --git a/lisp/startup.el b/lisp/startup.el index 7f601668369..bb8da76bdf1 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -2531,10 +2531,11 @@ command-line-1 ;; straight away upon any --directory/-L option. splice just-files ;; t if this follows the magic -- option. + applysym applyargs ;; function and arguments for --apply ;; This includes our standard options' long versions ;; and long versions of what's on command-switch-alist. (longopts - (append '("--funcall" "--load" "--insert" "--kill" + (append '("--funcall" "--apply" "--load" "--insert" "--kill" "--dump-file" "--seccomp" "--directory" "--eval" "--execute" "--no-splash" "--find-file" "--visit" "--file" "--no-desktop") @@ -2632,6 +2633,11 @@ command-line-1 (command-execute tem) (funcall tem))) + ((member argi '("-y" "-apply")) + (setq inhibit-startup-screen t) + ;; Subsequent file args will be accumulated into applyargs. + (setq applysym (intern (or argval (pop command-line-args-left))))) + ((member argi '("-eval" "-execute")) (setq inhibit-startup-screen t) (let* ((str-expr (or argval (pop command-line-args-left))) @@ -2763,13 +2769,19 @@ command-line-1 ;; screen for -nw? (unless initial-window-system (setq inhibit-startup-screen t)) - (funcall process-file-arg orig-argi))))) + (if applysym + (push orig-argi applyargs) + (funcall process-file-arg orig-argi)))))) ;; In unusual circumstances, the execution of Lisp code due ;; to command-line options can cause the last visible frame ;; to be deleted. In this case, kill emacs to avoid an ;; abort later. - (unless (frame-live-p (selected-frame)) (kill-emacs nil))))))) + (unless (frame-live-p (selected-frame)) (kill-emacs nil)))) + + ;; Call the function specified with --apply, if any. + (when applysym + (apply applysym (nreverse applyargs)))))) (when (eq initial-buffer-choice t) ;; When `initial-buffer-choice' equals t make sure that *scratch* diff --git a/src/emacs.c b/src/emacs.c index 80a013b68df..8de40936250 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -323,6 +323,8 @@ #define MAIN_PROGRAM --file FILE visit FILE\n\ --find-file FILE visit FILE\n\ --funcall, -f FUNC call Emacs Lisp function FUNC with no arguments\n\ +--apply, -y FUNC call Emacs Lisp function FUNC, passing\n\ + subsequent positional FILE arguments as strings\n\ --insert FILE insert contents of FILE into current buffer\n\ --kill exit without asking for confirmation\n\ --load, -l FILE load Emacs Lisp FILE using the load function\n\ @@ -2648,6 +2650,7 @@ main (int argc, char **argv) option. In any case, this is entirely an internal option. */ { "-scriptload", NULL, 0, 1 }, { "-f", "--funcall", 0, 1 }, + { "-y", "--apply", 0, 1 }, { "-funcall", 0, 0, 1 }, { "-eval", "--eval", 0, 1 }, { "-execute", "--execute", 0, 1 }, -- 2.41.0 --=-=-=--