From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Tino Calancha Newsgroups: gmane.emacs.devel Subject: Re: New opt to allow not erase out buffer between shell cmds Date: Thu, 28 Jul 2016 21:53:57 +0900 (JST) Message-ID: References: <57865044.2020807@gmail.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; BOUNDARY="8323329-1418571608-1469710440=:24483" X-Trace: ger.gmane.org 1469710560 8564 80.91.229.3 (28 Jul 2016 12:56:00 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 28 Jul 2016 12:56:00 +0000 (UTC) Cc: Emacs developers , =?ISO-8859-15?Q?Cl=E9ment_Pit--Claudel?= , Tino Calancha To: Yuri Khan Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Jul 28 14:55:53 2016 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1bSkqu-0000zC-OI for ged-emacs-devel@m.gmane.org; Thu, 28 Jul 2016 14:55:53 +0200 Original-Received: from localhost ([::1]:53124 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bSkqo-0004RO-Rd for ged-emacs-devel@m.gmane.org; Thu, 28 Jul 2016 08:55:46 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:43288) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bSkpE-0003gu-MB for emacs-devel@gnu.org; Thu, 28 Jul 2016 08:54:10 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bSkp8-0008JH-7Z for emacs-devel@gnu.org; Thu, 28 Jul 2016 08:54:08 -0400 Original-Received: from mail-pa0-x234.google.com ([2607:f8b0:400e:c03::234]:32998) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bSkp7-0008J6-SQ for emacs-devel@gnu.org; Thu, 28 Jul 2016 08:54:02 -0400 Original-Received: by mail-pa0-x234.google.com with SMTP id ks6so21029826pab.0 for ; Thu, 28 Jul 2016 05:54:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:date:to:cc:subject:in-reply-to:message-id:references :user-agent:mime-version; bh=65nZ2D8c2oaJpC0CgVxKUu7qu1GM2+kElyjkLq2KwN0=; b=vfdWu5l3Ni8vX9EQH+h6G1iqz/78i1Q2GAKeBNzeL1SYL0qfF6Q8rXs6+POcJycoiZ p60eQp0RATZ0/FKVantsAwpfIJQYjuJupfdFfEAOJsEF+jyoRHalRPScukEdnP6ZZ9dk hfYBmvprUVBpLo4xTzGplTf1pDuBLlKUM8DqMyKtKypvdBQRr5c6YBcBb+tcYroz+dS1 WZE6jCLQEFltD/gQ7kAIX2S31Dvs1vDfrMMz6NUqRwD8yC/TK1oBKbkxdRWuxLpqffCx /cPWjZbhsdDRU/0yx1BIZVTrTYIx/2dPAjJxZhpZ0EucYJUaC012UaQpr6VGFGANLl3C nOgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version; bh=65nZ2D8c2oaJpC0CgVxKUu7qu1GM2+kElyjkLq2KwN0=; b=RqHG73+QMXcY74d/vf2Dq77WYfFTTtUIQRbcBeoBxjB7+fltPc5hYvMiMCO6ifp6qC 6YEr1bSTfIyHeZzK0I4S/Vb3wWwAs05BJGOgNEFZ4ZhLBHXV4H0G0/0UdO5ueF6XhB0o VuCUW9a7/jDJ1fXxUqyC2BFYO+W8EwRTzlFuof5iHnjl3FMFmEjfqW8nhhYAOpDR5ZLz 7/xF16+9xjxa8PjWP0j+RcaBu3/oe0u1hq4nOF5IArL+tBGn4qgJHqaVROpGtoaI1S9y kcQoZIanzQ/dy2oeeblX6WzDNlgQCfM6xJOwG0FGT/BuE/dneEb2wK49ihZcbeYGC3bg m83g== X-Gm-Message-State: AEkoouvviMIhZbw0Ps2DKIY3oSDD+aZUySO3Oe+axgtUdrhgJtF7awGF3QKznpunRvW73g== X-Received: by 10.66.154.232 with SMTP id vr8mr58716293pab.104.1469710440907; Thu, 28 Jul 2016 05:54:00 -0700 (PDT) Original-Received: from calancha-pc ([210.160.37.23]) by smtp.gmail.com with ESMTPSA id s23sm17145112pfd.23.2016.07.28.05.53.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 28 Jul 2016 05:54:00 -0700 (PDT) X-Google-Original-From: Tino Calancha X-X-Sender: calancha@calancha-pc In-Reply-To: User-Agent: Alpine 2.20 (DEB 67 2015-01-07) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2607:f8b0:400e:c03::234 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:206206 Archived-At: This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. --8323329-1418571608-1469710440=:24483 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8BIT On Wed, 13 Jul 2016, Yuri Khan wrote: > On Wed, Jul 13, 2016 at 8:48 PM, Tino Calancha 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 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 --8323329-1418571608-1469710440=:24483--