Common Lisp the Language, 2nd Edition

Next: Compiling Format Control Up: Pretty Printing Previous: Dynamic Control of

# 27.4. Format Directive Interface

The primary interface to operations for dynamically determining the arrangement of output is provided through the functions above. However, an additional interface is provided via a set of format directives because, as shown by the examples in this section and the next, `format` strings are typically a much more compact way to specify pretty printing. In addition, without such an interface, one would have to abandon the use of `format` when interacting with the pretty printer.

`~W`
  Write. An arg, any Lisp object, is printed obeying every printer control variable (as by `write`). In addition, `~W` interacts correctly with depth abbreviation by not resetting the depth counter to zero. `~W` does not accept parameters. If given the colon modifier, `~W` binds `*print-pretty*` to `t`. If given the atsign modifier, `~W` binds `*print-level*` and `*print-length*` to `nil`.

  `~W` provides automatic support for circularity detection. If `*print-circle*` (and possibly also `*print-shared*`) is not `nil` and `~W` is applied to an argument that is a circular (or shared) reference, an appropriate ```#n#`'' marker is inserted in the output instead of printing the argument.

`~_`
  Conditional newline. Without any modifiers, `~_` is equivalent to `(pprint-newline :linear)`. The directive `~@_` is equivalent to `(pprint-newline :miser)`. The directive `~:_` is equivalent to `(pprint-newline :fill)`. The directive `~:@_` is equivalent to `(pprint-newline :mandatory)`.

`~<str~:>`
  Logical block. If `~:>` is used to terminate a `~<...` directive, the directive is equivalent to a call on `pprint-logical-block`. The `format` argument corresponding to the `~<...~:>` directive is treated in the same way as the list argument to `pprint-logical-block`, thereby providing automatic support for non-list arguments and the detection of circularity, sharing, and depth abbreviation. The portion of the `format` control string nested within the `~<...~:>` specifies the `:prefix` (or `:per-line-prefix`), `:suffix`, and body of the `pprint-logical-block`.

  The `format` string portion enclosed by `~<...~:>` can be divided into segments `~<prefix~;body~;suffix~:>` by `~;` directives. If the first section is terminated by `~@;`, it specifies a per-line prefix rather than a simple prefix. The prefix and suffix cannot contain `format` directives. An error is signaled if either the prefix or suffix fails to be a constant string or if the enclosed portion is divided into more than three segments.

  If the enclosed portion is divided into only two segments, the suffix defaults to the null string. If the enclosed portion consists of only a single segment, both the prefix and the suffix default to the null string. If the colon modifier is used (that is, `~:<...~:>`), the prefix and suffix default to `"("` and `")"`, respectively, instead of the null string.

  The body segment can be any arbitrary `format` control string. This `format` control string is applied to the elements of the list corresponding to the `~<...~:>` directive as a whole. Elements are extracted from this list using `pprint-pop`, thereby providing automatic support for malformed lists and the detection of circularity, sharing, and length abbreviation. Within the body segment, `~^` acts like `pprint-exit-if-list-exhausted`.

  `~<...~:>` supports a feature not supported by `pprint-logical-block`. If `~:@>` is used to terminate the directive (that is, `~<...~:@>`), then a fill-style conditional newline is automatically inserted after each group of blanks immediately contained in the body (except for blanks after a `~<newline>` directive). This makes it easy to achieve the equivalent of paragraph filling.

  If the atsign modifier is used with `~<...~:>`, the entire remaining argument list is passed to the directive as its argument. All of the remaining arguments are always consumed by `~@<...~:>`, even if they are not all used by the `format` string nested in the directive. Other than the difference in its argument, `~@<...~:>` is exactly the same as `~<...~:>`, except that circularity (and sharing) detection is not applied if the `~@<...~:>` is at top level in a `format` string. This ensures that circularity detection is applied only to data lists and not to `format` argument lists.

  To a considerable extent, the basic form of the directive `~<...~>` is incompatible with the dynamic control of the arrangement of output by `~W`, `~_`, `~<...~:>`, `~I`, and `~:T`. As a result, an error is signaled if any of these directives is nested within `~<...~>`. Beyond this, an error is also signaled if the `~<...~:;...~>` form of `~<...~>` is used in the same `format` string with `~W`, `~_`, `~<...~:>`, `~I`, or `~:T`.

`~I`
  Indent. `~nI` is equivalent to `(pprint-indent :block n)`. `~:nI` is equivalent to `(pprint-indent :current n)`. In both cases, n defaults to zero if it is omitted.

`~:T`
  Tabulate. If the colon modifier is used with the `~T` directive, the tabbing computation is done relative to the column where the section immediately containing the directive begins, rather than with respect to column zero. `~n,m:T` is equivalent to `(pprint-tab :section n m)`. `~n,m:@T` is equivalent to `(pprint-tab :section-relative n m)`. The numerical parameters are both interpreted as being in units of ems and both default to 1.

`~/name/`
  Call function. User-defined functions can be called from within a `format` string by using the directive `~/name/`. The colon modifier, the atsign modifier, and arbitrarily many parameters can be specified with the `~/name/` directive. The name can be any string that does not contain ```/`''. All of the characters in name are treated as if they were upper case. If name contains a ```:`'' or ```::`'', then everything up to but not including the first ```:`'' or ```::`'' is taken to be a string that names a package. Everything after the first ```:`'' or ```::`'' (if any) is taken to be a string that names a symbol. The function corresponding to a `~/name/` directive is obtained by looking up the symbol that has the indicated name in the indicated package. If name does not contain a ```:`'' or ```::`'', then the whole name string is looked up in the `user` package.

  When a `~/name/` directive is encountered, the indicated function is called with four or more arguments. The first four arguments are the output stream, the `format` argument corresponding to the directive, the value `t` if the colon modifier was used (`nil` otherwise), and the value `t` if the atsign modifier was used (`nil` otherwise). The remaining arguments consist of any parameters specified with the directive. The function should print the argument appropriately. Any values returned by the function are ignored.

  The three functions `pprint-linear`, `pprint-fill`, and `pprint-tabular` are designed so that they can be called by `~/.../` (that is, `~/pprint-linear/`, `~/pprint-fill/`, and `~/pprint-tabular/`. In particular they take colon and atsign arguments.

As examples of the convenience of specifying pretty printing with `format` strings, consider the functions `pprint-defun` and `pprint-let` used as examples in the last section. They can be more compactly defined as follows. The function `pprint-vector` cannot be defined using `format`, because the data structure it traverses is not a list. The function `pprint-tabular` is inconvenient to define using `format`, because of the need to pass its `tabsize` argument through to a `~:T` directive nested within an iteration over a list.

    (defun pprint-defun (list)
      (format t
    "~:<~W ~@_~:I~W ~:_~W~1I ~_~W~:>"
    list))

    (defun pprint-let (list)
      (format t "~:<~W~^ ~:<~@{~:<~@{~W~^ ~_~}~:>~^ ~:_~}~:>~1I~
                    ~@{~^ ~_~W~}~:>"
              list))

Next: Compiling Format Control Up: Pretty Printing Previous: Dynamic Control of