feat(prettier) Support should_break option for group doc (#1438)

This commit is contained in:
Cameron 2023-11-20 01:32:05 +00:00 committed by GitHub
parent 822ce76402
commit 008eb0d178
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 34 deletions

View file

@ -21,7 +21,7 @@ pub enum Doc<'a> {
/// Groups are usually nested, and the printer will try to fit everything on one line,
/// but if it doesn't fit it will break the outermost group first and try again.
/// It will continue breaking groups until everything fits (or there are no more groups to break).
Group(Vec<'a, Doc<'a>>),
Group(Group<'a>),
/// Specify a line break.
/// If an expression fits on one line, the line break will be replaced with a space.
/// Line breaks always indent the next line with the current level of indentation.
@ -36,6 +36,18 @@ pub enum Doc<'a> {
IfBreak(Box<'a, Doc<'a>>),
}
#[derive(Debug)]
pub struct Group<'a> {
pub contents: Vec<'a, Doc<'a>>,
pub should_break: bool,
}
impl<'a> Group<'a> {
pub fn new(contents: Vec<'a, Doc<'a>>, should_break: bool) -> Self {
Self { contents, should_break }
}
}
#[derive(Clone, Copy)]
#[allow(unused)]
pub enum Separator {
@ -129,15 +141,17 @@ fn print_do_to_debug(doc: &Doc<'_>) -> std::string::String {
}
string.push_str("]) \n");
}
Doc::Group(contents) => {
Doc::Group(group) => {
string.push_str("group([\n");
for (idx, doc) in contents.iter().enumerate() {
for (idx, doc) in group.contents.iter().enumerate() {
string.push_str(&print_do_to_debug(doc));
if idx != contents.len() - 1 {
if idx != group.contents.len() - 1 {
string.push_str(", ");
}
}
string.push_str("])\n");
string.push_str("], { shouldBreak: ");
string.push_str(&group.should_break.to_string());
string.push_str(" })");
}
Doc::Line => {
string.push_str("line");

View file

@ -2,7 +2,10 @@ use oxc_ast::ast::*;
use oxc_span::Span;
use crate::{
array, comment::DanglingCommentsPrintOptions, doc::Doc, group, indent, softline, ss, Prettier,
array,
comment::DanglingCommentsPrintOptions,
doc::{Doc, Group},
group, indent, softline, ss, Prettier,
};
use super::Format;
@ -68,7 +71,7 @@ pub(super) fn print_array<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Do
indent!(p, softline!(), elements)
};
parts.push(group!(p, ss!("["), parts_inner, softline!(), ss!("]")));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
}
fn print_empty_array_elements<'a>(p: &mut Prettier<'a>, array: &Array<'a, '_>) -> Doc<'a> {

View file

@ -1,7 +1,10 @@
use oxc_allocator::{Box, Vec};
use oxc_ast::ast::*;
use crate::{doc::Doc, if_break, ss, Format, Prettier};
use crate::{
doc::{Doc, Group},
if_break, ss, Format, Prettier,
};
pub(super) fn print_call_expression<'a>(
p: &mut Prettier<'a>,
@ -42,5 +45,5 @@ fn print_call_expression_arguments<'a>(
parts.push(if_break!(p, ","));
parts.push(Doc::Softline);
parts.push(ss!(")"));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
}

View file

@ -29,7 +29,7 @@ use oxc_span::GetSpan;
use crate::{
array,
doc::{Doc, Separator},
doc::{Doc, Group, Separator},
format, group, hardline, indent, line, softline, ss, string, wrap, Prettier,
};
@ -229,7 +229,7 @@ impl<'a> Format<'a> for ForInStatement<'a> {
parts.push(ss!(")"));
let body = format!(p, self.body);
parts.push(misc::adjust_clause(p, &self.body, body, false));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
})
}
}
@ -287,7 +287,7 @@ impl<'a> Format<'a> for ForOfStatement<'a> {
parts.push(ss!(")"));
let body = format!(p, self.body);
parts.push(misc::adjust_clause(p, &self.body, body, false));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
})
}
}
@ -314,7 +314,7 @@ impl<'a> Format<'a> for WhileStatement<'a> {
let body = format!(p, self.body);
parts.push(misc::adjust_clause(p, &self.body, body, false));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
})
}
}
@ -573,7 +573,7 @@ impl<'a> Format<'a> for VariableDeclaration<'a> {
parts.push(ss!(";"));
}
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
})
}
}
@ -1408,7 +1408,7 @@ impl<'a> Format<'a> for ObjectProperty<'a> {
parts.push(ss!(": "));
parts.push(format!(p, self.value));
}
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
}
}
}
@ -1660,7 +1660,7 @@ impl<'a> Format<'a> for ImportExpression<'a> {
}
parts.push(ss!(")"));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
}
}

View file

