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

Commit

Permalink
feature(formatter): LineSuffixBoundary and ExpandParent IR (#2590)
Browse files Browse the repository at this point in the history
This PR introduces  two new IR elements:

* `LineSuffixBoundary`: Forces the printer to flush any pending `LineSuffix`. For example necessary to avoid a comment inside of a JSX expression accidentally getting pushed into the content of an outer element. 
* `ExpandParent`: Forces the parent group to be printed as expended. E.g. should allow us to remove the `LineSuffix` special case inside of the printer by emitting a `ExpandParent` for each block comment.

Part of #2579
  • Loading branch information
MichaReiser committed May 18, 2022
1 parent 0e4c017 commit df38024
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 19 deletions.
69 changes: 69 additions & 0 deletions crates/rome_formatter/src/format_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,29 @@ pub fn line_suffix(element: impl Into<FormatElement>) -> FormatElement {
FormatElement::LineSuffix(Box::new(element.into()))
}

/// Inserts a boundary for line suffixes that forces to print all pending line suffixes. Helpful
/// if a line sufix shouldn't pass a certain point.
///
/// ## Examples
///
/// Forces the line suffix "c" to be printed before the token `d`.
/// ```
/// use rome_formatter::Formatted;
/// use rome_formatter::prelude::*;
///
/// let elements = format_elements![token("a"), line_suffix(token("c")), token("b"), line_suffix_boundary(), token("d")];
///
/// assert_eq!(
/// "abc\nd",
/// Formatted::new(elements, PrinterOptions::default())
/// .print()
/// .as_code()
/// );
/// ```
pub const fn line_suffix_boundary() -> FormatElement {
FormatElement::LineSuffixBoundary
}

/// Mark a [FormatElement] as being a piece of trivia
///
/// This does not directly influence how this content will be printed, but some
Expand Down Expand Up @@ -712,6 +735,41 @@ pub fn group_elements_with_options(
format_elements![leading, group, trailing]
}

/// IR element that forces the parent group to print in expanded mode.
///
/// Has no effect if used outside of a group or element that introduce implicit groups (fill element).
///
/// ## Examples
///
/// ```
/// use rome_formatter::{Formatted, LineWidth};
/// use rome_formatter::prelude::*;
///
/// let elements = group_elements(format_elements![
/// token("["),
/// soft_block_indent(format_elements![
/// token("'Good morning! How are you today?',"),
/// soft_line_break_or_space(),
/// token("2,"),
/// expand_parent(), // Forces the parent to expand
/// soft_line_break_or_space(),
/// token("3"),
/// ]),
/// token("]"),
/// ]);
///
/// assert_eq!(
/// "[\n\t'Good morning! How are you today?',\n\t2,\n\t3\n]",
/// Formatted::new(elements, PrinterOptions::default()).print().as_code()
/// );
/// ```
///
/// ## Prettier
/// Equivalent to Prettier's `break_parent` IR element
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.
Expand Down Expand Up @@ -1060,6 +1118,9 @@ pub enum FormatElement {
/// See [crate::group_elements] for documentation and examples.
Group(Group),

/// Forces the parent group to print in expanded mode.
ExpandParent,

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

Expand All @@ -1079,6 +1140,10 @@ pub enum FormatElement {
/// Delay the printing of its content until the next line break
LineSuffix(Content),

/// Prevents that line suffixes move past this boundary. Forces the printer to print any pending
/// line suffixes, potentially by inserting a hard line break.
LineSuffixBoundary,

/// Special semantic element letting the printer and formatter know this is
/// a trivia content, and it should only have a limited influence on the
/// formatting (for instance line breaks contained within will not cause
Expand Down Expand Up @@ -1163,11 +1228,13 @@ impl Debug for FormatElement {
FormatElement::LineSuffix(content) => {
fmt.debug_tuple("LineSuffix").field(content).finish()
}
FormatElement::LineSuffixBoundary => write!(fmt, "LineSuffixBoundary"),
FormatElement::Comment(content) => fmt.debug_tuple("Comment").field(content).finish(),
FormatElement::Verbatim(verbatim) => fmt
.debug_tuple("Verbatim")
.field(&verbatim.element)
.finish(),
FormatElement::ExpandParent => write!(fmt, "ExpandParent"),
}
}
}
Expand Down Expand Up @@ -1556,6 +1623,8 @@ impl FormatElement {
FormatElement::LineSuffix(_) => false,
FormatElement::Comment(content) => content.will_break(),
FormatElement::Verbatim(verbatim) => verbatim.element.will_break(),
FormatElement::LineSuffixBoundary => false,
FormatElement::ExpandParent => true,
}
}

