]> code.delx.au - gnu-emacs-elpa/commitdiff
Merge commit 'f2458211bc25749f07e0d70addde7c7745dcc79d'
authorKen Manheimer <ken.manheimer@gmail.com>
Fri, 12 Feb 2016 09:17:17 +0000 (04:17 -0500)
committerKen Manheimer <ken.manheimer@gmail.com>
Fri, 12 Feb 2016 09:17:17 +0000 (04:17 -0500)
1  2 
packages/multishell/multishell-list.el
packages/multishell/multishell.el

index 69299f272ddf83721e7f7c9c1def63a096dd5652,f3895e2201f2ef9491aa3e8a982c79944a1af16d..f3895e2201f2ef9491aa3e8a982c79944a1af16d
@@@ -3,7 -3,7 +3,7 @@@
  ;; Copyright (C) 2016 Free Software Foundation, Inc. and Ken Manheimer
  
  ;; Author: Ken Manheimer <ken.manheimer@gmail.com>
- ;; Version: 1.1.3
+ ;; Version: 1.1.4
  ;; Created: 2016 -- first public availability
  ;; Keywords: processes
  ;; URL: https://github.com/kenmanheimer/EmacsMultishell
@@@ -33,7 -33,7 +33,7 @@@ pop to the buffer but don't change its 
      (if arg
          (pop-to-buffer
           (multishell-bracket (multishell-name-from-entry entry)))
-       (multishell-pop-to-shell nil entry))
+       (multishell-list-dispatch-selected entry t))
      (with-current-buffer list-buffer
        (revert-buffer)
        (multishell-list-goto-item-by-entry entry))))
@@@ -44,7 -44,7 +44,7 @@@
    (let ((list-buffer (current-buffer))
          (entry (tabulated-list-get-id)))
      (message "%s <==" (multishell-name-from-entry entry))
-     (multishell-pop-to-shell '(16) entry)
+     (multishell-list-dispatch-selected entry t t)
      (with-current-buffer list-buffer
        (revert-buffer)
        (multishell-list-goto-item-by-entry entry))))
@@@ -61,7 -61,7 +61,7 @@@ switch to the buffer but don't activat
      (if arg
          (switch-to-buffer
           (multishell-bracket (multishell-name-from-entry entry)))
-       (multishell-pop-to-shell nil entry 'here))
+       (multishell-list-dispatch-selected entry nil))
      (with-current-buffer list-buffer
        (revert-buffer))))
  
@@@ -105,7 -105,7 +105,7 @@@ starting it if it's not already going.
          (with-current-buffer buffer
            (rename-buffer (multishell-bracket revised-name)))))
      (when arg
-       (multishell-pop-to-shell nil revised-name))
+       (multishell-list-dispatch-selected revised-name t))
      (with-current-buffer list-buffer
        (revert-buffer)
        (multishell-list-goto-item-by-entry revised))))
