Skip to content

Commit 0672419

Browse files
committed
wadler
1 parent ef7f703 commit 0672419

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

rfcs/0029-pretty.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
feature: phil-wadler
3+
authors:
4+
- "ice1000"
5+
start_date: "2022/12/01"
6+
---
7+
8+
# Wadler-style algebraic pretty printing API for SQL
9+
10+
This RFC proposes a new API for pretty-printing pseudo "structures".
11+
The purpose of the API is to supersede the current implementation of SQL explain,
12+
and maybe more.
13+
14+
## Goals
15+
16+
+ Make the output of SQL explain "cooler" in the sense that ASCII (or Unicode) art
17+
are used to help with the readability of the output.
18+
+ Implementation-wise, the API should be extensible and not tightly coupled with
19+
the actual SQL syntax so that it can be used for other purposes.
20+
+ The current implementation is going to be replaced by the new API, if things went well.
21+
22+
## Non-goals
23+
24+
+ The new API is not designed for performance-critical applications.
25+
SQL explain is not considered to be such an application.
26+
+ The new API does not aim to be super flexible like the `pretty` crate.
27+
This gives us spaces to simplify the design and implementation.
28+
29+
## Motivation
30+
31+
I tried to use the `pretty` crate to implement SQL explain, but it turned out to be limited in many ways:
32+
33+
+ The standard Wadler-style pretty printing API only controls lines, indentation, text wrapping, etc.
34+
which is not suitable for sophisticated insertion of the box-making or table-making characters.
35+
+ It does not support "wrapping" the output in any ways. We want to make a big "box" around the output.
36+
+ It does not support the tree-making characters, which are essential but requires a stack in the doc-to-string algorithm.
37+
The standard implementation of `pretty` is a pure `(Config, Doc) -> String` algorithm with potential configurations.
38+
I believe that we essentially need to upgrade this from a reader monad to a state monad.
39+
+ It supports horizontal and vertical "squeezing" of the output (say, limit the max column/line numbers,
40+
and try to fit in by inserting/removing new lines), but we only need horizontal squeezing.
41+
42+
However, the standard Wadler-style "algebraic" pretty printing API is well-designed and can be extended to support the features we desire.
43+
I saw a screenshot by `@xxchan` on a private Slack channel that shows the SQL explain output of databend's system,
44+
which inspired me to write this RFC.
45+
46+
## Intended behavior
47+
48+
+ Users specify a preferred width, usually the width of the terminal,
49+
or 80 or 120, etc.
50+
+ The API automatically calculates the actual width of the output,
51+
based on the preferred width.
52+
+ If everything can be done in one line, the actual width is the line's width, and the output will be one-linear.
53+
+ If the output cannot be done in one line, the output will try to break down the output into multiple lines, and retry to fit the output into the preferred width for every line.
54+
+ The API supports wrapping the output with beautiful ASCII/Unicode art.
55+
56+
## Implementation
57+
58+
These contents are subject to future changes.
59+
60+
### Types
61+
62+
#### Types `XmlNode` and `Pretty` for pretty printing data
63+
64+
+ These enums are inductive-inductively defined which represents an object that can be displayed as a string.
65+
+ The width and height of the pretty-printed string can be calculated in advance.
66+
+ Instances of the enum `Pretty` are hereafter called "pretty" or "pretties".
67+
+ Instances of struct `XmlNode` represent XML-like data that has a name, a list of attributes, and a list of children nodes.
68+
69+
Variants of `Pretty`:
70+
71+
+ Variant `Record` that brutally pretty-prints an XML-like data.
72+
+ It contains an XML node.
73+
+ Variant `Array` that brutally pretty-prints an array-like data.
74+
+ It contains a list of pretties.
75+
+ Variant `Text` that pretty-prints a string.
76+
+ It contains a copy-on-write string.
77+
78+
#### Record `PrettyConfig` for pretty printing configuration
79+
80+
It contains indentation, preferred width, etc.
81+
82+
#### Record `LinedBuffer` for actually writing the string
83+
84+
It contains a mutable reference to a `String`, and a `PrettyConfig`.
85+
It understands the intended width (precomputed by `PrettyConfig::interesting_*`),
86+
and will try to fill an incomplete line with spaces when asked so.
87+
88+
### Important methods
89+
90+
+ `Pretty::ol_len_*(&self) -> usize`
91+
+ Returns the length of the pretty-printed string, under a one-linear setting.
92+
+ `Pretty::ol_build_string_*(&self, build: &mut String)`
93+
+ Builds the pretty-printed string, under a one-linear setting.
94+
+ `PrettyConfig::interesting_*`
95+
+ Predicts the width and the total length of the pretty-printed string.
96+
+ `LinedBuffer::line_*` (private)
97+
+ Generate a line, **without** the starting `|` and the ending `|` and the indentations.
98+
It will try to fill the intermediate spaces and lines, but not the surrounding.
99+
+ `PrettyConfig::horizon`
100+
+ Generates a line of a given length with `+` at the ends and `-` in the middle.
101+
+ `PrettyConfig::ascii`
102+
+ Calls `interesting` to predict the output width, and then generate the beautiful output, using pure ASCII style.
103+
+ `PrettyConfig::unicode`
104+
+ Calls `interesting` to predict the output width, and then generate the beautiful output, using Unicode table-making characters.
105+
106+
### Edge cases
107+
108+
+ All methods handle empty lists and no-children records. No-field records are not tested yet.

0 commit comments

Comments
 (0)