(chibi show)

A library of procedures for formatting Scheme objects to text in various ways, and for easily concatenating, composing and extending these formatters.

Background

There are several approaches to text formatting. Building strings to display is not acceptable, since it doesn't scale to very large output. The simplest realistic idea, and what people resort to in typical portable Scheme, is to interleave display and write and manual loops, but this is both extremely verbose and doesn't compose well. A simple concept such as padding space can't be achieved directly without somehow capturing intermediate output.

The traditional approach is to use templates - typically strings, though in theory any object could be used and indeed Emacs' mode-line format templates allow arbitrary sexps. Templates can use either escape sequences (as in C's printf and CL's format) or pattern matching (as in Visual Basic's Format, Perl6's form, and SQL date formats). The primary disadvantage of templates is the relative difficulty (usually impossibility) of extending them, their opaqueness, and the unreadability that arises with complex formats. Templates are not without their advantages, but they are already addressed by other libraries such as SRFI-28 and SRFI-48.

This library takes a combinator approach. Formats are nested chains of closures, which are called to produce their output as needed. The primary goal of this library is to have, first and foremost, a maximally expressive and extensible formatting library. The next most important goal is scalability - to be able to handle arbitrarily large output and not build intermediate results except where necessary. The third goal is brevity and ease of use.

Interface

(show out [args ...])

The primary interface. Analogous to CL's format, the first argument is either an output port or a boolean, with #t indicating current-output-port and #f indicating a string port. The remaining arguments are formatters, combined as with each, run with output to the given destination. If out is #f then the accumulated output is returned, otherwise the result is unspecified.

Formatters

nl

Output a single newline.

(fl st)

"Fresh line" - output a newline iff we're not at the start of a fresh line.

(tab-to . o)

Move to a given tab-stop (using spaces, not tabs).

(space-to where)

Move to an explicit column.

(upcased . ls)

Show each of ls, uppercasing all generated text.

(downcased . ls)

Show each of ls, lowercasing all generated text.

(padded/both width . ls)

Pad the result of (each-in-list ls) to at least width characters, equally applied to the left and right, with any extra odd padding applied to the right. Uses the value of pad-char for padding, defaulting to #space.

(padded width . ls)

As padded/both but only applies padding on the right.

padded/right

An alias for padded.

(padded/left width . ls)

As padded/both but only applies padding on the left.

(trimmed width . ls)

Trims the result of (each-in-list ls) to at most width characters, removed from the right. If any characters are removed, then the value of ellipsis (default empty) is used in its place (trimming additional characters as needed to be sure the final output doesn't exceed width).

trimmed/right

An alias for trimmed.

(trimmed/left width . ls)

As trimmed but removes from the left.

(trimmed/both width . ls)

As trimmed but removes equally from both the left and the right, removing extra odd characters from the right, and inserting ellipsis on both sides.

(trimmed/lazy width . ls)

A trimmed, but truncates and terminates immediately if more than width characters are generated by ls. Thus ls may lazily generate an infinite amount of output safely (e.g. write-simple on an infinite list). The nature of this procedure means only truncating on the right is meaningful.

(fitted width . ls)

Fits the result of (each-in-list ls) to exactly width characters, padding or trimming on the right as needed.An alias for fitted.

(fitted/left width . ls)

As fitted but pads/trims from the left.

(fitted/both width . ls)

As fitted but pads/trims equally from both the left and the right.

(joined/general elt-f last-f dot-f init-ls sep)

(joined elt-f ls [sep])

Joins the result of applying elt-f to each element of the list ls together with sep, which defaults to the empty string.

(joined/prefix elt-f ls . o)

As joined but treats the separator as a prefix, inserting before every element instead of between.

(joined/suffix elt-f ls . o)

As joined but treats the separator as a suffix, inserting after every element instead of between.

(joined/last elt-f last-f ls . o)

As joined but applies last-f, instead of elt-f, to the last element of ls, useful for e.g. commas separating a list with "and" before the final element.

(joined/dot elt-f dot-f ls . o)

As joined but if ls is a dotted list applies dot-f to the dotted tail as a final element.

(joined/range elt-f start [end sep])

As joined but counts from start to end (exclusive), formatting each integer in the range. If end is #f or unspecified, produces an infinite stream of output.