comparison lisp/energize/energize-windows.el @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 ;;; -*- Mode:Emacs-Lisp -*-
2 ;;; Copyright © 1992 by Lucid, Inc. All Rights Reserved.
3
4 ;;; Displaying buffers. Why is this so hard?
5
6
7 ;;; This crud is damage control, because sometimes things get confused, and
8 ;;; the server asks us to display a buffer that has been killed.
9
10 (defun energize-request-kill-buffer-if-dead (buffer)
11 (cond ((not (bufferp buffer)) t)
12 ((null (buffer-name buffer))
13 (if (energize-buffer-p buffer)
14 (energize-request-kill-buffer buffer))
15 t)
16 (t nil)))
17
18 (defun energize-prune-killed-buffers-from-list (buffer-extent-list)
19 (let ((rest buffer-extent-list)
20 (buffer-count 0)
21 (deleted-count 0))
22 (while rest
23 (let* ((buffer (car rest))
24 (extent (car (cdr rest))))
25 (setq rest (cdr (cdr rest)))
26 (setq buffer-count (1+ buffer-count))
27 (if (energize-request-kill-buffer-if-dead buffer)
28 (progn
29 (setq deleted-count (1+ deleted-count))
30 (setq buffer-extent-list (delq buffer buffer-extent-list))
31 (setq buffer-extent-list (delq extent buffer-extent-list))))))
32 (if (> deleted-count 0)
33 (progn
34 (message
35 (format "Oops, confused about %s selected %s -- please try again."
36 (if (> deleted-count 1)
37 (format "%d of the" deleted-count)
38 (if (> buffer-count 1)
39 "one of the"
40 "the"))
41 (if (> buffer-count 1)
42 "buffers"
43 "buffer")))
44 (ding t)))
45 buffer-extent-list))
46
47
48 (defvar energize-auto-scroll-p t ;#### this should be nil, t is LOSING
49 "*If t, energize will scroll your debugger and error log buffers
50 to the bottom whenever output appears with reckless abandon. If nil,
51 it will behave just like normal shell and gdb-mode buffers.")
52
53 (defvar energize-error-log-context-lines 0
54 "*Number of lines to skip above the current error in the Energize error log")
55
56 ;;; called by energize-show-all-buffers
57 ;;; If the extent is specified:
58 ;;; - scrolls the window so that point is at at the beginning of the extent.
59 ;;; - If the buffer is "Error Log", the extent is moved to top-of-window.
60 ;;; - if `only-one' and the buffer is a source buffer, then... what?
61 ;;; If the buffer is "*Debugger*" or "Error Log", point is moved to eof,
62 ;;; IF and ONLY if it was at EOF already.
63 ;;;
64 (defun energize-scroll-window-at-extent (window extent only-one)
65 (let* ((buffer (window-buffer window))
66 (type (energize-buffer-type buffer)))
67 (if (and extent (null (extent-start-position extent)))
68 ;; it has been detached somehow.
69 (setq extent nil))
70 (if extent
71 (let ((pos (extent-start-position extent)))
72 (if (not (eq pos 0))
73 (progn
74 (set-window-point window pos)
75 (cond ((eq type 'energize-error-log-buffer)
76 ;; scroll the Error Log buffer so that the first error
77 ;; is at the top of the window.
78 (set-window-start window
79 (save-excursion
80 (set-buffer buffer)
81 (goto-char pos)
82 (forward-line
83 (-
84 energize-error-log-context-lines))
85 (beginning-of-line)
86 (point))))
87 ((and only-one (eq type 'energize-source-buffer))
88 ;; if only one buffer is requested to be visible and it
89 ;; is a source buffer then scroll point close to the top
90 (set-window-start window
91 (save-excursion
92 (set-buffer buffer)
93 (goto-char pos)
94 (beginning-of-line)
95 (if (> (window-height window)
96 next-screen-context-lines)
97 (vertical-motion
98 (- next-screen-context-lines)
99 window)
100 (vertical-motion -1 window))
101 (point)))))))))
102
103 (cond ((and (memq type '(energize-error-log-buffer
104 energize-debugger-buffer))
105 ; don't move point if it's before the last line
106 (or energize-auto-scroll-p
107 (>= (window-point window)
108 (save-excursion
109 (set-buffer (window-buffer window))
110 ;;(comint-mark)
111 (energize-user-input-buffer-mark)
112 )))
113 )
114 ;; Debugger and Error Log buffers generally get scrolled to
115 ;; the bottom when displayed.
116 (set-window-point window
117 (save-excursion (set-buffer buffer)
118 (+ 1 (buffer-size))))
119 ;; Careful to deactivate the selection when automatically moving
120 ;; the user to the end of the buffer. This is suboptimal, but
121 ;; otherwise we have bad interactions with the debugger-panel
122 ;; Print button. (Double-click on a value (point is now at the
123 ;; end of that word); hit Print; point is now at point-max, but
124 ;; the original word is still highlighted, which is incorrect -
125 ;; we're now in a state where the selection highlighting and the
126 ;; region between point and mark is out of sync. I'm not entirely
127 ;; sure how to fix this short of using a point-motion hook of some
128 ;; kind, so we'll punt, and just deactivate the region instead.)
129 (zmacs-deactivate-region)
130 ))))
131
132
133 ;;; called by energize-make-buffers-visible
134 ;;; For each of the contents of an plist of buffers and extents:
135 ;;; - If the buffer is visible in a window
136 ;;; - dedicate the window
137 ;;; - energize-scroll-window-at-extent
138 ;;; If we dedicated any windows, select the last one dedicated.
139 ;;; For each of the buffers and extents:
140 ;;; - pop-to-buffer
141 ;;; - remember the first window selected in this way
142 ;;; - dedicate the window
143 ;;; - energize-scroll-window-at-extent; only-one arg is true if there
144 ;;; is only one buffer/extent pair in the list
145 ;;; - if energize-edit-buffer-externally-p make it read-only
146 ;;; Un-dedicate the windows
147 ;;; Select the remembered window (the first one we popped-to-buffer on)
148 ;;; Maybe raise its frame
149 ;;;
150 (defun energize-show-all-buffers (buffer-extent-list)
151 (let ((pop-up-windows t)
152 (dedicated-windows ())
153 (buffer-extent-current)
154 (window-to-select ())
155 (only-one (null (cdr (cdr buffer-extent-list)))))
156 (setq buffer-extent-current buffer-extent-list)
157 (while buffer-extent-current
158 (let* ((buffer (car buffer-extent-current))
159 (extent (car (cdr buffer-extent-current)))
160 (window (get-buffer-window buffer (selected-frame))))
161 (if window
162 (progn
163 (set-window-buffer-dedicated window buffer)
164 (setq dedicated-windows (cons window dedicated-windows))
165 (energize-scroll-window-at-extent window extent only-one)))
166 (setq buffer-extent-current (cdr (cdr buffer-extent-current)))))
167 (if dedicated-windows
168 (select-window (car dedicated-windows)))
169 (setq buffer-extent-current buffer-extent-list)
170 (while buffer-extent-current
171 (let* ((buffer (car buffer-extent-current))
172 (extent (car (cdr buffer-extent-current))))
173 ;; ## what was this intended to do? a frame is being passed as the
174 ;; ## argument which means "always select a different window even if
175 ;; ## it's visible in the selected window.
176 ;; (pop-to-buffer buffer nil (selected-frame))
177 (pop-to-buffer buffer)
178 (if (energize-edit-buffer-externally-p buffer)
179 (setq buffer-read-only t))
180 (let ((window (selected-window)))
181 (if (null window-to-select)
182 (setq window-to-select window))
183 (set-window-buffer-dedicated window buffer)
184 (setq dedicated-windows (cons window dedicated-windows))
185 (energize-scroll-window-at-extent window extent only-one))
186 (setq buffer-extent-current (cdr (cdr buffer-extent-current)))))
187 (while dedicated-windows
188 (set-window-buffer-dedicated (car dedicated-windows) ())
189 (setq dedicated-windows (cdr dedicated-windows)))
190
191 (select-window window-to-select)
192 ;; now we may have to pop the frame up
193 (let ((frame (selected-frame)))
194 (if (and energize-auto-raise-screen
195 (or (not (frame-visible-p frame))
196 (not (frame-totally-visible-p frame))))
197 (progn
198 (sit-for 0)
199 (make-frame-visible frame))))))
200
201 ;;; called by energize-make-buffers-visible
202 (defun energize-main-buffer-of-list (list)
203 ;; Given an alternating list of buffers and extents, pick out the
204 ;; "interesting" buffer. If one of the buffers is in debugger-mode,
205 ;; or in breakpoint-mode, then that's the interesting one; otherwise,
206 ;; the last buffer in the list is the interesting one.
207 (let (buffer mode result)
208 (while list
209 (setq buffer (car list))
210 (or (memq mode '(energize-debugger-mode energize-breakpoint-mode))
211 (setq result buffer
212 mode (save-excursion (set-buffer buffer) major-mode)))
213 (setq list (cdr (cdr list))))
214 result))
215
216 ;;; called by energize-make-many-buffers-visible-function
217 ;;; If there is only one buffer/extent pair, and it's a source buffer, then
218 ;;; edit it in vi if that's the kind of kinkiness we're into.
219 ;;; Get the "main" buffer, and select a frame for it.
220 ;;; Then call energize-show-all-buffers.
221 ;;;
222 (defun energize-make-buffers-visible (buffer-extent-list)
223 (let ((main-buffer (energize-main-buffer-of-list buffer-extent-list))
224 window)
225 (if (and (null (cdr (cdr buffer-extent-list)))
226 (energize-edit-buffer-externally-p main-buffer))
227 (energize-edit-buffer-externally-1 main-buffer
228 (car (cdr buffer-extent-list)))
229 ;; This may create and/or select a frame as a side-effect.
230 ;; I'm not sure it's necessary to call this, as display-buffer
231 ;; calls it too. But it can't hurt to select the appropriate
232 ;; frame early...
233 (let ((hacked-frame nil))
234 (cond ((null energize-split-screens-p)
235 nil)
236 ((get-frame-name-for-buffer main-buffer)
237 (setq hacked-frame t)
238 (if pre-display-buffer-function
239 (funcall pre-display-buffer-function main-buffer nil nil))
240 )
241 ((setq window (get-buffer-window main-buffer t))
242 (cond (window
243 (setq hacked-frame t)
244 (select-frame (window-frame window))))))
245 (let ((pre-display-buffer-function
246 (if hacked-frame nil pre-display-buffer-function)))
247 (energize-show-all-buffers buffer-extent-list))
248 ;; ;; kludge!! Select the debugger frame, not the sources frame.
249 ;; (if (and (null energize-split-screens-p)
250 ;; pre-display-buffer-function)
251 ;; (funcall pre-display-buffer-function main-buffer nil nil))
252 ))))
253
254 ;;; this is the guts of energize-make-many-buffers-visible
255 ;;; `arg' is really two args: `buffer-extent-list' and `go-there'.
256 ;;; go-there is specified by
257 ;;; Given a list of buffer/extent pairs, make them all visible at once
258 ;;; (presumably in the same frame?)
259 ;;; If `go-there'
260 ;;; - call energize-make-buffers-visible
261 ;;; else
262 ;;; - dedicate the selected window
263 ;;; - call energize-make-buffers-visible
264 ;;; - re-select and undedicate the original selected window
265 ;;;
266 (defun energize-make-many-buffers-visible-function (arg)
267 (let ((buffer-extent-list (car arg))
268 (go-there (cdr arg)))
269 ;; enqueue an history record if we're going to move
270 (if go-there
271 (energize-history-enqueue))
272 (setq buffer-extent-list
273 (energize-prune-killed-buffers-from-list buffer-extent-list))
274 (if buffer-extent-list
275 (if go-there
276 (energize-make-buffers-visible buffer-extent-list)
277 (let ((window (selected-window)))
278 (set-window-buffer-dedicated window (window-buffer window))
279 (unwind-protect
280 (energize-make-buffers-visible buffer-extent-list)
281 (set-window-buffer-dedicated window ())
282 (select-window window)))))))
283
284 (defvar energize-make-many-buffers-visible-should-enqueue-event t
285 "Special variable bound by energize-execute-command to allow the
286 buffers to be selected while the command is executed")
287
288 ;;; called by by editorside.c:MakeBufferAndExtentVisible().
289 ;;; should-enqueue is bound by `energize-execute-command'
290 ;;;
291 (defun energize-make-many-buffers-visible (buffer-extent-list go-there)
292 "First arg is a list of buffers and extents. All those should be
293 made visible at the same time. If the second argument is T then point
294 should be moved to the first character of the extent of the first
295 buffer, or to the buffer if no extent is specified for this buffer.
296 If second argument is NIL point should not change."
297 (if energize-make-many-buffers-visible-should-enqueue-event
298 ;; don't do it from process filters, but wait until we come back to
299 ;; top-level. Using go-there should still be done sparingly, as we can
300 ;; surprise the user and grab their keystrokes into another buffer.
301 (enqueue-eval-event 'energize-make-many-buffers-visible-function
302 (cons buffer-extent-list go-there))
303 ;; go-there is always true when called from energize-execute-command,
304 ;; I guess under the assumption that it's always ok to select a buffer
305 ;; when we're doing something in direct response to a menu selection.
306 (energize-make-many-buffers-visible-function
307 (cons buffer-extent-list t))))
308
309
310 ;;; This deales with the energize history
311 (defvar energize-navigation-history '(nil)
312 "List of places where Energize took you to.
313 It is a list of (file-name/buffer-name . position)")
314
315 (defvar energize-history-maximum-length 20
316 "Maximum number of locations kept in the energize history")
317
318 (defvar energize-navigation-current ()
319 "Current pointer into the energize-navigation-history")
320
321 (defvar energize-navigation-current-length 0)
322
323 (defun energize-history-enqueue ()
324 "Memorize the current place in the history.
325 Trim the history if need be."
326 (let ((new-item
327 (cons (or buffer-file-truename (current-buffer))
328 (1+ (count-lines 1 (point))))))
329 (if (not (equal new-item (car energize-navigation-history)))
330 (progn
331 (setq energize-navigation-history
332 (cons new-item energize-navigation-history))
333 (setq energize-navigation-current-length
334 (1+ energize-navigation-current-length))
335 (if (> energize-navigation-current-length
336 (* 2 energize-history-maximum-length))
337 (let ((tail (nthcdr energize-history-maximum-length
338 energize-navigation-history)))
339 (rplacd tail nil)
340 (setq energize-navigation-current-length
341 energize-history-maximum-length)))))))
342
343 (defun energize-history-dequeue ()
344 "Forget the current place in the history"
345 (setq energize-navigation-history (cdr energize-navigation-history)))
346
347 (defun energize-history-go-back (item)
348 "Go back to the place memorized by item"
349 (let ((buffer-or-file (car item))
350 (position (cdr item))
351 (buffer ()))
352 (cond ((bufferp buffer-or-file)
353 (setq buffer buffer-or-file))
354 ((stringp buffer-or-file)
355 (setq buffer (or (get-file-buffer buffer-or-file)
356 (find-file-noselect buffer-or-file)))))
357 (if (null (buffer-name buffer))
358 ()
359 (pop-to-buffer buffer)
360 (goto-line position)
361 t)))
362
363 (defun energize-history-previous ()
364 "Go back in the history.
365 If the last command was the same go back more"
366 (interactive)
367 (if (not (eq last-command 'energize-history-previous))
368 (setq energize-navigation-current energize-navigation-history))
369 (energize-history-enqueue)
370 (while (and (car energize-navigation-current)
371 (not
372 (energize-history-go-back (car energize-navigation-current))))
373 (rplaca energize-navigation-current
374 (car (cdr energize-navigation-current)))
375 (rplacd energize-navigation-current
376 (cdr (cdr energize-navigation-current))))
377 (if (null (car energize-navigation-current))
378 (progn
379 (energize-history-dequeue)
380 (setq last-command 'beep)
381 (error "You reached the beginning of the Energize history"))
382 (setq energize-navigation-current
383 (cdr energize-navigation-current))))
384
385 (define-key global-map '(shift f14) 'energize-history-previous)
386
387 (defun energize-history ()
388 "Show the energize history in the energize history buffer"
389 (interactive)
390 (pop-to-buffer "*Energize History*")
391 (erase-buffer)
392 (mapcar (function (lambda (item)
393 (if item
394 (progn
395 (insert (format "%s" (car item)))
396 (indent-to-column 32 1)
397 (insert (format "%s\n" (cdr item)))))))
398 energize-navigation-history)
399 (goto-char (point-min))
400 (energize-history-mode))
401
402 (defun energize-history-mode ()
403 "Turn on energize history mode"
404 )