summaryrefslogtreecommitdiffhomepage
path: root/misc/esh-toggle.el
blob: 9b47f89fae2448ae39f9b626a9aa8f154946f085 (plain)
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
;;; esh-toggle --- toggle to and from the *eshell* buffer

;; Copyright (C) 1997, 1998, 2000, 2001 Mikael Sjdin (mic@docs.uu.se)

;; Author: Mikael Sjdin <mic@docs.uu.se>
;;         John Wiegley <johnw@gnu.org>
;; Created: 19 Nov 1998
;; Version: 2.0
;; Keywords: processes
;; X-URL: http://www.gci-net.com/users/j/johnw/eshell.html

;; This program is free software; you can 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.

;; This program 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.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Commentary:

;; Provides the command eshell-toggle which toggles between the
;; *eshell* buffer and whatever buffer you are editing.
;;
;; This is done in an "intelligent" way.  Features are:
;;
;;  - Starts a eshell if non is existing.
;;
;;  - Minimum distortion of your window configuration.
;;
;;  - When done in the eshell-buffer you are returned to the same
;;    window configuration you had before you toggled to the eshell.
;;
;;  - If you desire, you automagically get a "cd" command in the
;;    eshell to the directory where your current buffers file exists;
;;    just call eshell-toggle-cd instead of eshell-toggle.
;;
;;  - You can convinently choose if you want to have the eshell in
;;    another window or in the whole frame.  Just invoke eshell-toggle
;;    again to get the eshell in the whole frame.
;;
;; This file has been tested under Emacs 20.2.
;;
;; To use, call the functions `eshell-toggle' or `eshell-toggle-cd'.
;; It's most helpful to bind these to a key.

;;; Thanks to:

;; Christian Stern <Christian.Stern@physik.uni-regensburg.de> for
;; helpful sugestions.

;;; User Variables:

(defvar eshell-toggle-goto-eob t
  "*If non-nil `eshell-toggle' moves point to end of Eshell buffer.
When `eshell-toggle-cd' is called the point is always moved to the
end of the eshell-buffer")

(defvar eshell-toggle-automatic-cd t
  "*If non-nil `eshell-toggle-cd' will send a \"cd\" to Eshell.
If nil `eshell-toggle-cd' will only insert the \"cd\" command in the
eshell-buffer.  Leaving it to the user to press RET to send the
command to the eshell.")

;;; User Functions:

;;;###autoload
(defun eshell-toggle-cd ()
  "Calls `eshell-toggle' with a prefix argument.
See the command `eshell-toggle'"
  (interactive)
  (eshell-toggle t))

;;;###autoload
(defun eshell-toggle (make-cd)
  "Toggles between the *eshell* buffer and the current buffer.
With a prefix ARG also insert a \"cd DIR\" command into the eshell,
where DIR is the directory of the current buffer.

Call twice in a row to get a full screen window for the *eshell*
buffer.

When called in the *eshell* buffer returns you to the buffer you were
editing before caling the first time.

Options: `eshell-toggle-goto-eob'"
  (interactive "P")
  ;; Try to descide on one of three possibilities:
  ;; 1. If not in eshell-buffer, switch to it.
  ;; 2. If in eshell-buffer and called twice in a row, delete other
  ;;    windows
  ;; 3. If in eshell-buffer and not called twice in a row, return to
  ;;    state before going to the eshell-buffer
  (if (eq major-mode 'eshell-mode)
      (if (and (or (eq last-command 'eshell-toggle)
		   (eq last-command 'eshell-toggle-cd))
	       (not (eq (count-windows) 1)))
	  (delete-other-windows)
	(eshell-toggle-buffer-return-from-eshell))
    (eshell-toggle-buffer-goto-eshell make-cd)))

;;; Internal Functions:

(defvar eshell-toggle-pre-eshell-win-conf nil
  "Contains window config before the *eshell* buffer was selected")

(defun eshell-toggle-buffer-return-from-eshell ()
  "Restores window config used before switching the *eshell* buffer.
If no configuration has been stored, just bury the *eshell* buffer."
  (if (window-configuration-p eshell-toggle-pre-eshell-win-conf)
      (progn
	(set-window-configuration eshell-toggle-pre-eshell-win-conf)
	(setq eshell-toggle-pre-eshell-win-conf nil)
	(bury-buffer (get-buffer "*eshell*")))
    (bury-buffer)))

(defun eshell-toggle-buffer-goto-eshell (make-cd)
  "Switches other window to the *eshell* buffer.
If no *eshell* buffer exists start a new eshell and switch to it in
other window.  If argument MAKE-CD is non-nil, insert a \"cd DIR\"
command into the eshell, where DIR is the directory of the current
buffer.
Stores the window cofiguration before creating and/or switching window."
  (setq eshell-toggle-pre-eshell-win-conf (current-window-configuration))
  (let ((eshell-buffer (get-buffer "*eshell*"))
	(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))
             (and make-cd
                  default-directory
                  (concat "cd " default-directory)))))
    ;; Switch to an existin eshell if one exists, otherwise switch to
    ;; another window and start a new eshell
    (if eshell-buffer
	(switch-to-buffer-other-window eshell-buffer)
      (eshell-toggle-buffer-switch-to-other-window)
      ;; Sometimes an error is generated when I call `eshell' (it has
      ;; to do with my eshell-mode-hook which inserts text into the
      ;; newly created eshell-buffer and thats not allways a good
      ;; idea).
      (condition-case the-error
	  (eshell)
	(error (switch-to-buffer "*eshell*"))))
    (if (or cd-command eshell-toggle-goto-eob)
	(goto-char (point-max)))
    (if cd-command
	(progn
	  (insert cd-command)
	  (if eshell-toggle-automatic-cd
	      (eshell-send-input))))))

(defun eshell-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 'esh-toggle)

;;; esh-toggle.el ends here