Mercurial > hg > xemacs-beta
comparison lisp/ilisp/ilisp-out.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | b82b59fe008d |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;; -*- Mode: Emacs-Lisp -*- | |
2 | |
3 ;;; ilisp-out.el -- | |
4 | |
5 ;;; This file is part of ILISP. | |
6 ;;; Version: 5.7 | |
7 ;;; | |
8 ;;; Copyright (C) 1990, 1991, 1992, 1993 Chris McConnell | |
9 ;;; 1993, 1994 Ivan Vasquez | |
10 ;;; 1994, 1995 Marco Antoniotti and Rick Busdiecker | |
11 ;;; | |
12 ;;; Other authors' names for which this Copyright notice also holds | |
13 ;;; may appear later in this file. | |
14 ;;; | |
15 ;;; Send mail to 'ilisp-request@lehman.com' to be included in the | |
16 ;;; ILISP mailing list. 'ilisp@lehman.com' is the general ILISP | |
17 ;;; mailing list were bugs and improvements are discussed. | |
18 ;;; | |
19 ;;; ILISP is freely redistributable under the terms found in the file | |
20 ;;; COPYING. | |
21 | |
22 | |
23 | |
24 ;;; | |
25 ;;; ILISP output, including a popper replacement. | |
26 ;;; | |
27 | |
28 (defvar ilisp-output-buffer " *Output*") | |
29 (defvar ilisp-output-buffer-major-mode 'lisp-mode | |
30 "*The major mode for the ilisp typeout window.") | |
31 (defvar ilisp-output-min-height 2 | |
32 "*The minimum height of the typeout window used to display ilisp output.") | |
33 (defvar ilisp-output-max-height 25 | |
34 "*The maximum height of the typeout window used to display ilisp output.") | |
35 (defvar ilisp-display-output-function 'ilisp-display-output-default | |
36 "The name of a function to display all ilisp output. The function gets a | |
37 single argument, a string.") | |
38 | |
39 | |
40 ;; Minor mode (just to get a pretty mode line). | |
41 (defvar ilisp-output-mode-line nil) | |
42 (defvar ilisp-output-mode nil "If T, then we are in the ilisp-output minor mode.") | |
43 (make-variable-buffer-local 'ilisp-output-mode) | |
44 | |
45 (or (assq 'ilisp-output-mode minor-mode-alist) | |
46 (setq minor-mode-alist | |
47 (cons '(ilisp-output-mode ilisp-output-mode-line) minor-mode-alist))) | |
48 | |
49 | |
50 (defun ilisp-output-buffer (&optional create-p) | |
51 (let ((buffer (if create-p | |
52 (get-buffer-create ilisp-output-buffer) | |
53 (get-buffer ilisp-output-buffer)))) | |
54 (or ilisp-output-mode-line | |
55 (setq ilisp-output-mode-line | |
56 (list (format | |
57 " %s bury, %s scroll" | |
58 (ilisp-where-is 'ilisp-bury-output) | |
59 (ilisp-where-is 'ilisp-scroll-output))))) | |
60 buffer)) | |
61 | |
62 (defun ilisp-output-window () | |
63 (let ((buffer (get-buffer ilisp-output-buffer))) | |
64 (if buffer | |
65 (get-buffer-window buffer)))) | |
66 | |
67 | |
68 (defun lisp-display-output (output) | |
69 "Display OUTPUT in the appropriate place. | |
70 This calls the function given by the value of ilisp-display-output-function in | |
71 order to do the real work." | |
72 (cond ((null output)) | |
73 (t | |
74 ;; Bugcheck | |
75 (if (not (stringp output)) | |
76 (error "bug: not a string in lisp-display-output")) | |
77 | |
78 (if (ilisp-value 'comint-errorp t) | |
79 (setq output (funcall (ilisp-value 'ilisp-error-filter) | |
80 output))) | |
81 (funcall ilisp-display-output-function output)))) | |
82 | |
83 | |
84 | |
85 ;;; Popper replacement | |
86 | |
87 | |
88 (defun ilisp-bury-output () | |
89 "Delete the typeout window, if any" | |
90 (interactive) | |
91 (let* ((buffer (ilisp-output-buffer)) | |
92 (window (and buffer (get-buffer-window buffer)))) | |
93 (if buffer | |
94 (bury-buffer buffer)) | |
95 (if window | |
96 (ilisp-delete-window window)))) | |
97 | |
98 | |
99 (defun ilisp-show-output (&optional buffer) | |
100 "Make typeout visible, if it is not already." | |
101 (interactive) | |
102 (let ((buffer (or buffer (ilisp-output-buffer)))) | |
103 (if buffer | |
104 (ilisp-display-buffer-in-typeout-window buffer)))) | |
105 | |
106 | |
107 (defun ilisp-delete-window (window) | |
108 "Delete a window with minimal redisplay." | |
109 (let ((height (window-height window)) | |
110 (lower-window (ilisp-find-lower-window window))) | |
111 (delete-window window) | |
112 (if (and lower-window | |
113 (not (eq lower-window window))) | |
114 (let ((old-window (selected-window))) | |
115 (save-excursion | |
116 (select-window lower-window) | |
117 (set-buffer (window-buffer)) | |
118 (goto-char (window-start)) | |
119 (vertical-motion (- height)) | |
120 (set-window-start lower-window (point))) | |
121 (select-window old-window))))) | |
122 | |
123 | |
124 (defun ilisp-scroll-output (&optional lines) | |
125 "Scroll the typeout-window, if any." | |
126 (interactive "P") | |
127 (let* ((buffer (ilisp-output-buffer)) | |
128 (window (and buffer (get-buffer-window buffer))) | |
129 (old-window (selected-window))) | |
130 (if window | |
131 (unwind-protect | |
132 (progn | |
133 (select-window window) | |
134 (set-buffer buffer) | |
135 (scroll-up lines)) | |
136 (select-window old-window))))) | |
137 | |
138 | |
139 (defun ilisp-grow-output (&optional n) | |
140 "Grow the typeout window by ARG (default 1) lines." | |
141 (interactive "p") | |
142 (let* ((buffer (ilisp-output-buffer)) | |
143 (window (and buffer (get-buffer-window buffer))) | |
144 (old-window (selected-window))) | |
145 (if window | |
146 (unwind-protect | |
147 (progn | |
148 (select-window window) | |
149 (enlarge-window n)) | |
150 (if (ilisp-window-live-p old-window) | |
151 (select-window old-window)))))) | |
152 | |
153 | |
154 (defun ilisp-trim-blank-lines () | |
155 ;; Delete leading blank lines | |
156 (goto-char (point-min)) | |
157 (if (looking-at "\n+") | |
158 (replace-match "")) | |
159 ;; Delete trailing blank lines | |
160 (goto-char (point-max)) | |
161 (skip-chars-backward "\n") | |
162 (if (< (point) (point-max)) | |
163 (delete-region (1+ (point)) (point-max)))) | |
164 | |
165 | |
166 (defun ilisp-write-string-to-buffer (buffer string) | |
167 (save-excursion | |
168 (set-buffer buffer) | |
169 ;; Maybe an option to keep the old output? | |
170 (erase-buffer) | |
171 ;; New: select mode for the output buffer. | |
172 (if (not (eq major-mode ilisp-output-buffer-major-mode)) | |
173 (funcall ilisp-output-buffer-major-mode)) | |
174 (setq ilisp-output-mode t) | |
175 (princ string buffer) | |
176 (ilisp-trim-blank-lines) | |
177 (goto-char (point-min)))) | |
178 | |
179 | |
180 (defun ilisp-desired-height (buffer-or-window) | |
181 (let ((height | |
182 (cond ((bufferp buffer-or-window) | |
183 (ilisp-needed-buffer-height buffer-or-window)) | |
184 ((windowp buffer-or-window) | |
185 (ilisp-needed-window-height buffer-or-window))))) | |
186 (max window-min-height | |
187 (min ilisp-output-max-height | |
188 (max ilisp-output-min-height | |
189 height))))) | |
190 | |
191 | |
192 ;; A first guess at the height needed to display this buffer. | |
193 (defun ilisp-needed-buffer-height (buffer) | |
194 (save-excursion | |
195 (set-buffer buffer) | |
196 (1+ (count-lines (point-min) (point-max))))) | |
197 | |
198 | |
199 ;; The height this window must be to display its entire buffer. | |
200 (defun ilisp-needed-window-height (window) | |
201 (save-window-excursion | |
202 (select-window window) | |
203 (save-excursion | |
204 (set-buffer (window-buffer)) | |
205 (+ 2 (save-excursion | |
206 (goto-char (point-min)) | |
207 ;; Any upper bound on the height of an emacs window will | |
208 ;; do here. How about 1000. | |
209 (vertical-motion 1000)))))) | |
210 | |
211 | |
212 (defun ilisp-shrink-wrap-window (window) | |
213 (let ((previously-selected-window (selected-window)) | |
214 (buffer (window-buffer window))) | |
215 | |
216 (select-window window) | |
217 (let* ((current-height (window-height window)) | |
218 (desired-height (ilisp-desired-height window)) | |
219 (delta (- desired-height current-height))) | |
220 (enlarge-window delta) | |
221 (set-buffer buffer) | |
222 (goto-char (point-min)) | |
223 | |
224 ;; Now repair damage to the window below us, if it still exists. | |
225 (let ((lower-window (ilisp-find-lower-window window))) | |
226 (if lower-window | |
227 (progn | |
228 (select-window lower-window) | |
229 (let ((old-point (point))) | |
230 (goto-char (window-start)) | |
231 (vertical-motion delta) | |
232 (set-window-start lower-window (point)) | |
233 (goto-char old-point) | |
234 (if (not (pos-visible-in-window-p old-point)) | |
235 (recenter 0)))))) | |
236 ;; If there was no lower window, then we ought to preserve | |
237 ;; the start of the window above us, if any. | |
238 | |
239 (if (ilisp-window-live-p previously-selected-window) | |
240 (select-window previously-selected-window))))) | |
241 | |
242 | |
243 | |
244 (defun ilisp-window-live-p (window) | |
245 (let* ((initial-window (selected-window)) | |
246 (win initial-window) | |
247 (found nil)) | |
248 (while win | |
249 (cond ((eq window win) | |
250 (setq found t | |
251 win nil)) | |
252 (t | |
253 (setq win (next-window win 'no)) | |
254 (if (eq win initial-window) | |
255 (setq win nil))))) | |
256 found)) | |
257 | |
258 ;; XEmacs change -- window-edges is gone in 19.12+ so use | |
259 ;; next-vertical-window instead. | |
260 (defun ilisp-find-lower-window (window) | |
261 "Find the window directly below us, if any. This is probably the | |
262 window from which enlarge-window would steal lines." | |
263 (if (< emacs-minor-version 12) | |
264 (let* ((bottom (nth 3 (window-edges window))) | |
265 (window* nil) | |
266 (win window)) | |
267 (while (not (eq (setq win (next-window win 'no)) | |
268 window)) | |
269 (if (and (= (nth 1 (window-edges win)) | |
270 bottom) | |
271 (null window*)) | |
272 (setq window* win))) | |
273 window*) | |
274 (next-vertical-window window))) | |
275 | |
276 ;; XEmacs change -- There is now a primitive to do this. | |
277 (defun ilisp-find-top-left-most-window () | |
278 "Return the leftmost topmost window on the current screen." | |
279 (if (< emacs-minor-version 12) | |
280 (let* ((window* (selected-window)) | |
281 (edges* (window-edges window*)) | |
282 (win nil) | |
283 (edges nil) | |
284 (start-window window*)) | |
285 (while (not (eq (setq win (next-window win 'no)) | |
286 start-window)) | |
287 (setq edges (window-edges win)) | |
288 (if (or (< (car (cdr edges)) (car (cdr edges*))) ; top | |
289 (and (= (car (cdr edges)) (car (cdr edges*))) | |
290 (< (car edges) (car edges*)))) ; left | |
291 (setq window* win | |
292 edges* edges))) | |
293 window*) | |
294 (frame-highest-window (selected-frame) 0))) | |
295 | |
296 | |
297 ;; This causes the typeout window to be created by splitting or using the | |
298 ;; top-left-most window on the current screen. That is different behavior | |
299 ;; from the popper, which always split the current window. | |
300 (defun ilisp-window-to-use-for-typeout () | |
301 (ilisp-find-top-left-most-window)) | |
302 | |
303 | |
304 (defun ilisp-display-buffer-in-typeout-window (buffer) | |
305 "Display buffer in a window at the top of the screen." | |
306 (let ((window (get-buffer-window buffer))) | |
307 | |
308 ;; If buffer already has a window, keep it. | |
309 (if (null window) | |
310 ;; Otherwise, find a window to split. | |
311 (let* ((top-window (ilisp-window-to-use-for-typeout)) | |
312 (new-window nil) | |
313 (previously-selected-window (selected-window)) | |
314 (desired-height (ilisp-desired-height buffer))) | |
315 | |
316 ;; The new window is always the lower one. | |
317 (select-window top-window) | |
318 | |
319 ;; Always minimize redisplay (except in emacs 18). | |
320 (let ((split-window-keep-point nil)) | |
321 ;; If the top window is not big enough to split, commandeer it | |
322 ;; entirely. | |
323 (cond ((> desired-height (- (window-height) window-min-height)) | |
324 (setq new-window top-window)) | |
325 (t | |
326 (setq new-window (split-window-vertically desired-height))))) | |
327 | |
328 (set-window-buffer top-window buffer) | |
329 ;; The height is already correct, unless there was line wrapping. | |
330 ;; Account for that here. | |
331 (ilisp-shrink-wrap-window top-window) | |
332 | |
333 ;; Restore selected window. | |
334 (if (eq previously-selected-window top-window) | |
335 (select-window new-window) | |
336 (select-window previously-selected-window))) | |
337 | |
338 ;; Simply shrink-wrap an existing window. | |
339 (ilisp-shrink-wrap-window window)))) | |
340 | |
341 | |
342 | |
343 | |
344 | |
345 | |
346 | |
347 | |
348 ;;; Various functions to which to bind ilisp-display-output-function. | |
349 | |
350 ;; This function does what ilisp used to do, except that we use the | |
351 ;; new "popper". | |
352 | |
353 (defun ilisp-display-output-default (output) | |
354 "Dispatch on the value of lisp-no-popper: | |
355 lisp-no-popper = nil: display output in a typeout window. | |
356 lisp-no-popper = t: display output in the ilisp buffer | |
357 otherwise: display one-line output in the echo area, multiline output in the ilisp buffer." | |
358 (cond ((null lisp-no-popper) | |
359 (ilisp-display-output-in-typeout-window output)) | |
360 ((eq lisp-no-popper t) | |
361 (ilisp-display-output-in-lisp-listener output)) | |
362 (t | |
363 (ilisp-display-output-adaptively output)))) | |
364 | |
365 | |
366 ;; This is the display function I like to use. | |
367 | |
368 ;; Another trick which might be useful is to dispatch on the value | |
369 ;; this-command here, to make output from different ilisp commands | |
370 ;; go to different places. | |
371 | |
372 (defun ilisp-display-output-adaptively (output) | |
373 "Display one-liners in the echo area, others in the typeout window" | |
374 (cond ((or (string-match "\n" output) | |
375 (> (length output) (window-width (minibuffer-window)))) | |
376 (message "See above.") | |
377 (ilisp-display-output-in-typeout-window output)) | |
378 (t | |
379 (ilisp-display-output-in-echo-area output)))) | |
380 | |
381 | |
382 (defun ilisp-display-output-in-typeout-window (output) | |
383 "Display output in a shrink-wrapped window at the top of the screen." | |
384 (let ((buffer (ilisp-output-buffer t))) | |
385 (ilisp-write-string-to-buffer buffer output) | |
386 (ilisp-display-buffer-in-typeout-window buffer))) | |
387 | |
388 | |
389 (defun ilisp-display-output-in-echo-area (output) | |
390 "Display output as a message in the echo area." | |
391 ;; First clear any existing typeout so as to not confuse the user. | |
392 (or (eq (selected-window) (ilisp-output-window)) | |
393 (ilisp-bury-output)) | |
394 ;; Patch suggested by hunter@work.nlm.nih.gov (Larry Hunter) | |
395 ;; If output contains '%', 'message' loses. | |
396 ;; (message (ilisp-quote-%s output)) | |
397 ;; An alternative here could be '(princ output)', as suggested by | |
398 ;; Christopher Hoover <ch@lks.csi.com> | |
399 (princ output) | |
400 ) | |
401 | |
402 | |
403 ;;; ilisp-quote-%s -- | |
404 ;;; Patch suggested by hunter@work.nlm.nih.gov (Larry Hunter) | |
405 | |
406 (defun ilisp-quote-%s (string) | |
407 "Quote all the occurences of ?% in STRING in an ELisp fashion." | |
408 (mapconcat '(lambda (char) | |
409 (if (char-equal char ?%) | |
410 "%%" | |
411 (char-to-string char))) | |
412 string "")) | |
413 | |
414 | |
415 (defun ilisp-display-output-in-temp-buffer (output) | |
416 (with-output-to-temp-buffer ilisp-output-buffer | |
417 (princ output))) | |
418 | |
419 | |
420 (defun ilisp-display-output-in-lisp-listener (output) | |
421 "Display output in the ilisp buffer" | |
422 (let ((buffer (current-buffer)) | |
423 (window (selected-window))) | |
424 (unwind-protect | |
425 (progn | |
426 (lisp-pop-to-buffer (ilisp-buffer)) | |
427 (if (not (eq (current-buffer) buffer)) | |
428 (setq ilisp-last-buffer buffer)) | |
429 (comint-insert | |
430 (concat | |
431 (if ilisp-last-message | |
432 (concat ";;; " ilisp-last-message "\n")) | |
433 (comint-remove-whitespace output) | |
434 "\n" | |
435 ilisp-last-prompt)) | |
436 (setq ilisp-last-message nil)) | |
437 (if (window-point window) | |
438 (progn (select-window window) | |
439 (set-buffer buffer)))))) | |
440 | |
441 | |
442 | |
443 ;;; Changed according to suggestions by Robert P. Goldman | |
444 (defun lisp-pop-to-buffer (buffer) | |
445 "Like pop-to-buffer, but select a screen that buffer was shown in." | |
446 (let ((ilisp-window (if ilisp-epoch-running | |
447 (epoch::get-buffer-window buffer) | |
448 (get-buffer-window buffer)))) | |
449 (if ilisp-window | |
450 (select-window ilisp-window) | |
451 ;; It is not currently displayed, so find some place to display | |
452 ;; it. | |
453 (progn | |
454 (cond (ilisp-epoch-running | |
455 ;; Select a screen that the buffer has been displayed in before | |
456 ;; or the current screen otherwise. | |
457 (epoch::select-screen | |
458 ;; allowed-screens in epoch 3.2, was called screens before that | |
459 (or (car (save-excursion | |
460 (set-buffer buffer) | |
461 (symbol-value 'allowed-screens))) | |
462 (epoch::current-screen)))) | |
463 | |
464 ;; Next clauses patterned after a suggestion by R. P. Goldman. | |
465 ((eq +ilisp-emacs-version-id+ 'fsf-19) | |
466 (let* ((window (get-buffer-window buffer t)) | |
467 (frame (if window (window-frame window)))) | |
468 (if (eq 'x (framep frame)) | |
469 (progn | |
470 (raise-frame frame) | |
471 (select-frame frame))))) | |
472 (t nil)) ; fsf-18, but also lucid and | |
473 ; xemacs. | |
474 ; I do not know how to make | |
475 ; them work | |
476 ; Marco Antoniotti, Jan 4th 1995 | |
477 (ilisp-bury-output) | |
478 (pop-to-buffer buffer)))) | |
479 (set-buffer buffer)) | |
480 | |
481 ;(defun lisp-pop-to-buffer (buffer) | |
482 ; "Like pop-to-buffer, but select a screen that buffer was shown in. | |
483 ; Also, first bury any typeout-window." | |
484 ; (let ((ilisp-window (if ilisp-epoch-running | |
485 ; (epoch::get-buffer-window buffer) | |
486 ; (get-buffer-window buffer)))) | |
487 ; (if ilisp-window | |
488 ; (select-window ilisp-window) | |
489 ; ;; It is not currently displayed, so find some place to display it. | |
490 ; (if ilisp-epoch-running | |
491 ; ;; Select a screen that the buffer has been displayed in before | |
492 ; ;; or the current screen otherwise. | |
493 ; (epoch::select-screen | |
494 ; ;; allowed-screens in epoch 3.2, was called screens before that | |
495 ; (or (car (save-excursion | |
496 ; (set-buffer buffer) | |
497 ; (symbol-value 'allowed-screens))) | |
498 ; (epoch::current-screen)))) | |
499 ; ;; Do not pop to the output buffer. | |
500 ; (ilisp-bury-output) | |
501 ; (pop-to-buffer buffer))) | |
502 ; (set-buffer buffer)) | |
503 | |
504 | |
505 ;;; | |
506 (defun switch-to-lisp (eob-p &optional ilisp-only) | |
507 "If in an ILISP buffer, switch to the buffer that last switched to | |
508 an ILISP otherwise, switch to the current ILISP buffer. With | |
509 argument, positions cursor at end of buffer. If you don't want to | |
510 split windows, set pop-up-windows to NIL." | |
511 (interactive "P") | |
512 (if (and (not ilisp-only) ilisp-last-buffer | |
513 (memq major-mode ilisp-modes)) | |
514 (lisp-pop-to-buffer ilisp-last-buffer) | |
515 (if (not (memq major-mode ilisp-modes)) | |
516 (setq ilisp-last-buffer (current-buffer))) | |
517 (lisp-pop-to-buffer (ilisp-buffer)) | |
518 (cond (eob-p (goto-char (point-max)))))) |