Skip to content
This repository has been archived by the owner on Aug 31, 2023. It is now read-only.

refactor: Stabilize formatter #2597

Merged
merged 2 commits into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 11 additions & 69 deletions crates/rome_formatter/src/format_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,11 +728,15 @@ pub fn group_elements_with_options(
content: FormatElement,
options: GroupElementsOptions,
) -> FormatElement {
let (leading, content, trailing) = content.split_trivia();
if content.is_empty() {
content
} else {
let (leading, content, trailing) = content.split_trivia();

let group = Group::new(content).with_id(options.group_id);
let group = Group::new(content).with_id(options.group_id);

format_elements![leading, group, trailing]
format_elements![leading, group, trailing]
}
}

/// IR element that forces the parent group to print in expanded mode.
Expand Down Expand Up @@ -770,52 +774,6 @@ pub const fn expand_parent() -> FormatElement {
FormatElement::ExpandParent
}

/// Creates a group that forces all elements inside it to be printed on a
/// single line. This behavior can in turn be escaped by introducing an inner
/// `Group` element that will resume the normal breaking behavior of the printer.
///
/// This is useful for constructs that have a non-breaking head and a breaking
/// body, such class declarations:
/// ```js
/// abstract /* comment */ class Example
/// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ non-breaking part
/// { // <
/// } // < breaking part
/// ```
///
/// # Example
/// ```
/// use rome_formatter::Formatted;
/// use rome_formatter::prelude::*;
///
/// let elements = group_elements(hard_group_elements(format_elements![
/// if_group_breaks(token("not printed")),
/// empty_line(),
/// if_group_fits_on_single_line(token("printed")),
/// ]));
///
/// assert_eq!(
/// "\nprinted",
/// Formatted::new(elements, PrinterOptions::default())
/// .print()
/// .as_code()
/// );
/// ```
#[inline]
pub fn hard_group_elements<T: Into<FormatElement>>(content: T) -> FormatElement {
let content = content.into();

if content.is_empty() {
content
} else {
let (leading, content, trailing) = content.split_trivia();
format_elements![
leading,
FormatElement::HardGroup(Group::new(format_elements![content, trailing])),
]
}
}

