GNU bug report logs - #65511
[PATCH] copy-next-command-output suggestion

Previous Next

Package: emacs;

Reported by: Jeremy Bryant <jb <at> jeremybryant.net>

Date: Thu, 24 Aug 2023 21:53:01 UTC

Severity: wishlist

To reply to this bug, email your comments to 65511 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Thu, 24 Aug 2023 21:53:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Jeremy Bryant <jb <at> jeremybryant.net>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Thu, 24 Aug 2023 21:53:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Jeremy Bryant <jb <at> jeremybryant.net>
To: bug-gnu-emacs <at> gnu.org, Stefan Monnier <monnier <at> iro.umontreal.ca>
Subject: [PATCH] copy-next-command-output suggestion
Date: Thu, 24 Aug 2023 22:46:28 +0100
[Message part 1 (text/plain, inline)]
Hello, Emacs maintainers.

The command copy-next-command-output copies the output of the next
command, and having used it for several months, I would like to suggest
this for Emacs core.  It doesn't appear to be part of Emacs.  I
typically bind this C-c u.

This code was provided by Stefan on this list or emacs-devel, so the
author should be changed accordingly (I haven't modified Stefan's code,
just used it).

Thoughts welcome as this is my first patch suggestion.  It could also be
put in a package in ELPA.  I have signed the paperwork.

Thanks in advance

Jeremy



[0001-Add-output-of-next-command-to-the-kill-ring.patch (text/x-diff, attachment)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Fri, 25 Aug 2023 06:06:01 GMT) Full text and rfc822 format available.

Message #8 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Jeremy Bryant <jb <at> jeremybryant.net>
Cc: 65511 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Fri, 25 Aug 2023 09:05:42 +0300
> From: Jeremy Bryant <jb <at> jeremybryant.net>
> Date: Thu, 24 Aug 2023 22:46:28 +0100
> 
> The command copy-next-command-output copies the output of the next
> command, and having used it for several months, I would like to suggest
> this for Emacs core.  It doesn't appear to be part of Emacs.  I
> typically bind this C-c u.
> 
> This code was provided by Stefan on this list or emacs-devel, so the
> author should be changed accordingly (I haven't modified Stefan's code,
> just used it).
> 
> Thoughts welcome as this is my first patch suggestion.  It could also be
> put in a package in ELPA.  I have signed the paperwork.

Thanks.  On the formal level, this needs a NEWS entry and a suitable
change for the user manual.  Also, please always accompany changes by
a commit log message formatted according to our conventions (see
CONTRIBUTE and the examples shown by "git log").

Reading the code, I'm worried by adding/removing hooks without
suitable unwind-protect protection: what if some code signals an error
or the user hits C-g before this code runs to completion?  We need to
make sure these hooks are cleaned up properly in those cases.

I also wonder whether we should bind interprogram-cut-function to nil
around the call to kill-new, since this stuff probably should be put
in the clipboard, right?

Also, what happens if some process-filter or process-sentinel or timer
fire during the time these hooks are in effect: will the stuff added
to the kill-ring include their output as well? if not, how does this
command prevent that?

And finally, this feature only works with commands whose output goes
to *Messages*, right?  If so, there are commands which show messages
in other ways, and at the very least the doc string should mention
that caveat.  Bonus points for adding ways of capturing those other
kinds of output as well.




Severity set to 'wishlist' from 'normal' Request was from Stefan Kangas <stefankangas <at> gmail.com> to control <at> debbugs.gnu.org. (Sat, 02 Sep 2023 16:16:02 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Mon, 04 Sep 2023 22:18:02 GMT) Full text and rfc822 format available.

Message #13 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: Jeremy Bryant <jb <at> jeremybryant.net>, 65511 <at> debbugs.gnu.org
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Mon, 04 Sep 2023 18:17:44 -0400
> Reading the code, I'm worried by adding/removing hooks without
> suitable unwind-protect protection: what if some code signals an error
> or the user hits C-g before this code runs to completion?  We need to
> make sure these hooks are cleaned up properly in those cases.

This is a prefix command, like `C-u`, `C-x 8 u`, and a few more: it runs
to completion before it does anything useful, since its mode of
operation is to arrange for the next command to be run
slightly differently.

The way it tries to make sure to disable itself "soon" is to use
`pre/post-command-hooks` in a way that should hopefully ensure it won't
linger longer than desired.

It's not as definite as I'd like either, but it's the best way I could
come up with so far.  I think that if we want to make it better, then we
should seriously look at improving our command-loop to provide better
built-in support for prefix commands.

The patch below includes a longer comment explaining the various
possible states,, which should hopefully help convince oneself that it
should work acceptably.

> I also wonder whether we should bind interprogram-cut-function to nil
> around the call to kill-new, since this stuff probably should be put
> in the clipboard, right?

I don't understand: binding it to nil would *prevent* it from making it
to the clipboard, whereas I don't see why we shouldn't obey
`select-enable-clipboard` and `select-enable-primary` here.

> Also, what happens if some process-filter or process-sentinel or timer
> fire during the time these hooks are in effect: will the stuff added
> to the kill-ring include their output as well?

Yes.
Not sure we should try to do something about it.

> And finally, this feature only works with commands whose output goes
> to *Messages*, right?

Yup.

> If so, there are commands which show messages in other ways, and at
> the very least the doc string should mention that caveat.
> Bonus points for adding ways of capturing those other kinds of output
> as well.

Agreed.

BTW, the reason why I haven't pushed to include it in Emacs is that I'm
not really satisfied with the UI: in most cases I don't know beforehand
that I want to capture a command's output, so a "postfix command"
(i.e. one we can run after the fact) would be much preferable.

It might not be that hard to do: tho: just push markers in *Messages* at
the beginning/end of every command (unless there have been no messages
since the last push), make sure we throw away those markers that reach
`point-min`, and then add a `copy-last-command-output` command that uses
those markers to extract the last message using those markers.
The tricky part will be to find the right message when messages are
emitted (e.g. by the completion UI) while the user types
`M-x copy-last-command-output RET`.


        Stefan


diff --git a/doc/emacs/screen.texi b/doc/emacs/screen.texi
index 5e9e89e6b11..4e65bc1105f 100644
--- a/doc/emacs/screen.texi
+++ b/doc/emacs/screen.texi
@@ -146,6 +146,11 @@ Echo Area
 this limit, one line is deleted from the beginning whenever a new
 message line is added at the end.
 
+@cindex{copy-next-command-output}
+  You can also capture the messages of a command by running the
+command @code{copy-next-command-output} beforehand, which will put them
+in the kill ring.
+
   @xref{Display Custom}, for options that control how Emacs uses the
 echo area.
 
diff --git a/etc/NEWS b/etc/NEWS
index fbb13254e64..d5bd372ecfb 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -162,6 +162,8 @@ displayed on the mode line when 'appt-display-mode-line' is non-nil.
 
 * Editing Changes in Emacs 30.1
 
+** New command 'copy-next-command-output' to capture echo area messages
+
 ---
 ** New global minor mode 'kill-ring-deindent-mode'.
 When enabled, text being saved to the kill ring will be de-indented by
diff --git a/lisp/simple.el b/lisp/simple.el
index 05a3c4b93d6..2fc1b2dad96 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -5877,6 +5877,67 @@ copy-region-as-kill
   (setq deactivate-mark t)
   nil)
 
