;; Copyright (C) 1999-2016 Free Software Foundation, Inc. and Ken Manheimer
- ;; Author: Ken Manheimer <ken dot manheimer at gmail...>
- ;; Version: 1.0.0
- ;; Maintainer: Ken Manheimer <ken dot manheimer at gmail...>
+ ;; Author: Ken Manheimer <ken.manheimer@gmail.com>
+ ;; Version: 1.0.2
;; Created: 1999 -- first public availability
;; Keywords: processes
;; URL: https://github.com/kenmanheimer/EmacsUtils
;;
;;; TODO:
;;
+;; * Fix operation given local path without specified name
;; * Preserveable (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
+;; - During confirmation for new buffers - to use historical one
+;; - Or with minibuffer setup created key binding (isearch-like) M-e
+;; - M-e in empty initial provides completion on historicals
+;; - User can edit the entire path, changing the association
;; - New association overrides previous
;; - Deleting path removes association and history entry
+;; - Tracks buffer name changes
+;; - Using buffer-list-update-hook
;; * Customize activation of savehist
;; - Customize entry has warning about activating savehist
;; - Adds the name/path association list to savehist-additional-variables
"Shell name to use for un-modified pop-to-shell buffer target.")
(defvar multishell:buffer-name-history nil
"Distinct pop-to-shell completion history container.")
+(defvar multishell:buffer-name-path-history nil
+ "Another pop-to-shell completion history container, including paths.")
(defun pop-to-shell (&optional arg)
"Easily navigate to and within multiple shell buffers, local and remote.
(let* ((from-buffer (current-buffer))
(from-buffer-is-shell (eq major-mode 'shell-mode))
(doublearg (equal arg '(16)))
- (temp (if arg
- (multishell:read-bare-shell-buffer-name
- (format "Shell buffer name [%s]%s "
- (substring-no-properties
- multishell:primary-name
- 1 (- (length multishell:primary-name) 1))
- (if doublearg " <==" ":"))
- multishell:primary-name)
- multishell:primary-name))
- use-default-dir
- (target-shell-buffer-name
- ;; Derive target name, and default-dir if any, from temp.
- (cond ((string= temp "") multishell:primary-name)
- ((string-match "^\\*\\(/.*/\\)\\(.*\\)\\*" temp)
- (setq use-default-dir (match-string 1 temp))
- (multishell:bracket-asterisks
- (if (string= (match-string 2 temp) "")
- (let ((v (tramp-dissect-file-name
- use-default-dir)))
- (or (tramp-file-name-host v)
- (tramp-file-name-domain v)
- (tramp-file-name-localname v)
- use-default-dir))
- (match-string 2 temp))))
- (t (multishell:bracket-asterisks temp))))
+ (target-name-and-path
+ (multishell:derive-target-name-and-path
+ (if arg
+ (multishell:read-bare-shell-buffer-name
+ (format "Shell buffer name [%s]%s "
+ (substring-no-properties
+ multishell:primary-name
+ 1 (- (length multishell:primary-name) 1))
+ (if doublearg " <==" ":"))
+ multishell:primary-name)
+ multishell:primary-name)))
+ (use-default-dir (cadr target-name-and-path))
+ (target-shell-buffer-name (car target-name-and-path))
(curr-buff-proc (get-buffer-process from-buffer))
(target-buffer (if (and (or curr-buff-proc from-buffer-is-shell)
(not (member (buffer-name from-buffer)
target-shell-buffer-name))
(pop-to-buffer target-shell-buffer-name t))))
- ;; We're in the buffer.
+ ;; We're in the buffer. Activate:
- ;; Activate:
- (when (not (comint-check-proc (current-buffer)))
- (multishell:start-shell-in-buffer (buffer-name (current-buffer))))
- ;; If we have a use-default-dir, impose it:
- (when use-default-dir
- (cd use-default-dir))
+ (cond ((not (comint-check-proc (current-buffer)))
+ (multishell:start-shell-in-buffer (buffer-name (current-buffer))
+ use-default-dir))
+ (use-default-dir
+ (cd use-default-dir)))
;; If the destination buffer has a stopped process, resume it:
(let ((process (get-buffer-process (current-buffer))))
'multishell:buffer-name-history ; HIST
)))
(if (not (string= got "")) (multishell:bracket-asterisks got) default)))
+(defun multishell:derive-target-name-and-path (path-ish)
+ "Give tramp-style PATH-ISH, determine target name and default directory.
+
+The name is the part of the string after the final '/' slash, if
+any. Otherwise, it's either the host-name, domain-name, or local
+host name. The path is everything besides the string following
+the final '/' slash.
+
+Return them as a list (name dir), with dir nil if none given."
+ (let (name (path "") dir)
+ (cond ((string= path-ish "") (setq dir multishell:primary-name))
+ ((string-match "^\\*\\(/.*/\\)\\(.*\\)\\*" path-ish)
+ (setq path (match-string 1 path-ish))
+ (setq name
+ (multishell:bracket-asterisks
+ (if (string= (match-string 2 path-ish) "")
+ (let ((v (tramp-dissect-file-name
+ path)))
+ (or (tramp-file-name-host v)
+ (tramp-file-name-domain v)
+ (tramp-file-name-localname v)
+ path))
+ (match-string 2 path-ish)))))
+ (t (setq name (multishell:bracket-asterisks path-ish))))
+ (list name path)))
(defun multishell:bracket-asterisks (name)
"Return a copy of name, ensuring it has an asterisk at the beginning and end."
(if (string= (substring name -1) "*")
(setq name (substring name 0 -1)))
name)
- (defun multishell:start-shell-in-buffer (buffer-name)
+ (defun multishell:start-shell-in-buffer (buffer-name dir)
"Ensure a shell is started, using whatever name we're passed."
;; We work around shell-mode's bracketing of the buffer name, and do
;; some tramp-mode hygiene for remote connections.
(tramp-cleanup-connection
(tramp-dissect-file-name default-directory 'noexpand)
'keep-debug 'keep-password))
+ (if dir
+ (cd dir))
(setq buffer (set-buffer (apply 'make-comint
(multishell:unbracket-asterisks buffer-name)
prog