mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(prettier) Support should_break option for group doc (#1438)
This commit is contained in:
parent
822ce76402
commit
008eb0d178
8 changed files with 80 additions and 34 deletions
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ macro_rules! group {
|
|||
$(
|
||||
temp_vec.push($x);
|
||||
)*
|
||||
Doc::Group(temp_vec)
|
||||
Doc::Group($crate::doc::Group::new(temp_vec, false))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue