]> code.delx.au - gnu-emacs-elpa/blobdiff - poptoshell.el
In TODO - distinguish searching completions and history; other details.
[gnu-emacs-elpa] / poptoshell.el
index 57ee47352f7ee564c68e2d4b6468783980b7dd58..d2b8ef12de5693205d69f65dd49c951be9b9e3ec 100644 (file)
@@ -1,4 +1,4 @@
-;;; poptoshell.el --- get to the process buffer and input mark
+;;; poptoshell.el --- easily manage interaction with multiple shells
 
 ;; Copyright (C) 1999-2011 Free Software Foundation, Inc. and Ken Manheimer
 
 ;;
 ;;; Commentary:
 ;;
-;; I bind to M-<space>, via eg: (global-set-key "\M- " 'pop-to-shell)
 ;; See the pop-to-shell docstring for details.
+;; I bind to M-<space>, via eg: (global-set-key "\M- " 'pop-to-shell)
 ;;
-;; klm, 02/09/1999.
-
-(defvar non-interactive-process-buffers '("*compilation*" "*grep*"))
+;; TODO:
+;; * Preservable (savehist) history that associates names with paths
+;;   - Using an association list between names and paths
+;;   - Searched for search backwards/forwards on isearch-like M-r/M-s bindings
+;;     - *Not* searched for regular completion
+;;   - Editible
+;;     - Using isearch keybinding M-e
+;;     - Edits path
+;;     - New association overrides previous
+;;     - Deleting path removes association and history entry
+;; * Customize provision for activating the saves
+;;   - Customize entry has warning about activating savehist
+;;   - Adds the name/path association list to savehist-additional-variables
+;;   - Activates savehist, if inactive
+;; * Customize provision for keybinding
+;;   - See allout.el allout-command-prefix for dynamic customization example.
 
 (require 'comint)
 (require 'shell)
 
-(defcustom pop-to-shell-frame nil
+(defgroup multishell nil
+  "Allout extension that highlights outline structure graphically.
+
+Customize `allout-widgets-auto-activation' to activate allout-widgets
+with allout-mode."
+  :group 'shell)
+
+(defcustom multishell:non-interactive-process-buffers
+  '("*compilation*" "*grep*")
+  "Buffers with processes but not for interaction."
+  :type '(repeat string)
+  :group 'multishell)
+(defcustom multishell:command-key "\M- "
+  "Choose a key to use for "
+  :type 'string
+  :group 'multishell)
+(defun multishell:assert-command-key-or-not (&optional force)
+  "Activate multishell command key if customizations dictate.
+
+If optional FORCE is true and customizations dictate, globally
+unbind the key.
+
+* `multishell:assert-command-key' - Establish or keep the binding if true
+* `multishell:command-key' - Which key to use."
+  (if (boundp 'multishell:assert-command-key)
+      (cond ((and multishell:assert-command-key multishell:command-key)
+             (global-set-key multishell:command-key 'pop-to-shell))
+            ((and force (not multishell:assert-command-key))
+             (global-unset-key multishell:command-key)))
+    )
+  )
+(defun multishell:do-assert-command-key (option-name option-value)
+  "If `multishell:assert-command-key', globally bind pop-to-shell.
+
+Use keybinding identified by `multishell:command-key'."
+  (multishell:assert-command-key-or-not (not option-value))
+  )
+(defcustom multishell:assert-command-key nil
+  "Set this to impose the `multishell-command-key binding."
+  :type 'boolean
+  :set 'multishell:do-assert-command-key
+  :group 'multishell)
+
+(defcustom multishell:pop-to-frame nil
   "*If non-nil, jump to a frame already showing the shell, if any.
 
 Otherwise, open a new window in the current frame."
   :type 'boolean
-  :group 'comint)
+  :group 'shell)
+
+(defcustom pop-to-shell-persist-shell-names nil
+  "Remember shell name/path associations across sessions. Note well:
+This will activate minibuffer history persistence, in general, if it's not
+already active."
+  :type 'boolean
+  :group 'shell)
+
+(defvar multishell:name-path-assoc nil
+  "Assoc list from name to path")
 
 (defvar pop-to-shell-primary-name "*shell*"
   "Shell name to use for un-modified pop-to-shell buffer target.")
+(defvar pop-to-shell-buffer-name-history nil
+  "Distinct pop-to-shell completion history container.")
 
 (defun pop-to-shell (&optional arg)
 
@@ -64,7 +132,7 @@ disconnected or otherwise stopped, it's resumed.
 ===== Universal arg to start and select between named shell buffers:
 
 You can name alternate shell buffers to create or return to using
-one or two universal arguments:
+single or doubled universal arguments:
 
  - With a single universal argument, prompt for the buffer name
    to use (without the asterisks that shell mode will put around
@@ -79,7 +147,7 @@ one or two universal arguments:
    the default to that name, so the target shell becomes the
    primary.
 
-===== Select starting directory and remote:
+===== Select starting directory and remote host:
 
 The shell buffer name you give to the prompt for a universal arg
 can include a preceding path. That will be used for the startup
@@ -90,7 +158,17 @@ For example: '/ssh:myriadicity.net:/' or
 '/ssh:myriadicity.net|sudo:root@myriadicity.net:/\#myr', etc.
 The stuff between the '/' slashes will be used for
 starting the remote shell, and the stuff after the second
-slash will be used for the shell name."
+slash will be used for the shell name.
+
+===== Persisting your alternate shell buffer names and paths:
+
+You can use emacs builtin SaveHist to preserve your alternate
+shell buffer names and paths across emacs sessions. To do so,
+customize the `savehist' group, and:
+
+1. Add `pop-to-shell-buffer-name-history' to Savehist Additional Variables.
+2. Activate Savehist Mode, if not already activated.
+3. Save."
 
   (interactive "P")
 
@@ -125,11 +203,7 @@ slash will be used for the shell name."
                             use-default-dir))
                     (match-string 2 temp))))
                 (t (bracket-asterisks temp))))
-         (curr-buff-proc (or (get-buffer-process from-buffer)
-                             (and (fboundp 'rcirc-buffer-process)
-                                  (rcirc-buffer-process))
-                             (and (boundp 'erc-process)
-                                  erc-process)))
+         (curr-buff-proc (get-buffer-process from-buffer))
          (target-buffer (if (and curr-buff-proc
                         (not (member (buffer-name from-buffer)
                                      non-interactive-process-buffers)))
@@ -162,7 +236,7 @@ slash will be used for the shell name."
       (pop-to-buffer target-shell-buffer-name pop-up-windows))
 
        ;; Buffer exists and already has a window - jump to it:
-     (t (if (and pop-to-shell-frame
+     (t (if (and multishell:pop-to-frame
                  inwin
                  (not (equal (window-frame (selected-window))
                              (window-frame inwin))))
@@ -217,20 +291,38 @@ on empty input."
   (let ((got
          (completing-read
           prompt
-          (remq nil
-                  (mapcar (lambda (buffer)
-                            (let ((name (buffer-name buffer)))
-                              (if (with-current-buffer buffer
-                                         (eq major-mode 'shell-mode))
-                                  (if (> (length name) 2)
-                                      (substring name 1 (1- (length
-                                                             name)))
-                                    name))))
-                          (buffer-list)))
+          ;; COLLECTION:
+          (pop-to-shell-buffer-name-candidates)
+          ;; PREDICATE:
           nil
-          'confirm)))
+          ;; REQUIRE-MATCH:
+          'confirm
+          ;; INITIAL-INPUT:
+          nil
+          ;; HIST:
+          'pop-to-shell-buffer-name-history
+          )))
     (if (not (string= got "")) (bracket-asterisks got) default)))
 
+(defun pop-to-shell-buffer-name-candidates ()
+  "Return a list of the shell buffer name candidates.
+
+The list consists of the combination of existing shell buffer
+names plus the names in the history (which can include
+non-existent buffers, from saved history)."
+ (append (remq nil
+               (mapcar (lambda (buffer)
+                         (let ((name (buffer-name buffer)))
+                           (if (with-current-buffer buffer
+                                 (eq major-mode 'shell-mode))
+                               (if (> (length name) 2)
+                                   (substring name 1 (1- (length
+                                                          name)))
+                                 name))))
+                       (buffer-list)))
+         pop-to-shell-buffer-name-history)
+)
+
 (defun bracket-asterisks (name)
   "Return a copy of name, ensuring it has an asterisk at the beginning and end."
   (if (not (string= (substring name 0 1) "*"))