-
Notifications
You must be signed in to change notification settings - Fork 3
/
shell-toggle.el
190 lines (163 loc) · 7.22 KB
/
shell-toggle.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
;;; shell-toggle.el --- Toggle to and from the *shell* buffer
;;; Version 1.2 - 98-11-19
;;; Copyright (C) 1997, 1998 Mikael Sjödin (mic@docs.uu.se)
;;;
;;; Author: Mikael Sjödin -- mic@docs.uu.se
;;;
;;; This file is NOT part of GNU Emacs.
;;; You may however redistribute it and/or modify it under the terms of the GNU
;;; General Public License as published by the Free Software Foundation; either
;;; version 2, or (at your option) any later version.
;;;
;;; The file is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;; ----------------------------------------------------------------------
;;; Description:
;;;
;;; Provides the command shell-toggle which toggles between the
;;; *shell* buffer and whatever buffer you are editing.
;;;
;;; This is done in an "intelligent" way. Features are:
;;; o Starts a shell if non is existing.
;;; o Minimum distortion of your window configuration.
;;; o When done in the shell-buffer you are returned to the same window
;;; configuration you had before you toggled to the shell.
;;; o If you desire, you automagically get a "cd" command in the shell to the
;;; directory where your current buffers file exists; just call
;;; shell-toggle-cd instead of shell-toggle.
;;; o You can convinently choose if you want to have the shell in another
;;; window or in the whole frame. Just invoke shell-toggle again to get the
;;; shell in the whole frame.
;;;
;;; This file has been tested under Emacs 20.2.
;;;
;;; This file can be obtained from http://www.docs.uu.se/~mic/emacs.html
;;; ----------------------------------------------------------------------
;;; Installation:
;;;
;;; o Place this file in a directory in your 'load-path.
;;; o Put the following in your .emacs file:
;;; (autoload 'shell-toggle "shell-toggle"
;;; "Toggles between the *shell* buffer and whatever buffer you are editing."
;;; t)
;;; (autoload 'shell-toggle-cd "shell-toggle"
;;; "Pops up a shell-buffer and insert a \"cd <file-dir>\" command." t)
;;; (global-set-key [M-f1] 'shell-toggle)
;;; (global-set-key [C-f1] 'shell-toggle-cd)
;;; o Restart your Emacs. To use shell-toggle just hit M-f1 or C-f1
;;;
;;; For a list of user options look in code below.
;;;
;;; ----------------------------------------------------------------------
;;; BUGS:
;;; No reported bugs as of today
;;; ----------------------------------------------------------------------
;;; Thanks to:
;;; Christian Stern <Christian.Stern@physik.uni-regensburg.de> for helpful
;;; sugestions.
;;; ======================================================================
;;; User Options:
(defvar shell-toggle-goto-eob t
"*If non-nil `shell-toggle' will move point to the end of the shell-buffer
whenever the `shell-toggle' switched to the shell-buffer.
When `shell-toggle-cd' is called the point is allways moved to the end of the
shell-buffer")
(defvar shell-toggle-automatic-cd t
"*If non-nil `shell-toggle-cd' will send the \"cd\" command to the shell.
If nil `shell-toggle-cd' will only insert the \"cd\" command in the
shell-buffer. Leaving it to the user to press RET to send the command to
the shell.")
;;; ======================================================================
;;; Commands:
(defun shell-toggle-cd ()
"Calls `shell-toggle' with a prefix argument. Se command `shell-toggle'"
(interactive)
(shell-toggle t))
(defun shell-toggle (make-cd)
"Toggles between the *shell* buffer and whatever buffer you are editing.
With a prefix ARG also insert a \"cd DIR\" command into the shell, where DIR is
the directory of the current buffer.
Call twice in a row to get a full screen window for the *shell* buffer.
When called in the *shell* buffer returns you to the buffer you were editing
before caling the first time.
Options: `shell-toggle-goto-eob'"
(interactive "P")
;; Try to descide on one of three possibilities:
;; If not in shell-buffer, switch to it.
;; If in shell-buffer and called twice in a row, delete other windows
;; If in shell-buffer and not called twice in a row, return to state before
;; going to the shell-buffer
(if (eq major-mode 'shell-mode)
(if (and (or (eq last-command 'shell-toggle)
(eq last-command 'shell-toggle-cd))
(not (eq (count-windows) 1)))
(delete-other-windows)
(shell-toggle-buffer-return-from-shell))
(shell-toggle-buffer-goto-shell make-cd)))
;;; ======================================================================
;;; Internal functions and declarations
(defvar shell-toggle-pre-shell-win-conf nil
"Contains the window configuration before the *shell* buffer was selected")
(defun shell-toggle-buffer-return-from-shell ()
"Restores the window configuration used before switching the *shell* buffer.
If no configuration has been stored, just burry the *shell* buffer."
(if (window-configuration-p shell-toggle-pre-shell-win-conf)
(progn
(set-window-configuration shell-toggle-pre-shell-win-conf)
(setq shell-toggle-pre-shell-win-conf nil)
(bury-buffer (get-buffer "*shell*")))
(bury-buffer))
)
(defun shell-toggle-buffer-goto-shell (make-cd)
"Switches other window to the *shell* buffer. If no *shell* buffer exists
start a new shell and switch to it in other window. If argument MAKE-CD is
non-nil, insert a \"cd DIR\" command into the shell, where DIR is the directory
of the current buffer.
Stores the window cofiguration before creating and/or switching window."
(setq shell-toggle-pre-shell-win-conf (current-window-configuration))
(let ((shell-buffer (get-buffer "*shell*"))
(cd-command
;; Find out which directory we are in (the method differs for
;; different buffers)
(or (and make-cd
(buffer-file-name)
(file-name-directory (buffer-file-name))
(concat "cd " (file-name-directory (buffer-file-name))))
(and make-cd
list-buffers-directory
(concat "cd " list-buffers-directory)))))
;; Switch to an existin shell if one exists, otherwise switch to another
;; window and start a new shell
(if shell-buffer
(switch-to-buffer-other-window shell-buffer)
(shell-toggle-buffer-switch-to-other-window)
;; Sometimes an error is generated when I call `shell'
;; (it has to do with my shell-mode-hook which inserts text into the
;; newly created shell-buffer and thats not allways a good idea).
(condition-case the-error
(shell)
(error (switch-to-buffer "*shell*"))))
(if (or cd-command shell-toggle-goto-eob)
(goto-char (point-max)))
(if cd-command
(progn
(insert cd-command)
(if shell-toggle-automatic-cd
(comint-send-input))
))))
(defun shell-toggle-buffer-switch-to-other-window ()
"Switches to other window. If the current window is the only window in the
current frame, create a new window and switch to it.
\(This is less intrusive to the current window configuration then
`switch-buffer-other-window')"
(let ((this-window (selected-window)))
(other-window 1)
;; If we did not switch window then we only have one window and need to
;; create a new one.
(if (eq this-window (selected-window))
(progn
(split-window-vertically)
(other-window 1)))))
(provide 'shell-toggle)