1 ;;; poptoshell.el --- get to the process buffer and input mark
3 ;; Copyright (C) 1999-2011 Free Software Foundation, Inc. and Ken Manheimer
5 ;; Author: Ken Manheimer <ken dot manheimer at gmail...>
6 ;; Maintainer: Ken Manheimer <ken dot manheimer at gmail...>
7 ;; Created: 1999 -- first public release
9 ;; Website: http://myriadicity.net/software-and-systems/craft/crafty-hacks/emacs-sundries/poptoshell.el/view
13 ;; I bind to M-<space>, via eg: (global-set-key "\M- " 'pop-to-shell)
14 ;; See the pop-to-shell docstring for details.
18 (defvar non-interactive-process-buffers '("*compilation*" "*grep*"))
25 (defcustom pop-to-shell-frame nil
26 "*If non-nil, jump to a frame already showing the shell, if any.
28 Otherwise, open a new window in the current frame."
32 (defvar pop-to-shell-primary-name "*shell*"
33 "Shell name to use for un-modified pop-to-shell buffer target.")
35 (defun pop-to-shell (&optional arg)
37 "Navigate to or within a shell buffer.
39 Use this command from within a shell subprocess buffer to get to
40 the shell input point, or from outside a shell buffer to pop to a
41 shell buffer, without displacing the current buffer.
43 Specifically, like 'shell' command but:
45 - If the current buffer is associated with a subprocess (and one not
46 among those named on `non-interactive-process-buffers'), then focus
47 is moved to the process input point, else...
48 - Goes to a window that is already showing a shell buffer, if any.
49 In this case, the cursor is left in its prior position in the shell
50 buffer. (Repeating the command will then go to the process input
51 point, by the behavior mentioned just before this.) Else...
52 - Pops open a new shell buffer, if none is around.
54 In any cases where the shell buffer already existed, the process
55 is resumed if it was stopped.
59 - With a universal argument, the user is prompted for the buffer name to
60 use (it will be bracketed by asterisks - a regrettable comint
61 requirement), defaulting to 'shell'. This makes it easy to switch
62 between multiple process-associated buffers.
63 - A double universal argument will set the default target shell buffer name
64 to the provided one, making the target shell subsequently primary."
68 (if (not (boundp 'shell-buffer-name))
69 (setq shell-buffer-name "*shell*"))
71 (let* ((from (current-buffer))
72 (doublearg (equal arg '(16)))
74 (read-shell-buffer-name-sans
75 (format "Shell buffer name [%s]%s "
76 pop-to-shell-primary-name
77 (if doublearg " <==" ":"))
78 pop-to-shell-primary-name)
79 pop-to-shell-primary-name))
80 ;; Make sure it is bracketed with asterisks; silly.
81 (target-shell-buffer-name (if (string= temp "")
82 pop-to-shell-primary-name
83 (bracket-asterisks temp)))
84 (curr-buff-proc (or (get-buffer-process from)
85 (and (fboundp 'rcirc-buffer-process)
86 (rcirc-buffer-process))
87 (and (boundp 'erc-process)
89 (buff (if (and curr-buff-proc
90 (not (member (buffer-name from)
91 non-interactive-process-buffers)))
93 (get-buffer target-shell-buffer-name)))
98 (setq pop-to-shell-primary-name target-shell-buffer-name))
99 (if (and curr-buff-proc
102 (not (eq target-shell-buffer-name (buffer-name from))))
103 ;; We're in a buffer with a shell process, but not named shell
104 ;; - stick with it, but go to end:
105 (setq already-there t)
107 ; Already in the shell buffer:
108 ((string= (buffer-name) target-shell-buffer-name)
109 (setq already-there t))
111 (not (catch 'got-a-vis
113 (function (lambda (win)
114 (if (and (eq (window-buffer win) buff)
115 (equal (frame-parameter
116 (selected-frame) 'display)
118 (window-frame win) 'display)))
119 (progn (setq inwin win)
120 (throw 'got-a-vis win))
121 (setq num (1+ num)))))
124 ;; No preexisting shell buffer, or not in a visible window:
125 (pop-to-buffer target-shell-buffer-name pop-up-windows))
126 ;; Buffer exists and already has a window - jump to it:
127 (t (if (and pop-to-shell-frame
129 (not (equal (window-frame (selected-window))
130 (window-frame inwin))))
131 (select-frame-set-input-focus (window-frame inwin)))
132 (if (not (string= (buffer-name (current-buffer))
133 target-shell-buffer-name))
134 (pop-to-buffer target-shell-buffer-name t))))
136 (if (not (comint-check-proc (current-buffer)))
137 (start-shell-in-buffer (buffer-name (current-buffer))))
139 ;; Whoops - can't get to the default directory, keep trying
140 ;; superior ones till we get somewhere that's acceptable:
141 (while (and (not (string= default-directory ""))
142 (not (condition-case err (progn (shell) t)
144 (setq default-directory
146 (substring default-directory
148 (1- (length default-directory)))))))
150 ;; If the destination buffer has a stopped process, resume it:
151 (let ((process (get-buffer-process (current-buffer))))
152 (if (and process (equal 'stop (process-status process)))
153 (continue-process process)))
154 (if (and (not already-there)
155 (not (equal (current-buffer) from)))
157 (goto-char (point-max))
158 (and (get-buffer-process from)
159 (goto-char (process-mark (get-buffer-process from)))))
162 (defun my-walk-windows (func &optional minibuf all-frames selected)
163 (if (featurep 'xemacs)
164 (walk-windows func minibuf all-frames (selected-device))
165 (walk-windows func minibuf all-frames)))
167 (defun my-set-mouse-position (window x y)
168 "Adapt for both xemacs and fsf emacs"
169 (if (string= (substring (emacs-version) 0 6) "XEmacs")
170 (set-mouse-position window x y)
171 (let ((frame (window-frame window)))
172 (select-frame-set-input-focus frame))))
175 (defun read-shell-buffer-name-sans (prompt default)
176 "Obtain name without asterisks of shell buffer, adding the asterisks.
178 Return indicated default on empty input."
183 (mapcar (lambda (buffer)
184 (let ((name (buffer-name buffer)))
185 (if (with-current-buffer buffer
186 (eq major-mode 'shell-mode))
187 (if (> (length name) 2)
188 (substring name 1 (1- (length
192 (if (not (string= got "")) (bracket-asterisks got) default)))
194 (defun bracket-asterisks (name)
195 "Return a copy of name, ensuring it has an asterisk at the beginning and end."
196 (if (not (string= (substring name 0 1) "*"))
197 (setq name (concat "*" name)))
198 (if (not (string= (substring name -1) "*"))
199 (setq name (concat name "*")))
201 (defun unbracket-asterisks (name)
202 "Return a copy of name, removing asterisks at beg and end, if any."
203 (if (string= (substring name 0 1) "*")
204 (setq name (substring name 1)))
205 (if (string= (substring name -1) "*")
206 (setq name (substring name 0 -1)))
208 (defun start-shell-in-buffer (buffer-name)
209 ;; Damn comint requires buffer name be bracketed by "*" asterisks.
213 (let* ((buffer buffer-name)
214 (prog (or explicit-shell-file-name
218 (name (file-name-nondirectory prog))
219 (startfile (concat "~/.emacs_" name))
220 (xargs-name (intern-soft (concat "explicit-" name "-args"))))
221 (setq buffer (set-buffer (apply 'make-comint
222 (unbracket-asterisks buffer-name)
224 (if (file-exists-p startfile)
228 (symbol-value xargs-name)
230 (set-buffer buffer-name)