Subject: Re: bug#4719: 23.1; M-& to run commands asynchronously (async-shell-command)

From: Juri Linkov <[email-masked]>
Date: Tue, 17 Jul 2012 21:57:12 +0300

> Ok, let's see what's missing to do.
> I saw following topics being discussed (summary here):
> http://article.gmane.org/gmane.emacs.devel/100293
>
> - command can be in background or not: we have this
> - the output might be visible or not
> - a new buffer might be spawned for each process or not

The problem with the design and implementation of this feature is that
there is too wide range of opinions and wishes.

So I propose a minimal change that just removes the current annoyance
where async-shell-command asks to kill the buffer instead of doing
something more constructive like creating a new buffer for running
another asynchronous command.

This is implemented in the patch below.

As for displaying the output buffer or not, I think this is the
responsibility of the window configuration system to decide whether
and where to display the output buffer.

=== modified file 'lisp/simple.el'
--- lisp/simple.el	2012-07-17 18:40:15 +0000
+++ lisp/simple.el	2012-07-17 18:55:25 +0000
@@ -2244,6 +2316,24 @@ (defun read-shell-command (prompt &optio
 	   (or hist 'shell-command-history)
 	   args)))
 
+(defcustom async-shell-command-buffer 'confirm-new-buffer
+  "What to do when the output buffer is used by another shell command.
+This option specifies how to resolve the conflict where a new command
+want to direct its output to the buffer `*Async Shell Command*',
+but this buffer is already taken by another running shell command."
+  :type '(choice (const :tag "Confirm killing of running command"
+			confirm-kill-process)
+		 (const :tag "Confirm renaming of existing buffer"
+			confirm-rename-buffer)
+		 (const :tag "Confirm creation of a new buffer"
+			confirm-new-buffer)
+		 (const :tag "Rename the existing buffer"
+			rename-buffer)
+		 (const :tag "Create a new buffer"
+			new-buffer))
+  :group 'shell
+  :version "24.2")
+
 (defun async-shell-command (command &optional output-buffer error-buffer)
   "Execute string COMMAND asynchronously in background.
 
@@ -2398,12 +2488,40 @@ (defun shell-command (command &optional
 		    proc)
 		;; Remove the ampersand.
 		(setq command (substring command 0 (match-beginning 0)))
-		;; If will kill a process, query first.
+		;; Ask the user what to do with already running process.
 		(setq proc (get-buffer-process buffer))
-		(if proc
+		(when proc
+		  (cond
+		   ((eq async-shell-command-buffer 'confirm-kill-process)
+		    ;; If will kill a process, query first.
 		    (if (yes-or-no-p "A command is running.  Kill it? ")
 			(kill-process proc)
 		      (error "Shell command in progress")))
+		   ((eq async-shell-command-buffer 'confirm-rename-buffer)
+		    ;; If will create a new buffer, query first.
+		    (if (yes-or-no-p "A command is running.  Rename its output buffer before running a new command? ")
+			(progn
+			  (with-current-buffer buffer
+			    (rename-uniquely))
+			  (setq buffer (get-buffer-create
+					(or output-buffer "*Async Shell Command*"))))
+		      (error "Shell command in progress")))
+		   ((eq async-shell-command-buffer 'confirm-new-buffer)
+		    ;; If will create a new buffer, query first.
+		    (if (yes-or-no-p "A command is running in the default buffer.  Run in a new buffer? ")
+			(setq buffer (generate-new-buffer
+				      (or output-buffer "*Async Shell Command*")))
+		      (error "Shell command in progress")))
+		   ((eq async-shell-command-buffer 'rename-buffer)
+		    ;; It will create a new buffer.
+		    (with-current-buffer buffer
+		      (rename-uniquely))
+		    (setq buffer (get-buffer-create
+				  (or output-buffer "*Async Shell Command*"))))
+		   ((eq async-shell-command-buffer 'new-buffer)
+		    ;; It will create a new buffer.
+		    (setq buffer (generate-new-buffer
+				  (or output-buffer "*Async Shell Command*"))))))
 		(with-current-buffer buffer
 		  (setq buffer-read-only nil)
 		  ;; Setting buffer-read-only to nil doesn't suffice