# (srfi 166 base)

#### `(fn . x)`

The minimal base formatting combinators and show interface.

#### `(output-default str)`

Raw output - displays str to the formatter output port and updates row and col.

#### `(show out [args ...])`

Run the combinators `args`, accumulating the output to `out`, which is either an output port or a boolean, with `#t` indicating `current-output-port` and `#f` to collect the output as a string.

#### `(with params x ... y)`

Temporarily bind the parameters in the body `x`.

#### `nothing`

The noop formatter. Generates no output and leaves the state unmodified.

#### `(displayed x)`

Formats a displayed version of x - if a string or char, outputs the raw characters (as with `display'), if x is already a formatter defers to that, otherwise outputs a written version of x.

#### `(written x)`

Formats a written version of x, as with `write'. The formatting can be updated with the `'writer` field.

#### `(each-in-list args)`

Takes a single list of formatters, combined in sequence with `each`.

#### `(each . args)`

Combines each of the formatters in a sequence using `displayed`, so that strings and chars will be output directly and other objects will be `written`.

#### `(call-with-output producer consumer)`

Captures the output of `producer` and formats the result with `consumer`.

## String utilities

#### `(escaped fmt [quot esc rename])`

Outputs the string str, escaping any quote or escape characters. If esc-ch, which defaults to #\, is #f, escapes only the quote-ch, which defaults to #, by doubling it, as in SQL strings and CSV values. If renamer is provided, it should be a procedure of one character which maps that character to its escape value, e.g. #newline => #n, or #f if there is no escape value.

#### `(maybe-escaped fmt pred [quot esc rename])`

Only escape if there are special characters, in which case also wrap in quotes. For writing symbols in |...| escapes, or CSV fields, etc. The predicate indicates which characters cause slashification - this is in addition to automatic slashifying when either the quote or escape char is present.

#### `(numeric n [rad prec sgn comma commasep decsep])`

#### `(numeric/si n [base separator])`

#### `(numeric/fitted width n . args)`

#### `(numeric/comma n . o)`

#### `(written-shared obj)`

#### `(written-simply obj)`

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`

"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.

#### `(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/right width . ls)`

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

#### `(padded/left width . ls)`

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

#### `padded`

An alias for `padded/left`.

#### `(trimmed/right 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/left width . ls)`

As `trimmed/right` but removes from the left.

#### `trimmed`

An alias for `trimmed/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/right width . ls)`

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

#### `(fitted/left width . ls)`

As `fitted` but pads/trims from the left.

#### `fitted`

An alias for `fitted/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.