/// Adds a conditional content that is emitted only if it isn't inside an enclosing `Group` that
/// is printed on a single line. The element allows, for example, to insert a trailing comma after the last
/// array element only if the array doesn't fit on a single line.
Expand Down Expand Up @@ -1121,9 +1079,6 @@ pub enum FormatElement {
/// Forces the parent group to print in expanded mode.
ExpandParent,

/// See [crate::hard_group_elements] for documentation and examples.
HardGroup(Group),

/// Allows to specify content that gets printed depending on whatever the enclosing group
/// is printed on a single line or multiple lines. See [crate::if_group_breaks] for examples.
ConditionalGroupContent(ConditionalGroupContent),
Expand Down Expand Up @@ -1215,10 +1170,6 @@ impl Debug for FormatElement {
write!(fmt, "Group")?;
content.fmt(fmt)
}
FormatElement::HardGroup(content) => {
write!(fmt, "HardGroup")?;
content.fmt(fmt)
}
FormatElement::ConditionalGroupContent(content) => content.fmt(fmt),
FormatElement::List(content) => {
write!(fmt, "List ")?;
Expand Down Expand Up @@ -1678,9 +1629,7 @@ impl FormatElement {
FormatElement::Space => false,
FormatElement::Line(line) => matches!(line.mode, LineMode::Hard | LineMode::Empty),
FormatElement::Indent(indent) => indent.content.will_break(),
FormatElement::Group(group) | FormatElement::HardGroup(group) => {
group.content.will_break()
}
FormatElement::Group(group) => group.content.will_break(),
FormatElement::ConditionalGroupContent(group) => group.content.will_break(),
FormatElement::List(list) | FormatElement::Fill(list) => {
list.content.iter().any(FormatElement::will_break)
Expand All @@ -1697,8 +1646,8 @@ impl FormatElement {

/// Splits off the leading and trailing trivias (comments) from this [FormatElement]
///
/// For [FormatElement::HardGroup] and [FormatElement::Group], the trailing and leading trivias
/// are automatically moved outside of the group. The group itself is then recreated around the
/// For [FormatElement::HardGroup], the trailing trivia
/// is automatically moved outside of the group. The group itself is then recreated around the
/// content itself.
pub fn split_trivia(self) -> (FormatElement, FormatElement, FormatElement) {
match self {
Expand Down Expand Up @@ -1737,11 +1686,6 @@ impl FormatElement {
(FormatElement::List(list), empty_element(), empty_element())
}
}
FormatElement::HardGroup(group) => {
let (leading, content, trailing) = group.content.split_trivia();
// re-create the grouping around the content only
(leading, hard_group_elements(content), trailing)
}
// Non-list elements are returned directly
_ => (empty_element(), self, empty_element()),
}
Expand All @@ -1759,9 +1703,7 @@ impl FormatElement {
FormatElement::Empty | FormatElement::Line(_) | FormatElement::Comment(_) => None,

FormatElement::Indent(indent) => indent.content.last_element(),
FormatElement::Group(group) | FormatElement::HardGroup(group) => {
group.content.last_element()
}
FormatElement::Group(group) => group.content.last_element(),

_ => Some(self),
}
Expand Down
10 changes: 5 additions & 5 deletions crates/rome_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ use crate::printer::{Printer, PrinterOptions};
pub use builders::ConcatBuilder;
pub use format_element::{
block_indent, comment, concat_elements, empty_element, empty_line, fill_elements,
group_elements, hard_group_elements, hard_line_break, if_group_breaks,
if_group_fits_on_single_line, indent, join_elements, join_elements_hard_line,
join_elements_soft_line, join_elements_with, line_suffix, normalize_newlines,
soft_block_indent, soft_line_break, soft_line_break_or_space, soft_line_indent_or_space,
space_token, token, FormatElement, Token, Verbatim, LINE_TERMINATORS,
group_elements, hard_line_break, if_group_breaks, if_group_fits_on_single_line, indent,
join_elements, join_elements_hard_line, join_elements_soft_line, join_elements_with,
line_suffix, normalize_newlines, soft_block_indent, soft_line_break, soft_line_break_or_space,
soft_line_indent_or_space, space_token, token, FormatElement, Token, Verbatim,
LINE_TERMINATORS,
};
pub use group_id::GroupId;
use rome_rowan::{
Expand Down
126 changes: 7 additions & 119 deletions crates/rome_formatter/src/printer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,7 @@ impl<'a> Printer<'a> {
self.print_str(token);
}

FormatElement::HardGroup(group) => queue.enqueue(PrintElementCall::new(
&group.content,
args.with_hard_group(true),
)),

FormatElement::Group(Group { content, id }) => {
let args = args.with_hard_group(false);

let group_mode = match args.mode {
PrintMode::Flat if self.state.measured_group_fits => {
// A parent group has already verified that this group fits on a single line
Expand Down Expand Up @@ -177,17 +170,13 @@ impl<'a> Printer<'a> {
}
};

if args.hard_group {
if mode == &PrintMode::Flat {
queue.enqueue(PrintElementCall::new(content, args));
}
} else if &group_mode == mode {
if &group_mode == mode {
queue.enqueue(PrintElementCall::new(content, args));
}
}

FormatElement::Line(line) => {
if (args.mode.is_flat() || args.hard_group)
if args.mode.is_flat()
&& matches!(line.mode, LineMode::Soft | LineMode::SoftOrSpace)
{
if line.mode == LineMode::SoftOrSpace && self.state.line_width > 0 {
Expand Down Expand Up @@ -525,7 +514,6 @@ impl PrinterState<'_> {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct PrintElementArgs {
indent: u16,
hard_group: bool,
mode: PrintMode,
}

Expand All @@ -542,11 +530,6 @@ impl PrintElementArgs {
self
}

pub fn with_hard_group(mut self, hard_group: bool) -> Self {
self.hard_group = hard_group;
self
}

pub fn with_print_mode(mut self, mode: PrintMode) -> Self {
self.mode = mode;
self
Expand All @@ -557,7 +540,6 @@ impl Default for PrintElementArgs {
fn default() -> Self {
Self {
indent: 0,
hard_group: false,
mode: PrintMode::Expanded,
}
}
Expand Down Expand Up @@ -703,16 +685,14 @@ fn fits_element_on_line<'a, 'rest>(
}

FormatElement::Line(line) => {
if args.mode.is_flat() || args.hard_group {
if args.mode.is_flat() {
match line.mode {
LineMode::SoftOrSpace => {
state.pending_space = true;
}
LineMode::Soft => {}
LineMode::Hard | LineMode::Empty => {
// Propagate the line break to make it break the parent too, except if this is
// a hard group that ALWAYS fits on a single line.
return Fits::from(args.hard_group);
return Fits::No;
}
}
} else {
Expand All @@ -729,21 +709,13 @@ fn fits_element_on_line<'a, 'rest>(
args.with_incremented_indent(),
)),

FormatElement::HardGroup(group) => queue.enqueue(PrintElementCall::new(
&group.content,
args.with_hard_group(true),
)),
FormatElement::Group(group) => queue.enqueue(PrintElementCall::new(
&group.content,
args.with_hard_group(false).with_print_mode(PrintMode::Flat),
args.with_print_mode(PrintMode::Flat),
)),

FormatElement::ConditionalGroupContent(conditional) => {
if args.hard_group {
if conditional.mode == PrintMode::Flat {
queue.enqueue(PrintElementCall::new(&conditional.content, args))
}
} else if args.mode == conditional.mode {
if args.mode == conditional.mode {
queue.enqueue(PrintElementCall::new(&conditional.content, args))
}
}
Expand Down Expand Up @@ -813,7 +785,7 @@ fn fits_element_on_line<'a, 'rest>(
queue.enqueue(PrintElementCall::new(content, args))
}
FormatElement::ExpandParent => {
if args.mode.is_flat() || args.hard_group {
if args.mode.is_flat() {
return Fits::No;
}
}
Expand Down Expand Up @@ -1103,51 +1075,6 @@ two lines`,
assert_eq!("a\n\nb", result.as_code())
}

#[test]
fn test_sequence() {
let document = format_elements![
hard_group_elements(format_elements![
token("something"),
space_token(),
token("&&")
]),
group_elements(soft_line_indent_or_space(format_elements![
token("elsewhere"),
space_token(),
token("&&"),
soft_line_break_or_space(),
token("happy"),
space_token(),
token("&&"),
soft_line_break_or_space(),
token("thoughts"),
space_token(),
token("&&"),
soft_line_break_or_space(),
token("dldldlldldldldldldldl"),
space_token(),
token("&&"),
soft_line_break_or_space(),
token("dldldlldldldldldldldl")
])),
token(";"),
hard_line_break()
];

let printed = print_element(document);

assert_eq!(
r#"something &&
elsewhere &&
happy &&
thoughts &&
dldldlldldldldldldldl &&
dldldlldldldldldldldl;
"#,
printed.as_code()
);
}

#[test]
fn test_fill_breaks() {
let document = fill_elements(vec![
Expand Down Expand Up @@ -1205,45 +1132,6 @@ two lines`,
assert_eq!(printed.as_code(), "[1, 2, 3]; // trailing")
}

#[test]
fn hard_group_inner_group_breaks() {
let document = format_elements![hard_group_elements(format_elements![
token("do"),
space_token(),
group_elements(format_elements![token("{"), token("}")]),
space_token(),
token("while"),
space_token(),
group_elements(format_elements![
token("("),
soft_block_indent(format_elements![
hard_group_elements(token("testsomelongerid")),
space_token(),
token("&&"),
soft_line_break_or_space(),
token("thoughts"),
space_token(),
token("&&"),
soft_line_break_or_space(),
token("somethingsomethingsomethingsomethin")
]),
token(")")
]),
token(";")
])];

let printed = print_element(document);

assert_eq!(
printed.as_code(),
r#"do {} while (
testsomelongerid &&
thoughts &&
somethingsomethingsomethingsomethin
);"#
);
}

fn create_array_element(items: Vec<FormatElement>) -> FormatElement {
let separator = format_elements![token(","), soft_line_break_or_space(),];

Expand Down
Loading