@@@ -131,7 -131,26 +131,26 @@@ The already existing original entry is 
        (revert-buffer)
        (multishell-list-goto-item-by-entry new)
        (when arg
-         (multishell-pop-to-shell nil new-name)))))
+         (multishell-list-dispatch-selected new-name t)))))
+ (defun multishell-list-mouse-select (event)
+   "Select the shell whose line is clicked."
+   (interactive "e")
+   (select-window (posn-window (event-end event)))
+   (let ((entry (tabulated-list-get-id (posn-point (event-end event)))))
+     (multishell-list-dispatch-selected entry nil)))
+ (defun multishell-list-dispatch-selected (entry pop &optional set-primary)
+   "Go to multishell ENTRY, popping to window if POP is non-nil.
+ Optional arg SET-PRIMARY non-nil sets `multishell-primary-name' to entry.
+ Provide for concluding minibuffer interaction if we're in completing mode."
+   (let ((set-primary-as-arg (and set-primary '(16))))
+     (if multishell-completing-read
+         ;; In multishell completing-read, arrange to conclude minibuffer input:
+         (throw 'multishell-minibuffer-exit (list entry pop set-primary-as-arg))
+       (multishell-pop-to-shell set-primary-as-arg entry (not pop)))))
  
  (defun multishell-list-placeholder (value default)
    "Return VALUE if non-empty string, else DEFAULT."
                                        multishell-list-active-flag)
                                       (t multishell-list-inactive-flag)))
                         (rest (cadr splat))
-                        (dir (or (file-remote-p rest 'localname)
-                                 rest))
-                        (hops (and (file-remote-p rest 'localname)
+                        (dir (and rest (or (file-remote-p rest 'localname)
+                                           rest)))
+                        (hops (and dir
+                                   (file-remote-p rest 'localname)
                                    (substring
                                     rest 0 (- (length rest) (length dir))))))
                    (when (not name)
                'font-lock-face 'multishell-list-name
                'mouse-face 'highlight))
  
- (defun multishell-list-mouse-select (event)
-   "Select the shell whose line is clicked."
-   (interactive "e")
-   (select-window (posn-window (event-end event)))
-   (let ((entry (tabulated-list-get-id (posn-point (event-end event)))))
-     (multishell-pop-to-shell nil entry 'here)))
  (defvar multishell-list-mode-map
    (let ((map (make-sparse-keymap)))
      (set-keymap-parent map tabulated-list-mode-map)
@@@ -234,23 -247,59 +247,59 @@@ Initial sort is from most to least rece
          tabulated-list-entries #'multishell-list-entries)
    (tabulated-list-init-header))
  
+ (defun multishell-list-cull-dups (entries)
+   "Return list of multishell ENTRIES sans ones with duplicate names.
+ For duplicates, we prefer the ones that have paths."
+   (let ((tally (make-hash-table :test #'equal))
+         got name already)
+     (mapcar #'(lambda (entry)
+                 (setq name (multishell-name-from-entry entry)
+                       already (gethash name tally nil))
+                 (when (or (not already) (< (length already) (length entry)))
+                   ;; Add new or replace shorter prior entry for name:
+                   (puthash name entry tally)))
+             entries)
+     (maphash #'(lambda (key value) (push value got)) tally)
+     got))
  ;;;###autoload
- (defun multishell-list ()
+ (defun multishell-list (&optional completing)
    "Edit your current and historic list of shell buffers.
  
- Hit ? for a list of commands.
+ If optional COMPLETING is nil, we present the full
+ `multishell-history' list in a popped buffer named '*Shells*'.
+ In the buffer, hit ? or h for a list of commands.
+ When optional COMPLETING is non-nil, it must be a list of
+ multishell-history completion candidate entries, as provided by
+ `completing-read'. Then we present the list as a part of
+ minibuffer completion.
  
- You can get to this shell listing manager by
- recursively invoking \\[multishell-pop-to-shell] at either of the
- `multishell-pop-to-shell' universal argument prompts."
+ You can get to the shells listing by recursively invoking
+ \\[multishell-pop-to-shell] at the `multishell-pop-to-shell'
+ `universal-argument' prompts."
    (interactive)
    (let ((from-entry (car (multishell-history-entries
                            (multishell-unbracket (buffer-name
                                                   (current-buffer))))))
-         (buffer (get-buffer-create "*Shells*")))
-     (pop-to-buffer buffer)
+         (buffer (get-buffer-create (if completing
+                                        "*Completions*"
+                                      "*Shells*"))))
+     (if completing
+         (set-buffer buffer)
+       (pop-to-buffer buffer))
      (multishell-list-mode)
-     (tabulated-list-print)
+     (progv
+         ;; Temporarily assign multishell-history only when completing:
+         (when completing '(multishell-history))
+         (when completing
+           (list (multishell-list-cull-dups (mapcar 'substring-no-properties
+                                                    completing))))
+       (tabulated-list-print))
+     (when completing
+       )
      (when from-entry
        (multishell-list-goto-item-by-entry from-entry))))
  
index 8d19a051096c6b723e87f64fb16e912f21e7d8db,8056669c0e78578240ed8adc8ef0e5796dc230e1..8056669c0e78578240ed8adc8ef0e5796dc230e1
@@@ -1,9 -1,9 +1,9 @@@
- ;;; multishell.el --- facilitate multiple local and remote shell buffers
+ ;;; multishell.el --- Easily use multiple shell buffers, local and remote.
  
  ;; Copyright (C) 1999-2016 Free Software Foundation, Inc.
  
  ;; Author: Ken Manheimer <ken.manheimer@gmail.com>
- ;; Version: 1.1.3
+ ;; Version: 1.1.4
  ;; Created: 1999 -- first public availability
  ;; Keywords: processes
  ;; URL: https://github.com/kenmanheimer/EmacsMultishell
  ;;
  ;; Change Log:
  ;;
+ ;; * 2016-02-11 1.1.4 Ken Manheimer:
+ ;;   - hookup multishell-list as completion help buffer.
+ ;;     Mouse and keyboard selections from help listing properly exits
+ ;;     minibuffer.
  ;; * 2016-02-09 1.1.3 Ken Manheimer:
  ;;   multishell-list:
  ;;   - add some handy operations, like cloning new entry from existing
  ;;
  ;; TODO and Known Issues:
  ;;
