Wiki
Download
Manual
Eggs
API
Tests
Bugs
show
edit
You can edit this page using
wiki syntax
for markup.
Article contents:
[[tags: egg]] == wl-pprint [[toc:]] === Description {{wl-pprint}} is a Wadler/Leijen-style pretty-printing combinator library. It contains an algebraic type {{document}}, combinators for building documents, and a renderer that lays them out to fit a given line width, backtracking over {{group}} choice points as needed. It is a port of Francois Pottier and Nicolas Pouillard's PPrint library (INRIA Paris-Rocquencourt), itself an adaptation of Daan Leijen's PPrint, based on the ideas in Philip Wadler's "A Prettier Printer". See: * [[http://www.cs.uu.nl/~daan/pprint.html]] * [[http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf]] * [[https://github.com/iraikov/pprint]] {{wl-print}} works by buildling a document via {{text}}, {{^^}}, {{group}}, and friends, described below. Output is produced by {{pretty}} or {{compact}}. The central abstraction is the {{group}} / conditional-break pair: a {{group}} first tries to render its contents "flat" (as if on one line), and only falls back to breaking at the specified {{break}}s, which are converted into actual newlines plus indentation if the flat rendering would not fit in the given width. === Author Ivan Raikov === Repository [[https://github.com/iraikov/chicken-wl-pprint]] === Requirements * [[datatype]] * [[srfi-13]] === API ==== Document construction <procedure>(document? x) -> boolean</procedure> Returns {{#t}} if {{x}} is a document, {{#f}} otherwise. <procedure>(empty) -> document</procedure> {{empty}} represents the empty document, the identity element for {{^^}}. It renders as nothing and is eliminated by concatenation: {{(^^ empty x)}} and {{(^^ x empty)}} are both just {{x}}. <procedure>(^^ x y) -> document</procedure> Concatenates two documents, eliminating {{empty}} on either side. <procedure>(dcat doc ...) -> document</procedure> Variadic convenience wrapper over {{^^}} for concatenating any number of documents. <procedure>(ifflat d1 d2) -> document</procedure> Renders as {{d1}} if the enclosing {{group}} is being rendered flat, as {{d2}} otherwise. {{break}}, {{break0}}, and {{break1}} (below) are all defined in terms of {{ifflat}}. <procedure>(hardline) -> document</procedure> {{hardline}} represents a document that always renders as a newline, regardless of whether it occurs inside a flattened {{group}}. A {{hardline}} anywhere inside a {{group}} forces that group to break. <procedure>(char c) -> document</procedure> A document consisting of the single character {{c}}. Signals an error if {{c}} is {{#\newline}}; use {{hardline}} or {{break}} for line breaks instead. <procedure>(text-span s ofs len) -> document</procedure> A document consisting of {{len}} characters of {{s}} starting at offset {{ofs}}. Renders to {{empty}} if {{len}} is 0. <procedure>(text s) -> document</procedure> A document consisting of the entire string {{s}}. {{s}} must not contain embedded newlines; use {{text-lines}} for that. <procedure>(blank n) -> document</procedure> A document consisting of {{n}} literal space characters. Renders to {{empty}} if {{n}} is 0. ==== Indentation and alignment <procedure>(nest i x) -> document</procedure> Increases the indentation level used after any newline rendered inside {{x}} by {{i}} columns. {{i}} must be non-negative; signals an error otherwise. <procedure>(column f) -> document</procedure> Renders as {{(f k)}}, where {{k}} is the column the renderer is currently at. <procedure>(nesting f) -> document</procedure> Renders as {{(f i)}}, where {{i}} is the current indentation level. <procedure>(group x) -> document</procedure> Marks {{x}} as a unit that the renderer should try to render flat (all its {{break}}s collapsed) if it fits within the width and ribbon; otherwise it is rendered with all its {{break}}s turned into newlines. This is the central layout primitive of the library. <procedure>(align d) -> document</procedure> Renders {{d}} with its indentation level set to the current column, so continuation lines line up under wherever {{d}} started rather than under a fixed offset. Useful when the start column varies, e.g. after a variable-length prefix. <procedure>(hang i d) -> document</procedure> {{align}} plus {{i}} extra columns of indentation: {{(align (nest i d))}}. <procedure>(indent i d) -> document</procedure> Like {{hang}}, but also prefixes {{d}} with {{i}} literal spaces: {{(hang i (^^ (blank i) d))}}. ==== Punctuation constants Single-character documents for common punctuation, all defined via {{char}}: lparen rparen langle rangle lbrace rbrace lbracket rbracket squote dquote bquote semi colon comma space dot sharp backslash equals qmark tilde at percent dollar caret ampersand star plus minus underscore bang bar ==== Breaks and text helpers <procedure>(break i) -> document</procedure> A conditional break: renders as {{i}} literal spaces when its enclosing {{group}} is flat, or as a newline (plus the current indentation) when it breaks. <parameter>break0</parameter> Shortcut for {{(ifflat empty hardline)}}: a conditional break with no space when flat. <parameter>break1</parameter> Shortcut for {{(ifflat space hardline)}}: a conditional break with one space when flat. <procedure>(text-lines s) -> document</procedure> Splits {{s}} on embedded newlines and joins the pieces with {{break1}}, so a multi-line string participates correctly in the enclosing {{group}}'s flatten/break decision instead of dumping raw newlines into the middle of a line. <procedure>(words s) -> document</procedure> Splits {{s}} on runs of whitespace and lays the words out with grouped breaks between them, so a paragraph of text wraps at the current width like a text-fill. ==== Enclosing <procedure>(enclose l r x) -> document</procedure> Wraps {{x}} between documents {{l}} and {{r}}: {{(^^ l (^^ x r))}}. <procedure>(parens x) -> document</procedure> <procedure>(braces x) -> document</procedure> <procedure>(brackets x) -> document</procedure> <procedure>(angles x) -> document</procedure> <procedure>(squotes x) -> document</procedure> <procedure>(dquotes x) -> document</procedure> <procedure>(bquotes x) -> document</procedure> {{enclose}} instantiated with {{( )}}, {{{ }}}, {{[ ]}}, {{< >}}, {{' '}}, {{" "}}, and <code>` `</code> respectively. ==== Folds <procedure>(fold f docs) -> document</procedure> Right fold of two-argument document-combining procedure {{f}} over list {{docs}}, with {{empty}} as the base case for {{'()}}. <procedure>(fold1 f docs) -> document</procedure> Like {{fold}}, but a singleton list returns its one element unmodified rather than combining it with {{empty}}; {{'()}} still returns {{empty}}. <procedure>(fold1map f g docs) -> document</procedure> Like {{fold1}}, but maps {{g}} over each element of {{docs}} before combining with {{f}}. <procedure>(sepmap sep g docs) -> document</procedure> Maps {{g}} over {{docs}} and joins the results with separator document {{sep}}: {{(fold1map (lambda (x y) (^^ x (^^ sep y))) g docs)}}. <procedure>(group1 d) -> document</procedure> <procedure>(group2 d) -> document</procedure> {{(group (nest 1 d))}} and {{(group (nest 2 d))}}. ==== Surround and seq <procedure>(surround n sep open-doc contents close-doc) -> document</procedure> Wraps {{contents}} between {{open-doc}} and {{close-doc}} as a single {{group}}, with {{sep}} as the gap on each side and {{n}} columns of extra indentation when the group breaks. Open, gap, contents, and close all flatten or break together. <procedure>(surround1 open-txt contents close-txt) -> document</procedure> {{surround}} with {{n = 1}}, {{sep = break0}}, and string delimiters {{open-txt}}/{{close-txt}} wrapped in {{text}}. <procedure>(surround2 open-txt contents close-txt) -> document</procedure> {{surround}} with {{n = 2}}, {{sep = break1}}, and string delimiters {{open-txt}}/{{close-txt}} wrapped in {{text}}. <procedure>(soft-surround n sep open-doc contents close-doc) -> document</procedure> Like {{surround}}, but the open/close gap and {{contents}} are each their own {{group}}, so they can flatten or break independently -- e.g. delimiters that stay on one line each while the body they enclose still wraps across several. <procedure>(seq indent-n brk empty-seq open-seq sep-seq close-seq xs) -> document</procedure> The general list-to-delimited-sequence builder: renders {{empty-seq}} for {{'()}}, otherwise {{(surround indent-n brk open-seq ... close-seq)}} around {{xs}} joined by {{sep-seq}}. <procedure>(seq1 open-txt sep-txt close-txt) -> (list -> document)</procedure> Returns a procedure that renders a list of documents as a tuple-like sequence: {{surround1}}-style delimiters, {{break0}} gap, elements separated by {{sep-txt}} followed by {{break1}}. <procedure>(seq2 open-txt sep-txt close-txt) -> (list -> document)</procedure> Like {{seq1}} but {{surround2}}-style: 2 columns of indentation, {{break1}} gap. ==== Rendering <procedure>(pretty rfrac width port doc) -> undefined</procedure> Pretty-prints {{doc}} to {{port}}. {{width}} is the maximum number of characters per line; {{rfrac}} is the ribbon width as a fraction of {{width}} (the maximum number of non-indentation characters per line). {{1.0}} means the ribbon is the same as the width. <procedure>(compact port doc) -> undefined</procedure> Prints {{doc}} to {{port}} with no indentation and no width tracking: every {{group}} renders flat and only {{hardline}}s produce actual newlines. Useful for a fast single-line (or hardline-delimited) rendering, e.g. for embedding a document in a comment. ==== Value-representation helpers Helpers for printing debug representations of algebraic values, e.g. tuples, variants, records, options, lists, and base types -- in an ML-like notation. Useful as a quick {{write}}-style pretty-printer for ad hoc data while debugging. <procedure>(ml-tuple docs) -> document</procedure> Renders a list of documents as an ML tuple: {{(seq1 "(" "," ")")}}. <procedure>(ml-variant type-name cons-name tag args) -> document</procedure> Renders a constructor application as {{ConsName}} (if {{args}} is {{'()}}) or {{ConsName(arg, ...)}}. {{type-name}} and {{tag}} are accepted for parity with the SML source but not used in the rendering. <procedure>(ml-record type-name fields) -> document</procedure> Renders an association list of {{(name . doc)}} pairs as an ML-style record: {{{ name1=doc1, name2=doc2 }}}. <procedure>(ml-option f x) -> document</procedure> Renders {{(f x)}} wrapped as {{Some(...)}} if {{x}} is truthy, or {{None}} if {{x}} is {{#f}}. Scheme has no direct analog of SML's option type, so {{#f}} doubles as {{None}}; this cannot distinguish {{None}} from {{Some #f}}, which is acceptable for the debug-printing use this helper is intended for. <procedure>(ml-list f xs) -> document</procedure> Renders {{(map f xs)}} as an ML-style list: {{[ e1, e2, ... ]}}. <procedure>(ml-string s) -> document</procedure> Renders string {{s}} via {{text-lines}} (so embedded newlines still participate correctly in group flattening). <procedure>(ml-int i) -> document</procedure> <procedure>(ml-real x) -> document</procedure> <procedure>(ml-bool b) -> document</procedure> Render an integer, a real number, or a boolean ({{true}}/{{false}}). <procedure>(ml-char c) -> document</procedure> Renders character {{c}}, escaping it in the manner of (though not byte-identical to) SML's {{Char.toString}}: printable ASCII passes through, common control characters get a backslash escape ({{\n}}, {{\t}}, {{\r}}, {{\\}}), anything else falls back to a decimal code escape. <procedure>(ml-unknown type-name x) -> document</procedure> Renders as {{<type-name>}}, a placeholder for values with no dedicated {{ml-*}} representation. {{x}} is accepted for parity with the SML source but not used in the rendering. === Examples <enscript highlight="scheme"> (import scheme (chicken port) wl-pprint) ;; A call-like document that breaks onto multiple lines only if it ;; doesn't fit in the given width. (define call-doc (group (nest 2 (dcat (text "foo(") break0 (text "a,") break1 (text "b") break0 (text ")"))))) (display (call-with-output-string (lambda (p) (pretty 1.0 80 p call-doc)))) ;; => foo(a, b) (display (call-with-output-string (lambda (p) (pretty 1.0 5 p call-doc)))) ;; => foo( ;; a, ;; b ;; ) ;; ml-* helpers, for quick debug-printing of algebraic values. (define point (ml-record "point" (list (cons "x" (ml-int 1)) (cons "y" (ml-int 2))))) (display (call-with-output-string (lambda (p) (pretty 1.0 80 p point)))) ;; => { x=1, y=2 } </enscript> See also {{examples/tutorial.scm}} in the repository for a longer, runnable tour of the whole API, including a worked example that formats a tiny C-like declaration syntax. === License <pre> The MIT License (MIT) Copyright (c) 2026 Ivan Raikov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. </pre> === Version history ; 1.0 : Initial release.
Description of your changes:
I would like to authenticate
Authentication
Username:
Password:
Spam control
What do you get when you multiply 1 by 4?