[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#22679: 25.0.91; ibuffer-do-shell-command-pipe truncate output

From: Tino Calancha
Subject: bug#22679: 25.0.91; ibuffer-do-shell-command-pipe truncate output
Date: Wed, 24 Aug 2016 00:08:57 +0900 (JST)
User-agent: Alpine 2.20 (DEB 67 2015-01-07)

On Mon, 22 Aug 2016, Stefan Monnier wrote:
I understand.  I do not suggest to improve shell-command.
I suggest instead to extract from shell-command a new Elisp function
which includes the part of shell-command that you need, and then rewrite
shell-command by making it use the new function.

So shell-command would still work exactly as before, but its
implementation would now be spread over 2 functions, the inner one of
which would be useful to other Elisp libraries such as ibuffer.
Thank you Stefan, i understand now.  Its a good idea.
See the patch below.

Hmm... I now see this new variable.  It has several problems indeed.
The "set the point" part is weird and I'm not sure it makes much sense
to fold it this way into the same var as the "don-t erase" part.
If you could write a few lines with yor main concerns about
this option here:
i guess it might encourage others to give their opinion helping to decide
if we keep the option, discard it, or implement it in a better way.

Here, for example, I'd expect maybe something like

    (point-min) (point-max) command))

Maybe with one or two new additional args.  Or maybe

   (let ((out-buf (get-buffer-create shell-command-buffer-name)))
     (with-current-buffer out-buf (goto-char (point-max)))
     (call-shell-on-region (point-min) (point-max)
                           out-buf command)))
I have called the new function: call-shell-region
in analogy with call-process-region; but call-shell-on-region seems
a little more descriptive.
How should i call it?
Do you thing the call-shell-region discussion should move to emacs-devel list?

I think we should first aim at a simple and clean fix, yes.
Following patch, concerning just the lisp/ibuf-ext,
(the call-shell-command part eventually should go to a separated commit)
looks quite simple (compared with my first patch in this report):

From 9ba85fdf3c5543e87a7b1905b2404a334891581f Mon Sep 17 00:00:00 2001
From: Tino Calancha <address@hidden>
Date: Tue, 23 Aug 2016 23:46:37 +0900
Subject: [PATCH] call-shell-region: New defun

Fix Bug#22679
* lisp/subr.el (call-shell-region): New defun; execute a command
in an inferior shell with the buffer region as input.
* lisp/ibuf-ext.el (shell-command-pipe, shell-command-pipe-replace):
Use it (Bug#22679).
* lisp/simple.el (shell-command-on-region): Idem.
* lisp/ibuf-ext.el (shell-command-file):
Use call-process-shell-command instead of shell-command.
If FILE, the file that the buffer object is visiting,
exists and the buffer object is up-to-date, then use
FILE instead of creating a temporary file (Bug#22679).
* doc/lispref/processes.texi: Document call-shell-region in the manual.
;* etc/NEWS: Add entry for this new function.
 doc/lispref/processes.texi | 20 +++++++++++++-------
 etc/NEWS                   |  4 ++++
 lisp/ibuf-ext.el           | 33 +++++++++++++++++++--------------
 lisp/simple.el             | 36 +++++++++++++++---------------------
 lisp/subr.el               | 22 ++++++++++++++++++++++
 5 files changed, 73 insertions(+), 42 deletions(-)

diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index cd12012..e043578 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -492,20 +492,17 @@ Synchronous Processes
 @end smallexample

   For example, the @code{shell-command-on-region} command uses
address@hidden in a manner similar to this:
address@hidden in a manner similar to this:

  start end
- shell-file-name      ; @r{name of program}
+ command              ; @r{shell command}
  nil                  ; @r{do not delete region}
- buffer               ; @r{send output to @code{buffer}}
- nil                  ; @r{no redisplay during output}
- "-c" command)        ; @r{arguments for the shell}
+ buffer)              ; @r{send output to @code{buffer}}
 @end group
 @end smallexample
address@hidden It actually uses shell-command-switch, but no need to mention that here.
 @end defun

@defun call-process-shell-command command &optional infile destination display
@@ -525,6 +522,15 @@ Synchronous Processes
 supported, but strongly discouraged.
 @end defun

address@hidden call-shell-region start end command &optional delete destination
+This function sends the text from @var{start} to @var{end} as
+standard input to an inferior shell running @var{command}.  This function
+is similar than @code{call-process-region}, with process being a shell.
+The arguments @code{delete}, @code{destination} and the return value
+are like in @code{call-process-region}.
+Note that this funtion doesn't accept additional arguments.
address@hidden defun
 @defun shell-command-to-string command
 This function executes @var{command} (a string) as a shell command,
 then returns the command's output as a string.
diff --git a/etc/NEWS b/etc/NEWS
index 494a091..d30d1fa 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -56,6 +56,10 @@ affected by this, as SGI stopped supporting IRIX in December 2013.
 * Changes in Emacs 25.2

+** The new funtion 'call-shell-region' executes a command in an
+inferior shell with the buffer region as input.
 ** 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 controls where
diff --git a/lisp/ibuf-ext.el b/lisp/ibuf-ext.el
index f93957e..a34c264 100644
--- a/lisp/ibuf-ext.el
+++ b/lisp/ibuf-ext.el
@@ -352,8 +352,10 @@ shell-command-pipe
   (:interactive "sPipe to shell command: "
    :opstring "Shell command executed on"
    :modifier-p nil)
-  (shell-command-on-region
-   (point-min) (point-max) command))
+  (let ((out-buf (get-buffer-create "*Shell Command Output*")))
+    (with-current-buffer out-buf (goto-char (point-max)))
+    (call-shell-region (point-min) (point-max)
+                       command nil out-buf)))

