-
-
Notifications
You must be signed in to change notification settings - Fork 499
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(js_formatter): Use fluid assignment layout when left side is breakable #1021
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -232,6 +232,10 @@ impl FormatElement { | |
pub const fn is_space(&self) -> bool { | ||
matches!(self, FormatElement::Space) | ||
} | ||
|
||
pub const fn is_line(&self) -> bool { | ||
matches!(self, FormatElement::Line(_)) | ||
} | ||
} | ||
|
||
impl FormatElements for FormatElement { | ||
|
@@ -253,6 +257,10 @@ impl FormatElements for FormatElement { | |
} | ||
} | ||
|
||
fn may_directly_break(&self) -> bool { | ||
matches!(self, FormatElement::Line(_)) | ||
} | ||
|
||
fn has_label(&self, label_id: LabelId) -> bool { | ||
match self { | ||
FormatElement::Tag(Tag::StartLabelled(actual)) => *actual == label_id, | ||
|
@@ -341,6 +349,15 @@ pub trait FormatElements { | |
/// lines if this element is part of a group and the group doesn't fit on a single line. | ||
fn will_break(&self) -> bool; | ||
|
||
/// Returns true if this [FormatElement] has the potential to break across multiple lines when printed. | ||
/// This is the case _only_ if this format element recursively contains a [FormatElement::Line]. | ||
/// | ||
/// It's possible for [FormatElements::will_break] to return true while this function returns false, | ||
/// such as when the group contains a [crate::builders::expand_parent] or some text within the group | ||
/// contains a newline. Neither of those cases directly contain a [FormatElement::Line], and so they | ||
/// do not _directly_ break. | ||
fn may_directly_break(&self) -> bool; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't mind the name of the function, but I wonder if at this point, we should rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Honestly I don't know which is the better name between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right. I hope to find better names , because the current ones aren't very good and the prettier code base doesn't help |
||
|
||
/// Returns true if the element has the given label. | ||
fn has_label(&self, label: LabelId) -> bool; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -576,6 +576,38 @@ impl FormatElements for [FormatElement] { | |
false | ||
} | ||
|
||
fn may_directly_break(&self) -> bool { | ||
use Tag::*; | ||
let mut ignore_depth = 0usize; | ||
|
||
for element in self { | ||
match element { | ||
// Line suffix | ||
// Ignore if any of its content breaks | ||
FormatElement::Tag(StartLineSuffix) => { | ||
ignore_depth += 1; | ||
} | ||
FormatElement::Tag(EndLineSuffix) => { | ||
ignore_depth -= 1; | ||
} | ||
FormatElement::Interned(interned) if ignore_depth == 0 => { | ||
if interned.may_directly_break() { | ||
return true; | ||
} | ||
} | ||
Comment on lines
+584
to
+597
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to not duplicate this code again, but idk a cleaner way to write it out. I think this state management is still necessary for this function, since it also shouldn't be inspecting text content on suffixes, but I'm not 100% sure. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine :) the duplicated code isn't that much |
||
|
||
element if ignore_depth == 0 && element.may_directly_break() => { | ||
return true; | ||
} | ||
_ => continue, | ||
} | ||
} | ||
|
||
debug_assert_eq!(ignore_depth, 0, "Unclosed start container"); | ||
|
||
false | ||
} | ||
|
||
fn has_label(&self, expected: LabelId) -> bool { | ||
self.first() | ||
.map_or(false, |element| element.has_label(expected)) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,10 @@ where | |
let modifiers = sort_modifiers_by_precedence(&self.list); | ||
let should_expand = should_expand_decorators(&self.list); | ||
|
||
if self.list.is_empty() { | ||
return Ok(()); | ||
} | ||
Comment on lines
+54
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returning early here is important, because otherwise this node returns a group that always has a class Test {
prop1 = // comment
true;
} Without this early escape, the IR gets written as:
and that group with just the soft line is this modifier list. With this early return, that group no longer exists, meaning the outer group won't contain any potential breaks, and the comments get formatted as expected by Prettier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a great comment, and a I think we should have it inside the code :) (maybe a variation of that) |
||
|
||
// need to use peek the iterator to check if the current node is a decorator and don't advance the iterator | ||
let mut iter = modifiers.into_iter().peekable(); | ||
let decorators = format_once(|f| { | ||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda surprised this didn't exist before. Turns out it's not actually necessary because
may_directly_break
does this check itself, but I figure this makes sense to keep around anyway.