doc: Format

This commit is contained in:
E.W.Ayers 2022-08-16 13:33:43 +01:00 committed by Leonardo de Moura
parent 2e99e8c22d
commit ff5b02622c
2 changed files with 65 additions and 6 deletions

View file

@ -10,25 +10,63 @@ import Init.Data.String.Basic
namespace Std
/-- Determines how groups should have linebreaks inserted when the
text would overfill its remaining space.
- `allOrNone` will make a linebreak on every `Format.line` in the group or none of them.
```
[1,
2,
3]
```
- `fill` will only make linebreaks on as few `Format.line`s as possible:
```
[1, 2,
3]
```
-/
inductive Format.FlattenBehavior where
| allOrNone
| fill
deriving Inhabited, BEq
open Format in
/-- A string with pretty-printing information for rendering in a column-width-aware way.
The pretty-printing algorithm is based on Wadler's paper
[_A Prettier Printer_](https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf). -/
inductive Format where
| nil : Format
| line : Format
| text : String → Format
| nest (indent : Int) : Format → Format
| append : Format → Format → Format
| group : Format → (behavior : FlattenBehavior := FlattenBehavior.allOrNone) → Format
| /-- The empty format. -/
nil : Format
| /-- A position where a newline may be inserted
if the current group does not fit within the allotted column width. -/
line : Format
| /-- A node containing a plain string. -/
text : String → Format
| /-- `nest n f` tells the formatter that `f` is nested inside something with length `n`
so that it is pretty-printed with the correct indentation on a line break.
For example, we can define a formatter for list `l : List Format` as:
```
let f := join <| l.intersperse <| ", " ++ Format.line
group (nest 1 <| "[" ++ f ++ "]")
```
This will be written all on one line, but if the text is too large,
the formatter will put in linebreaks after the commas and indent later lines by 1.
-/
nest (indent : Int) : Format → Format
| /-- Concatenation of two Formats. -/
append : Format → Format → Format
| /-- Creates a new flattening group for the given inner format. -/
group : Format → (behavior : FlattenBehavior := FlattenBehavior.allOrNone) → Format
| /-- Used for associating auxiliary information (e.g. `Expr`s) with `Format` objects. -/
tag : Nat → Format → Format
deriving Inhabited
namespace Format
/-- Check whether the given format contains no characters. -/
def isEmpty : Format → Bool
| nil => true
| line => false
@ -38,6 +76,7 @@ def isEmpty : Format → Bool
| group f _ => f.isEmpty
| tag _ f => f.isEmpty
/-- Alias for a group with `FlattenBehavior` set to `fill`. -/
def fill (f : Format) : Format :=
group f (behavior := FlattenBehavior.fill)
@ -182,31 +221,43 @@ private partial def be (w : Nat) [Monad m] [MonadPrettyFormat m] : List WorkGrou
else
pushGroup flb [{ i with f }] (gs' is) w >>= be w
/-- Render the given `f : Format` with a line width of `w`.
`indent` is the starting amount to indent each line by. -/
def prettyM (f : Format) (w : Nat) (indent : Nat := 0) [Monad m] [MonadPrettyFormat m] : m Unit :=
be w [{ flb := FlattenBehavior.allOrNone, flatten := false, items := [{ f := f, indent, activeTags := 0 }]}]
/-- Create a format `l ++ f ++ r` with a flatten group.
FlattenBehaviour is `allOrNone`; for `fill` use `bracketFill`. -/
@[inline] def bracket (l : String) (f : Format) (r : String) : Format :=
group (nest l.length $ l ++ f ++ r)
/-- Creates the format `"(" ++ f ++ ")"` with a flattening group.-/
@[inline] def paren (f : Format) : Format :=
bracket "(" f ")"
/-- Creates the format `"(" ++ f ++ ")"` with a flattening group.-/
@[inline] def sbracket (f : Format) : Format :=
bracket "[" f "]"
/-- Same as `bracket` except uses the `fill` flattening behaviour. -/
@[inline] def bracketFill (l : String) (f : Format) (r : String) : Format :=
fill (nest l.length $ l ++ f ++ r)
/-- Default indentation. -/
def defIndent := 2
def defUnicode := true
/-- Default width of the targeted output pane. -/
def defWidth := 120
/-- Nest with the default indentation amount.-/
def nestD (f : Format) : Format :=
nest defIndent f
/-- Insert a newline and then `f`, all nested by the default indent amount. -/
def indentD (f : Format) : Format :=
nestD (Format.line ++ f)
/-- State for formatting a pretty string. -/
private structure State where
out : String := ""
column : Nat := 0
@ -227,6 +278,8 @@ def pretty (f : Format) (w : Nat := defWidth) : String :=
end Format
/-- Class for converting a given type α to a `Format` object for pretty-printing.
See also `Repr`, which also outputs a `Format` object. -/
class ToFormat (α : Type u) where
format : α → Format
@ -239,15 +292,18 @@ instance : ToFormat Format where
instance : ToFormat String where
format s := Format.text s
/-- Intersperse the given list (each item printed with `format`) with the given `sep` format. -/
def Format.joinSep {α : Type u} [ToFormat α] : List α → Format → Format
| [], _ => nil
| [a], _ => format a
| a::as, sep => format a ++ sep ++ joinSep as sep
/-- format each item in `items` and prepend prefix `pre`. -/
def Format.prefixJoin {α : Type u} [ToFormat α] (pre : Format) : List α → Format
| [] => nil
| a::as => pre ++ format a ++ prefixJoin pre as
/-- format each item in `items` and append `suffix`. -/
def Format.joinSuffix {α : Type u} [ToFormat α] : List α → Format → Format
| [], _ => nil
| a::as, suffix => format a ++ suffix ++ joinSuffix as suffix

View file

@ -38,6 +38,9 @@ partial def formatStxAux (maxDepth : Option Nat) (showInfo : Bool) : Nat → Syn
if args.size > 0 && depth > maxDepth.getD depth then [".."] else args.toList.map (formatStxAux maxDepth showInfo depth);
paren $ joinSep (header :: body) line
/-- Pretty print the given syntax `stx` as a `Format`.
Nodes deeper than `maxDepth` are omitted.
Setting the `showInfo` flag will also print the `SourceInfo` for each node. -/
def formatStx (stx : Syntax) (maxDepth : Option Nat := none) (showInfo := false) : Format :=
formatStxAux maxDepth showInfo 0 stx