- ;; * Add mouse actions - buttons - to multishell-list entries
- ;;   - see buf-menu.el, eg Buffer-menu-mouse-select
- ;; * Resolve multishell-list sort glitches:
- ;;   - Fix config so multishell-list-revert-buffer-kludge is not needed
- ;;   - Make multishell-list-edit-entry in-place, so changed entries recency
- ;;     doesn't change.
- ;;   - Fill in kill-buffer prompting gaps, eg if default live-process
- ;;     prompts are inhibited.
  ;; * Add custom shell launch prep actions
  ;;   - for, eg, port knocking, interface activations
  ;;   - shell commands to execute when shell name or path matches a regexp
  ;;   - list of (regexp, which - name, path, or both, command)
- ;; * Adapt multishell-list facilities for all-completions
- ;;   - See info on minibuffer-completion-help, display-completion-list
  ;; * Investigate whether we can recognize and provide for failed hops.
  ;;   - Tramp doesn't provide useful reactions for any hop but the first
  ;;   - Might be stuff we can do to detect and convey failures?
@@@ -267,6 -261,10 +261,10 @@@ one emacs session to be resumed at the 
  `savehist-additional-variables' to include the
  `multishell-primary-name'.")
  
+ (defvar multishell-completing-read nil
+   "Internal use, conveying whether or not we're in the midst of a multishell
+ completing-read.")
  ;; Multiple entries happen because completion also adds name to history.
  (defun multishell-register-name-to-path (name path)
    "Add or replace entry associating NAME with PATH in `multishell-history'.
@@@ -428,11 -426,19 +426,19 @@@ customize the savehist group to activat
  
    (let ((token '(token)))
      (if (window-minibuffer-p)
-         (throw 'multishell-do-list token)
-       (if (equal token
-                  (catch 'multishell-do-list
-                    (multishell-pop-to-shell-worker arg name here)))
-           (multishell-list)))))
+         (throw 'multishell-minibuffer-exit token)
+       (let ((got (catch 'multishell-minibuffer-exit
+                    (multishell-pop-to-shell-worker arg name here))))
+         ;; Handle catch or plain fall-through - see cond comments for protocol.
+         (cond
+          ;; Caught token from recursive invocation in minibuffer:
+          ((equal token got) (multishell-list))
+          ;; Caught specifaction of multishell args, eg from multishell-list:
+          ((listp got) (multishell-pop-to-shell-worker (nth 2 got)
+                                                       (nth 0 got)
+                                                       (nth 1 got)))
+          ;; Regular fallthrough - just relay the result:
+          (t got))))))
  
  (defun multishell-pop-to-shell-worker (&optional arg name here)
    "Do real work of `multishell-pop-to-shell', which see."
@@@ -616,7 -622,14 +622,14 @@@ Input and completion can include associ
  Return what's provided, if anything, else nil."
    (let* ((was-multishell-history multishell-history)
           (candidates (multishell-all-entries 'active-duplicated))
-          (got (completing-read prompt
+          (multishell-completing-read t)
+          (got
+           ;; Use `cl-letf' to dynamically bind multishell-list to
+           ;; display-completion-list, so multishell-list is used when doing
+           ;; minibuffer-completion-help.
+           (cl-letf (((symbol-function 'display-completion-list)
+                      #'multishell-list))
+               (completing-read prompt
                                 ;; COLLECTION:
                                 (reverse candidates)
                                 ;; PREDICATE:
                                 ;; INITIAL-INPUT
                                 initial
                                 ;; HIST:
-                                'multishell-history)))
+                                'multishell-history))))
      (when no-record
        (setq multishell-history was-multishell-history))
      (if (not (string= got ""))
@@@ -685,7 -698,11 +698,11 @@@ and path nil if none is resolved.
  
        (when (and (derived-mode-p 'shell-mode) (file-remote-p path))
          ;; Returning to disconnected remote shell - do some tidying.
-         ;; (Prevents the "Args out of range" failure when reconnecting.)
+         ;; Without this cleanup, occasionally restarting a disconnected
+         ;; remote session, particularly one that includes sudo, results in
+         ;; an untraceable "Args out of range" error. That never happens if
+         ;; we precedeed connection attempts with this cleanup -
+         ;; prophylactic.
          (tramp-cleanup-connection
           (tramp-dissect-file-name default-directory 'noexpand)
           'keep-debug 'keep-password))