(hack-local-variables): Ignore attempts to bind enable-local-eval.
[bpt/emacs.git] / lisp / emacs-lisp / cust-print.el
CommitLineData
fd7fa35a 1;; cust-print.el -- handles print-level and print-circle.
ecb4184d 2
9750e079
ER
3;; Copyright (C) 1992 Free Software Foundation, Inc.
4
e5167999
ER
5;; Author: Daniel LaLiberte <liberte@cs.uiuc.edu>
6;; Version: 1.0
e5167999 7;; Adapted-By: ESR
fd7fa35a 8;; Keyword: extensions
ecb4184d 9
ecb4184d
ER
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
e5167999 14;; the Free Software Foundation; either version 2, or (at your option)
ecb4184d
ER
15;; any later version.
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to
24;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25
e5167999
ER
26;;; Commentary:
27
ecb4184d
ER
28;; This package provides a general print handler for prin1 and princ
29;; that supports print-level and print-circle, and by the way,
30;; print-length since the standard routines are being replaced. Also,
31;; to print custom types constructed from lists and vectors, use
32;; custom-print-list and custom-print-vector. See the documentation
33;; strings of these variables for more details.
34
35;; If the results of your expressions contain circular references to
36;; other parts of the same structure, the standard Emacs print
37;; subroutines may fail to print with an untrappable error,
38;; "Apparently circular structure being printed". If you only use cdr
39;; circular lists (where cdrs of lists point back; what is the right
40;; term here?), you can limit the length of printing with
41;; print-length. But car circular lists and circular vectors generate
42;; the above mentioned untrappable error in Emacs version 18. Version
43;; 19 will support print-level, but it is often useful to get a better
44;; print representation of circular structures; the print-circle
45;; option may be used to print more concise representations.
46
47;; There are two main ways to use this package. First, you may
48;; replace prin1, princ, and some subroutines that use them by calling
49;; install-custom-print-funcs so that any use of these functions in
50;; lisp code will be affected. Second, you could call the custom
51;; routines directly, thus only affecting the printing that requires
52;; them.
53
54;; Note that subroutines which call print subroutines directly will not
55;; use the custom print functions. In particular, the evaluation
56;; functions like eval-region call the print subroutines directly.
57;; Therefore, evaluating (aref circ-list 0), which calls error
58;; directly (because circ-list is not an array), will jump to the top
59;; level instead of printing the circular list.
60
61;; Obviously the right way to implement this custom-print facility
62;; is in C. Please volunteer since I don't have the time or need.
63
64;; Implementation design: we want to use the same list and vector
65;; processing algorithm for all versions of prin1 and princ, since how
66;; the processing is done depends on print-length, print-level, and
67;; print-circle. For circle printing, a preprocessing step is
68;; required before the final printing. Thanks to Jamie Zawinski
69;; for motivation and algorithms.
70
71;;=========================================================
72;; export list:
73
74;; print-level
75;; print-circle
76
77;; custom-print-list
78;; custom-print-vector
79;; add-custom-print-list
80;; add-custom-print-vector
81
82;; install-custom-print-funcs
83;; uninstall-custom-print-funcs
84
85;; custom-prin1
86;; custom-princ
87;; custom-prin1-to-string
88;; custom-print
89;; custom-format
90;; custom-message
91;; custom-error
92
e5167999 93;;; Code:
ecb4184d
ER
94
95(provide 'custom-print)
ecb4184d
ER
96
97;;(defvar print-length nil
98;; "*Controls how many elements of a list, at each level, are printed.
99;;This is defined by emacs.")
100
101(defvar print-level nil
102 "*Controls how many levels deep a nested data object will print.
103
104If nil, printing proceeds recursively and may lead to
105max-lisp-eval-depth being exceeded or an untrappable error may occur:
fb252f97
RS
106`Apparently circular structure being printed.'
107Also see `print-length' and `print-circle'.
ecb4184d 108
fb252f97 109If non-nil, components at levels equal to or greater than `print-level'
ecb4184d
ER
110are printed simply as \"#\". The object to be printed is at level 0,
111and if the object is a list or vector, its top-level components are at
112level 1.")
113
114
115(defvar print-circle nil
116 "*Controls the printing of recursive structures.
117
118If nil, printing proceeds recursively and may lead to
fb252f97 119`max-lisp-eval-depth' being exceeded or an untrappable error may occur:
ecb4184d 120\"Apparently circular structure being printed.\" Also see
fb252f97 121`print-length' and `print-level'.
ecb4184d
ER
122
123If non-nil, shared substructures anywhere in the structure are printed
fb252f97
RS
124with `#N=' before the first occurance (in the order of the print
125representation) and `#N#' in place of each subsequent occurance,
126where N is a positive decimal integer.
ecb4184d
ER
127
128Currently, there is no way to read this representation in Emacs.")
129
130
131(defconst custom-print-list
132 nil
133 ;; e.g. '((floatp . float-to-string))
fb252f97
RS
134 "An alist for custom printing of lists.
135Pairs are of the form (PRED . CONVERTER). If PREDICATE is true
136for an object, then CONVERTER is called with the object and should
137return a string to be printed with `princ'.
138Also see `custom-print-vector'.")
ecb4184d
ER
139
140(defconst custom-print-vector
141 nil
fb252f97
RS
142 "An alist for custom printing of vectors.
143Pairs are of the form (PRED . CONVERTER). If PREDICATE is true
144for an object, then CONVERTER is called with the object and should
145return a string to be printed with `princ'.
146Also see `custom-print-list'.")
ecb4184d
ER
147
148
149(defun add-custom-print-list (pred converter)
fb252f97 150 "Add a pair of PREDICATE and CONVERTER to `custom-print-list'.
ecb4184d
ER
151Any pair that has the same PREDICATE is first removed."
152 (setq custom-print-list (cons (cons pred converter)
153 (delq (assq pred custom-print-list)
154 custom-print-list))))
155;; e.g. (add-custom-print-list 'floatp 'float-to-string)
156
157
158(defun add-custom-print-vector (pred converter)
fb252f97 159 "Add a pair of PREDICATE and CONVERTER to `custom-print-vector'.
ecb4184d
ER
160Any pair that has the same PREDICATE is first removed."
161 (setq custom-print-vector (cons (cons pred converter)
162 (delq (assq pred custom-print-vector)
163 custom-print-vector))))
164
165
166;;====================================================
167;; Saving and restoring internal printing routines.
168
fb252f97 169(defun cust-print-set-function-cell (symbol-pair)
ecb4184d
ER
170 (fset (car symbol-pair)
171 (symbol-function (car (cdr symbol-pair)))))
172
173
fb252f97
RS
174(if (not (fboundp 'cust-print-internal-prin1))
175 (mapcar 'cust-print-set-function-cell
176 '((cust-print-internal-prin1 prin1)
177 (cust-print-internal-princ princ)
178 (cust-print-internal-print print)
179 (cust-print-internal-prin1-to-string prin1-to-string)
180 (cust-print-internal-format format)
181 (cust-print-internal-message message)
182 (cust-print-internal-error error))))
ecb4184d
ER
183
184
185(defun install-custom-print-funcs ()
fb252f97
RS
186 "Replace print functions with general, customizable, Lisp versions.
187The internal subroutines are saved away, and you can reinstall them
188by running `uninstall-custom-print-funcs'."
ecb4184d 189 (interactive)
fb252f97 190 (mapcar 'cust-print-set-function-cell
ecb4184d
ER
191 '((prin1 custom-prin1)
192 (princ custom-princ)
193 (print custom-print)
194 (prin1-to-string custom-prin1-to-string)
195 (format custom-format)
196 (message custom-message)
197 (error custom-error)
198 )))
199
200(defun uninstall-custom-print-funcs ()
201 "Reset print functions to their internal subroutines."
202 (interactive)
fb252f97
RS
203 (mapcar 'cust-print-set-function-cell
204 '((prin1 cust-print-internal-prin1)
205 (princ cust-print-internal-princ)
206 (print cust-print-internal-print)
207 (prin1-to-string cust-print-internal-prin1-to-string)
208 (format cust-print-internal-format)
209 (message cust-print-internal-message)
210 (error cust-print-internal-error)
ecb4184d
ER
211 )))
212
213
214;;===============================================================
215;; Lisp replacements for prin1 and princ and for subrs that use prin1
216;; (or princ) -- so far only the printing and formatting subrs.
217
218(defun custom-prin1 (object &optional stream)
fb252f97
RS
219 "Replacement for standard `prin1'.
220Uses the appropriate printer depending on the values of `print-level'
221and `print-circle' (which see).
ecb4184d
ER
222
223Output the printed representation of OBJECT, any Lisp object.
224Quoting characters are printed when needed to make output that `read'
225can handle, whenever this is possible.
226Output stream is STREAM, or value of `standard-output' (which see)."
fb252f97 227 (cust-print-top-level object stream 'cust-print-internal-prin1))
ecb4184d
ER
228
229
230(defun custom-princ (object &optional stream)
fb252f97
RS
231 "Same as `custom-prin1' except no quoting."
232 (cust-print-top-level object stream 'cust-print-internal-princ))
ecb4184d
ER
233
234(defun custom-prin1-to-string-func (c)
fb252f97 235 "Stream function for `custom-prin1-to-string'."
ecb4184d
ER
236 (setq prin1-chars (cons c prin1-chars)))
237
238(defun custom-prin1-to-string (object)
fb252f97 239 "Replacement for standard `prin1-to-string'."
ecb4184d
ER
240 (let ((prin1-chars nil))
241 (custom-prin1 object 'custom-prin1-to-string-func)
242 (concat (nreverse prin1-chars))))
243
244
245(defun custom-print (object &optional stream)
fb252f97
RS
246 "Replacement for standard `print'."
247 (cust-print-internal-princ "\n")
ecb4184d 248 (custom-prin1 object stream)
fb252f97 249 (cust-print-internal-princ "\n"))
ecb4184d
ER
250
251
252(defun custom-format (fmt &rest args)
fb252f97 253 "Replacement for standard `format'.
ecb4184d
ER
254
255Calls format after first making strings for list or vector args.
fb252f97 256The format specification for such args should be `%s' in any case, so a
ecb4184d 257string argument will also work. The string is generated with
fb252f97
RS
258`custom-prin1-to-string', which quotes quotable characters."
259 (apply 'cust-print-internal-format fmt
ecb4184d
ER
260 (mapcar (function (lambda (arg)
261 (if (or (listp arg) (vectorp arg))
262 (custom-prin1-to-string arg)
263 arg)))
264 args)))
265
266
267
268(defun custom-message (fmt &rest args)
fb252f97 269 "Replacement for standard `message' that works like `custom-format'."
ecb4184d
ER
270 ;; It doesnt work to princ the result of custom-format
271 ;; because the echo area requires special handling
fb252f97
RS
272 ;; to avoid duplicating the output. cust-print-internal-message does it right.
273 ;; (cust-print-internal-princ (apply 'custom-format fmt args))
274 (apply 'cust-print-internal-message fmt
ecb4184d
ER
275 (mapcar (function (lambda (arg)
276 (if (or (listp arg) (vectorp arg))
277 (custom-prin1-to-string arg)
278 arg)))
279 args)))
280
281
282(defun custom-error (fmt &rest args)
fb252f97 283 "Replacement for standard `error' that uses `custom-format'"
ecb4184d
ER
284 (signal 'error (list (apply 'custom-format fmt args))))
285
286
287;;=========================================
288;; Support for custom prin1 and princ
289
fb252f97 290(defun cust-print-top-level (object stream internal-printer)
ecb4184d
ER
291 "Set up for printing."
292 (let ((standard-output (or stream standard-output))
fb252f97 293 (circle-table (and print-circle (cust-print-preprocess-circle-tree object)))
ecb4184d
ER
294 (level (or print-level -1))
295 )
296
fb252f97
RS
297 (fset 'cust-print-internal-printer internal-printer)
298 (fset 'cust-print-low-level-prin
ecb4184d
ER
299 (cond
300 ((or custom-print-list
301 custom-print-vector
302 print-level ; comment out for version 19
303 )
fb252f97 304 'cust-print-custom-object)
ecb4184d 305 (circle-table
fb252f97
RS
306 'cust-print-object)
307 (t 'cust-print-internal-printer)))
308 (fset 'cust-print-prin (if circle-table 'cust-print-circular 'cust-print-low-level-prin))
ecb4184d 309
fb252f97 310 (cust-print-prin object)
ecb4184d
ER
311 object))
312
313
fb252f97
RS
314;; Test object type and print accordingly.
315(defun cust-print-object (object)
316 ;; Could be called as either cust-print-low-level-prin or cust-print-prin.
ecb4184d 317 (cond
fb252f97
RS
318 ((null object) (cust-print-internal-printer object))
319 ((consp object) (cust-print-list object))
320 ((vectorp object) (cust-print-vector object))
ecb4184d 321 ;; All other types, just print.
fb252f97 322 (t (cust-print-internal-printer object))))
ecb4184d
ER
323
324
fb252f97
RS
325;; Test object type and print accordingly.
326(defun cust-print-custom-object (object)
327 ;; Could be called as either cust-print-low-level-prin or cust-print-prin.
ecb4184d 328 (cond
fb252f97 329 ((null object) (cust-print-internal-printer object))
ecb4184d
ER
330
331 ((consp object)
332 (or (and custom-print-list
fb252f97
RS
333 (cust-print-custom-object1 object custom-print-list))
334 (cust-print-list object)))
ecb4184d
ER
335
336 ((vectorp object)
337 (or (and custom-print-vector
fb252f97
RS
338 (cust-print-custom-object1 object custom-print-vector))
339 (cust-print-vector object)))
ecb4184d
ER
340
341 ;; All other types, just print.
fb252f97 342 (t (cust-print-internal-printer object))))
ecb4184d
ER
343
344
fb252f97
RS
345;; Helper for cust-print-custom-object.
346;; Print the custom OBJECT using the custom type ALIST.
347;; For the first predicate that matches the object, the corresponding
348;; converter is evaluated with the object and the string that results is
349;; printed with princ. Return nil if no predicte matches the object.
350(defun cust-print-custom-object1 (object alist)
ecb4184d
ER
351 (while (and alist (not (funcall (car (car alist)) object)))
352 (setq alist (cdr alist)))
353 ;; If alist is not null, then something matched.
354 (if alist
fb252f97 355 (cust-print-internal-princ
ecb4184d
ER
356 (funcall (cdr (car alist)) object) ; returns string
357 )))
358
359
fb252f97
RS
360(defun cust-print-circular (object)
361 "Printer for `prin1' and `princ' that handles circular structures.
ecb4184d 362If OBJECT appears multiply, and has not yet been printed,
fb252f97 363prefix with label; if it has been printed, use `#N#' instead.
ecb4184d
ER
364Otherwise, print normally."
365 (let ((tag (assq object circle-table)))
366 (if tag
367 (let ((id (cdr tag)))
368 (if (> id 0)
369 (progn
370 ;; Already printed, so just print id.
fb252f97
RS
371 (cust-print-internal-princ "#")
372 (cust-print-internal-princ id)
373 (cust-print-internal-princ "#"))
ecb4184d
ER
374 ;; Not printed yet, so label with id and print object.
375 (setcdr tag (- id)) ; mark it as printed
fb252f97
RS
376 (cust-print-internal-princ "#")
377 (cust-print-internal-princ (- id))
378 (cust-print-internal-princ "=")
379 (cust-print-low-level-prin object)
ecb4184d
ER
380 ))
381 ;; Not repeated in structure.
fb252f97 382 (cust-print-low-level-prin object))))
ecb4184d
ER
383
384
385;;================================================
386;; List and vector processing for print functions.
387
fb252f97
RS
388;; Print a list using print-length, print-level, and print-circle.
389(defun cust-print-list (list)
ecb4184d 390 (if (= level 0)
fb252f97 391 (cust-print-internal-princ "#")
ecb4184d 392 (let ((level (1- level)))
fb252f97 393 (cust-print-internal-princ "(")
ecb4184d
ER
394 (let ((length (or print-length 0)))
395
396 ;; Print the first element always (even if length = 0).
fb252f97 397 (cust-print-prin (car list))
ecb4184d 398 (setq list (cdr list))
fb252f97 399 (if list (cust-print-internal-princ " "))
ecb4184d
ER
400 (setq length (1- length))
401
402 ;; Print the rest of the elements.
403 (while (and list (/= 0 length))
404 (if (and (listp list)
405 (not (assq list circle-table)))
406 (progn
fb252f97 407 (cust-print-prin (car list))
ecb4184d
ER
408 (setq list (cdr list)))
409
410 ;; cdr is not a list, or it is in circle-table.
fb252f97
RS
411 (cust-print-internal-princ ". ")
412 (cust-print-prin list)
ecb4184d
ER
413 (setq list nil))
414
415 (setq length (1- length))
fb252f97 416 (if list (cust-print-internal-princ " ")))
ecb4184d 417
fb252f97
RS
418 (if (and list (= length 0)) (cust-print-internal-princ "..."))
419 (cust-print-internal-princ ")"))))
ecb4184d
ER
420 list)
421
422
fb252f97
RS
423;; Print a vector according to print-length, print-level, and print-circle.
424(defun cust-print-vector (vector)
ecb4184d 425 (if (= level 0)
fb252f97 426 (cust-print-internal-princ "#")
ecb4184d
ER
427 (let ((level (1- level))
428 (i 0)
429 (len (length vector)))
fb252f97 430 (cust-print-internal-princ "[")
ecb4184d
ER
431
432 (if print-length
433 (setq len (min print-length len)))
434 ;; Print the elements
435 (while (< i len)
fb252f97 436 (cust-print-prin (aref vector i))
ecb4184d 437 (setq i (1+ i))
fb252f97 438 (if (< i (length vector)) (cust-print-internal-princ " ")))
ecb4184d 439
fb252f97
RS
440 (if (< i (length vector)) (cust-print-internal-princ "..."))
441 (cust-print-internal-princ "]")
ecb4184d
ER
442 ))
443 vector)
444
445
446;;==================================
447;; Circular structure preprocessing
448
fb252f97 449(defun cust-print-preprocess-circle-tree (object)
ecb4184d
ER
450 ;; Fill up the table.
451 (let (;; Table of tags for each object in an object to be printed.
452 ;; A tag is of the form:
453 ;; ( <object> <nil-t-or-id-number> )
454 ;; The id-number is generated after the entire table has been computed.
455 ;; During walk through, the real circle-table lives in the cdr so we
456 ;; can use setcdr to add new elements instead of having to setq the
457 ;; variable sometimes (poor man's locf).
458 (circle-table (list nil)))
fb252f97 459 (cust-print-walk-circle-tree object)
ecb4184d
ER
460
461 ;; Reverse table so it is in the order that the objects will be printed.
462 ;; This pass could be avoided if we always added to the end of the
463 ;; table with setcdr in walk-circle-tree.
464 (setcdr circle-table (nreverse (cdr circle-table)))
465
466 ;; Walk through the table, assigning id-numbers to those
467 ;; objects which will be printed using #N= syntax. Delete those
468 ;; objects which will be printed only once (to speed up assq later).
469 (let ((rest circle-table)
470 (id -1))
471 (while (cdr rest)
472 (let ((tag (car (cdr rest))))
473 (cond ((cdr tag)
474 (setcdr tag id)
475 (setq id (1- id))
476 (setq rest (cdr rest)))
477 ;; Else delete this object.
478 (t (setcdr rest (cdr (cdr rest))))))
479 ))
480 ;; Drop the car.
481 (cdr circle-table)
482 ))
483
484
485
fb252f97 486(defun cust-print-walk-circle-tree (object)
ecb4184d
ER
487 (let (read-equivalent-p tag)
488 (while object
489 (setq read-equivalent-p (or (numberp object) (symbolp object))
490 tag (and (not read-equivalent-p)
491 (assq object (cdr circle-table))))
492 (cond (tag
493 ;; Seen this object already, so note that.
494 (setcdr tag t))
495
496 ((not read-equivalent-p)
497 ;; Add a tag for this object.
498 (setcdr circle-table
499 (cons (list object)
500 (cdr circle-table)))))
501 (setq object
502 (cond
503 (tag ;; No need to descend since we have already.
504 nil)
505
506 ((consp object)
507 ;; Walk the car of the list recursively.
fb252f97 508 (cust-print-walk-circle-tree (car object))
ecb4184d
ER
509 ;; But walk the cdr with the above while loop
510 ;; to avoid problems with max-lisp-eval-depth.
511 ;; And it should be faster than recursion.
512 (cdr object))
513
514 ((vectorp object)
515 ;; Walk the vector.
516 (let ((i (length object))
517 (j 0))
518 (while (< j i)
fb252f97 519 (cust-print-walk-circle-tree (aref object j))
ecb4184d
ER
520 (setq j (1+ j))))))))))
521
522
523
524;;=======================================
525
526(quote
527 examples
528
529 (progn
530 ;; Create some circular structures.
531 (setq circ-sym (let ((x (make-symbol "FOO"))) (list x x)))
532 (setq circ-list (list 'a 'b (vector 1 2 3 4) 'd 'e 'f))
533 (setcar (nthcdr 3 circ-list) circ-list)
534 (aset (nth 2 circ-list) 2 circ-list)
535 (setq dotted-circ-list (list 'a 'b 'c))
536 (setcdr (cdr (cdr dotted-circ-list)) dotted-circ-list)
537 (setq circ-vector (vector 1 2 3 4 (list 'a 'b 'c 'd) 6 7))
538 (aset circ-vector 5 (make-symbol "-gensym-"))
539 (setcar (cdr (aref circ-vector 4)) (aref circ-vector 5))
540 nil)
541
542 (install-custom-print-funcs)
543 ;; (setq print-circle t)
544
545 (let ((print-circle t))
546 (or (equal (prin1-to-string circ-list) "#1=(a b [1 2 #1# 4] #1# e f)")
547 (error "circular object with array printing")))
548
549 (let ((print-circle t))
550 (or (equal (prin1-to-string dotted-circ-list) "#1=(a b c . #1#)")
551 (error "circular object with array printing")))
552
553 (let* ((print-circle t)
554 (x (list 'p 'q))
555 (y (list (list 'a 'b) x 'foo x)))
556 (setcdr (cdr (cdr (cdr y))) (cdr y))
557 (or (equal (prin1-to-string y) "((a b) . #1=(#2=(p q) foo #2# . #1#))"
558 )
559 (error "circular list example from CL manual")))
560
561 ;; There's no special handling of uninterned symbols in custom-print.
562 (let ((print-circle nil))
563 (or (equal (prin1-to-string circ-sym) "(#:FOO #:FOO)")
564 (error "uninterned symbols in list")))
565 (let ((print-circle t))
566 (or (equal (prin1-to-string circ-sym) "(#1=FOO #1#)")
567 (error "circular uninterned symbols in list")))
568
569 (uninstall-custom-print-funcs)
570 )
571
fd7fa35a 572;;; cust-print.el ends here