;;;###autoload (autoload 'ibuffer-do-shell-command-pipe-replace "ibuf-ext")
 (define-ibuffer-op shell-command-pipe-replace (command)
@@ -364,8 +366,8 @@ shell-command-pipe-replace
    :dangerous t
    :modifier-p t)
   (with-current-buffer buf
-    (shell-command-on-region (point-min) (point-max)
-                            command nil t)))
+    (call-shell-region (point-min) (point-max)
+                       command 'delete buf)))

 ;;;###autoload (autoload 'ibuffer-do-shell-command-file "ibuf-ext")
 (define-ibuffer-op shell-command-file (command)
@@ -373,16 +375,19 @@ shell-command-file
   (:interactive "sShell command on buffer's file: "
    :opstring "Shell command executed on"
    :modifier-p nil)
-  (shell-command (concat command " "
-                        (shell-quote-argument
-                         (or buffer-file-name
-                             (let ((file
-                                    (make-temp-file
-                                     (substring
-                                      (buffer-name) 0
-                                      (min 10 (length (buffer-name)))))))
-                               (write-region nil nil file nil 0)
-                               file))))))
+  (let ((file (and (not (buffer-modified-p))
+                   buffer-file-name))
+        (out-buf (get-buffer-create "*Shell Command Output*")))
+    (when (or (null file) (not (file-exists-p file)))
+      (setq file
+            (make-temp-file
+             (substring
+              (buffer-name) 0
+              (min 10 (length (buffer-name))))))
+      (write-region nil nil file nil 0))
+    (with-current-buffer out-buf (goto-char (point-max)))
+    (call-process-shell-command (format "%s %s" command file)
+                                nil out-buf nil)))

 ;;;###autoload (autoload 'ibuffer-do-eval "ibuf-ext")
 (define-ibuffer-op eval (form)
diff --git a/lisp/simple.el b/lisp/simple.el
index 51b24bb..dbfaae3 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -3651,10 +3651,7 @@ shell-command-on-region
             (insert input)
-            (call-process-region (point-min) (point-max)
-                                 shell-file-name t t
-                                 nil shell-command-switch
-                                 command)
+            (call-shell-region (point-min) (point-max) command 'delete t)
             (setq output (split-string (buffer-string) "\n")))
           (goto-char start)
           (funcall region-insert-function output))
@@ -3667,11 +3664,10 @@ shell-command-on-region
             (goto-char start)
             (and replace (push-mark (point) 'nomsg))
             (setq exit-status
-                  (call-process-region start end shell-file-name replace
-                                       (if error-file
-                                           (list t error-file)
-                                         t)
-                                       nil shell-command-switch command))
+                  (call-shell-region start end command replace
+                                     (if error-file
+                                         (list t error-file)
+                                       t)))
;; It is rude to delete a buffer which the command is not using. ;; (let ((shell-buffer (get-buffer "*Shell Command Output*"))) ;; (and shell-buffer (not (eq shell-buffer (current-buffer)))
@@ -3694,13 +3690,12 @@ shell-command-on-region
                          (delete-region (max start end) (point-max))
                          (delete-region (point-min) (min start end))
                          (setq exit-status
- (call-process-region (point-min) (point-max)
-                                                    shell-file-name t
-                                                    (if error-file
- (list t error-file)
-                                                      t)
- nil shell-command-switch
-                                                    command)))
+                               (call-shell-region (point-min) (point-max)
+                                                  command 'delete
+                                                  (if error-file
+                                                      (list t error-file)
+                                                    t)
+                                                  )))
                 ;; Clear the output buffer, then run the command with
                 ;; output there.
                 (let ((directory default-directory))
@@ -3709,11 +3704,10 @@ shell-command-on-region
                         (setq default-directory directory))
                 (setq exit-status
-                      (call-process-region start end shell-file-name nil
-                                           (if error-file
-                                               (list buffer error-file)
-                                             buffer)
- nil shell-command-switch command)))
+                      (call-shell-region start end command nil
+                                         (if error-file
+                                             (list buffer error-file)
+                                           buffer))))
             ;; Report the output.
             (with-current-buffer buffer
               (setq mode-line-process
diff --git a/lisp/subr.el b/lisp/subr.el
index 8ab1178..a33f997 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3078,6 +3078,28 @@ process-file-shell-command
    infile buffer display
    (if (file-remote-p default-directory) "-c" shell-command-switch)
    (mapconcat 'identity (cons command args) " ")))
+(defun call-shell-region (start end command &optional delete buffer)
+"Send text from START to END as input to an inferior shell running COMMAND.
+Delete the text if fourth arg DELETE is non-nil.
+Insert output in BUFFER before point; t means current buffer; nil for
+ BUFFER means discard it; 0 means discard and don't wait; and `(:file
+ FILE)', where FILE is a file name string, means that it should be
+ written to that file (if the file already exists it is overwritten).
+BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case,
+REAL-BUFFER says what to do with standard output, as above,
+while STDERR-FILE says what to do with standard error in the child.
+STDERR-FILE may be nil (discard standard error output),
+t (mix it with ordinary output), or a file name string.
+If BUFFER is 0, `call-shell-region' returns immediately with value nil.
+Otherwise it waits for COMMAND to terminate
+and returns a numeric exit status or a signal description string.
+If you quit, the process is killed with SIGINT, or SIGKILL if you quit again."
+(call-process-region start end
+                     shell-file-name delete buffer nil
+                     shell-command-switch command))

 ;;;; Lisp macros to do various things temporarily.



In GNU Emacs (x86_64-pc-linux-gnu, GTK+ Version 3.20.7)
 of 2016-08-23 built on calancha-pc
Repository revision: f345fdd7e64064194a9235406971f62b9da09ae2


reply via email to

[Prev in Thread] Current Thread [Next in Thread]