[[ru:1]]
It is sometimes annoying to use multiple shells from within emacs. One must create a shell, rename it, create another, etc.

== Native Eshell ==

Eshell itself can open a specific new buffer when invoked as (eshell 'N) where N is a positive integer. When invoked as (eshell 'Z) where Z is not a positive integer, it will open the next sequential free shell number. If you would like to provide a function to perform this, you may use something similar to the following:

<pre>
(defun eshell-new()
  "Open a new instance of eshell."
  (interactive)
  (eshell 'N))
</pre>

== Shell-switcher ==

[https://github.com/DamienCassou/shell-switcher shell-switcher] is an emacs minor mode to easily switch between shell buffers (like with alt+tab). It works with eshell and any other shell.

Check the [http://www.youtube.com/watch?v=jNSrrQwcCr4 screencast]!


== Multi-eshell ==

[https://github.com/stucchio/newemacsconfig/blob/master/lisp/multi-eshell.el multi-eshell.el] exists. It maintains a ring of shell buffers, and has 3 useful functions:

multi-eshell -- Creates a NEW shell and switches to it, even if one already exists.

multi-eshell-switch -- If not in a shell buffer, return to the last EXISTING
                       shell buffer. Otherwise, switch to the next buffer in
                       the shell ring.

multi-eshell-go-back -- Switch to the previous buffer in the shell ring.

Q: What advantages does this provide over using M-x eshell-new along with various buffer switching techniques?

A: Convenience, nothing more. One-button cycling through eshell buffers can be faster than C-x b *eshell*<2> (especially if you don't remember which *eshell*<?> you want to switch to). Also, is eshell-new part of emacs? It doesn't appear to be in 22.1.50 (of Carbon emacs).

[new:Anonymous:2012-04-13 12:09 UTC]
multi-eshell-function calls multi-eshell-shell-function that may change default-directory (the shell command does that). Thus, when wanting to start a new shell with multi-eshell-shell-function=shell, the new shell will be started in the same directory than the previous shell while it would make more sense to launch it in the default-directory where the multi-eshell was launched. This should fix this issues :

{{{
--- b/multi-eshell.el
+++ a/multi-eshell.el
@@ -45,7 +45,16 @@
   :type 'string
   :group 'multi-eshell)

-(defun multi-eshell-function () "This function opens the appropriate shell." (eval multi-eshell-shell-function) )
+(defun multi-eshell-function ()
+  "This function opens the appropriate shell and restores the default-directory
+after"
+  (let(
+	   (cur_dir default-directory)
+	   )
+   (eval multi-eshell-shell-function)
+   (setq default-directory cur_dir)
+   )
+)
 ;;;(defvar multi-eshell-function `(shell) ) ;;; Defines the shell. ('shell) or ('eshell)
 ;(defvar multi-eshell-name "*eshell*") ;;; Name of default shell or eshell buffer
}}}

== Multi-Sh ==
This one is fairly minimal, but I didn't like how multi-eshell and shell-switcher work.  Unlike multi-eshell and shell-switcher, it allows multiplexing different types of shells at the same time (so for instance you can use terms and eshells at the same time and switch between them).  The main functions are multi-sh-new, multi-sh-next, multi-sh-previous and multi-sh-switch-to-buffer.  Previous and next functions order the shells by when they were last visited.

{{{
;;;; Implements a shell multiplexer for emacs shell and terminal modes
;;;; Author: Qudit314159
;;;; http://www.emacswiki.org/cgi-bin/emacs#toc4

(require 'cl)
(require 'dash)

(defvar multi-sh-buffers nil
  "The buffers tracked by multi-sh listed in order of how recently they were visited.")

(defun multi-sh-filter-buffers ()
  (setq multi-sh-buffers (filter 'buffer-live-p multi-sh-buffers)))

(defun multi-sh-new (new-shell-function)
  "Create a new multi-sh buffer by calling new-shell-function."
  (multi-sh-filter-buffers)
  (funcall new-shell-function)
  (when current-prefix-arg
    (rename-buffer (read-from-minibuffer "Buffer name: ")))
  (setq multi-sh-buffers (cons (current-buffer) multi-sh-buffers)))

(defun multi-sh-p (buf)
  "Determine if the buffer is being tracked."
  (member buf multi-sh-buffers))

(defun multi-sh-switch (offset dir)
  (multi-sh-filter-buffers)
  (if (null offset)
      (setq offset (cl-ecase dir
                    (next 1)
                    (previous -1))))
  (if multi-sh-buffers
      (let* ((n (length multi-sh-buffers))
             (buf (nth (mod offset n) multi-sh-buffers))
             (multi-sh-buffers-orig (cl-copy-list multi-sh-buffers)) ; Some code in this function (such as with-selected-window which calls select-window (triggering our advice)) so we save this first.
             multi-sh-wins
             multi-sh-win)
        ;; If a multi-sh buffer is in a visible window, select it first instead of using the current window.
        (dolist (win (window-list))
          (with-selected-window win
            (when (multi-sh-p (current-buffer))
              (push win multi-sh-wins))
            (when (equal (current-buffer) (car multi-sh-buffers-orig))
              (setq multi-sh-win win))))
        (unless multi-sh-win
          (setq multi-sh-win (car multi-sh-wins)))
        (if (not (multi-sh-p (current-buffer)))
            (progn
              (when multi-sh-win
                (select-window multi-sh-win))
              (switch-to-buffer (car multi-sh-buffers-orig)))
          (switch-to-buffer buf))
        (setq multi-sh-buffers (-rotate (- (cl-position (current-buffer) multi-sh-buffers-orig))
                                        multi-sh-buffers-orig)))
    (message "Nothing to switch to...")))

(defun multi-sh-next (&optional offset)
  "Go to the next multi-sh buffer if in a multi-sh buffer or the
last multi-sh buffer otherwise.  If OFFSET is `non-nil', will
goto the next term buffer with OFFSET."
  (interactive "P")
  (multi-sh-switch offset 'next))

(defun multi-sh-previous (&optional offset)
  "Go to the previous multi-sh buffer if in a multi-sh buffer or the
last multi-sh buffer otherwise.  If OFFSET is `non-nil', will
goto the previous term buffer with OFFSET."
  (interactive "P")
  (multi-sh-switch offset 'previous))

(defun multi-sh-switch-to-buffer ()
  "Switch to a tracked buffer."
  (interactive)
  (multi-sh-filter-buffers)
  (let* ((buffer-names (mapcar 'buffer-name multi-sh-buffers))
         (buffer (completing-read "pattern: " buffer-names)))
    (switch-to-buffer buffer)))

(dolist (fun '(switch-to-buffer select-window select-frame))
  (eval `(defadvice ,fun (after set-last-multi-sh-buffer activate)
           "If the buffer switched to is being tracked, remember that it was the last multi-sh buffer."
           (when (multi-sh-p (current-buffer))
             (setq multi-sh-buffers (cons (current-buffer)
                                          (remove (current-buffer) multi-sh-buffers)))))))

(provide 'multi-sh)
}}}


== Helm eshell switch buffer ==
This method leverages Helm, to either switch or create new eshell buffers. It can be customized to switch to any desired buffered major-mode, or to name the new buffers to one's pleasure.

{{{
;;;
;;; Helm EShell switch buffer
;;; 

(defcustom helm-eshell-switch-buffer-actions
  '(("Switch to buffer" .
     (lambda (candidate)
       (if (get-buffer candidate)
	   (switch-to-buffer candidate)
	 (let ((new-eshell-buffer
		(get-buffer-create (concat "*eshell " candidate "*"))))
	   (cl-assert (and new-eshell-buffer (buffer-live-p new-eshell-buffer)))
	   (pop-to-buffer-same-window new-eshell-buffer)
	   (unless (derived-mode-p 'eshell-mode)
	     (eshell-mode))))))
    ("Kill buffer" . (lambda (candidate)
		       (kill-buffer candidate))))
  "Actions for switching eshell buffers"
  :type '(alist :key-type string :value-type function))

(defvar helm-eshell-switch-buffer-source
  (helm-build-in-buffer-source "*eshell buffers*"
    :candidates (lambda ()
		  (with-temp-buffer
		    (let* ((all-buffers (buffer-list))
			   (eshell-buffers
			    (seq-filter
			     (lambda (checked-buffer)
			       (with-current-buffer checked-buffer
				 (string-equal major-mode "eshell-mode")))
			     all-buffers))
			   (eshell-buffer-names (mapcar 'buffer-name eshell-buffers))
			   (all-buffers (cons helm-input eshell-buffer-names)))
		      (mapcar* #'cons all-buffers all-buffers))))
    :action 'helm-eshell-switch-buffer-actions
    :fuzzy-match t))

(defun helm-eshell-switch-buffer ()
  "Switches to an existing or non-existing eshell buffer."
  (interactive)
  (helm-other-buffer 'helm-eshell-switch-buffer-source "*helm eshell buffers*"))

}}}

----
CategoryEshell
