Skip to content
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 Printer group modes #6815

Merged
merged 1 commit into from
Aug 24, 2023
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
12 changes: 11 additions & 1 deletion crates/ruff_formatter/src/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::prelude::TagKind;
use crate::GroupId;
use ruff_text_size::TextRange;
use std::error::Error;

Expand Down Expand Up @@ -86,7 +87,9 @@ pub enum InvalidDocumentError {
/// Text
/// EndGroup
/// ```
StartTagMissing { kind: TagKind },
StartTagMissing {
kind: TagKind,
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice


/// Expected a specific start tag but instead is:
/// - at the end of the document
Expand All @@ -96,6 +99,10 @@ pub enum InvalidDocumentError {
expected_start: TagKind,
actual: ActualStart,
},

UnknownGroupId {
group_id: GroupId,
},
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
Expand Down Expand Up @@ -148,6 +155,9 @@ impl std::fmt::Display for InvalidDocumentError {
}
}
}
InvalidDocumentError::UnknownGroupId { group_id } => {
std::write!(f, "Encountered unknown group id {group_id:?}. Ensure that the group with the id {group_id:?} exists and that the group is a parent of or comes before the element referring to it.")
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/ruff_formatter/src/group_id.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::num::NonZeroU32;
use std::sync::atomic::{AtomicU32, Ordering};

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct DebugGroupId {
value: NonZeroU32,
#[cfg_attr(feature = "serde", serde(skip))]
name: &'static str,
}

Expand All @@ -28,6 +30,7 @@ impl std::fmt::Debug for DebugGroupId {
/// See [`crate::Formatter::group_id`] on how to get a unique id.
#[repr(transparent)]
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ReleaseGroupId {
value: NonZeroU32,
}
Expand Down
136 changes: 68 additions & 68 deletions crates/ruff_formatter/src/printer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,40 @@ impl<'a> Printer<'a> {
}

FormatElement::Tag(StartGroup(group)) => {
let print_mode =
self.print_group(TagKind::Group, group.mode(), args, queue, stack)?;
let print_mode = match group.mode() {
GroupMode::Expand | GroupMode::Propagated => PrintMode::Expanded,
GroupMode::Flat => {
self.flat_group_print_mode(TagKind::Group, group.id(), args, queue, stack)?
}
};

if let Some(id) = group.id() {
self.state.group_modes.insert_print_mode(id, print_mode);
}

stack.push(TagKind::Group, args.with_print_mode(print_mode));
}

FormatElement::Tag(StartConditionalGroup(group)) => {
let condition = group.condition();
let expected_mode = match condition.group_id {
None => args.mode(),
Some(id) => self.state.group_modes.unwrap_print_mode(id, element),
Some(id) => self.state.group_modes.get_print_mode(id)?,
};

if expected_mode == condition.mode {
self.print_group(TagKind::ConditionalGroup, group.mode(), args, queue, stack)?;
let print_mode = match group.mode() {
GroupMode::Expand | GroupMode::Propagated => PrintMode::Expanded,
GroupMode::Flat => self.flat_group_print_mode(
TagKind::ConditionalGroup,
None,
args,
queue,
stack,
)?,
};

stack.push(TagKind::ConditionalGroup, args.with_print_mode(print_mode));
} else {
// Condition isn't met, render as normal content
stack.push(TagKind::ConditionalGroup, args);
Expand Down Expand Up @@ -193,7 +210,7 @@ impl<'a> Printer<'a> {
FormatElement::Tag(StartConditionalContent(Condition { mode, group_id })) => {
let group_mode = match group_id {
None => args.mode(),
Some(id) => self.state.group_modes.unwrap_print_mode(*id, element),
Some(id) => self.state.group_modes.get_print_mode(*id)?,
};

if *mode == group_mode {
Expand All @@ -204,7 +221,7 @@ impl<'a> Printer<'a> {
}

FormatElement::Tag(StartIndentIfGroupBreaks(group_id)) => {
let group_mode = self.state.group_modes.unwrap_print_mode(*group_id, element);
let group_mode = self.state.group_modes.get_print_mode(*group_id)?;

let args = match group_mode {
PrintMode::Flat => args,
Expand Down Expand Up @@ -237,9 +254,7 @@ impl<'a> Printer<'a> {
let condition_met = match condition {
Some(condition) => {
let group_mode = match condition.group_id {
Some(group_id) => {
self.state.group_modes.unwrap_print_mode(group_id, element)
}
Some(group_id) => self.state.group_modes.get_print_mode(group_id)?,
None => args.mode(),
};

Expand Down Expand Up @@ -289,47 +304,46 @@ impl<'a> Printer<'a> {
result
}

fn print_group(
fn flat_group_print_mode(
&mut self,
kind: TagKind,
mode: GroupMode,
id: Option<GroupId>,
args: PrintElementArgs,
queue: &PrintQueue<'a>,
stack: &mut PrintCallStack,
) -> PrintResult<PrintMode> {
let group_mode = match mode {
GroupMode::Expand | GroupMode::Propagated => PrintMode::Expanded,
GroupMode::Flat => {
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
// Thus, just continue in flat mode
PrintMode::Flat
}
// The printer is either in expanded mode or it's necessary to re-measure if the group fits
// because the printer printed a line break
_ => {
self.state.measured_group_fits = true;

// Measure to see if the group fits up on a single line. If that's the case,
// print the group in "flat" mode, otherwise continue in expanded mode
stack.push(kind, args.with_print_mode(PrintMode::Flat));
let fits = self.fits(queue, stack)?;
stack.pop(kind)?;

if fits {
PrintMode::Flat
} else {
PrintMode::Expanded
}
}
let print_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
// Thus, just continue in flat mode
PrintMode::Flat
}
// The printer is either in expanded mode or it's necessary to re-measure if the group fits
// because the printer printed a line break
_ => {
self.state.measured_group_fits = true;

if let Some(id) = id {
self.state
.group_modes
.insert_print_mode(id, PrintMode::Flat);
}

// Measure to see if the group fits up on a single line. If that's the case,
// print the group in "flat" mode, otherwise continue in expanded mode
stack.push(kind, args.with_print_mode(PrintMode::Flat));
let fits = self.fits(queue, stack)?;
stack.pop(kind)?;

if fits {
PrintMode::Flat
} else {
PrintMode::Expanded
}
}
};

stack.push(kind, args.with_print_mode(group_mode));

Ok(group_mode)
Ok(print_mode)
}

fn print_text(&mut self, text: &str, source_range: Option<TextRange>) {
Expand Down Expand Up @@ -785,17 +799,15 @@ impl GroupModes {
self.0[index] = Some(mode);
}

fn get_print_mode(&self, group_id: GroupId) -> Option<PrintMode> {
fn get_print_mode(&self, group_id: GroupId) -> PrintResult<PrintMode> {
let index = u32::from(group_id) as usize;
self.0
.get(index)
.and_then(|option| option.as_ref().copied())
}

fn unwrap_print_mode(&self, group_id: GroupId, next_element: &FormatElement) -> PrintMode {
self.get_print_mode(group_id).unwrap_or_else(|| {
panic!("Expected group with id {group_id:?} to exist but it wasn't present in the document. Ensure that a group with such a document appears in the document before the element {next_element:?}.")
})
match self.0.get(index) {
Some(Some(print_mode)) => Ok(*print_mode),
None | Some(None) => Err(PrintError::InvalidDocument(
InvalidDocumentError::UnknownGroupId { group_id },
)),
}
}
}

Expand Down Expand Up @@ -1123,10 +1135,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {

let print_mode = match condition.group_id {
None => args.mode(),
Some(group_id) => self
.group_modes()
.get_print_mode(group_id)
.unwrap_or_else(|| args.mode()),
Some(group_id) => self.group_modes().get_print_mode(group_id)?,
};

if condition.mode == print_mode {
Expand All @@ -1143,10 +1152,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
FormatElement::Tag(StartConditionalContent(condition)) => {
let print_mode = match condition.group_id {
None => args.mode(),
Some(group_id) => self
.group_modes()
.get_print_mode(group_id)
.unwrap_or_else(|| args.mode()),
Some(group_id) => self.group_modes().get_print_mode(group_id)?,
};

if condition.mode == print_mode {
Expand All @@ -1157,10 +1163,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
}

FormatElement::Tag(StartIndentIfGroupBreaks(id)) => {
let print_mode = self
.group_modes()
.get_print_mode(*id)
.unwrap_or_else(|| args.mode());
let print_mode = self.group_modes().get_print_mode(*id)?;

match print_mode {
PrintMode::Flat => {
Expand Down Expand Up @@ -1191,10 +1194,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
let condition_met = match condition {
Some(condition) => {
let group_mode = match condition.group_id {
Some(group_id) => self
.group_modes()
.get_print_mode(group_id)
.unwrap_or_else(|| args.mode()),
Some(group_id) => self.group_modes().get_print_mode(group_id)?,
None => args.mode(),
};

Expand Down Expand Up @@ -1250,17 +1250,17 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
fn fits_group(
&mut self,
kind: TagKind,
mode: GroupMode,
group_mode: GroupMode,
id: Option<GroupId>,
args: PrintElementArgs,
) -> Fits {
if self.must_be_flat && !mode.is_flat() {
if self.must_be_flat && !group_mode.is_flat() {
return Fits::No;
}

// Continue printing groups in expanded mode if measuring a `best_fitting` element where
// a group expands.
let print_mode = if mode.is_flat() {
let print_mode = if group_mode.is_flat() {
args.mode()
} else {
PrintMode::Expanded
Expand Down
Loading