On this page:
5.1 General-purpose custom write helpers
custom-write-mode/  c
write/  mode
make-write/  mode
empty-printing-value
empty-printing-value?
custom-printing-value
multiline-printing-string
printing-append
printing-add-separators
make-constructor-style-printer
constructor-style-printing-value
5.2 Cooperating with racket/  pretty
printing-sequence
delimited-printing-sequence
printing-hang
install-pretty-print-handler!
5.2.1 Printing unquoted expressions
quasiexpr
~if
5.2.2 Installing a custom overflow handler
with-printing-overflow-handler
9.1.0.9

5 Printing🔗

 (require toolbox/print) package: toolbox-lib

The toolbox/print module provides utilities for printing Racket values. In particular, it is intended to aid in writing custom write procedures for use with prop:custom-write.

    5.1 General-purpose custom write helpers

    5.2 Cooperating with racket/pretty

      5.2.1 Printing unquoted expressions

      5.2.2 Installing a custom overflow handler

5.1 General-purpose custom write helpers🔗

value

custom-write-mode/c : flat-contract? = (or/c #f #t 0 1)

A contract that describes the mode argument to a custom write procedure.

procedure

(write/mode v out mode)  void?

  v : any/c
  out : output-port?
  mode : custom-write-mode/c
Writes v to out using either display, write, or print depending on the given mode. This can be useful when printing values inside a custom write procedure.

Examples:
> (struct tuple1 (value)
    #:property prop:custom-write
    (λ (self out mode)
      (write-string "#<tuple1: " out)
      (write/mode (tuple1-value self) out mode)
      (write-string ">" out)))
> (tuple1 'ok)

#<tuple1: 'ok>

procedure

(make-write/mode out mode)  (->* [any/c] [output-port?] void?)

  out : output-port?
  mode : custom-write-mode/c
Like write/mode, but returns a procedure like display, write, or print, except that the returned procedure writes to out by default instead of (current-output-port).

Examples:
> (struct tuple2 (a b)
    #:property prop:custom-write
    (λ (self out mode)
      (define recur (make-write/mode out mode))
      (write-string "#<tuple2: " out)
      (recur (tuple2-a self))
      (write-string " " out)
      (recur (tuple2-b self))
      (write-string ">" out)))
> (tuple2 1 2)

#<tuple2: 1 2>

A value that always prints as nothing.

Examples:

procedure

(custom-printing-value proc    
  [#:quotable quotability])  any/c
  proc : (-> output-port? custom-write-mode/c any)
  quotability : (or/c 'self 'never 'always 'maybe) = 'self
Returns a value that prints like a structure with proc as its custom write procedure and quotability as the value of prop:custom-print-quotable. This can be used to create “anonymous” custom printing values of arbitrary quotability.

Example:
> (list (custom-printing-value
         #:quotable 'never
         (λ (out mode)
           (write/mode "never quoted" out mode))))

(list "never quoted")

procedure

(multiline-printing-string 
  str 
  [#:indent-blank? indent-blank? 
  #:indent-trailing? indent-trailing?]) 
  any/c
  str : string?
  indent-blank? : any/c = #f
  indent-trailing? : any/c = indent-blank?
Returns a value that prints like (unquoted-printing-string str), except that when line location and column location counting has been enabled for an output port, spaces are inserted after each printed #\newline character to align each subsequent line with the first.

Example:
> (list 'prefix: (multiline-printing-string "hello,\nworld!"))

'(prefix: hello,

          world!)

The indent-blank? and indent-trailing? arguments control whether empty lines should be indented. If indent-blank? is #f (the default), then spaces are not inserted after newline characters followed immediately by another newline. This is generally the desired behavior, as such lines would otherwise consist entirely of invisible space characters.

Separately, indent-trailing? controls whether spaces should be inserted after a newline if it is the last character in str. By default, the indent-trailing? argument is simply the value of indent-blank?, but it can be configured separately because it can be useful if further printing follows the printed string that should be similarly indented.

Examples:
> (list 'prefix: (multiline-printing-string "hello,\nworld!\n"))

'(prefix: hello,

          world!

)

> (list 'prefix: (multiline-printing-string "hello,\nworld!\n"
                                            #:indent-trailing? #t))

'(prefix: hello,

          world!

          )

Note that, unlike some of the other functions provided by this module, the way a value returned by multiline-printing-string is printed does not depend on the value of the pretty-printing parameter, only on the result of port-counts-lines?. However, when pretty printing, multiline-printing-string will additionally cooperate with the pretty printer by using pretty-print-newline to print newline characters.

procedure

(printing-append v ...)  any/c

  v : any/c
Returns a value that prints as each v printed immediately after the other, with no separation between them.

Example:
> (printing-append '(one two) '(3 4))

'(one two)'(3 4)

procedure

(printing-add-separators vs    
  [#:trailing trailing-v    
  #:leading leading-v])  list?
  vs : list?
  trailing-v : any/c = empty-printing-value
  leading-v : any/c = empty-printing-value
Returns a list with the same number of values as vs. Each element of the result prints like the corresponding element of vs, except trailing-v is printed after every element except the last and leading-v is printed after every element except the first.

Example:
> (printing-add-separators
   '(one two three)
   #:trailing (unquoted-printing-string "<trailing>")
   #:leading (unquoted-printing-string "<leading>"))

'(one<trailing> <leading>two<trailing> <leading>three)

procedure

(make-constructor-style-printer get-name 
  get-args 
  [#:expression? expression?]) 
  (-> any/c output-port? custom-write-mode/c void?)
  get-name : (-> any/c (or/c symbol? string?))
  get-args : (-> any/c list?)
  expression? : any/c = #t
Like make-constructor-style-printer from racket/struct, but if expression? is #f, expression-style printing will never be used.

procedure

(constructor-style-printing-value name 
  args 
  [#:expression? expression?]) 
  any/c
  name : (or/c symbol? string?)
  args : list?
  expression? : any/c = #t
Returns a value that prints like a structure that uses make-constructor-style-printer as its custom write procedure. If expression? is #f, the value of the prop:custom-print-quotable property will be 'never, otherwise it will be 'self.

5.2 Cooperating with racket/pretty🔗

The bindings in this section assist in writing custom write procedures that automatically adapt when pretty printing via racket/pretty. Specifically, when (pretty-printing) is #t and line location and column location counting has been enabled for an output port, they may break their printed output over multiple lines to avoid exceeding the target column width controlled by pretty-print-columns.

procedure

(printing-sequence vs    
  [#:space-after space-after    
  #:hang hang-indent])  any/c
  vs : list?
  space-after : exact-nonnegative-integer? = 0
  hang-indent : exact-nonnegative-integer? = 0
Returns a value that prints like vs but without any enclosing parentheses. When not pretty printing, this means each element of vs is simply printed one after the other, separated by a single space character. However, when pretty printing, the elements of vs may be printed on separate lines, indented as needed for alignment, if they do not fit within (- (pretty-print-columns) space-after).

Examples:
> (cons 'prefix (printing-sequence '(three short values)))

'(prefix . three short values)

> (cons 'prefix (printing-sequence '(some-very-long-values
                                     that-will-be-printed
                                     over-multiple-lines
                                     to-avoid-overflowing
                                     the-desired-width)))

'(prefix

  .

  some-very-long-values

  that-will-be-printed

  over-multiple-lines

  to-avoid-overflowing

  the-desired-width)

The space-after argument is useful when the printed sequence will be followed by a closing delimiter such as ) or >, as it ensures the sequence will be broken over multiple lines if the delimiter would not fit.

When printing is broken over multiple lines, the hang-indent argument controls how much additional indentation should be printed after each line break.

Example:
> (printing-sequence
   #:hang 2
   '(some-long-values
     that-are-broken-over-several-lines
     and-are-indented-after-the-first-line))

'some-long-values

  'that-are-broken-over-several-lines

  'and-are-indented-after-the-first-line

procedure

(delimited-printing-sequence vs    
  [#:before before-str    
  #:after after-str    
  #:hang hang-indent])  any/c
  vs : list?
  before-str : string? = ""
  after-str : string? = ""
  hang-indent : exact-nonnegative-integer? = 0
Like printing-sequence, but before-str and after-str are printed before or after the elements of vs, respectively.

Example:
> (delimited-printing-sequence
   #:before "#<"
   #:after ">"
   '(my-cool-struct 3))

#<'my-cool-struct 3>

procedure

(printing-hang herald    
  body    
  [#:indent indent-amount    
  #:space-after space-after])  any/c
  herald : any/c
  body : any/c
  indent-amount : exact-nonnegative-integer? = 1
  space-after : exact-nonnegative-integer? = 0
Returns a value that prints like herald followed by body. When not pretty printing, herald and body are printed on the same line separated by a single space. When pretty printing, body is printed on a subsequent line if printing it on the same line would not fit within (- (pretty-print-columns) space-after); the line is indented by indent-amount spaces.

Example:
> (printing-hang
   #:indent 2
   (unquoted-printing-string "here is a long list:")
   '(it-gets-wrapped-over-several-lines
     because-it-is-too-long
     and-the-lines-are-indented))

here is a long list:

  '(it-gets-wrapped-over-several-lines

    because-it-is-too-long

    and-the-lines-are-indented)

Configures the global port print handler to use pretty-print and enables line location and column location counting on (current-output-port) and (current-error-port). Use this at the start of the main module of a program to configure print to use the pretty printer by default.

5.2.1 Printing unquoted expressions🔗

syntax

(quasiexpr quasi-term)

 
term = ,expr
  | {~seq head-term ...}
  | {~if expr term term}
  | (head-term ... . term)
  | datum
     
head-term = ,@expr
  | {~@ . term}
  | {~if expr head-term}
  | {~if expr head-term head-term}
  | term
Constructs a value that prints like an unquoted expression. For example:

> (quasiexpr (list (+ 1 2)))

(list (+ 1 2))

Uses of unquote or unquote-splicing escape as in quasiquote, and any value inserted via an escape is printed via print with a quote depth of 0:

> (quasiexpr (list a ()))

(list a ())

> (quasiexpr (list ,'a ,'()))

(list 'a '())

Sequences produced by quasiexpr may be broken over multiple lines when pretty printing. Subsequences that should not be split, such as keyword argument pairs, can be grouped with ~seq:

> (quasiexpr (foo #:a 'really-long-arguments
                  #:b 'that-cause-wrapping
                  #:c 'over-multiple-lines
                  #:d 'without-any-explicit-grouping))

(foo

 #:a

 'really-long-arguments

 #:b

 'that-cause-wrapping

 #:c

 'over-multiple-lines

 #:d

 'without-any-explicit-grouping)

> (quasiexpr (foo {~seq #:a 'really-long-arguments}
                  {~seq #:b 'that-cause-wrapping}
                  {~seq #:c 'over-multiple-lines}
                  {~seq #:d 'with-explicit-grouping}))

(foo

 #:a 'really-long-arguments

 #:b 'that-cause-wrapping

 #:c 'over-multiple-lines

 #:d 'with-explicit-grouping)

Like syntax, {~@ . term} can be used within a head-term to splice a list term into the enclosing term. However, as quasiterm does not support repetitions via ..., the main use of ~@ is usually only useful as the empty sequence {~@} in one arm of a use of ~if.

An {~if cond-expr then-term else-term} term is a convenient abbreviation for a conditional subterm. If cond-expr evaluates to #f, it prints like else-term; otherwise, it prints like then-term. Within a head-term, {~if expr term} is equivalent to {~if expr term {~@}}.

The quasiexpr form can be useful when implementing custom write procedures for values that should print as applications of the functions used to create them, such as contracts.

syntax

~if

Recognized specially by quasiexpr. An ~if form as an expression is a syntax error.

5.2.2 Installing a custom overflow handler🔗

procedure

(with-printing-overflow-handler out 
  single-line-proc 
  multi-line-proc 
  [#:width width 
  #:space-after space-after]) 
  void?
  out : output-port?
  single-line-proc : (-> output-port? any)
  multi-line-proc : (-> (->* [output-port? exact-positive-integer?] void?) any)
  width : exact-positive-integer? = (pretty-print-columns)
  space-after : exact-nonnegative-integer? = 0
If not currently pretty printing, simply calls (single-line-proc out). Otherwise, single-line-proc is applied to the result of make-tentative-pretty-print-output-port. If single-line-proc prints to the port in any way that would exceed the allowed width, it is immediately aborted, and multi-line-proc is applied, instead, which should print to out directly.

The procedure supplied to multi-line-proc is like pretty-print-newline, but its arguments default to out and width. Additionally, after writing a newline, it write spaces until the next column (as returned by port-next-location) is the same as it was when with-printing-overflow-handler was called. This has the effect of ensuring all subsequent lines of the print are correctly indented to align with the first line.

Internally, higher-level abstractions like printing-sequence and printing-hang use with-printing-overflow-handler to automatically adapt to the available space when pretty-printing via racket/pretty. In most cases, it is not necessary to use directly, but it can be useful if maximum control is needed.