mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
Allow parenthesized content exceed configured line width (#7490)
This commit is contained in:
parent
5849a75223
commit
192463c2fb
13 changed files with 171 additions and 151 deletions
|
@ -2155,15 +2155,18 @@ impl<Context> std::fmt::Debug for IndentIfGroupBreaks<'_, Context> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Changes the definition of *fits* for `content`. Instead of measuring it in *flat*, measure it with
|
||||
/// all line breaks expanded and test if no line exceeds the line width. The [`FitsExpanded`] acts
|
||||
/// as a expands boundary similar to best fitting, meaning that a [`hard_line_break`] will not cause the parent group to expand.
|
||||
/// Changes the definition of *fits* for `content`. It measures the width of all lines and allows
|
||||
/// the content inside of the [`fits_expanded`] to exceed the configured line width. The content
|
||||
/// coming before and after [`fits_expanded`] must fit into the configured line width.
|
||||
///
|
||||
/// The [`fits_expanded`] acts as a expands boundary similar to best fitting,
|
||||
/// meaning that a [`hard_line_break`] will not cause the parent group to expand.
|
||||
///
|
||||
/// Useful in conjunction with a group with a condition.
|
||||
///
|
||||
/// ## Examples
|
||||
/// The outer group with the binary expression remains *flat* regardless of the array expression
|
||||
/// that spans multiple lines.
|
||||
/// The outer group with the binary expression remains *flat* regardless of the array expression that
|
||||
/// spans multiple lines with items exceeding the configured line width.
|
||||
///
|
||||
/// ```
|
||||
/// # use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions, write};
|
||||
|
@ -2183,7 +2186,7 @@ impl<Context> std::fmt::Debug for IndentIfGroupBreaks<'_, Context> {
|
|||
/// token("["),
|
||||
/// soft_block_indent(&format_args![
|
||||
/// token("a,"), space(), token("# comment"), expand_parent(), soft_line_break_or_space(),
|
||||
/// token("b")
|
||||
/// token("'A very long string that exceeds the configured line width of 80 characters but the enclosing binary expression still fits.'")
|
||||
/// ]),
|
||||
/// token("]")
|
||||
/// ]))
|
||||
|
@ -2194,7 +2197,7 @@ impl<Context> std::fmt::Debug for IndentIfGroupBreaks<'_, Context> {
|
|||
/// let formatted = format!(SimpleFormatContext::default(), [content])?;
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// "a + [\n\ta, # comment\n\tb\n]",
|
||||
/// "a + [\n\ta, # comment\n\t'A very long string that exceeds the configured line width of 80 characters but the enclosing binary expression still fits.'\n]",
|
||||
/// formatted.print()?.as_code()
|
||||
/// );
|
||||
/// # Ok(())
|
||||
|
|
|
@ -84,11 +84,14 @@ pub enum Tag {
|
|||
StartFitsExpanded(FitsExpanded),
|
||||
EndFitsExpanded,
|
||||
|
||||
/// Marks the start and end of a best-fitting variant.
|
||||
StartBestFittingEntry,
|
||||
EndBestFittingEntry,
|
||||
|
||||
/// Parenthesizes the content but only if adding the parentheses and indenting the content
|
||||
/// makes the content fit in the configured line width.
|
||||
///
|
||||
/// See [`crate::builders::best_fit_parenthesize`] for an in-depth explanation.
|
||||
StartBestFitParenthesize {
|
||||
id: Option<GroupId>,
|
||||
},
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use crate::prelude::*;
|
||||
use std::cell::OnceCell;
|
||||
use std::marker::PhantomData;
|
||||
|
|
|
@ -1183,7 +1183,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
|||
// line break should be printed as regular line break
|
||||
return Ok(Fits::Yes);
|
||||
}
|
||||
MeasureMode::AllLines => {
|
||||
MeasureMode::AllLines | MeasureMode::AllLinesAllowTextOverflow => {
|
||||
// Continue measuring on the next line
|
||||
self.state.line_width = 0;
|
||||
self.state.pending_indent = args.indention();
|
||||
|
@ -1354,9 +1354,11 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
|||
}
|
||||
|
||||
FormatElement::Tag(StartLineSuffix { reserved_width }) => {
|
||||
self.state.line_width += reserved_width;
|
||||
if self.state.line_width > self.options().line_width.into() {
|
||||
return Ok(Fits::No);
|
||||
if *reserved_width > 0 {
|
||||
self.state.line_width += reserved_width;
|
||||
if self.state.line_width > self.options().line_width.into() {
|
||||
return Ok(Fits::No);
|
||||
}
|
||||
}
|
||||
self.queue.skip_content(TagKind::LineSuffix);
|
||||
self.state.has_line_suffix = true;
|
||||
|
@ -1370,32 +1372,42 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
|||
condition,
|
||||
propagate_expand,
|
||||
})) => {
|
||||
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)?,
|
||||
None => args.mode(),
|
||||
match args.mode() {
|
||||
PrintMode::Expanded => {
|
||||
// As usual, nothing to measure
|
||||
self.stack.push(TagKind::FitsExpanded, args);
|
||||
}
|
||||
PrintMode::Flat => {
|
||||
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)?
|
||||
}
|
||||
None => args.mode(),
|
||||
};
|
||||
|
||||
condition.mode == group_mode
|
||||
}
|
||||
None => true,
|
||||
};
|
||||
|
||||
condition.mode == group_mode
|
||||
}
|
||||
None => true,
|
||||
};
|
||||
if condition_met {
|
||||
// Measure in fully expanded mode and allow overflows
|
||||
self.stack.push(
|
||||
TagKind::FitsExpanded,
|
||||
args.with_measure_mode(MeasureMode::AllLinesAllowTextOverflow)
|
||||
.with_print_mode(PrintMode::Expanded),
|
||||
);
|
||||
} else {
|
||||
if propagate_expand.get() {
|
||||
return Ok(Fits::No);
|
||||
}
|
||||
|
||||
if condition_met {
|
||||
// Measure in fully expanded mode.
|
||||
self.stack.push(
|
||||
TagKind::FitsExpanded,
|
||||
args.with_print_mode(PrintMode::Expanded)
|
||||
.with_measure_mode(MeasureMode::AllLines),
|
||||
);
|
||||
} else {
|
||||
if propagate_expand.get() && args.mode().is_flat() {
|
||||
return Ok(Fits::No);
|
||||
// As usual
|
||||
self.stack.push(TagKind::FitsExpanded, args);
|
||||
}
|
||||
}
|
||||
|
||||
// As usual
|
||||
self.stack.push(TagKind::FitsExpanded, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1482,7 +1494,8 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
|||
}
|
||||
match args.measure_mode() {
|
||||
MeasureMode::FirstLine => return Fits::Yes,
|
||||
MeasureMode::AllLines => {
|
||||
MeasureMode::AllLines
|
||||
| MeasureMode::AllLinesAllowTextOverflow => {
|
||||
self.state.line_width = 0;
|
||||
continue;
|
||||
}
|
||||
|
@ -1498,7 +1511,9 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
|||
}
|
||||
}
|
||||
|
||||
if self.state.line_width > self.options().line_width.into() {
|
||||
if self.state.line_width > self.options().line_width.into()
|
||||
&& !args.measure_mode().allows_text_overflow()
|
||||
{
|
||||
return Fits::No;
|
||||
}
|
||||
|
||||
|
@ -1601,6 +1616,17 @@ enum MeasureMode {
|
|||
/// The content only fits if none of the lines exceed the print width. Lines are terminated by either
|
||||
/// a hard line break or a soft line break in [`PrintMode::Expanded`].
|
||||
AllLines,
|
||||
|
||||
/// Measures all lines and allows lines to exceed the configured line width. Useful when it only matters
|
||||
/// whether the content *before* and *after* fits.
|
||||
AllLinesAllowTextOverflow,
|
||||
}
|
||||
|
||||
impl MeasureMode {
|
||||
/// Returns `true` if this mode allows text exceeding the configured line width.
|
||||
const fn allows_text_overflow(self) -> bool {
|
||||
matches!(self, MeasureMode::AllLinesAllowTextOverflow)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BestFittingMode> for MeasureMode {
|
||||
|
|
|
@ -120,7 +120,6 @@ impl SourceMapGeneration {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum LineEnding {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue