Rust crate to help build a code formatter.
Use:
rust
let result = dprint_core::print(print_items, PrintOptions {
indent_width: 4,
max_width: 10,
// Set this to true while testing. It runs additional validation on the
// strings to ensure the print items are being parsed out correctly.
is_testing: false,
use_tabs: false,
newline_kind: "\n",
});
Or do the steps individually:
```rust // Send the print items to be transformed into write items. let writeitems = dprintcore::getwriteitems(printitems, GetWriteItemsOptions { indentwidth: 4, maxwidth: 10, istesting: false, });
// Write out the write items to a string. let result = dprintcore::printwriteitems(writeitems, PrintWriteItemsOptions { usetabs: false, newlinekind: "\n", indent_width: 4, }) ```
This reimplements the example from overview.md, but in rust.
Given the following AST nodes:
```rust enum Node { ArrayLiteralExpression(ArrayLiteralExpression), ArrayElement(ArrayElement), }
struct Position { /// Line number in the original source code. pub linenumber: u32, /// Column number in the original source code. pub columnnumber: u32, }
struct ArrayLiteralExpression {
pub position: Position,
pub elements: Vec
struct ArrayElement { pub position: Position, pub text: String, } ```
With the following expected outputs (when max line width configured in printer is 10):
```ts // input [a , b , c ] // output [a, b, c]
// input [four, four, four] // output (since it exceeds the line width of 10) [ four, four, four ]
// input [ four] // output (since first element was placed on a different line) [ four ] ```
Here's some example IR generation:
```rust extern crate dprint_core;
use dprint_core::*;
pub fn format(expr: ArrayLiteralExpression) -> String { // Parse out the print items from the AST. let printitems = parsenode(Node::ArrayLiteralExpression(expr));
// print them
dprint_core::print(print_items, GetWriteItemsOptions {
indent_width: 4,
max_width: 10,
is_testing: false,
use_tabs: false,
newline_kind: "\n",
});
}
// node parsing functions
fn parse_node(node: Node) -> Vec
match node {
Node::ArrayLiteralExpression(expr) => parse_array_literal_expression(&expr),
Node::ArrayElement(array_element) => parse_array_element(&array_element),
}
}
fn parsearrayliteralexpression(expr: &ArrayLiteralExpression) -> Vec
items.push(start_info.into());
items.push("[".into());
items.push(if_true(is_multiple_lines.clone(), PrintItem::NewLine));
let parsed_elements = parse_elements(&expr.elements, &is_multiple_lines);
items.push(Condition::new("indentIfMultipleLines", ConditionProperties {
condition: Box::new(is_multiple_lines.clone()),
true_path: Some(with_indent(parsed_elements.clone())),
false_path: Some(parsed_elements),
}).into());
items.push(if_true(is_multiple_lines, PrintItem::NewLine));
items.push("]".into());
items.push(end_info.into());
return items;
fn parse_elements(
elements: &Vec<ArrayElement>,
is_multiple_lines: &(impl Fn(&mut ConditionResolverContext) -> Option<bool> + Clone + 'static)
) -> Vec<PrintItem> {
let mut items = Vec::new();
for i in 0..elements.len() {
items.extend_from_slice(&parse_node(Node::ArrayElement(elements[i].clone())));
if i < elements.len() - 1 {
items.push(",".into());
items.push(if_true_or(
is_multiple_lines.clone(),
PrintItem::NewLine,
PrintItem::SpaceOrNewLine
));
}
}
items
}
}
fn parsearrayelement(element: &ArrayElement) -> Vec
// helper functions
fn createismultiplelinesresolver(
parentposition: Position,
childpositions: Vec
return move |condition_context: &mut ConditionResolverContext| {
// no items, so format on the same line
if child_positions.len() == 0 {
return Some(false);
}
// first child is on a different line than the start of the parent
// so format all the children as multi-line
if parent_position.line_number < child_positions[0].line_number {
return Some(true);
}
// check if it spans multiple lines, and if it does then make it multi-line
let resolved_start_info = condition_context.get_resolved_info(&captured_start_info).unwrap();
let optional_resolved_end_info = condition_context.get_resolved_info(&captured_end_info);
optional_resolved_end_info.map(|resolved_end_info| {
resolved_start_info.line_number < resolved_end_info.line_number
})
};
}
fn with_indent(mut elements: Vec
fn iftrue(
resolver: impl Fn(&mut ConditionResolverContext) -> Option
fn iftrueor(
resolver: impl Fn(&mut ConditionResolverContext) -> Option