1 ;;; pretty-print.el --- Emacs Lisp pretty printer and macro expander
3 ;; Copyright (C) 1992,1993 Guido Bosch <Guido.Bosch@loria.fr>
7 ;; Keywords: lisp, internal
9 ;; This file is part of XEmacs.
11 ;; XEmacs is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; XEmacs is distributed in the hope that it will be useful, but
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 ;; General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free
23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 ;;; Synched up with: Not in FSF.
30 ;; Please send bugs and comments to the author.
33 ;; This program is still under development. Neither the author nor
34 ;; CRIN-INRIA accepts responsibility to anyone for the consequences of
35 ;; using it or for whether it serves any particular purpose or works
38 ;; The package has been developed under Lucid Emacs 19, but also runs
39 ;; on Emacs 18, if it is compiled with the version 19 byte compiler
40 ;; (function `compiled-function-p' lacking).
43 ;; Installation and Usage
44 ;; ----------------------
46 ;; This package provides an Emacs Lisp sexpression pretty printer and
47 ;; macroexpander. To install it, put the following line in your .emacs,
48 ;; default.el or site-init.el/site-run.el (for Lucid Emacs):
51 ;; The package can also be made autoloadable, with the following entry
53 ;; (autoload 'pp-function "pp" nil t)
54 ;; (autoload 'pp-variable "pp" nil t)
55 ;; (autoload 'pp-plist "pp" nil t)
56 ;; (autoload 'macroexpand-sexp "pp" nil t)
57 ;; (autoload 'macroexpand-all-sexp "pp" nil t)
58 ;; (autoload 'prettyexpand-sexp "pp" nil t)
59 ;; (autoload 'prettyexpand-all-sexp "pp" nil t)
61 ;;(define-key emacs-lisp-mode-map '(control meta m) 'macroexpand-sexp)
62 ;;(define-key emacs-lisp-mode-map '(control meta M) 'macroexpand-all-sexp)
63 ;;(define-key emacs-lisp-mode-map '(control symbol m) 'prettyexpand-sexp)
64 ;;(define-key emacs-lisp-mode-map '(control symbol M) 'prettyexpand-all-sexp)
66 ;;(define-key lisp-interaction-mode-map '(control meta m) 'macroexpand-sexp)
67 ;;(define-key lisp-interaction-mode-map '(control meta M) 'macroexpand-all-sexp)
68 ;;(define-key lisp-interaction-mode-map '(control symbol m) 'prettyexpand-sexp)
69 ;;(define-key lisp-interaction-mode-map '(control symbol M) 'prettyexpand-all-sexp)
72 ;; Pretty printing of the different cells of a symbol is done with the
79 ;; They print a symbol's function definition, variable value and
80 ;; property list, respectively. These commands pop up a separate
81 ;; window in which the pretty printed lisp object is displayed.
82 ;; Completion for function and variable symbols is provided. If a
83 ;; function is byte compiled, `pp-function' proposes to call the Emacs
84 ;; Lisp disassembler (this feature only works for Emacs 19, as it
85 ;; needs the `compiled-function-p' predicate).
87 ;; To use the macro expander, put the cursor at the beginning of the
88 ;; form to be expanded, then type
90 ;; C-M-m (macroexpand-sexp)
91 ;; or C-M-Sh-M (macroexpand-all-sexp)
93 ;; Both commands will pop up a temporary window containing the
94 ;; macroexpanded code. The only difference is that the second command
95 ;; expands recursively all containing macro calls, while the first one
96 ;; does it only for the uppermost sexpression.
97 ;; With a prefix argument, the macro expansion isn't displayed in a
98 ;; separate buffer but replaces the original code in the current
99 ;; buffer. Be aware: Comments will be lost.
100 ;; You can get back the original sexpression using the `undo'
101 ;; command on `C-x u'.
103 ;; There is also a prettyfied version of the macroexpander:
105 ;; C-Sym-m (prettyexpand-sexp)
106 ;; or C-Sym-M (prettyexpand-all-sexp)
108 ;; The only difference with the corresponding macroexpand commands is
109 ;; that calls to macros specified in the variable
110 ;; `pp-shadow-expansion-list' are not expanded, in order to make the
111 ;; code look nicer. This is only useful for Lucid Emacs or code that
112 ;; uses Dave Gillespies cl package, as it inhibits expansion of the
113 ;; following macros: block, eval-when, defun*, defmacro*, function*,
118 ; $Log: pretty-print.el,v $
119 ; Revision 1.3 2000-10-06 09:35:05 youngs
120 ; Martin's Monster Mega typo patch
122 ; Revision 1.2 1998/02/10 16:23:33 steveb
125 ; Revision 1.4 1993/03/25 14:09:52 bosch
126 ; Commands `prettyexpand-sexp' and `prettyexpand-all-sexp' and
127 ; corresponding key bindings added. Commands pp-{function, variable}
128 ; rewritten. `pp-plist' added. Function `pp-internal-loop' (for Dave
129 ; Gillespies CL loop macro) added.
131 ; Revision 1.3 1993/03/03 12:24:13 bosch
132 ; Macroexpander rewritten. Function `pp-macroexpand-all' added (snarfed
133 ; from Dave Gillespies cl-extra.el). Pretty printing for top level
134 ; defining forms added (`pp-internal-def'). Key bindings for
135 ; `emacs-lisp-mode-map' and `lisp-interaction-mode-map' added. Built-in
136 ; variable `print-gensym' set for printinng uninterned symbols. Started
137 ; adding support for cl-dg (defun*, defmacro*, ...). Minor bug fixes.
139 ; Revision 1.2 1993/02/25 17:35:02 bosch
140 ; Comments about Emacs 18 compatibility added.
142 ; Revision 1.1 1993/02/25 16:55:01 bosch
150 ;; Provide full Emacs 18 compatibility.
153 (defvar pp-buffer-name "*Pretty Print*")
154 (defvar pp-macroexpand-buffer-name "*Macro Expansion*")
155 (if (featurep 'popper)
156 (or (eq popper-pop-buffers 't)
157 (setq popper-pop-buffers
159 (cons pp-macroexpand-buffer-name
160 popper-pop-buffers)))))
162 ;; User level functions
164 (defun pp-function (symbol)
165 "Pretty print the function definition of SYMBOL in a separate buffer"
167 (list (pp-read-symbol 'fboundp "Pretty print function definition of: ")))
168 (if (compiled-function-p (symbol-function symbol))
170 (format "Function %s is byte compiled. Disassemble? " symbol))
171 (disassemble (symbol-function symbol))
172 (pp-symbol-cell symbol 'symbol-function))
173 (pp-symbol-cell symbol 'symbol-function)))
176 (defun pp-variable (symbol)
177 "Pretty print the variable value of SYMBOL in a separate buffer"
179 (list (pp-read-symbol 'boundp "Pretty print variable value of: ")))
180 (pp-symbol-cell symbol 'symbol-value))
183 (defun pp-plist (symbol)
184 "Pretty print the property list of SYMBOL in a separate buffer"
186 (list (pp-read-symbol 'symbol-plist "Pretty print property list of: ")))
187 (pp-symbol-cell symbol 'symbol-plist))
189 (defun pp-read-symbol (predicate prompt)
190 "Read a symbol for which PREDICATE is true, promptiong with PROMPT."
192 (while (or (not symbol) (not (funcall predicate symbol)))
200 (and symbol (symbol-name symbol))))))
203 (defun pp-symbol-cell (symbol accessor)
204 "Pretty print the contents of the cell of SYMBOL that can be reached
205 with the function ACCESSOR."
206 (with-output-to-temp-buffer pp-buffer-name
207 (set-buffer pp-buffer-name)
211 (funcall accessor symbol)
212 (format "%s's %s is:\n" symbol accessor))
217 ;; Macro expansion (user level)
220 (defun macroexpand-sexp (&optional replace)
221 "Macro expand the sexpression following point. Pretty print expansion in a
222 temporary buffer. With prefix argument, replace the original
223 sexpression by its expansion in the current buffer."
225 (pp-macroexpand-internal 'macroexpand replace t))
228 (defun macroexpand-all-sexp (&optional replace)
229 "Macro expand recursively the sexpression following point. Pretty print
230 expansion in a temporary buffer. With prefix argument, replace the
231 original sexpression by its expansion in the current buffer."
233 (pp-macroexpand-internal 'pp-macroexpand-all replace t))
236 (defun prettyexpand-sexp (&optional replace)
237 "Macro expand the sexpression following point. Pretty print expansion
238 in a temporary buffer. With prefix argument, replace the original
239 sexpression by its expansion in the current buffer.
240 However, calls to macros specified in the variable
241 `pp-shadow-expansion-list' are not expanded, in order to make the code
245 (pp-macroexpand-internal 'macroexpand replace))
248 (defun prettyexpand-all-sexp (&optional replace)
249 "Macro expand recursively the sexpression following point. Pretty print
250 expansion in a temporary buffer. With prefix argument, replace the
251 original sexpression by its expansion in the current buffer.
252 However, calls to macros specified in the variable
253 `pp-shadow-expansion-list' are not expanded, in order to make the code
256 (pp-macroexpand-internal 'pp-macroexpand-all replace))
258 ;; XEmacs: don't do this at load time.
259 ;;(define-key emacs-lisp-mode-map '(control meta m) 'macroexpand-sexp)
260 ;;(define-key emacs-lisp-mode-map '(control meta M) 'macroexpand-all-sexp)
261 ;;(define-key emacs-lisp-mode-map '(control symbol m) 'prettyexpand-sexp)
262 ;;(define-key emacs-lisp-mode-map '(control symbol M) 'prettyexpand-all-sexp)
264 ;;(define-key lisp-interaction-mode-map '(control meta m) 'macroexpand-sexp)
265 ;;(define-key lisp-interaction-mode-map '(control meta M) 'macroexpand-all-sexp)
266 ;;(define-key lisp-interaction-mode-map '(control symbol m) 'prettyexpand-sexp)
267 ;;(define-key lisp-interaction-mode-map '(control symbol M) 'prettyexpand-all-sexp)
270 ;; Macro expansion (internals)
272 (defvar pp-shadow-expansion-list
273 (mapcar 'list '(block eval-when defun* defmacro* function* setf))
274 "The value of this variable is given as the optional environment
275 argument of the macroexpand functions. Forms specified in this list are
278 (defun pp-macroexpand-internal
279 (macroexpand-function replace &optional dont-shadow)
280 "Macro expand the sexp that starts at point, using
281 MACROEXPAND-FUNCTION. If REPLACE is non-nil, replace the original
282 text by its expansion, otherwise pretty print the expansion in a
283 temporary buffer. With optional argument DONT-SHADOW non-nil, do not
284 use the `pp-shadow-expansion-list' to inhibit expansion of some
291 (let ((stab (syntax-table)))
294 (set-syntax-table emacs-lisp-mode-syntax-table)
296 (read (current-buffer)))
297 (set-syntax-table stab)))
300 pp-shadow-expansion-list))))
303 (let ((start (point))
304 (end (progn (forward-sexp 1) (point))))
305 (delete-region start end)
306 (pp-internal expansion))
307 (with-output-to-temp-buffer pp-macroexpand-buffer-name
308 (set-buffer pp-macroexpand-buffer-name)
311 (pp-internal expansion))))))
313 ;; Internal pretty print functions
316 (defun pp-internal (form &optional title)
317 "Pretty print FORM in in the current buffer.
318 Optional string TITLE is inserted before the pretty print."
320 (if title (princ title))
322 ;; print-escape-newlines must be t, otherwise we cannot use
323 ;; (current-column) to detect good line breaks
324 (let ((print-escape-newlines t)
327 (prin1 form (current-buffer))
329 (pp-internal-sexp))))
331 (defun pp-internal-sexp ()
332 "Pretty print the following sexp.
333 Point must be on or before the first character."
335 (skip-chars-forward " \n\t")
336 (let* ((char (following-char))
337 (ch-class (char-syntax char))
344 (if (memq (char-syntax (following-char)) '(?_ ?w))
345 (let ((symbol (read (current-buffer))))
346 (cond ((and (symbolp symbol)
349 (pp-internal-function symbol))
350 ((memq symbol '(lambda macro))
351 (pp-internal-lambda))
354 (pp-internal-list))))
359 ((memq ch-class '(?_ ; symbol
363 ?\' ; quote (for uninterned symbols)
367 ((eq char ?\[) (pp-internal-list))
370 (t (error "pp-internal-sexp: character class not treated yet: `%c'"
373 (defun pp-internal-function (func)
374 "Pretty print a functuion call.
375 Point must be on the open paren. the function symbol may be passed as an
377 (let ((start (point))
378 (too-large (>= (save-excursion
382 (indent-info (get func lisp-indent-function)))
384 ;; skip over function name
387 ((memq func '(let let*)) (pp-internal-let))
389 ((eq func 'cond) (pp-internal-cond))
391 ((memq func '(if while with-output-to-temp-buffer catch block))
393 (pp-internal-body 't))
395 ((eq func 'quote) (pp-internal-quote))
399 save-window-excursion
402 (pp-internal-body 't))
404 ((memq func '(defun defmacro defsubst defun* defmacro*))
407 ((eq func 'loop) (pp-internal-loop))
409 ('t (pp-internal-body too-large)))))
411 (defun pp-internal-def ()
412 (forward-sexp 1) ; skip name
413 (if (looking-at " nil") ; replace nil by ()
414 (replace-match " ()")
416 (if (looking-at " \"")
417 ;; comment string. Replace all escaped linefeeds by real ones
418 (let ((limit (save-excursion (forward-sexp 1) (point-marker))))
420 (while (re-search-forward "\\\\n" limit t)
421 (replace-match "\n" nil nil))
423 (pp-internal-body 't))
425 (defun pp-internal-list ()
426 "Pretty print a list or a vector.
427 Point must be on the open paren."
428 (let ((too-large (>= (save-excursion
434 (pp-internal-body too-large)))
436 (defun pp-internal-body (&optional force-indent)
437 "Prety print a body of sexp. Stop after reaching a `)'. If argument
438 FORCE-INDENT is non-nil, break line after each sexpression of the
440 (skip-chars-forward " \n\t")
442 ;; while not closing paren
443 (while (/= (setq ch-class (char-syntax (following-char))) ?\))
444 (if force-indent (newline-and-indent))
448 (defun pp-internal-loop ()
449 "Prety print a loop body. Stop after reaching a `)'.
450 Line breaks are done before the following keywords: "
452 (skip-chars-forward " \n\t")
454 ;; while not closing paren
455 (while (/= (setq ch-class (char-syntax (following-char))) ?\))
456 (if (not (looking-at "for\\|repeat\\|with\\|while\\|until\\|always\\|never\\|thereis\\|collect\\|append\\|nconc\\|sum\\|count\\|maximize\\|minimize\\|if\\|when\\|else\\|unless\\|do\\W\\|initially\\|finally\\|return\\|named"))
460 (skip-chars-forward " \n\t"))
463 (defun pp-internal-body-list ()
464 (let ((too-large (>= (save-excursion
471 (while (/= (setq ch-class (char-syntax (following-char))) ?\))
472 (if too-large (newline-and-indent))
476 (defun pp-internal-lambda ()
477 (forward-sexp 1) ; arguments
478 (pp-internal-body 't))
480 (defun pp-internal-let ()
481 "Pretty print a let-like form.
482 Cursor is behind function symbol."
484 (while (not (= (following-char) ?\)))
485 (if (= (following-char) ?\()
486 (pp-internal-body-list)
488 (if (not (= (following-char) ?\)))
489 (newline-and-indent)))
491 (pp-internal-body 't))
493 (defun pp-internal-cond ()
494 "Pretty print a cond-like form.
495 Cursor is behind function symbol."
496 (skip-chars-forward " \n\t")
497 (while (not (= (following-char) ?\)))
498 (pp-internal-body-list)
499 (if (not (= (following-char) ?\)))
500 (newline-and-indent)))
504 (defun pp-internal-quote ()
505 "Pretty print a quoted list.
506 Cursor is behind the symbol quote."
507 (skip-chars-forward " \n\t")
510 (delete-region (point) end)
518 (if (= (char-syntax (following-char)) ?\()
519 ;; don't print it as sexp, because it could be (let ... ) or
520 ;; (cond ... ) or whatever.
522 (pp-internal-sexp))))
525 ;; Stolen form Dave Gillespies cl-extra.el
526 (defun pp-macroexpand-all (form &optional env)
527 "Expand all macro calls through a Lisp FORM.
528 This also does some trivial optimizations to make the form prettier."
529 (setq form (macroexpand form env))
531 ((not (consp form)) form)
532 ((memq (car form) '(let let*))
533 (if (null (nth 1 form))
534 (pp-macroexpand-all (cons 'progn (cdr (cdr form))) env)
536 (cons (pp-macroexpand-lets (nth 1 form) env)
537 (pp-macroexpand-body (cdr (cdr form)) env)))))
538 ((eq (car form) 'cond)
540 (mapcar (function (lambda (x) (pp-macroexpand-body x env)))
542 ((eq (car form) 'condition-case)
545 (cons (pp-macroexpand-all (nth 2 form) env)
547 (cdr (cdr (cdr form))) env)))))
548 ((memq (car form) '(quote function))
549 (if (eq (car-safe (nth 1 form)) 'lambda)
552 (cons (car (cdr (car (cdr form))))
554 (cdr (cdr (car (cdr form)))) env))))
556 ((memq (car form) '(defun defmacro))
559 (pp-macroexpand-body (cdr (cdr form)) env))))
560 ((and (eq (car form) 'progn) (not (cdr (cdr form))))
561 (pp-macroexpand-all (nth 1 form) env))
563 (cons (car form) (pp-macroexpand-body (cdr form) env)))))
565 (defun pp-macroexpand-body (body &optional env)
566 (mapcar (function (lambda (x) (pp-macroexpand-all x env))) body))
568 (defun pp-macroexpand-lets (list &optional env)
571 (if (consp x) (cons (car x) (pp-macroexpand-body (cdr x) env))
574 (run-hooks 'pp-load-hook)
577 ;;; pretty-print.el ends here