@ -1,6 +1,9 @@
use oxc_allocator::Vec;
use crate::{doc::Doc, group, if_break, line, softline, ss, Prettier};
use crate::{
doc::{Doc, Group},
group, if_break, line, softline, ss, Prettier,
};
use super::Format;
@ -36,7 +39,7 @@ pub(super) fn print_object_properties<'a, F: Format<'a>>(
}
parts.push(ss!("}"));
Doc::Group(parts)
Doc::Group(Group::new(parts, false))
};
content

View file

@ -1,6 +1,9 @@
use oxc_allocator::Vec;
use crate::{doc::Doc, hardline, Prettier};
use crate::{
doc::{Doc, Group},
hardline, Prettier,
};
use oxc_span::GetSpan;
use super::Format;
@ -17,7 +20,7 @@ pub(super) fn print_statement_sequence<'a, F: Format<'a> + GetSpan>(
if remove_last_statement_hardline && i == stmts.len() - 1 {
match docs {
Doc::Array(ref mut docs) | Doc::Group(ref mut docs) => {
Doc::Array(ref mut docs) | Doc::Group(Group { contents: ref mut docs, .. }) => {
if matches!(docs.last(), Some(Doc::Hardline)) {
docs.pop();
}

View file

@ -90,7 +90,7 @@ macro_rules! group {
$(
temp_vec.push($x);
)*
Doc::Group(temp_vec)
Doc::Group($crate::doc::Group::new(temp_vec, false))
}
};
}

View file

@ -7,7 +7,10 @@ mod command;
use std::collections::VecDeque;
use crate::{doc::Doc, PrettierOptions};
use crate::{
doc::{Doc, Group},
PrettierOptions,
};
use self::command::{Command, Indent, Mode};
@ -51,7 +54,7 @@ impl<'a> Printer<'a> {
Doc::Str(s) => self.handle_str(s),
Doc::Array(docs) => self.handle_array(indent, mode, docs),
Doc::Indent(docs) => self.handle_indent(indent, mode, docs),
Doc::Group(docs) => self.handle_group(indent, mode, docs),
Doc::Group(group) => self.handle_group(indent, mode, group),
Doc::IndentIfBreak(docs) => self.handle_indent_if_break(indent, mode, docs),
Doc::Line => self.handle_line(indent, mode),
Doc::Softline => self.handle_softline(indent, mode),
@ -78,25 +81,37 @@ impl<'a> Printer<'a> {
);
}
fn handle_group(&mut self, indent: Indent, mode: Mode, docs: oxc_allocator::Vec<'a, Doc<'a>>) {
fn handle_group(&mut self, indent: Indent, mode: Mode, group: Group<'a>) {
match mode {
Mode::Flat => {
// TODO: consider supporting `group mode` e.g. Break/Flat
self.cmds.extend(
docs.into_iter().rev().map(|doc| Command::new(indent, Mode::Flat, doc)),
);
self.cmds.extend(group.contents.into_iter().rev().map(|doc| {
Command::new(
indent,
if group.should_break { Mode::Break } else { Mode::Flat },
doc,
)
}));
}
Mode::Break => {
#[allow(clippy::cast_possible_wrap)]
let remaining_width = (self.options.print_width as isize) - (self.pos as isize);
if self.fits(&docs, indent, remaining_width) {
if !group.should_break && self.fits(&group.contents, indent, remaining_width) {
self.cmds.extend(
docs.into_iter().rev().map(|doc| Command::new(indent, Mode::Flat, doc)),
group
.contents
.into_iter()
.rev()
.map(|doc| Command::new(indent, Mode::Flat, doc)),
);
} else {
self.cmds.extend(
docs.into_iter().rev().map(|doc| Command::new(indent, Mode::Break, doc)),
group
.contents
.into_iter()
.rev()
.map(|doc| Command::new(indent, Mode::Break, doc)),
);
}
}
@ -167,10 +182,7 @@ impl<'a> Printer<'a> {
Doc::Str(string) => {
remaining_width -= string.len() as isize;
}
Doc::IndentIfBreak(docs)
| Doc::Array(docs)
| Doc::Indent(docs)
| Doc::Group(docs) => {
Doc::IndentIfBreak(docs) | Doc::Array(docs) | Doc::Indent(docs) => {
// Prepend docs to the queue
for d in docs.iter().rev() {
queue.push_front(d);
@ -180,6 +192,14 @@ impl<'a> Printer<'a> {
remaining_width -= (self.options.tab_width * indent.length) as isize;
}
}
Doc::Group(group) => {
if group.should_break {
return false;
}
for d in group.contents.iter().rev() {
queue.push_front(d);
}
}
// trying to fit on a single line, so we don't need to consider line breaks
Doc::IfBreak { .. } | Doc::Softline => {}
Doc::Line => remaining_width -= 1,