feat(prettier) use groupId in fluid assignments (#1560)

This commit is contained in:
Cameron 2023-11-28 02:29:32 +00:00 committed by GitHub
parent 7d9d04c569
commit cda0b97ade
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 50 deletions

View file

@ -15,7 +15,7 @@ pub enum Doc<'a> {
Array(Vec<'a, Doc<'a>>),
/// Increase the level of indentation.
Indent(Vec<'a, Doc<'a>>),
IndentIfBreak(Vec<'a, Doc<'a>>),
IndentIfBreak(IndentIfBreak<'a>),
/// Mark a group of items which the printer should try to fit on one line.
/// This is the basic command to tell the printer when to break.
/// Groups are usually nested, and the printer will try to fit everything on one line,
@ -77,18 +77,33 @@ impl Line {
pub struct Group<'a> {
pub contents: Vec<'a, Doc<'a>>,
pub should_break: bool,
pub id: Option<u32>,
pub id: Option<GroupId>,
}
impl<'a> Group<'a> {
pub fn new(contents: Vec<'a, Doc<'a>>, should_break: bool) -> Self {
Self { contents, should_break, id: None }
}
pub fn with_id(mut self, id: u32) -> Self {
pub fn with_id(mut self, id: GroupId) -> Self {
self.id = Some(id);
self
}
}
#[derive(Debug)]
pub struct IndentIfBreak<'a> {
pub contents: Vec<'a, Doc<'a>>,
pub group_id: Option<GroupId>,
}
impl<'a> IndentIfBreak<'a> {
pub fn new(contents: Vec<'a, Doc<'a>>) -> Self {
Self { contents, group_id: None }
}
pub fn with_id(mut self, id: GroupId) -> Self {
self.group_id = Some(id);
self
}
}
#[derive(Debug)]
pub struct Fill<'a> {
@ -212,16 +227,21 @@ fn print_doc_to_debug(doc: &Doc<'_>) -> std::string::String {
}
string.push_str("])");
}
Doc::IndentIfBreak(contents) => {
Doc::IndentIfBreak(indent_if_break) => {
string.push_str("indentIfBreak(");
string.push_str("[\n");
for (idx, doc) in contents.iter().enumerate() {
for (idx, doc) in indent_if_break.contents.iter().enumerate() {
string.push_str(&print_doc_to_debug(doc));
if idx != contents.len() - 1 {
if idx != indent_if_break.contents.len() - 1 {
string.push_str(", ");
}
}
string.push_str("]) \n");
if let Some(id) = indent_if_break.group_id {
string.push_str(&format!(", {{id: {id}}}"));
}
string.push_str("])");
}
Doc::Group(group) => {
string.push_str("group([\n");

View file

@ -8,7 +8,7 @@ use oxc_ast::{
use crate::{
array,
doc::{Doc, DocBuilder},
doc::{Doc, DocBuilder, Group, IndentIfBreak},
group, indent, line, ss, Format, Prettier,
};
@ -67,14 +67,21 @@ fn print_assignment<'a>(
}
// First break right-hand side, then after operator
Layout::Fluid => {
group!(
p,
group!(p, left_doc),
op,
group!(p, indent!(p, line!())),
// TODO: wrap `right_doc` in indent_if_break!() when we have support for group IDs.
right_doc
)
let group_id = p.next_id();
let after_op = {
let mut parts = p.vec();
parts.push(indent!(p, line!()));
Doc::Group(Group::new(parts, false).with_id(group_id))
};
let right_doc = {
let mut parts = p.vec();
parts.push(group!(p, right_doc));
Doc::IndentIfBreak(IndentIfBreak::new(parts).with_id(group_id))
};
group!(p, group!(p, left_doc), op, after_op, right_doc)
}
Layout::BreakLhs => {
group!(p, left_doc, op, ss!(" "), group!(p, right_doc))

View file

@ -9,7 +9,7 @@ use oxc_allocator::Allocator;
use std::collections::{HashMap, VecDeque};
use crate::{
doc::{Doc, DocBuilder, Fill, IfBreak, Line},
doc::{Doc, DocBuilder, Fill, IfBreak, IndentIfBreak, Line},
GroupId, PrettierOptions,
};
@ -122,28 +122,24 @@ impl<'a> Printer<'a> {
fn handle_group(&mut self, indent: Indent, mode: Mode, doc: Doc<'a>) {
match mode {
Mode::Flat => {
let Doc::Group(group) = doc else {
return;
};
let Doc::Group(group) = doc else { unreachable!() };
self.cmds.extend(group.contents.into_iter().rev().map(|doc| {
Command::new(indent, if group.should_break { Mode::Break } else { mode }, doc)
}));
self.set_group_mode_from_last_cmd(group.id);
}
Mode::Break => {
#[allow(clippy::cast_possible_wrap)]
let remaining_width = self.remaining_width();
let Doc::Group(group) = &doc else {
return;
};
let Doc::Group(group) = &doc else { unreachable!() };
let should_break = group.should_break;
let id = group.id;
let group_id = group.id;
let cmd = Command::new(indent, Mode::Flat, doc);
if !should_break && self.fits(&cmd, remaining_width) {
self.cmds.push(Command::new(indent, Mode::Flat, cmd.doc));
} else {
let Doc::Group(group) = cmd.doc else {
return;
};
let Doc::Group(group) = cmd.doc else { unreachable!() };
self.cmds.extend(
group
.contents
@ -152,34 +148,29 @@ impl<'a> Printer<'a> {
.map(|doc| Command::new(indent, Mode::Break, doc)),
);
}
if let Some(id) = id {
let Some(mode) = self.cmds.last().map(|cmd| cmd.mode) else { return };
self.group_mode_map.insert(id, mode);
}
self.set_group_mode_from_last_cmd(group_id);
}
}
}
fn handle_indent_if_break(
&mut self,
indent: Indent,
mode: Mode,
docs: oxc_allocator::Vec<'a, Doc<'a>>,
) {
match mode {
Mode::Flat => {
self.cmds.extend(
docs.into_iter().rev().map(|doc| Command::new(indent, Mode::Flat, doc)),
);
fn handle_indent_if_break(&mut self, indent: Indent, mode: Mode, doc: IndentIfBreak<'a>) {
let IndentIfBreak { contents, group_id } = doc;
let group_mode = group_id.map_or(Some(mode), |id| self.group_mode_map.get(&id).copied());
match group_mode {
Some(Mode::Flat) => {
self.cmds
.extend(contents.into_iter().rev().map(|doc| Command::new(indent, mode, doc)));
}
Mode::Break => {
Some(Mode::Break) => {
self.cmds.extend(
docs.into_iter()
contents
.into_iter()
.rev()
.map(|doc| Command::new(Indent::new(indent.length + 1), Mode::Break, doc)),
.map(|doc| Command::new(Indent::new(indent.length + 1), mode, doc)),
);
}
None => {}
}
}
@ -341,6 +332,12 @@ impl<'a> Printer<'a> {
}
}
fn set_group_mode_from_last_cmd(&mut self, id: Option<GroupId>) {
let Some(id) = id else { return };
let Some(mode) = self.cmds.last().map(|cmd| cmd.mode) else { return };
self.group_mode_map.insert(id, mode);
}
#[allow(clippy::cast_possible_wrap)]
fn fits(&self, next: &Command<'a>, width: isize) -> bool {
let mut remaining_width = width;
@ -353,7 +350,9 @@ impl<'a> Printer<'a> {
Doc::Str(string) => {
remaining_width -= string.len() as isize;
}
Doc::IndentIfBreak(docs) | Doc::Indent(docs) | Doc::Array(docs) => {
Doc::IndentIfBreak(IndentIfBreak { contents: docs, .. })
| Doc::Indent(docs)
| Doc::Array(docs) => {
// Prepend docs to the queue
for d in docs.iter().rev() {
queue.push_front((mode, d));
@ -425,7 +424,9 @@ impl<'a> Printer<'a> {
group.should_break
}
Doc::IfBreak(d) => Self::propagate_breaks(&mut d.break_contents),
Doc::Array(arr) | Doc::Indent(arr) | Doc::IndentIfBreak(arr) => {
Doc::Array(arr)
| Doc::Indent(arr)
| Doc::IndentIfBreak(IndentIfBreak { contents: arr, .. }) => {
arr.iter_mut().any(|doc| Self::propagate_breaks(doc))
}
_ => false,

View file

@ -1,4 +1,4 @@
Compatibility: 177/591 (29.95%)
Compatibility: 178/591 (30.12%)
# Failed
@ -56,7 +56,6 @@ Compatibility: 177/591 (29.95%)
* assignment/chain.js
* assignment/discussion-15196.js
* assignment/issue-10218.js
* assignment/issue-1419.js
* assignment/issue-15534.js
* assignment/issue-2482-2.js
* assignment/issue-2540.js