unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Tino Calancha <tino.calancha@gmail.com>
To: Yuri Khan <yuri.v.khan@gmail.com>
Cc: "Emacs developers" <emacs-devel@gnu.org>,
	"Clément Pit--Claudel" <clement.pit@gmail.com>,
	"Tino Calancha" <tino.calancha@gmail.com>
Subject: Re: New opt to allow not erase out buffer between shell cmds
Date: Thu, 28 Jul 2016 21:53:57 +0900 (JST)	[thread overview]
Message-ID: <alpine.DEB.2.20.1607282147040.24483@calancha-pc> (raw)
In-Reply-To: <CAP_d_8VExY7MCe3T4XzMEOPLOkHpOWUHc6O8MY2KMgc5w93_sg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 12270 bytes --]



On Wed, 13 Jul 2016, Yuri Khan wrote:

> On Wed, Jul 13, 2016 at 8:48 PM, Tino Calancha <tino.calancha@gmail.com> wrote:
>
>>> I think something went wrong with the grammar here.
>>>
>>>> -                    (erase-buffer)))
>>>> +                    (if keep
>>>> +                        (goto-char (point-max))
>>>> +                      (erase-buffer))))
>>>
>>>
>>> Is this in a save-excursion? If not, is there a way to preserve the point
>>> in the target buffer? (Is that desirable?)
>>
>> I should drop the `goto-char' call, right?
>
> I believe Clément is not asking you to drop the goto-char. No, he’s
> asking you to *think*. And maybe make a UI design decision.
>
>> I added that line in order to insert the output of commad 'i+1' after the
>> output from command 'i'.
>
> That is a good goal, and (goto-char (point-max)) achieves it.
> Inserting new output right where the point is would be very unnatural.
>
> However, Clément hints that, if the user desires to retain the
> previous contents of the buffer, maybe they also want to retain their
> position in said buffer. If they do, you’d better save the original
> point position and return there after inserting the new command’s
> output; this is easiest done with save-excursion.
>
> On the other hand, the user might want to keep old output but skip
> straight to the new output. In this case, jumping to the end and then
> inserting new output is ok.
>
> On the third hand (there always is a third hand!), if the new output
> is longer than a windowful, the user may also like to start at the
> beginning of the new output rather than the end.
>
> It is now up to you, as the designer of the new feature, to decide
> which of the above behaviors you want to support.

I want to support all 3 behaviours and let the user decide.
Here is my patch.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

From efce1dff95902ec9b1be304a0872321b8677d3d4 Mon Sep 17 00:00:00 2001
From: Tino Calancha <tino.calancha@gmail.com>
Date: Thu, 28 Jul 2016 21:41:03 +0900
Subject: [PATCH] Allow not erase output buffer

* lisp/simple.el (shell-command-not-erase-buffer): New option to allow
not erasing the output buffer between shell commands.  Defaults to nil.
(shell-command-on-region): Use it.
(shell-command--save-pos-or-erase): New defun; store a buffer position
if 'shell-command-not-erase-buffer' is non-nil; otherwise
erase the output buffer of the shell command.
(shell-command, shell-command-on-region): Use it.
(shell-command--set-point-after-cmd): New defun;
if 'shell-command-not-erase-buffer' is non-nil, set point in the
output buffer of the shell command to the buffer position
in 'shell-command--save-pos-or-erase'.
(shell-command-sentinel, shell-command-on-region): Use it.
; etc/NEWS: Add entry for this new feature.
See discussion on:
http://lists.gnu.org/archive/html/emacs-devel/2016-07/msg00610.html
---
  etc/NEWS       |   9 +++++
  lisp/simple.el | 107 
+++++++++++++++++++++++++++++++++++++++++++++++----------
  2 files changed, 98 insertions(+), 18 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 6462eff..63a8158 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -59,6 +59,15 @@ affected by this, as SGI stopped supporting IRIX in 
December 2013.

  * Changes in Emacs 25.2

+** The new user option 'shell-command-not-erase-buffer' controls
+if the output buffer is erased between shell commands; if non-nil,
+the output buffer is not erased; this variable also control where
+to set the point in the output buffer: beginning of the output,
+end of the buffer or seave the point.
+When 'shell-command-not-erase-buffer' is nil, the default value,
+the behaviour of 'shell-command', 'shell-command-on-region' and
+'async-shell-command' is as usual.
+
  +++
  ** The new user option 'mouse-select-region-move-to-beginning'
  controls the position of point when double-clicking mouse-1 on the end
diff --git a/lisp/simple.el b/lisp/simple.el
index e91b6e0..f77c9f8 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -37,6 +37,27 @@
  (defvar compilation-current-error)
  (defvar compilation-context-lines)

+(defcustom shell-command-not-erase-buffer nil
+  "If non-nil, output buffer is not erased between shell commands.
+Also, a non-nil value set the point in the output buffer
+once the command complete.
+The value `beg-last-out' set point at the beginning of the output,
+`end-last-out' set point at the end of the buffer, `save-point'
+restore the buffer position before the command."
+  :type '(choice
+          (const :tag "Erase buffer" nil)
+          (const :tag "Set point to beginning of last output" 
beg-last-out)
+          (const :tag "Set point to end of last output" end-last-out)
+          (const :tag "Save point" save-point))
+  :group 'shell
+  :version "25.2")
+
+(defvar shell-command-saved-pos nil
+  "Point position in the output buffer after command complete.
+It is an alist (BUFFER . POS), where BUFFER is the output
+buffer, and POS is the point position in BUFFER once the command finish.
+This variable is used when `shell-command-not-erase-buffer' is non-nil.")
+
  (defcustom idle-update-delay 0.5
    "Idle time delay before updating various things on the screen.
  Various Emacs features that update auxiliary information when point moves
@@ -3210,6 +3231,53 @@ async-shell-command-buffer
    :group 'shell
    :version "24.3")

+(defun shell-command--save-pos-or-erase ()
+  "Store a buffer position or erase the buffer.
+See `shell-command-not-erase-buffer'."
+  (let ((sym shell-command-not-erase-buffer)
+        pos)
+    (setq buffer-read-only nil)
+    ;; Setting buffer-read-only to nil doesn't suffice
+    ;; if some text has a non-nil read-only property,
+    ;; which comint sometimes adds for prompts.
+    (setq pos
+          (cond ((eq sym 'save-point) (point))
+                ((eq sym 'beg-last-out) (point-max))
+                ((not sym)
+                 (let ((inhibit-read-only t))
+                   (erase-buffer) nil))))
+    (when pos
+      (goto-char (point-max))
+      (push (cons (current-buffer) pos)
+            shell-command-saved-pos))))
+
+(defun shell-command--set-point-after-cmd (&optional buffer)
+  "Set point in BUFFER after command complete.
+BUFFER is the output buffer of the command; if nil, then defaults
+to the current BUFFER.
+Set point to the `cdr' of the element in `shell-command-saved-pos'
+whose `car' is BUFFER."
+  (when shell-command-not-erase-buffer
+    (let* ((sym  shell-command-not-erase-buffer)
+           (buf  (or buffer (current-buffer)))
+           (pos  (alist-get buf shell-command-saved-pos)))
+      (setq shell-command-saved-pos
+            (assq-delete-all buf shell-command-saved-pos))
+      (when (buffer-live-p buf)
+        (let ((win   (car (get-buffer-window-list buf)))
+              (pmax  (with-current-buffer buf (point-max))))
+          (unless (and pos (memq sym '(save-point beg-last-out)))
+            (setq pos pmax))
+          ;; Set point in the window displaying buf, if any; otherwise
+          ;; display buf temporary in selected frame and set the point.
+          (if win
+              (set-window-point win pos)
+            (save-window-excursion
+              (let ((win (display-buffer
+                          buf
+                          '(nil (inhibit-switch-frame . t)))))
+                (set-window-point win pos)))))))))
+
  (defun async-shell-command (command &optional output-buffer error-buffer)
    "Execute string COMMAND asynchronously in background.

@@ -3271,7 +3339,8 @@ shell-command
  The optional second argument OUTPUT-BUFFER, if non-nil,
  says to put the output in some other buffer.
  If OUTPUT-BUFFER is a buffer or buffer name, erase that buffer
-and insert the output there.
+and insert the output there; a non-nil value of
+`shell-command-not-erase-buffer' prevent to erase the buffer.
  If OUTPUT-BUFFER is not a buffer and not nil, insert the output
  in current buffer after point leaving mark after it.
  This cannot be done asynchronously.
@@ -3408,13 +3477,8 @@ shell-command
  		    (setq buffer (get-buffer-create
  				  (or output-buffer "*Async Shell 
Command*"))))))
  		(with-current-buffer buffer
-		  (setq buffer-read-only nil)
-		  ;; Setting buffer-read-only to nil doesn't suffice
-		  ;; if some text has a non-nil read-only property,
-		  ;; which comint sometimes adds for prompts.
-		  (let ((inhibit-read-only t))
-		    (erase-buffer))
  		  (display-buffer buffer '(nil (allow-no-window . t)))
+                  (shell-command--save-pos-or-erase)
  		  (setq default-directory directory)
  		  (setq proc (start-process "Shell" buffer shell-file-name
  					    shell-command-switch command))
@@ -3497,12 +3561,14 @@ display-message-or-buffer


  ;; We have a sentinel to prevent insertion of a termination message
-;; in the buffer itself.
+;; in the buffer itself, and to set the point in the buffer when
+;; `shell-command-not-erase-buffer' is non-nil.
  (defun shell-command-sentinel (process signal)
-  (if (memq (process-status process) '(exit signal))
-      (message "%s: %s."
-	       (car (cdr (cdr (process-command process))))
-	       (substring signal 0 -1))))
+  (when (memq (process-status process) '(exit signal))
+    (shell-command--set-point-after-cmd (process-buffer process))
+    (message "%s: %s."
+             (car (cdr (cdr (process-command process))))
+             (substring signal 0 -1))))

  (defun shell-command-on-region (start end command
  				      &optional output-buffer replace
@@ -3536,7 +3602,8 @@ shell-command-on-region

  Optional fourth arg OUTPUT-BUFFER specifies where to put the
  command's output.  If the value is a buffer or buffer name,
-erase that buffer and insert the output there.
+erase that buffer and insert the output there; a non-nil value of
+`shell-command-not-erase-buffer' prevent to erase the buffer.
  If the value is nil, use the buffer `*Shell Command Output*'.
  Any other non-nil value means to insert the output in the
  current buffer after START.
@@ -3616,7 +3683,10 @@ shell-command-on-region
          (let ((buffer (get-buffer-create
                         (or output-buffer "*Shell Command Output*"))))
            (unwind-protect
-              (if (eq buffer (current-buffer))
+              (if (and (eq buffer (current-buffer))
+                       (or (not shell-command-not-erase-buffer)
+                           (and (not (eq buffer (get-buffer "*Shell 
Command Output*")))
+                                (not (region-active-p)))))
                    ;; If the input is the same buffer as the output,
                    ;; delete everything but the specified region,
                    ;; then replace that region with the output.
@@ -3635,10 +3705,9 @@ shell-command-on-region
                  ;; output there.
                  (let ((directory default-directory))
                    (with-current-buffer buffer
-                    (setq buffer-read-only nil)
                      (if (not output-buffer)
                          (setq default-directory directory))
-                    (erase-buffer)))
+                    (shell-command--save-pos-or-erase)))
                  (setq exit-status
                        (call-process-region start end shell-file-name nil
                                             (if error-file
@@ -3656,8 +3725,10 @@ shell-command-on-region
                             (format " - Exit [%d]" exit-status)))))
              (if (with-current-buffer buffer (> (point-max) (point-min)))
                  ;; There's some output, display it
-                (display-message-or-buffer buffer)
-              ;; No output; error?
+                (progn
+                  (display-message-or-buffer buffer)
+                  (shell-command--set-point-after-cmd buffer))
+            ;; No output; error?
                (let ((output
                       (if (and error-file
                                (< 0 (nth 7 (file-attributes error-file))))
-- 
2.8.1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

In GNU Emacs 25.1.50.2 (x86_64-pc-linux-gnu, GTK+ Version 3.20.6)
  of 2016-07-28 built
Repository revision: ec359399a47f852b4d022a30245449438e349193

  parent reply	other threads:[~2016-07-28 12:53 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-07-13 14:09 New optional arg to [async-]shell-command[-on-region] Tino Calancha
2016-07-13 14:29 ` Clément Pit--Claudel
2016-07-13 14:48   ` Tino Calancha
2016-07-13 15:06     ` Yuri Khan
2016-07-13 15:27       ` Tino Calancha
2016-07-13 15:58         ` Clément Pit--Claudel
2016-07-13 16:02           ` Clément Pit--Claudel
2016-07-28 12:53       ` Tino Calancha [this message]
2016-08-24 15:10         ` New opt to allow not erase out buffer between shell cmds Clément Pit--Claudel
2016-08-26  6:43           ` Tino Calancha

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.DEB.2.20.1607282147040.24483@calancha-pc \
    --to=tino.calancha@gmail.com \
    --cc=clement.pit@gmail.com \
    --cc=emacs-devel@gnu.org \
    --cc=yuri.v.khan@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).