Expand Down
29 changes: 25 additions & 4 deletions crates/rome_formatter/src/printer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::format_element::{
ConditionalGroupContent, Group, LineMode, List, PrintMode, VerbatimKind,
};
use crate::intersperse::Intersperse;
use crate::{FormatElement, GroupId, Printed, SourceMarker, TextRange};
use crate::{hard_line_break, FormatElement, GroupId, Printed, SourceMarker, TextRange};

use crate::prelude::Line;
use rome_rowan::TextSize;
Expand Down Expand Up @@ -221,6 +221,11 @@ impl<'a> Printer<'a> {
.line_suffixes
.push(PrintElementCall::new(&**suffix, args));
}
FormatElement::LineSuffixBoundary => {
const HARD_BREAK: &FormatElement = &hard_line_break();
self.queue_line_suffixes(HARD_BREAK, args, queue);
}

FormatElement::Comment(content) => {
queue.enqueue(PrintElementCall::new(content.as_ref(), args));
}
Expand All @@ -235,6 +240,13 @@ impl<'a> Printer<'a> {

queue.enqueue(PrintElementCall::new(&verbatim.element, args));
}
FormatElement::ExpandParent => {
// No-op, only has an effect on `fits`
debug_assert!(
!args.mode.is_flat(),
"Fits should always return false for `ExpandParent`"
);
}
}
}

Expand Down Expand Up @@ -597,6 +609,7 @@ fn fits_on_line<'a>(
pending_indent: printer.state.pending_indent,
pending_space: printer.state.pending_space,
line_width: printer.state.line_width,
has_line_suffix: !printer.state.line_suffixes.is_empty(),
};

let result = loop {
Expand Down Expand Up @@ -738,9 +751,11 @@ fn fits_element_on_line<'a, 'rest>(
}

FormatElement::LineSuffix(_) => {
// The current behavior is to return `false` for all line suffixes if trying to print
// something in "flat" mode.
if args.mode.is_flat() {
state.has_line_suffix = true;
}

FormatElement::LineSuffixBoundary => {
if state.has_line_suffix {
return Fits::No;
}
}
Expand All @@ -750,6 +765,11 @@ fn fits_element_on_line<'a, 'rest>(
FormatElement::Verbatim(verbatim) => {
queue.enqueue(PrintElementCall::new(&verbatim.element, args))
}
FormatElement::ExpandParent => {
if args.mode.is_flat() || args.hard_group {
return Fits::No;
}
}
}

Fits::Maybe
Expand Down Expand Up @@ -779,6 +799,7 @@ impl From<bool> for Fits {
struct MeasureState {
pending_indent: u16,
pending_space: bool,
has_line_suffix: bool,
line_width: usize,
}

Expand Down
5 changes: 4 additions & 1 deletion crates/rome_js_formatter/src/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ where
]),
]
} else {
line_suffix(format_elements![space_token(), comment, space_token()])
format_elements![
line_suffix(format_elements![space_token(), comment]),
expand_parent()
]
};

elements.push(crate::comment(content));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ impl FormatNodeFields<JsAssignmentExpression> for FormatNodeRule<JsAssignmentExp
left.format(),
space_token(),
operator_token.format(),
line_suffix_boundary(),
group_elements(soft_line_indent_or_space(formatted![
formatter,
[right.format()]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ impl FormatNodeFields<JsxExpressionAttributeValue> for FormatNodeRule<JsxExpress
[
l_curly_token.format(),
formatted_expression,
line_suffix_boundary(),
r_curly_token.format(),
]
]?))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
source: crates/rome_js_formatter/tests/prettier_tests.rs
assertion_line: 144
expression: function.js

---
# Input
```js
Expand Down Expand Up @@ -89,15 +87,15 @@ f3 =
a = b, //comment
) => {};

f4 = () => {}; // Comment
f4 = // Comment
() => {};

f5 =
// Comment

() => {};

f6 =
/* comment */
f6 = /* comment */
// Comment

() => {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
source: crates/rome_js_formatter/tests/prettier_tests.rs
assertion_line: 144
expression: number.js

---
# Input
```js
Expand Down Expand Up @@ -70,8 +68,7 @@ fnNumber =
fnNumber = /* comment */ 3;
fnNumber =
/* comments0 */
fnNumber = /* comments0 */
/* comments1 */
3;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
---
source: crates/rome_js_formatter/tests/prettier_tests.rs
assertion_line: 144
expression: string.js

---
# Input
```js
Expand Down Expand Up @@ -118,12 +116,12 @@ fnString =
"long" +
"string";
fnString =
// Comment0
fnString = // Comment0
// Comment1
"some" + "long" + "string";
fnString = "some" + "long" + "string"; // Comment
fnString = // Comment
"some" + "long" + "string";
fnString =
// Comment
Expand Down

0 comments on commit df38024

Please sign in to comment.