[gnu.emacs] Changes to cmushell and comint to allow more than one shell buffer

worley@EDDIE.MIT.EDU (Dale Worley) (02/24/89)

The following changes allow more than one shell buffer.  The argument
to M-x cmushell gives the number of the shell.  The second, third,
etc., shells are called *cmushell<2>*, *cmushell<3>*, etc.  Shells 2
and greater will only be selected if they already exist.  Shell 1 (the
default) will be selected and created even if it doesn't exist.
Giving a negative argument to M-x cmushell will create and select a
shell with the smallest unused number.

All of this selection stuff is in the function
comint-select-process-by-number.  cmushell just calls it to get the
right buffer and process name.

These features could be easily grafted into other process interaction
commands.

Dale
worley@compass.com

---- addition to comint.el

;;; Code for running more than one shell process, etc.

(defun comint-select-process-by-number (number string)
  "Generate a pair (buffer-name . process-name) given a NUMBER and a base
STRING.
NUMBER = 1 generates (\"*STRING*\" . \"STRING\").
NUMBER > 2 generates (\"*STRING<NUMBER>*\" . \"STRING<NUMBER>\"), but reports an
error if there is no process by that name.
NUMBER < 1 finds the first number > 1 that does not have a process and returns
the appropriate pair.
One way to use this function is:
        (let* ((temp (comint-select-process-by-number n s))
               (buffer (car temp))
               (process (cdr temp)))
          (...))
Commands that use comint-select-process-by-number usually take a prefix argument
which selects the process (if positive or omitted), or to create a new process
\(if negative)."
  ;; first, compute the correct process number and check for errors
  (let ((n (cond
	    ;; a negative argument means find an unused number
	    ((< number 1)
	     (let ((new-number 2))
	       (while
		   (comint-check-proc (format "*%s<%d>*" string new-number))
		 (setq new-number (1+ new-number)))
	       new-number))
	    ;; if number > 1, check to see if it exists first
	    ((> number 1)
	     (if (not (comint-check-proc (format "*%s<%d>*" string number)))
		 (error "Process %s<%d> does not exist" string number))
	     number)
	    ;; 1 is always OK
	    (t number))))
    ;; now construct the correct pair
    (if (= n 1)
	;; process 1 doesn't have a <1>
	(cons (format "*%s*" string)
	      string)
      ;; larger process numbers have <n>
      (cons (format "*%s<%d>*" string n)
	    (format "%s<%d>" string n)))))

---- change to cmushell in cmushell.el

(defun cmushell (number)
  "Run an inferior shell, with I/O through buffer *cmushell*.
If buffer exists but shell process is not running, make new shell.
If buffer exists and shell process is running, 
 just switch to buffer *cmushell*.
Program used comes from variable explicit-shell-file-name,
 or (if that is nil) from the ESHELL environment variable,
 or else from SHELL if there is no ESHELL.
If a file ~/.emacs_SHELLNAME exists, it is given as initial input
 (Note that this may lose due to a timing error if the shell
  discards input when it starts up.)
 It is particularly useful to have this file set the environment
 variable 'PAGER' to the value 'cat'.
The buffer is put in cmushell-mode, giving commands for sending input
and controlling the subjobs of the shell.  See cmushell-mode.
See also variable shell-prompt-pattern.

The shell file name (sans directories) is used to make a symbol name
such as `explicit-csh-arguments'.  If that symbol is a variable,
its value is used as a list of arguments when invoking the shell.
Otherwise, one argument `-i' is passed to the shell.

Prefix arguments can be used to select multiple shells (prefix `-' means
to create a new one).  See  comint-select-process-by-number  for more details.

\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
  (interactive "p")
  (let* ((temp (comint-select-process-by-number number "cmushell"))
	 (buffer-name (car temp))
	 (process-name (cdr temp)))
    (cond ((not (comint-check-proc buffer-name))
	   (let* ((prog (or explicit-shell-file-name
			    (getenv "ESHELL")
			    (getenv "SHELL")
			    "/bin/sh"))		     
		  (name (file-name-nondirectory prog))
		  (startfile (concat "~/.emacs_" name))
		  (xargs-name (intern-soft (concat "explicit-" name "-args"))))
	     (set-buffer (apply 'make-comint process-name prog
				(if (file-exists-p startfile) startfile)
				(if (and xargs-name (boundp xargs-name))
				    (symbol-value xargs-name)
				  '("-i"))))
	     (cmushell-mode))))
    (switch-to-buffer buffer-name)))