3 unstable releases
0.2.0 | Apr 23, 2024 |
---|---|
0.1.1 | Sep 25, 2023 |
0.1.0 | Sep 16, 2023 |
#616 in Text processing
5,461 downloads per month
Used in 15 crates
(5 directly)
36KB
325 lines
tiny_pretty
Tiny implementation of Wadler-style pretty printing algorithm, with some advanced options like controlling line break and indentation kind.
For tutorial and API documentation, please refer to docs.rs.
Credits
License
MIT License
Copyright (c) 2023-present Pig Fang
lib.rs
:
Tiny implementation of Wadler-style pretty printing algorithm.
Basic Usage
Supposed we're going to print a code snippet of function calls, and we already have data structure defined as:
struct FunctionCall {
name: String,
args: Vec<FunctionCall>,
}
We may have a function call that is very very long, so we need to pretty print it for better readability. Our function call may behave like:
let fn_call = FunctionCall {
name: "foo".into(),
args: vec![
FunctionCall { name: "really_long_arg".into(), args: vec![] },
FunctionCall { name: "omg_so_many_parameters".into(), args: vec![] },
FunctionCall { name: "we_should_refactor_this".into(), args: vec![] },
FunctionCall { name: "is_there_seriously_another_one".into(), args: vec![] },
],
};
(This example is copied from Prettier with modifications.)
Now we're going to implement about building [Doc
] from the data structure above.
We expect arguments should be placed on a single line as possible.
If they're too long to fit, we insert line break with indentation:
- When being on a single line, there're no spaces after left paren and before right paren, and there must be a space after each argument comma.
- When being splitted into different lines, there must be indentation when printing arguments, and there must be a line break between arguments.
So, we can build [Doc
] like this:
use itertools::Itertools;
use tiny_pretty::Doc;
fn build_doc(fn_call: &FunctionCall) -> Doc {
Doc::text(&fn_call.name)
.append(Doc::text("("))
.append(
Doc::line_or_nil()
.append(Doc::list(Itertools::intersperse(
fn_call.args.iter().map(build_doc),
Doc::text(",").append(Doc::line_or_space())
).collect()))
.nest(2)
.append(Doc::line_or_nil())
.group()
)
.append(Doc::text(")"))
}
Once we have a [Doc
], we can pretty print it:
#
use tiny_pretty::{print, PrintOptions};
assert_eq!(r#"
foo(
really_long_arg(),
omg_so_many_parameters(),
we_should_refactor_this(),
is_there_seriously_another_one()
)"#.trim(), &print(&build_doc(&fn_call), &PrintOptions::default()));
Besides, if we have a function call which is short enough to fit on single line:
use tiny_pretty::{print, PrintOptions};
let fn_call = FunctionCall {
name: "foo".into(),
args: vec![
FunctionCall { name: "a".into(), args: vec![] },
FunctionCall { name: "b".into(), args: vec![] },
FunctionCall { name: "c".into(), args: vec![] },
FunctionCall { name: "d".into(), args: vec![] },
],
};
#
assert_eq!(
"foo(a(), b(), c(), d())",
&print(&build_doc(&fn_call), &PrintOptions::default()),
);
You can specify advanced printing options, such as controlling line break and
indentation kind. See PrintOptions
for details.
Text Width Measurement
By default, text width is measured as "visual width". This strategy makes it satisfy the width limitation visually.
But sometimes for some Unicode characters, you may want the column to
be close to width limitation as possible, though it will exceed visually.
To achieve that, please enable the unicode-width
feature gate.
Dependencies
~0–330KB