+(defun copy-next-command-output ()
+  "Prefix command to add the output of the next command to the `kill-ring`.
+\"Output\" here refers to text emitted in the echo area, and currently this
+is limited to those messages which also appear in the *Messages* buffer."
+  (interactive)
+  (let ((md (minibuffer-depth))
+        (marker (with-current-buffer "*Messages*"
+                  (point-max-marker))))
+    ;; We consider the following states:
+    ;; - The command (and potentially a few other prefix commands) has just
+    ;;   been run, `post-command-hook' is unaffected yet and `pre-command-hook'
+    ;;   and `prefix-command-*' hooks are set.
+    ;; - The next command is about to be executed: we already run
+    ;;   `pre-command-hook'.  All the hooks are set.
+    ;; - We just finished running the next command: `post-command-hook'
+    ;;   should then hopefully remove all the hooks.
+    ;; - Within a minibuffer: commands run in the minibuffer should not affects
+    ;;   hooks since they are either "within" another prefix command
+    ;;   (such as `C-x 8 u') or within the command we want to affect.
+    ;;   We do (re)set the `marker', OTOH so as to try and skip the messages
+    ;;   that occur while we're inside the minibuffer.
+    (cl-labels ((pre ()
+                     (unless (> (minibuffer-depth) md)
+                       (add-hook 'post-command-hook #'post)
+                       (prepare)))
+                (prepare ()
+                         (with-current-buffer "*Messages*"
+                           (move-marker marker (point-max))))
+                (preserve ()
+                          (unless (> (minibuffer-depth) md)
+                            (remove-hook 'post-command-hook #'post)
+                            (add-hook 'pre-command-hook #'pre)))
+                (echo ()
+                      (unless (> (minibuffer-depth) md)
+                        "[copy-output]"))
+                (post ()
+                      (if (> (minibuffer-depth) md)
+                          ;; Prepare, in case there's no pre-command-hook before
+                          ;; the next post-command-hook.  E.g. in the case of
+                          ;; execute-extended-command.
+                          (prepare)
+                        (remove-hook 'pre-command-hook #'pre)
+                        (remove-hook 'post-command-hook #'post)
+                        (remove-hook 'prefix-command-preserve-state-hook
+                                     #'preserve)
+                        (remove-hook 'prefix-command-echo-keystrokes-functions
+                                     #'echo)
+                        (prefix-command-update)
+                        (with-current-buffer (marker-buffer marker)
+                          (when (< marker (point-max))
+                            (kill-new (buffer-substring marker (point-max)))))
+                          (set-marker marker nil))))
+      (add-hook 'prefix-command-preserve-state-hook #'preserve)
+      (add-hook 'prefix-command-echo-keystrokes-functions #'echo)
+      ;; (message "BEFORE: prefix-arg=%S current-prefix-arg=%S"
+      ;;          prefix-arg current-prefix-arg)
+      (prefix-command-preserve-state)
+      ;; (message "AFTER: prefix-arg=%S current-prefix-arg=%S"
+      ;;          prefix-arg current-prefix-arg)
+      )))
+
 (defun kill-ring-save (beg end &optional region)
   "Save the region as if killed, but don't kill it.
 In Transient Mark mode, deactivate the mark.





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Tue, 05 Sep 2023 11:16:01 GMT) Full text and rfc822 format available.

Message #16 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: jb <at> jeremybryant.net, 65511 <at> debbugs.gnu.org
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Tue, 05 Sep 2023 14:14:48 +0300
> From: Stefan Monnier <monnier <at> iro.umontreal.ca>
> Cc: Jeremy Bryant <jb <at> jeremybryant.net>,  65511 <at> debbugs.gnu.org
> Date: Mon, 04 Sep 2023 18:17:44 -0400
> 
> > I also wonder whether we should bind interprogram-cut-function to nil
> > around the call to kill-new, since this stuff probably should be put
> > in the clipboard, right?
> 
> I don't understand: binding it to nil would *prevent* it from making it
> to the clipboard, whereas I don't see why we shouldn't obey
> `select-enable-clipboard` and `select-enable-primary` here.

Sorry, I meant to say that this stuff should NOT be put into the
clipboard.  Which is why I suggested to bind interprogram-cut-function
to nil.

> > Also, what happens if some process-filter or process-sentinel or timer
> > fire during the time these hooks are in effect: will the stuff added
> > to the kill-ring include their output as well?
> 
> Yes.
> Not sure we should try to do something about it.

Maybe just document it?

> BTW, the reason why I haven't pushed to include it in Emacs is that I'm
> not really satisfied with the UI: in most cases I don't know beforehand
> that I want to capture a command's output, so a "postfix command"
> (i.e. one we can run after the fact) would be much preferable.
> 
> It might not be that hard to do: tho: just push markers in *Messages* at
> the beginning/end of every command (unless there have been no messages
> since the last push), make sure we throw away those markers that reach
> `point-min`, and then add a `copy-last-command-output` command that uses
> those markers to extract the last message using those markers.
> The tricky part will be to find the right message when messages are
> emitted (e.g. by the completion UI) while the user types
> `M-x copy-last-command-output RET`.

Maybe we should indeed try to come up with such an alternative
implementation.

> +@cindex{copy-next-command-output}
> +  You can also capture the messages of a command by running the
> +command @code{copy-next-command-output} beforehand, which will put them
> +in the kill ring.

That "them" is ambiguous.  Better say "those messages" or somesuch.

> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -162,6 +162,8 @@ displayed on the mode line when 'appt-display-mode-line' is non-nil.
>  
>  * Editing Changes in Emacs 30.1
>  
> +** New command 'copy-next-command-output' to capture echo area messages
                                                                          ^
Period missing there.

> +    ;; - Within a minibuffer: commands run in the minibuffer should not affects
                                                                           ^^^^^^^

"affect"





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Tue, 05 Sep 2023 13:11:02 GMT) Full text and rfc822 format available.

Message #19 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: jb <at> jeremybryant.net, 65511 <at> debbugs.gnu.org
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Tue, 05 Sep 2023 09:10:25 -0400
>> It might not be that hard to do: tho: just push markers in *Messages* at
>> the beginning/end of every command (unless there have been no messages
>> since the last push), make sure we throw away those markers that reach
>> `point-min`, and then add a `copy-last-command-output` command that uses
>> those markers to extract the last message using those markers.
>> The tricky part will be to find the right message when messages are
>> emitted (e.g. by the completion UI) while the user types
>> `M-x copy-last-command-output RET`.
> Maybe we should indeed try to come up with such an alternative
> implementation.

Jeremy, do you want to take a crack at it?


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Tue, 05 Sep 2023 18:35:02 GMT) Full text and rfc822 format available.

Message #22 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Jeremy Bryant <jb <at> jeremybryant.net>
To: Stefan Monnier <monnier <at> iro.umontreal.ca>
Cc: Eli Zaretskii <eliz <at> gnu.org>, 65511 <at> debbugs.gnu.org
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Tue, 05 Sep 2023 19:33:30 +0100
Yes, I will work on this.

Stefan Monnier <monnier <at> iro.umontreal.ca> writes:

>>> It might not be that hard to do: tho: just push markers in *Messages* at
>>> the beginning/end of every command (unless there have been no messages
>>> since the last push), make sure we throw away those markers that reach
>>> `point-min`, and then add a `copy-last-command-output` command that uses
>>> those markers to extract the last message using those markers.
>>> The tricky part will be to find the right message when messages are
>>> emitted (e.g. by the completion UI) while the user types
>>> `M-x copy-last-command-output RET`.
>> Maybe we should indeed try to come up with such an alternative
>> implementation.
>
> Jeremy, do you want to take a crack at it?
>
>
>         Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Mon, 13 Nov 2023 23:03:02 GMT) Full text and rfc822 format available.

Message #25 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Monnier <monnier <at> iro.umontreal.ca>
To: Jeremy Bryant <jb <at> jeremybryant.net>
Cc: 65511 <at> debbugs.gnu.org
Subject: Re: copy-last-command-output Help needed regarding Bug #65511
Date: Mon, 13 Nov 2023 17:59:10 -0500
> I have tried to work on bug #65511 but got confused with markers (even
> after reading the manual.)
>
> This was an attempt to write copy-last-command-output as a symmetrical
> version of copy-next-command-output
>
> The below is my test code but it doesn't work yet.

Any hint about what "doesn't work"?

> (defun copy-last-command-output ()
>   "Copy last command output."
>   (interactive)
>   (with-current-buffer "*Messages*"
>     ;; TODO: isolate those messages not arising from completion UI

What do you mean by this TODO?

>     (copy-region-as-kill (marker-position output-marker-beg)
>                          (marker-position output-marker-end))
>     (message "Output is:"))
>   )

The `message` call looks odd.
Did you mean to add further info after the `:`?

> (defun output-marker-pre ()
>   "Hook for pre."
>   (with-current-buffer "*Messages*"
>     (let ((buffer-read-only nil))

Better bind `inhibit-read-only` instead of `buffer-read-only`.
Also beware that *Messages* may have been killed (it's OK if the
command doesn't work in this case, but the pre/post hooks should avoid
signaling a never-ending stream of errors).

> (defun output-marker-post ()
>   "Hook for post."
>   (with-current-buffer "*Messages*"
>     (let ((buffer-read-only nil))
>       (setq output-marker-end (point-marker))
>       (message "End:%s" (marker-position output-marker-end))
>       ;;      (insert "post- marker\n")

Any reason why you can't just use `point-max` instead of
`output-marker-end`?


        Stefan





Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Thu, 13 Feb 2025 08:05:02 GMT) Full text and rfc822 format available.

Message #28 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Stefan Kangas <stefankangas <at> gmail.com>
To: Jeremy Bryant <jb <at> jeremybryant.net>
Cc: Eli Zaretskii <eliz <at> gnu.org>, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 65511 <at> debbugs.gnu.org
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Thu, 13 Feb 2025 00:03:53 -0800
Jeremy Bryant <jb <at> jeremybryant.net> writes:

> Yes, I will work on this.
>
> Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
>
>>>> It might not be that hard to do: tho: just push markers in *Messages* at
>>>> the beginning/end of every command (unless there have been no messages
>>>> since the last push), make sure we throw away those markers that reach
>>>> `point-min`, and then add a `copy-last-command-output` command that uses
>>>> those markers to extract the last message using those markers.
>>>> The tricky part will be to find the right message when messages are
>>>> emitted (e.g. by the completion UI) while the user types
>>>> `M-x copy-last-command-output RET`.
>>> Maybe we should indeed try to come up with such an alternative
>>> implementation.
>>
>> Jeremy, do you want to take a crack at it?

Jeremy, were you able to make any progress here?




Removed tag(s) patch. Request was from Stefan Kangas <stefankangas <at> gmail.com> to control <at> debbugs.gnu.org. (Thu, 13 Feb 2025 08:05:03 GMT) Full text and rfc822 format available.

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#65511; Package emacs. (Thu, 13 Feb 2025 23:21:02 GMT) Full text and rfc822 format available.

Message #33 received at 65511 <at> debbugs.gnu.org (full text, mbox):

From: Jeremy Bryant <jb <at> jeremybryant.net>
To: Stefan Kangas <stefankangas <at> gmail.com>
Cc: Eli Zaretskii <eliz <at> gnu.org>, Stefan Monnier <monnier <at> iro.umontreal.ca>,
 65511 <at> debbugs.gnu.org
Subject: Re: bug#65511: [PATCH] copy-next-command-output suggestion
Date: Thu, 13 Feb 2025 23:20:20 +0000
Stefan Kangas <stefankangas <at> gmail.com> writes:

> Jeremy Bryant <jb <at> jeremybryant.net> writes:
>
>> Yes, I will work on this.
>>
>> Stefan Monnier <monnier <at> iro.umontreal.ca> writes:
>>
>>>>> It might not be that hard to do: tho: just push markers in *Messages* at
>>>>> the beginning/end of every command (unless there have been no messages
>>>>> since the last push), make sure we throw away those markers that reach
>>>>> `point-min`, and then add a `copy-last-command-output` command that uses
>>>>> those markers to extract the last message using those markers.
>>>>> The tricky part will be to find the right message when messages are
>>>>> emitted (e.g. by the completion UI) while the user types
>>>>> `M-x copy-last-command-output RET`.
>>>> Maybe we should indeed try to come up with such an alternative
>>>> implementation.
>>>
>>> Jeremy, do you want to take a crack at it?
>
> Jeremy, were you able to make any progress here?

I worked on it but got stuck.
The facility is useful - I currently use that snippet from Stefan M in my
.emacs, as is.
I will see if I have time to revisit.
Thanks for the chaser.




This bug report was last modified 121 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.