mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 10:22:24 +00:00
Remove allow(pedantic)
from formatter (#6549)
This commit is contained in:
parent
c39bcbadff
commit
9584f613b9
25 changed files with 348 additions and 316 deletions
|
@ -16,7 +16,7 @@ pub(crate) fn bindings(checker: &mut Checker) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for binding in checker.semantic.bindings.iter() {
|
for binding in &*checker.semantic.bindings {
|
||||||
if checker.enabled(Rule::UnusedVariable) {
|
if checker.enabled(Rule::UnusedVariable) {
|
||||||
if binding.kind.is_bound_exception()
|
if binding.kind.is_bound_exception()
|
||||||
&& !binding.is_used()
|
&& !binding.is_used()
|
||||||
|
|
|
@ -59,7 +59,7 @@ impl Eq for LineWidth {}
|
||||||
|
|
||||||
impl PartialOrd for LineWidth {
|
impl PartialOrd for LineWidth {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
self.width.partial_cmp(&other.width)
|
Some(self.cmp(other))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,7 +114,7 @@ impl TryFrom<Options> for Settings {
|
||||||
.ignore_names
|
.ignore_names
|
||||||
.unwrap_or_else(default_ignore_names)
|
.unwrap_or_else(default_ignore_names)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(options.extend_ignore_names.unwrap_or_default().into_iter())
|
.chain(options.extend_ignore_names.unwrap_or_default())
|
||||||
.map(|name| IdentifierPattern::new(&name).map_err(SettingsError::InvalidIgnoreName))
|
.map(|name| IdentifierPattern::new(&name).map_err(SettingsError::InvalidIgnoreName))
|
||||||
.collect::<Result<Vec<_>, Self::Error>>()?,
|
.collect::<Result<Vec<_>, Self::Error>>()?,
|
||||||
classmethod_decorators: options.classmethod_decorators.unwrap_or_default(),
|
classmethod_decorators: options.classmethod_decorators.unwrap_or_default(),
|
||||||
|
|
|
@ -132,7 +132,7 @@ static FORMAT_SPECIFIER: Lazy<Regex> =
|
||||||
Lazy::new(|| Regex::new(r"\{(?P<int>\d+)(?P<fmt>.*?)}").unwrap());
|
Lazy::new(|| Regex::new(r"\{(?P<int>\d+)(?P<fmt>.*?)}").unwrap());
|
||||||
|
|
||||||
/// Remove the explicit positional indices from a format string.
|
/// Remove the explicit positional indices from a format string.
|
||||||
fn remove_specifiers<'a>(value: &mut Expression<'a>, arena: &'a mut typed_arena::Arena<String>) {
|
fn remove_specifiers<'a>(value: &mut Expression<'a>, arena: &'a typed_arena::Arena<String>) {
|
||||||
match value {
|
match value {
|
||||||
Expression::SimpleString(expr) => {
|
Expression::SimpleString(expr) => {
|
||||||
expr.value = arena.alloc(
|
expr.value = arena.alloc(
|
||||||
|
@ -217,8 +217,8 @@ fn generate_call(
|
||||||
|
|
||||||
// Fix the string itself.
|
// Fix the string itself.
|
||||||
let item = match_attribute(&mut call.func)?;
|
let item = match_attribute(&mut call.func)?;
|
||||||
let mut arena = typed_arena::Arena::new();
|
let arena = typed_arena::Arena::new();
|
||||||
remove_specifiers(&mut item.value, &mut arena);
|
remove_specifiers(&mut item.value, &arena);
|
||||||
|
|
||||||
// Remove the parentheses (first and last characters).
|
// Remove the parentheses (first and last characters).
|
||||||
let mut output = expression.codegen_stylist(stylist);
|
let mut output = expression.codegen_stylist(stylist);
|
||||||
|
|
|
@ -3,8 +3,8 @@ use crate::FormatResult;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Mono-morphed type to format an object. Used by the [crate::format!], [crate::format_args!], and
|
/// Mono-morphed type to format an object. Used by the [`crate::format`!], [`crate::format_args`!], and
|
||||||
/// [crate::write!] macros.
|
/// [`crate::write`!] macros.
|
||||||
///
|
///
|
||||||
/// This struct is similar to a dynamic dispatch (using `dyn Format`) because it stores a pointer to the value.
|
/// This struct is similar to a dynamic dispatch (using `dyn Format`) because it stores a pointer to the value.
|
||||||
/// However, it doesn't store the pointer to `dyn Format`'s vtable, instead it statically resolves the function
|
/// However, it doesn't store the pointer to `dyn Format`'s vtable, instead it statically resolves the function
|
||||||
|
@ -33,23 +33,26 @@ impl<'fmt, Context> Argument<'fmt, Context> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<F: Format<Context>>(value: &'fmt F) -> Self {
|
pub fn new<F: Format<Context>>(value: &'fmt F) -> Self {
|
||||||
|
#[allow(clippy::inline_always)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn formatter<F: Format<Context>, Context>(
|
fn formatter<F: Format<Context>, Context>(
|
||||||
ptr: *const c_void,
|
ptr: *const c_void,
|
||||||
fmt: &mut Formatter<Context>,
|
fmt: &mut Formatter<Context>,
|
||||||
) -> FormatResult<()> {
|
) -> FormatResult<()> {
|
||||||
// SAFETY: Safe because the 'fmt lifetime is captured by the 'lifetime' field.
|
// SAFETY: Safe because the 'fmt lifetime is captured by the 'lifetime' field.
|
||||||
F::fmt(unsafe { &*(ptr as *const F) }, fmt)
|
#[allow(unsafe_code)]
|
||||||
|
F::fmt(unsafe { &*ptr.cast::<F>() }, fmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
value: value as *const F as *const c_void,
|
value: (value as *const F).cast::<std::ffi::c_void>(),
|
||||||
lifetime: PhantomData,
|
lifetime: PhantomData,
|
||||||
formatter: formatter::<F, Context>,
|
formatter: formatter::<F, Context>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Formats the value stored by this argument using the given formatter.
|
/// Formats the value stored by this argument using the given formatter.
|
||||||
|
#[allow(clippy::inline_always)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn format(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
pub(super) fn format(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
(self.formatter)(self.value, f)
|
(self.formatter)(self.value, f)
|
||||||
|
@ -79,6 +82,7 @@ impl<'fmt, Context> Argument<'fmt, Context> {
|
||||||
pub struct Arguments<'fmt, Context>(pub &'fmt [Argument<'fmt, Context>]);
|
pub struct Arguments<'fmt, Context>(pub &'fmt [Argument<'fmt, Context>]);
|
||||||
|
|
||||||
impl<'fmt, Context> Arguments<'fmt, Context> {
|
impl<'fmt, Context> Arguments<'fmt, Context> {
|
||||||
|
#[allow(clippy::inline_always)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(arguments: &'fmt [Argument<'fmt, Context>]) -> Self {
|
pub fn new(arguments: &'fmt [Argument<'fmt, Context>]) -> Self {
|
||||||
|
@ -87,6 +91,7 @@ impl<'fmt, Context> Arguments<'fmt, Context> {
|
||||||
|
|
||||||
/// Returns the arguments
|
/// Returns the arguments
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::trivially_copy_pass_by_ref)] // Bug in Clippy? Sizeof Arguments is 16
|
||||||
pub(super) fn items(&self) -> &'fmt [Argument<'fmt, Context>] {
|
pub(super) fn items(&self) -> &'fmt [Argument<'fmt, Context>] {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
@ -101,6 +106,7 @@ impl<Context> Clone for Arguments<'_, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Context> Format<Context> for Arguments<'_, Context> {
|
impl<Context> Format<Context> for Arguments<'_, Context> {
|
||||||
|
#[allow(clippy::inline_always)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fmt(&self, formatter: &mut Formatter<Context>) -> FormatResult<()> {
|
fn fmt(&self, formatter: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
formatter.write_fmt(*self)
|
formatter.write_fmt(*self)
|
||||||
|
|
|
@ -7,15 +7,15 @@ use std::any::{Any, TypeId};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
/// A trait for writing or formatting into [FormatElement]-accepting buffers or streams.
|
/// A trait for writing or formatting into [`FormatElement`]-accepting buffers or streams.
|
||||||
pub trait Buffer {
|
pub trait Buffer {
|
||||||
/// The context used during formatting
|
/// The context used during formatting
|
||||||
type Context;
|
type Context;
|
||||||
|
|
||||||
/// Writes a [crate::FormatElement] into this buffer, returning whether the write succeeded.
|
/// Writes a [`crate::FormatElement`] into this buffer, returning whether the write succeeded.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// This function will return an instance of [crate::FormatError] on error.
|
/// This function will return an instance of [`crate::FormatError`] on error.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -122,7 +122,7 @@ impl BufferSnapshot {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
panic!(
|
panic!(
|
||||||
"Tried to unwrap snapshot of type {:?} as {:?}",
|
"Tried to unwrap snapshot of type {:?} as {:?}",
|
||||||
err.type_id(),
|
(*err).type_id(),
|
||||||
TypeId::of::<T>()
|
TypeId::of::<T>()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,7 @@ impl<W: Buffer<Context = Context> + ?Sized, Context> Buffer for &mut W {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
||||||
(**self).restore_snapshot(snapshot)
|
(**self).restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +426,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
||||||
self.inner.restore_snapshot(snapshot)
|
self.inner.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,59 +508,58 @@ fn clean_interned(
|
||||||
interned: &Interned,
|
interned: &Interned,
|
||||||
interned_cache: &mut FxHashMap<Interned, Interned>,
|
interned_cache: &mut FxHashMap<Interned, Interned>,
|
||||||
) -> Interned {
|
) -> Interned {
|
||||||
match interned_cache.get(interned) {
|
if let Some(cleaned) = interned_cache.get(interned) {
|
||||||
Some(cleaned) => cleaned.clone(),
|
cleaned.clone()
|
||||||
None => {
|
} else {
|
||||||
// Find the first soft line break element or interned element that must be changed
|
// Find the first soft line break element or interned element that must be changed
|
||||||
let result = interned
|
let result = interned
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(index, element)| match element {
|
.find_map(|(index, element)| match element {
|
||||||
FormatElement::Line(LineMode::Soft | LineMode::SoftOrSpace) => {
|
FormatElement::Line(LineMode::Soft | LineMode::SoftOrSpace) => {
|
||||||
let mut cleaned = Vec::new();
|
let mut cleaned = Vec::new();
|
||||||
cleaned.extend_from_slice(&interned[..index]);
|
cleaned.extend_from_slice(&interned[..index]);
|
||||||
Some((cleaned, &interned[index..]))
|
Some((cleaned, &interned[index..]))
|
||||||
}
|
|
||||||
FormatElement::Interned(inner) => {
|
|
||||||
let cleaned_inner = clean_interned(inner, interned_cache);
|
|
||||||
|
|
||||||
if &cleaned_inner != inner {
|
|
||||||
let mut cleaned = Vec::with_capacity(interned.len());
|
|
||||||
cleaned.extend_from_slice(&interned[..index]);
|
|
||||||
cleaned.push(FormatElement::Interned(cleaned_inner));
|
|
||||||
Some((cleaned, &interned[index + 1..]))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let result = match result {
|
|
||||||
// Copy the whole interned buffer so that becomes possible to change the necessary elements.
|
|
||||||
Some((mut cleaned, rest)) => {
|
|
||||||
for element in rest {
|
|
||||||
let element = match element {
|
|
||||||
FormatElement::Line(LineMode::Soft) => continue,
|
|
||||||
FormatElement::Line(LineMode::SoftOrSpace) => FormatElement::Space,
|
|
||||||
FormatElement::Interned(interned) => {
|
|
||||||
FormatElement::Interned(clean_interned(interned, interned_cache))
|
|
||||||
}
|
|
||||||
element => element.clone(),
|
|
||||||
};
|
|
||||||
cleaned.push(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
Interned::new(cleaned)
|
|
||||||
}
|
}
|
||||||
// No change necessary, return existing interned element
|
FormatElement::Interned(inner) => {
|
||||||
None => interned.clone(),
|
let cleaned_inner = clean_interned(inner, interned_cache);
|
||||||
};
|
|
||||||
|
|
||||||
interned_cache.insert(interned.clone(), result.clone());
|
if &cleaned_inner == inner {
|
||||||
result
|
None
|
||||||
}
|
} else {
|
||||||
|
let mut cleaned = Vec::with_capacity(interned.len());
|
||||||
|
cleaned.extend_from_slice(&interned[..index]);
|
||||||
|
cleaned.push(FormatElement::Interned(cleaned_inner));
|
||||||
|
Some((cleaned, &interned[index + 1..]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = match result {
|
||||||
|
// Copy the whole interned buffer so that becomes possible to change the necessary elements.
|
||||||
|
Some((mut cleaned, rest)) => {
|
||||||
|
for element in rest {
|
||||||
|
let element = match element {
|
||||||
|
FormatElement::Line(LineMode::Soft) => continue,
|
||||||
|
FormatElement::Line(LineMode::SoftOrSpace) => FormatElement::Space,
|
||||||
|
FormatElement::Interned(interned) => {
|
||||||
|
FormatElement::Interned(clean_interned(interned, interned_cache))
|
||||||
|
}
|
||||||
|
element => element.clone(),
|
||||||
|
};
|
||||||
|
cleaned.push(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
Interned::new(cleaned)
|
||||||
|
}
|
||||||
|
// No change necessary, return existing interned element
|
||||||
|
None => interned.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
interned_cache.insert(interned.clone(), result.clone());
|
||||||
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,7 +596,7 @@ impl<Context> Buffer for RemoveSoftLinesBuffer<'_, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
||||||
self.inner.restore_snapshot(snapshot)
|
self.inner.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,7 +657,7 @@ pub trait BufferExtensions: Buffer + Sized {
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = FormatElement>,
|
I: IntoIterator<Item = FormatElement>,
|
||||||
{
|
{
|
||||||
for element in elements.into_iter() {
|
for element in elements {
|
||||||
self.write_element(element)?;
|
self.write_element(element)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,12 +684,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn write_fmt(&mut self, arguments: Arguments<B::Context>) -> FormatResult<()> {
|
pub fn write_fmt(&mut self, arguments: Arguments<B::Context>) -> FormatResult<()> {
|
||||||
self.buffer.write_fmt(arguments)
|
self.buffer.write_fmt(arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
|
pub fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
|
||||||
self.buffer.write_element(element)
|
self.buffer.write_element(element)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use ruff_text_size::TextRange;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZeroU8;
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Tag::*;
|
use Tag::*;
|
||||||
|
|
||||||
/// A line break that only gets printed if the enclosing `Group` doesn't fit on a single line.
|
/// A line break that only gets printed if the enclosing `Group` doesn't fit on a single line.
|
||||||
|
@ -34,7 +35,7 @@ use Tag::*;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
/// See [soft_line_break_or_space] if you want to insert a space between the elements if the enclosing
|
/// See [`soft_line_break_or_space`] if you want to insert a space between the elements if the enclosing
|
||||||
/// `Group` fits on a single line.
|
/// `Group` fits on a single line.
|
||||||
///
|
///
|
||||||
/// Soft line breaks are emitted if the enclosing `Group` doesn't fit on a single line
|
/// Soft line breaks are emitted if the enclosing `Group` doesn't fit on a single line
|
||||||
|
@ -217,7 +218,7 @@ impl std::fmt::Debug for Line {
|
||||||
///
|
///
|
||||||
/// # Line feeds
|
/// # Line feeds
|
||||||
/// Tokens may contain line breaks but they must use the line feeds (`\n`).
|
/// Tokens may contain line breaks but they must use the line feeds (`\n`).
|
||||||
/// The [crate::Printer] converts the line feed characters to the character specified in the [crate::PrinterOptions].
|
/// The [`crate::Printer`] converts the line feed characters to the character specified in the [`crate::PrinterOptions`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -520,7 +521,7 @@ impl<Context> Format<Context> for LineSuffixBoundary {
|
||||||
///
|
///
|
||||||
/// This does not directly influence how this content will be printed, but some
|
/// This does not directly influence how this content will be printed, but some
|
||||||
/// parts of the formatter may inspect the [labelled element](Tag::StartLabelled)
|
/// parts of the formatter may inspect the [labelled element](Tag::StartLabelled)
|
||||||
/// using [FormatElements::has_label].
|
/// using [`FormatElements::has_label`].
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
///
|
///
|
||||||
|
@ -648,7 +649,7 @@ impl<Context> Format<Context> for Space {
|
||||||
/// the line breaks have to be manually added.
|
/// the line breaks have to be manually added.
|
||||||
///
|
///
|
||||||
/// This helper should be used only in rare cases, instead you should rely more on
|
/// This helper should be used only in rare cases, instead you should rely more on
|
||||||
/// [block_indent] and [soft_block_indent]
|
/// [`block_indent`] and [`soft_block_indent`]
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -970,7 +971,7 @@ impl<Context> std::fmt::Debug for Align<'_, Context> {
|
||||||
/// Block indents indent a block of code, such as in a function body, and therefore insert a line
|
/// Block indents indent a block of code, such as in a function body, and therefore insert a line
|
||||||
/// break before and after the content.
|
/// break before and after the content.
|
||||||
///
|
///
|
||||||
/// Doesn't create an indention if the passed in content is [FormatElement.is_empty].
|
/// Doesn't create an indention if the passed in content is [`FormatElement.is_empty`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -1176,7 +1177,7 @@ impl<Context> Format<Context> for BlockIndent<'_, Context> {
|
||||||
IndentMode::Soft => write!(f, [soft_line_break()])?,
|
IndentMode::Soft => write!(f, [soft_line_break()])?,
|
||||||
IndentMode::Block => write!(f, [hard_line_break()])?,
|
IndentMode::Block => write!(f, [hard_line_break()])?,
|
||||||
IndentMode::SoftLineOrSpace | IndentMode::SoftSpace => {
|
IndentMode::SoftLineOrSpace | IndentMode::SoftSpace => {
|
||||||
write!(f, [soft_line_break_or_space()])?
|
write!(f, [soft_line_break_or_space()])?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1374,17 +1375,19 @@ pub struct Group<'a, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Context> Group<'_, Context> {
|
impl<Context> Group<'_, Context> {
|
||||||
|
#[must_use]
|
||||||
pub fn with_group_id(mut self, group_id: Option<GroupId>) -> Self {
|
pub fn with_group_id(mut self, group_id: Option<GroupId>) -> Self {
|
||||||
self.group_id = group_id;
|
self.group_id = group_id;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Changes the [PrintMode] of the group from [`Flat`](PrintMode::Flat) to [`Expanded`](PrintMode::Expanded).
|
/// Changes the [`PrintMode`] of the group from [`Flat`](PrintMode::Flat) to [`Expanded`](PrintMode::Expanded).
|
||||||
/// The result is that any soft-line break gets printed as a regular line break.
|
/// The result is that any soft-line break gets printed as a regular line break.
|
||||||
///
|
///
|
||||||
/// This is useful for content rendered inside of a [FormatElement::BestFitting] that prints each variant
|
/// This is useful for content rendered inside of a [`FormatElement::BestFitting`] that prints each variant
|
||||||
/// in [PrintMode::Flat] to change some content to be printed in [`Expanded`](PrintMode::Expanded) regardless.
|
/// in [`PrintMode::Flat`] to change some content to be printed in [`Expanded`](PrintMode::Expanded) regardless.
|
||||||
/// See the documentation of the [`best_fitting`] macro for an example.
|
/// See the documentation of the [`best_fitting`] macro for an example.
|
||||||
|
#[must_use]
|
||||||
pub fn should_expand(mut self, should_expand: bool) -> Self {
|
pub fn should_expand(mut self, should_expand: bool) -> Self {
|
||||||
self.should_expand = should_expand;
|
self.should_expand = should_expand;
|
||||||
self
|
self
|
||||||
|
@ -1393,9 +1396,10 @@ impl<Context> Group<'_, Context> {
|
||||||
|
|
||||||
impl<Context> Format<Context> for Group<'_, Context> {
|
impl<Context> Format<Context> for Group<'_, Context> {
|
||||||
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
let mode = match self.should_expand {
|
let mode = if self.should_expand {
|
||||||
true => GroupMode::Expand,
|
GroupMode::Expand
|
||||||
false => GroupMode::Flat,
|
} else {
|
||||||
|
GroupMode::Flat
|
||||||
};
|
};
|
||||||
|
|
||||||
f.write_element(FormatElement::Tag(StartGroup(
|
f.write_element(FormatElement::Tag(StartGroup(
|
||||||
|
@ -1602,7 +1606,7 @@ impl<Context> Format<Context> for ExpandParent {
|
||||||
///
|
///
|
||||||
/// The element has no special meaning if used outside of a `Group`. In that case, the content is always emitted.
|
/// The element has no special meaning if used outside of a `Group`. In that case, the content is always emitted.
|
||||||
///
|
///
|
||||||
/// If you're looking for a way to only print something if the `Group` fits on a single line see [self::if_group_fits_on_line].
|
/// If you're looking for a way to only print something if the `Group` fits on a single line see [`self::if_group_fits_on_line`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -1684,7 +1688,7 @@ where
|
||||||
/// Adds a conditional content specific for `Group`s that fit on a single line. The content isn't
|
/// Adds a conditional content specific for `Group`s that fit on a single line. The content isn't
|
||||||
/// emitted for `Group`s spanning multiple lines.
|
/// emitted for `Group`s spanning multiple lines.
|
||||||
///
|
///
|
||||||
/// See [if_group_breaks] if you're looking for a way to print content only for groups spanning multiple lines.
|
/// See [`if_group_breaks`] if you're looking for a way to print content only for groups spanning multiple lines.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -1823,6 +1827,7 @@ impl<Context> IfGroupBreaks<'_, Context> {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use]
|
||||||
pub fn with_group_id(mut self, group_id: Option<GroupId>) -> Self {
|
pub fn with_group_id(mut self, group_id: Option<GroupId>) -> Self {
|
||||||
self.group_id = group_id;
|
self.group_id = group_id;
|
||||||
self
|
self
|
||||||
|
@ -1855,7 +1860,7 @@ impl<Context> std::fmt::Debug for IfGroupBreaks<'_, Context> {
|
||||||
|
|
||||||
/// Increases the indent level by one if the group with the specified id breaks.
|
/// Increases the indent level by one if the group with the specified id breaks.
|
||||||
///
|
///
|
||||||
/// This IR has the same semantics as using [if_group_breaks] and [if_group_fits_on_line] together.
|
/// This IR has the same semantics as using [`if_group_breaks`] and [`if_group_fits_on_line`] together.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use ruff_formatter::prelude::*;
|
/// # use ruff_formatter::prelude::*;
|
||||||
|
@ -1874,7 +1879,7 @@ impl<Context> std::fmt::Debug for IfGroupBreaks<'_, Context> {
|
||||||
///
|
///
|
||||||
/// If you want to indent some content if the enclosing group breaks, use [`indent`].
|
/// If you want to indent some content if the enclosing group breaks, use [`indent`].
|
||||||
///
|
///
|
||||||
/// Use [if_group_breaks] or [if_group_fits_on_line] if the fitting and breaking content differs more than just the
|
/// Use [`if_group_breaks`] or [`if_group_fits_on_line`] if the fitting and breaking content differs more than just the
|
||||||
/// indention level.
|
/// indention level.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -1972,7 +1977,7 @@ impl<Context> std::fmt::Debug for IndentIfGroupBreaks<'_, Context> {
|
||||||
|
|
||||||
/// Changes the definition of *fits* for `content`. Instead of measuring it in *flat*, measure it with
|
/// 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
|
/// 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.
|
/// 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.
|
/// Useful in conjunction with a group with a condition.
|
||||||
///
|
///
|
||||||
|
@ -2034,6 +2039,7 @@ pub struct FitsExpanded<'a, Context> {
|
||||||
impl<Context> FitsExpanded<'_, Context> {
|
impl<Context> FitsExpanded<'_, Context> {
|
||||||
/// Sets a `condition` to when the content should fit in expanded mode. The content uses the regular fits
|
/// Sets a `condition` to when the content should fit in expanded mode. The content uses the regular fits
|
||||||
/// definition if the `condition` is not met.
|
/// definition if the `condition` is not met.
|
||||||
|
#[must_use]
|
||||||
pub fn with_condition(mut self, condition: Option<Condition>) -> Self {
|
pub fn with_condition(mut self, condition: Option<Condition>) -> Self {
|
||||||
self.condition = condition;
|
self.condition = condition;
|
||||||
self
|
self
|
||||||
|
@ -2061,7 +2067,7 @@ impl<Context, T> Format<Context> for FormatWith<Context, T>
|
||||||
where
|
where
|
||||||
T: Fn(&mut Formatter<Context>) -> FormatResult<()>,
|
T: Fn(&mut Formatter<Context>) -> FormatResult<()>,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
(self.formatter)(f)
|
(self.formatter)(f)
|
||||||
}
|
}
|
||||||
|
@ -2207,7 +2213,7 @@ impl<T, Context> Format<Context> for FormatOnce<T, Context>
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Formatter<Context>) -> FormatResult<()>,
|
T: FnOnce(&mut Formatter<Context>) -> FormatResult<()>,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
let formatter = self.formatter.take().expect("Tried to format a `format_once` at least twice. This is not allowed. You may want to use `format_with` or `format.memoized` instead.");
|
let formatter = self.formatter.take().expect("Tried to format a `format_once` at least twice. This is not allowed. You may want to use `format_with` or `format.memoized` instead.");
|
||||||
|
|
||||||
|
@ -2222,7 +2228,7 @@ impl<T, Context> std::fmt::Debug for FormatOnce<T, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder to join together a sequence of content.
|
/// Builder to join together a sequence of content.
|
||||||
/// See [Formatter::join]
|
/// See [`Formatter::join`]
|
||||||
#[must_use = "must eventually call `finish()` on Format builders"]
|
#[must_use = "must eventually call `finish()` on Format builders"]
|
||||||
pub struct JoinBuilder<'fmt, 'buf, Separator, Context> {
|
pub struct JoinBuilder<'fmt, 'buf, Separator, Context> {
|
||||||
result: FormatResult<()>,
|
result: FormatResult<()>,
|
||||||
|
@ -2367,7 +2373,9 @@ impl<'a, Context> BestFitting<'a, Context> {
|
||||||
/// You're looking for a way to create a `BestFitting` object, use the `best_fitting![least_expanded, most_expanded]` macro.
|
/// You're looking for a way to create a `BestFitting` object, use the `best_fitting![least_expanded, most_expanded]` macro.
|
||||||
///
|
///
|
||||||
/// ## Safety
|
/// ## Safety
|
||||||
|
|
||||||
/// The slice must contain at least two variants.
|
/// The slice must contain at least two variants.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
pub unsafe fn from_arguments_unchecked(variants: Arguments<'a, Context>) -> Self {
|
pub unsafe fn from_arguments_unchecked(variants: Arguments<'a, Context>) -> Self {
|
||||||
assert!(
|
assert!(
|
||||||
variants.0.len() >= 2,
|
variants.0.len() >= 2,
|
||||||
|
@ -2395,6 +2403,7 @@ impl<Context> Format<Context> for BestFitting<'_, Context> {
|
||||||
|
|
||||||
// SAFETY: The constructor guarantees that there are always at least two variants. It's, therefore,
|
// SAFETY: The constructor guarantees that there are always at least two variants. It's, therefore,
|
||||||
// safe to call into the unsafe `from_vec_unchecked` function
|
// safe to call into the unsafe `from_vec_unchecked` function
|
||||||
|
#[allow(unsafe_code)]
|
||||||
let element = unsafe {
|
let element = unsafe {
|
||||||
FormatElement::BestFitting {
|
FormatElement::BestFitting {
|
||||||
variants: format_element::BestFittingVariants::from_vec_unchecked(
|
variants: format_element::BestFittingVariants::from_vec_unchecked(
|
||||||
|
|
|
@ -13,7 +13,7 @@ use ruff_text_size::TextSize;
|
||||||
|
|
||||||
/// Language agnostic IR for formatting source code.
|
/// Language agnostic IR for formatting source code.
|
||||||
///
|
///
|
||||||
/// Use the helper functions like [crate::builders::space], [crate::builders::soft_line_break] etc. defined in this file to create elements.
|
/// Use the helper functions like [`crate::builders::space`], [`crate::builders::soft_line_break`] etc. defined in this file to create elements.
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub enum FormatElement {
|
pub enum FormatElement {
|
||||||
/// A space token, see [crate::builders::space] for documentation.
|
/// A space token, see [crate::builders::space] for documentation.
|
||||||
|
@ -88,9 +88,7 @@ impl std::fmt::Debug for FormatElement {
|
||||||
.debug_struct("BestFitting")
|
.debug_struct("BestFitting")
|
||||||
.field("variants", variants)
|
.field("variants", variants)
|
||||||
.finish(),
|
.finish(),
|
||||||
FormatElement::Interned(interned) => {
|
FormatElement::Interned(interned) => fmt.debug_list().entries(&**interned).finish(),
|
||||||
fmt.debug_list().entries(interned.deref()).finish()
|
|
||||||
}
|
|
||||||
FormatElement::Tag(tag) => fmt.debug_tuple("Tag").field(tag).finish(),
|
FormatElement::Tag(tag) => fmt.debug_tuple("Tag").field(tag).finish(),
|
||||||
FormatElement::SourcePosition(position) => {
|
FormatElement::SourcePosition(position) => {
|
||||||
fmt.debug_tuple("SourcePosition").field(position).finish()
|
fmt.debug_tuple("SourcePosition").field(position).finish()
|
||||||
|
@ -180,7 +178,7 @@ impl Deref for Interned {
|
||||||
type Target = [FormatElement];
|
type Target = [FormatElement];
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
self.0.deref()
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,12 +215,12 @@ pub fn normalize_newlines<const N: usize>(text: &str, terminators: [char; N]) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatElement {
|
impl FormatElement {
|
||||||
/// Returns `true` if self is a [FormatElement::Tag]
|
/// Returns `true` if self is a [`FormatElement::Tag`]
|
||||||
pub const fn is_tag(&self) -> bool {
|
pub const fn is_tag(&self) -> bool {
|
||||||
matches!(self, FormatElement::Tag(_))
|
matches!(self, FormatElement::Tag(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if self is a [FormatElement::Tag] and [Tag::is_start] is `true`.
|
/// Returns `true` if self is a [`FormatElement::Tag`] and [`Tag::is_start`] is `true`.
|
||||||
pub const fn is_start_tag(&self) -> bool {
|
pub const fn is_start_tag(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
FormatElement::Tag(tag) => tag.is_start(),
|
FormatElement::Tag(tag) => tag.is_start(),
|
||||||
|
@ -230,7 +228,7 @@ impl FormatElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if self is a [FormatElement::Tag] and [Tag::is_end] is `true`.
|
/// Returns `true` if self is a [`FormatElement::Tag`] and [`Tag::is_end`] is `true`.
|
||||||
pub const fn is_end_tag(&self) -> bool {
|
pub const fn is_end_tag(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
FormatElement::Tag(tag) => tag.is_end(),
|
FormatElement::Tag(tag) => tag.is_end(),
|
||||||
|
@ -313,6 +311,7 @@ impl BestFittingVariants {
|
||||||
/// ## Safety
|
/// ## Safety
|
||||||
/// The slice must contain at least two variants.
|
/// The slice must contain at least two variants.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
#[allow(unsafe_code)]
|
||||||
pub unsafe fn from_vec_unchecked(variants: Vec<Box<[FormatElement]>>) -> Self {
|
pub unsafe fn from_vec_unchecked(variants: Vec<Box<[FormatElement]>>) -> Self {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
variants.len() >= 2,
|
variants.len() >= 2,
|
||||||
|
@ -359,9 +358,9 @@ impl<'a> IntoIterator for &'a BestFittingVariants {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FormatElements {
|
pub trait FormatElements {
|
||||||
/// Returns true if this [FormatElement] is guaranteed to break across multiple lines by the printer.
|
/// Returns true if this [`FormatElement`] is guaranteed to break across multiple lines by the printer.
|
||||||
/// This is the case if this format element recursively contains a:
|
/// This is the case if this format element recursively contains a:
|
||||||
/// - [crate::builders::empty_line] or [crate::builders::hard_line_break]
|
/// - [`crate::builders::empty_line`] or [`crate::builders::hard_line_break`]
|
||||||
/// - A token containing '\n'
|
/// - A token containing '\n'
|
||||||
///
|
///
|
||||||
/// Use this with caution, this is only a heuristic and the printer may print the element over multiple
|
/// Use this with caution, this is only a heuristic and the printer may print the element over multiple
|
||||||
|
|
|
@ -21,9 +21,9 @@ pub struct Document {
|
||||||
|
|
||||||
impl Document {
|
impl Document {
|
||||||
/// Sets [`expand`](tag::Group::expand) to [`GroupMode::Propagated`] if the group contains any of:
|
/// Sets [`expand`](tag::Group::expand) to [`GroupMode::Propagated`] if the group contains any of:
|
||||||
/// - a group with [`expand`](tag::Group::expand) set to [GroupMode::Propagated] or [GroupMode::Expand].
|
/// - a group with [`expand`](tag::Group::expand) set to [`GroupMode::Propagated`] or [`GroupMode::Expand`].
|
||||||
/// - a non-soft [line break](FormatElement::Line) with mode [LineMode::Hard], [LineMode::Empty], or [LineMode::Literal].
|
/// - a non-soft [line break](FormatElement::Line) with mode [`LineMode::Hard`], [`LineMode::Empty`], or [`LineMode::Literal`].
|
||||||
/// - a [FormatElement::ExpandParent]
|
/// - a [`FormatElement::ExpandParent`]
|
||||||
///
|
///
|
||||||
/// [`BestFitting`] elements act as expand boundaries, meaning that the fact that a
|
/// [`BestFitting`] elements act as expand boundaries, meaning that the fact that a
|
||||||
/// [`BestFitting`]'s content expands is not propagated past the [`BestFitting`] element.
|
/// [`BestFitting`]'s content expands is not propagated past the [`BestFitting`] element.
|
||||||
|
@ -71,15 +71,16 @@ impl Document {
|
||||||
Some(Enclosing::ConditionalGroup(group)) => !group.mode().is_flat(),
|
Some(Enclosing::ConditionalGroup(group)) => !group.mode().is_flat(),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
FormatElement::Interned(interned) => match checked_interned.get(interned) {
|
FormatElement::Interned(interned) => {
|
||||||
Some(interned_expands) => *interned_expands,
|
if let Some(interned_expands) = checked_interned.get(interned) {
|
||||||
None => {
|
*interned_expands
|
||||||
|
} else {
|
||||||
let interned_expands =
|
let interned_expands =
|
||||||
propagate_expands(interned, enclosing, checked_interned);
|
propagate_expands(interned, enclosing, checked_interned);
|
||||||
checked_interned.insert(interned, interned_expands);
|
checked_interned.insert(interned, interned_expands);
|
||||||
interned_expands
|
interned_expands
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
FormatElement::BestFitting { variants } => {
|
FormatElement::BestFitting { variants } => {
|
||||||
enclosing.push(Enclosing::BestFitting);
|
enclosing.push(Enclosing::BestFitting);
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ impl Document {
|
||||||
|
|
||||||
if element_expands {
|
if element_expands {
|
||||||
expands = true;
|
expands = true;
|
||||||
expand_parent(enclosing)
|
expand_parent(enclosing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,6 +227,7 @@ impl FormatOptions for IrFormatOptions {
|
||||||
|
|
||||||
impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||||
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Tag::*;
|
use Tag::*;
|
||||||
|
|
||||||
write!(f, [ContentArrayStart])?;
|
write!(f, [ContentArrayStart])?;
|
||||||
|
@ -245,16 +247,10 @@ impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||||
first_element = false;
|
first_element = false;
|
||||||
|
|
||||||
match element {
|
match element {
|
||||||
element @ FormatElement::Space
|
element @ (FormatElement::Space
|
||||||
| element @ FormatElement::StaticText { .. }
|
| FormatElement::StaticText { .. }
|
||||||
| element @ FormatElement::DynamicText { .. }
|
| FormatElement::DynamicText { .. }
|
||||||
| element @ FormatElement::SourceCodeSlice { .. } => {
|
| FormatElement::SourceCodeSlice { .. }) => {
|
||||||
if !in_text {
|
|
||||||
write!(f, [text("\"")])?;
|
|
||||||
}
|
|
||||||
|
|
||||||
in_text = true;
|
|
||||||
|
|
||||||
fn write_escaped(
|
fn write_escaped(
|
||||||
element: &FormatElement,
|
element: &FormatElement,
|
||||||
f: &mut Formatter<IrFormatContext>,
|
f: &mut Formatter<IrFormatContext>,
|
||||||
|
@ -277,6 +273,12 @@ impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !in_text {
|
||||||
|
write!(f, [text("\"")])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_text = true;
|
||||||
|
|
||||||
match element {
|
match element {
|
||||||
FormatElement::Space => {
|
FormatElement::Space => {
|
||||||
write!(f, [text(" ")])?;
|
write!(f, [text(" ")])?;
|
||||||
|
@ -317,7 +319,7 @@ impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[dynamic_text(
|
[dynamic_text(
|
||||||
&std::format!("source_position({:?})", position),
|
&std::format!("source_position({position:?})"),
|
||||||
None
|
None
|
||||||
)]
|
)]
|
||||||
)?;
|
)?;
|
||||||
|
@ -335,7 +337,7 @@ impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||||
])?;
|
])?;
|
||||||
|
|
||||||
for variant in variants {
|
for variant in variants {
|
||||||
write!(f, [variant.deref(), hard_line_break()])?;
|
write!(f, [&**variant, hard_line_break()])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write_elements([
|
f.write_elements([
|
||||||
|
@ -359,7 +361,7 @@ impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||||
[
|
[
|
||||||
dynamic_text(&std::format!("<interned {index}>"), None),
|
dynamic_text(&std::format!("<interned {index}>"), None),
|
||||||
space(),
|
space(),
|
||||||
&interned.deref(),
|
&&**interned,
|
||||||
]
|
]
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -621,7 +623,7 @@ struct ContentArrayStart;
|
||||||
|
|
||||||
impl Format<IrFormatContext<'_>> for ContentArrayStart {
|
impl Format<IrFormatContext<'_>> for ContentArrayStart {
|
||||||
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
||||||
use Tag::*;
|
use Tag::{StartGroup, StartIndent};
|
||||||
|
|
||||||
write!(f, [text("[")])?;
|
write!(f, [text("[")])?;
|
||||||
|
|
||||||
|
@ -637,7 +639,7 @@ struct ContentArrayEnd;
|
||||||
|
|
||||||
impl Format<IrFormatContext<'_>> for ContentArrayEnd {
|
impl Format<IrFormatContext<'_>> for ContentArrayEnd {
|
||||||
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
||||||
use Tag::*;
|
use Tag::{EndGroup, EndIndent};
|
||||||
f.write_elements([
|
f.write_elements([
|
||||||
FormatElement::Tag(EndIndent),
|
FormatElement::Tag(EndIndent),
|
||||||
FormatElement::Line(LineMode::Soft),
|
FormatElement::Line(LineMode::Soft),
|
||||||
|
@ -650,7 +652,7 @@ impl Format<IrFormatContext<'_>> for ContentArrayEnd {
|
||||||
|
|
||||||
impl FormatElements for [FormatElement] {
|
impl FormatElements for [FormatElement] {
|
||||||
fn will_break(&self) -> bool {
|
fn will_break(&self) -> bool {
|
||||||
use Tag::*;
|
use Tag::{EndLineSuffix, StartLineSuffix};
|
||||||
let mut ignore_depth = 0usize;
|
let mut ignore_depth = 0usize;
|
||||||
|
|
||||||
for element in self {
|
for element in self {
|
||||||
|
@ -687,9 +689,6 @@ impl FormatElements for [FormatElement] {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_tag(&self, kind: TagKind) -> Option<&Tag> {
|
fn start_tag(&self, kind: TagKind) -> Option<&Tag> {
|
||||||
// Assert that the document ends at a tag with the specified kind;
|
|
||||||
let _ = self.end_tag(kind)?;
|
|
||||||
|
|
||||||
fn traverse_slice<'a>(
|
fn traverse_slice<'a>(
|
||||||
slice: &'a [FormatElement],
|
slice: &'a [FormatElement],
|
||||||
kind: TagKind,
|
kind: TagKind,
|
||||||
|
@ -704,9 +703,8 @@ impl FormatElements for [FormatElement] {
|
||||||
return None;
|
return None;
|
||||||
} else if *depth == 1 {
|
} else if *depth == 1 {
|
||||||
return Some(tag);
|
return Some(tag);
|
||||||
} else {
|
|
||||||
*depth -= 1;
|
|
||||||
}
|
}
|
||||||
|
*depth -= 1;
|
||||||
} else {
|
} else {
|
||||||
*depth += 1;
|
*depth += 1;
|
||||||
}
|
}
|
||||||
|
@ -731,6 +729,8 @@ impl FormatElements for [FormatElement] {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
// Assert that the document ends at a tag with the specified kind;
|
||||||
|
let _ = self.end_tag(kind)?;
|
||||||
|
|
||||||
let mut depth = 0usize;
|
let mut depth = 0usize;
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,7 @@ impl Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn kind(&self) -> TagKind {
|
pub const fn kind(&self) -> TagKind {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Tag::*;
|
use Tag::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
@ -180,13 +181,14 @@ impl FitsExpanded {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_condition(mut self, condition: Option<Condition>) -> Self {
|
pub fn with_condition(mut self, condition: Option<Condition>) -> Self {
|
||||||
self.condition = condition;
|
self.condition = condition;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn propagate_expand(&self) {
|
pub fn propagate_expand(&self) {
|
||||||
self.propagate_expand.set(true)
|
self.propagate_expand.set(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,11 +206,13 @@ impl Group {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_id(mut self, id: Option<GroupId>) -> Self {
|
pub fn with_id(mut self, id: Option<GroupId>) -> Self {
|
||||||
self.id = id;
|
self.id = id;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_mode(mut self, mode: GroupMode) -> Self {
|
pub fn with_mode(mut self, mode: GroupMode) -> Self {
|
||||||
self.mode = Cell::new(mode);
|
self.mode = Cell::new(mode);
|
||||||
self
|
self
|
||||||
|
@ -220,7 +224,7 @@ impl Group {
|
||||||
|
|
||||||
pub fn propagate_expand(&self) {
|
pub fn propagate_expand(&self) {
|
||||||
if self.mode.get() == GroupMode::Flat {
|
if self.mode.get() == GroupMode::Flat {
|
||||||
self.mode.set(GroupMode::Propagated)
|
self.mode.set(GroupMode::Propagated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +252,7 @@ impl ConditionalGroup {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn propagate_expand(&self) {
|
pub fn propagate_expand(&self) {
|
||||||
self.mode.set(GroupMode::Propagated)
|
self.mode.set(GroupMode::Propagated);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mode(&self) -> GroupMode {
|
pub fn mode(&self) -> GroupMode {
|
||||||
|
@ -312,6 +316,7 @@ impl Condition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_group_id(mut self, id: Option<GroupId>) -> Self {
|
pub fn with_group_id(mut self, id: Option<GroupId>) -> Self {
|
||||||
self.group_id = id;
|
self.group_id = id;
|
||||||
self
|
self
|
||||||
|
@ -350,6 +355,7 @@ impl PartialEq for LabelId {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LabelId {
|
impl LabelId {
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
pub fn of<T: LabelDefinition>(label: T) -> Self {
|
pub fn of<T: LabelDefinition>(label: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value: label.value(),
|
value: label.value(),
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use crate::Buffer;
|
use crate::Buffer;
|
||||||
|
|
||||||
|
@ -149,7 +148,7 @@ where
|
||||||
.get_or_insert_with(|| f.intern(&self.inner));
|
.get_or_insert_with(|| f.intern(&self.inner));
|
||||||
|
|
||||||
match result.as_ref() {
|
match result.as_ref() {
|
||||||
Ok(Some(FormatElement::Interned(interned))) => Ok(interned.deref()),
|
Ok(Some(FormatElement::Interned(interned))) => Ok(&**interned),
|
||||||
Ok(Some(other)) => Ok(std::slice::from_ref(other)),
|
Ok(Some(other)) => Ok(std::slice::from_ref(other)),
|
||||||
Ok(None) => Ok(&[]),
|
Ok(None) => Ok(&[]),
|
||||||
Err(error) => Err(*error),
|
Err(error) => Err(*error),
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl<'buf, Context> Formatter<'buf, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new group id that is unique to this document. The passed debug name is used in the
|
/// Creates a new group id that is unique to this document. The passed debug name is used in the
|
||||||
/// [std::fmt::Debug] of the document if this is a debug build.
|
/// [`std::fmt::Debug`] of the document if this is a debug build.
|
||||||
/// The name is unused for production builds and has no meaning on the equality of two group ids.
|
/// The name is unused for production builds and has no meaning on the equality of two group ids.
|
||||||
pub fn group_id(&self, debug_name: &'static str) -> GroupId {
|
pub fn group_id(&self, debug_name: &'static str) -> GroupId {
|
||||||
self.state().group_id(debug_name)
|
self.state().group_id(debug_name)
|
||||||
|
@ -108,7 +108,7 @@ impl<'buf, Context> Formatter<'buf, Context> {
|
||||||
JoinBuilder::with_separator(self, joiner)
|
JoinBuilder::with_separator(self, joiner)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Concatenates a list of [crate::Format] objects with spaces and line breaks to fit
|
/// Concatenates a list of [`crate::Format`] objects with spaces and line breaks to fit
|
||||||
/// them on as few lines as possible. Each element introduces a conceptual group. The printer
|
/// them on as few lines as possible. Each element introduces a conceptual group. The printer
|
||||||
/// first tries to print the item in flat mode but then prints it in expanded mode if it doesn't fit.
|
/// first tries to print the item in flat mode but then prints it in expanded mode if it doesn't fit.
|
||||||
///
|
///
|
||||||
|
@ -205,7 +205,7 @@ where
|
||||||
impl<Context> Buffer for Formatter<'_, Context> {
|
impl<Context> Buffer for Formatter<'_, Context> {
|
||||||
type Context = Context;
|
type Context = Context;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
|
fn write_element(&mut self, element: FormatElement) -> FormatResult<()> {
|
||||||
self.buffer.write_element(element)
|
self.buffer.write_element(element)
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ impl<Context> Buffer for Formatter<'_, Context> {
|
||||||
self.buffer.elements()
|
self.buffer.elements()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn write_fmt(&mut self, arguments: Arguments<Self::Context>) -> FormatResult<()> {
|
fn write_fmt(&mut self, arguments: Arguments<Self::Context>) -> FormatResult<()> {
|
||||||
for argument in arguments.items() {
|
for argument in arguments.items() {
|
||||||
argument.format(self)?;
|
argument.format(self)?;
|
||||||
|
@ -235,7 +235,7 @@ impl<Context> Buffer for Formatter<'_, Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
fn restore_snapshot(&mut self, snapshot: BufferSnapshot) {
|
||||||
self.buffer.restore_snapshot(snapshot)
|
self.buffer.restore_snapshot(snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ impl std::fmt::Debug for DebugGroupId {
|
||||||
|
|
||||||
/// Unique identification for a group.
|
/// Unique identification for a group.
|
||||||
///
|
///
|
||||||
/// See [crate::Formatter::group_id] on how to get a unique id.
|
/// See [`crate::Formatter::group_id`] on how to get a unique id.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub struct ReleaseGroupId {
|
pub struct ReleaseGroupId {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
//! Infrastructure for code formatting
|
//! Infrastructure for code formatting
|
||||||
//!
|
//!
|
||||||
//! This module defines [FormatElement], an IR to format code documents and provides a mean to print
|
//! This module defines [`FormatElement`], an IR to format code documents and provides a mean to print
|
||||||
//! such a document to a string. Objects that know how to format themselves implement the [Format] trait.
|
//! such a document to a string. Objects that know how to format themselves implement the [Format] trait.
|
||||||
//!
|
//!
|
||||||
//! ## Formatting Traits
|
//! ## Formatting Traits
|
||||||
//!
|
//!
|
||||||
//! * [Format]: Implemented by objects that can be formatted.
|
//! * [Format]: Implemented by objects that can be formatted.
|
||||||
//! * [FormatRule]: Rule that knows how to format an object of another type. Necessary in the situation where
|
//! * [`FormatRule`]: Rule that knows how to format an object of another type. Necessary in the situation where
|
||||||
//! it's necessary to implement [Format] on an object from another crate. This module defines the
|
//! it's necessary to implement [Format] on an object from another crate. This module defines the
|
||||||
//! [FormatRefWithRule] and [FormatOwnedWithRule] structs to pass an item with its corresponding rule.
|
//! [`FormatRefWithRule`] and [`FormatOwnedWithRule`] structs to pass an item with its corresponding rule.
|
||||||
//! * [FormatWithRule] implemented by objects that know how to format another type. Useful for implementing
|
//! * [`FormatWithRule`] implemented by objects that know how to format another type. Useful for implementing
|
||||||
//! some reusable formatting logic inside of this module if the type itself doesn't implement [Format]
|
//! some reusable formatting logic inside of this module if the type itself doesn't implement [Format]
|
||||||
//!
|
//!
|
||||||
//! ## Formatting Macros
|
//! ## Formatting Macros
|
||||||
|
@ -19,9 +19,6 @@
|
||||||
//! * [`format_args!`]: Concatenates a sequence of Format objects.
|
//! * [`format_args!`]: Concatenates a sequence of Format objects.
|
||||||
//! * [`write!`]: Writes a sequence of formatable objects into an output buffer.
|
//! * [`write!`]: Writes a sequence of formatable objects into an output buffer.
|
||||||
|
|
||||||
#![allow(clippy::pedantic, unsafe_code)]
|
|
||||||
#![deny(rustdoc::broken_intra_doc_links)]
|
|
||||||
|
|
||||||
mod arguments;
|
mod arguments;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod builders;
|
mod builders;
|
||||||
|
@ -73,12 +70,12 @@ pub enum IndentStyle {
|
||||||
impl IndentStyle {
|
impl IndentStyle {
|
||||||
pub const DEFAULT_SPACES: u8 = 2;
|
pub const DEFAULT_SPACES: u8 = 2;
|
||||||
|
|
||||||
/// Returns `true` if this is an [IndentStyle::Tab].
|
/// Returns `true` if this is an [`IndentStyle::Tab`].
|
||||||
pub const fn is_tab(&self) -> bool {
|
pub const fn is_tab(&self) -> bool {
|
||||||
matches!(self, IndentStyle::Tab)
|
matches!(self, IndentStyle::Tab)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this is an [IndentStyle::Space].
|
/// Returns `true` if this is an [`IndentStyle::Space`].
|
||||||
pub const fn is_space(&self) -> bool {
|
pub const fn is_space(&self) -> bool {
|
||||||
matches!(self, IndentStyle::Space(_))
|
matches!(self, IndentStyle::Space(_))
|
||||||
}
|
}
|
||||||
|
@ -121,10 +118,10 @@ impl std::fmt::Display for IndentStyle {
|
||||||
pub struct LineWidth(u16);
|
pub struct LineWidth(u16);
|
||||||
|
|
||||||
impl LineWidth {
|
impl LineWidth {
|
||||||
/// Maximum allowed value for a valid [LineWidth]
|
/// Maximum allowed value for a valid [`LineWidth`]
|
||||||
pub const MAX: u16 = 320;
|
pub const MAX: u16 = 320;
|
||||||
|
|
||||||
/// Return the numeric value for this [LineWidth]
|
/// Return the numeric value for this [`LineWidth`]
|
||||||
pub fn value(&self) -> u16 {
|
pub fn value(&self) -> u16 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
|
@ -136,7 +133,7 @@ impl Default for LineWidth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error type returned when parsing a [LineWidth] from a string fails
|
/// Error type returned when parsing a [`LineWidth`] from a string fails
|
||||||
pub enum ParseLineWidthError {
|
pub enum ParseLineWidthError {
|
||||||
/// The string could not be parsed as a valid [u16]
|
/// The string could not be parsed as a valid [u16]
|
||||||
ParseError(ParseIntError),
|
ParseError(ParseIntError),
|
||||||
|
@ -169,7 +166,7 @@ impl FromStr for LineWidth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error type returned when converting a u16 to a [LineWidth] fails
|
/// Error type returned when converting a u16 to a [`LineWidth`] fails
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct LineWidthFromIntError(pub u16);
|
pub struct LineWidthFromIntError(pub u16);
|
||||||
|
|
||||||
|
@ -238,6 +235,7 @@ impl SimpleFormatContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_source_code(mut self, code: &str) -> Self {
|
pub fn with_source_code(mut self, code: &str) -> Self {
|
||||||
self.source_code = String::from(code);
|
self.source_code = String::from(code);
|
||||||
self
|
self
|
||||||
|
@ -390,20 +388,20 @@ impl Printed {
|
||||||
self.range
|
self.range
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of [SourceMarker] mapping byte positions
|
/// Returns a list of [`SourceMarker`] mapping byte positions
|
||||||
/// in the output string to the input source code.
|
/// in the output string to the input source code.
|
||||||
/// It's not guaranteed that the markers are sorted by source position.
|
/// It's not guaranteed that the markers are sorted by source position.
|
||||||
pub fn sourcemap(&self) -> &[SourceMarker] {
|
pub fn sourcemap(&self) -> &[SourceMarker] {
|
||||||
&self.sourcemap
|
&self.sourcemap
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of [SourceMarker] mapping byte positions
|
/// Returns a list of [`SourceMarker`] mapping byte positions
|
||||||
/// in the output string to the input source code, consuming the result
|
/// in the output string to the input source code, consuming the result
|
||||||
pub fn into_sourcemap(self) -> Vec<SourceMarker> {
|
pub fn into_sourcemap(self) -> Vec<SourceMarker> {
|
||||||
self.sourcemap
|
self.sourcemap
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes the list of [SourceMarker] mapping byte positions in the output string
|
/// Takes the list of [`SourceMarker`] mapping byte positions in the output string
|
||||||
/// to the input source code.
|
/// to the input source code.
|
||||||
pub fn take_sourcemap(&mut self) -> Vec<SourceMarker> {
|
pub fn take_sourcemap(&mut self) -> Vec<SourceMarker> {
|
||||||
std::mem::take(&mut self.sourcemap)
|
std::mem::take(&mut self.sourcemap)
|
||||||
|
@ -441,7 +439,7 @@ impl Printed {
|
||||||
pub type FormatResult<F> = Result<F, FormatError>;
|
pub type FormatResult<F> = Result<F, FormatError>;
|
||||||
|
|
||||||
/// Formatting trait for types that can create a formatted representation. The `ruff_formatter` equivalent
|
/// Formatting trait for types that can create a formatted representation. The `ruff_formatter` equivalent
|
||||||
/// to [std::fmt::Display].
|
/// to [`std::fmt::Display`].
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// Implementing `Format` for a custom struct
|
/// Implementing `Format` for a custom struct
|
||||||
|
@ -480,7 +478,7 @@ impl<T, Context> Format<Context> for &T
|
||||||
where
|
where
|
||||||
T: ?Sized + Format<Context>,
|
T: ?Sized + Format<Context>,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
Format::fmt(&**self, f)
|
Format::fmt(&**self, f)
|
||||||
}
|
}
|
||||||
|
@ -490,7 +488,7 @@ impl<T, Context> Format<Context> for &mut T
|
||||||
where
|
where
|
||||||
T: ?Sized + Format<Context>,
|
T: ?Sized + Format<Context>,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
Format::fmt(&**self, f)
|
Format::fmt(&**self, f)
|
||||||
}
|
}
|
||||||
|
@ -518,7 +516,7 @@ impl<Context> Format<Context> for () {
|
||||||
|
|
||||||
/// Rule that knows how to format an object of type `T`.
|
/// Rule that knows how to format an object of type `T`.
|
||||||
///
|
///
|
||||||
/// Implementing [Format] on the object itself is preferred over implementing [FormatRule] but
|
/// Implementing [Format] on the object itself is preferred over implementing [`FormatRule`] but
|
||||||
/// this isn't possible inside of a dependent crate for external type.
|
/// this isn't possible inside of a dependent crate for external type.
|
||||||
///
|
///
|
||||||
/// For example, the `ruff_js_formatter` crate isn't able to implement [Format] on `JsIfStatement`
|
/// For example, the `ruff_js_formatter` crate isn't able to implement [Format] on `JsIfStatement`
|
||||||
|
@ -535,6 +533,7 @@ pub trait FormatRuleWithOptions<T, C>: FormatRule<T, C> {
|
||||||
type Options;
|
type Options;
|
||||||
|
|
||||||
/// Returns a new rule that uses the given options to format an object.
|
/// Returns a new rule that uses the given options to format an object.
|
||||||
|
#[must_use]
|
||||||
fn with_options(self, options: Self::Options) -> Self;
|
fn with_options(self, options: Self::Options) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,9 +546,9 @@ pub trait FormatRuleWithOptions<T, C>: FormatRule<T, C> {
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
///
|
///
|
||||||
/// This can be useful if you want to format a `SyntaxNode` inside ruff_formatter.. `SyntaxNode` doesn't implement [Format]
|
/// This can be useful if you want to format a `SyntaxNode` inside `ruff_formatter`.. `SyntaxNode` doesn't implement [Format]
|
||||||
/// itself but the language specific crate implements `AsFormat` and `IntoFormat` for it and the returned [Format]
|
/// itself but the language specific crate implements `AsFormat` and `IntoFormat` for it and the returned [Format]
|
||||||
/// implement [FormatWithRule].
|
/// implement [`FormatWithRule`].
|
||||||
///
|
///
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// use ruff_formatter::prelude::*;
|
/// use ruff_formatter::prelude::*;
|
||||||
|
@ -597,6 +596,7 @@ impl<T, R, O, C> FormatRefWithRule<'_, T, R, C>
|
||||||
where
|
where
|
||||||
R: FormatRuleWithOptions<T, C, Options = O>,
|
R: FormatRuleWithOptions<T, C, Options = O>,
|
||||||
{
|
{
|
||||||
|
#[must_use]
|
||||||
pub fn with_options(mut self, options: O) -> Self {
|
pub fn with_options(mut self, options: O) -> Self {
|
||||||
self.rule = self.rule.with_options(options);
|
self.rule = self.rule.with_options(options);
|
||||||
self
|
self
|
||||||
|
@ -618,7 +618,7 @@ impl<T, R, C> Format<C> for FormatRefWithRule<'_, T, R, C>
|
||||||
where
|
where
|
||||||
R: FormatRule<T, C>,
|
R: FormatRule<T, C>,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter<C>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<C>) -> FormatResult<()> {
|
||||||
self.rule.fmt(self.item, f)
|
self.rule.fmt(self.item, f)
|
||||||
}
|
}
|
||||||
|
@ -647,6 +647,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_item(mut self, item: T) -> Self {
|
pub fn with_item(mut self, item: T) -> Self {
|
||||||
self.item = item;
|
self.item = item;
|
||||||
self
|
self
|
||||||
|
@ -661,7 +662,7 @@ impl<T, R, C> Format<C> for FormatOwnedWithRule<T, R, C>
|
||||||
where
|
where
|
||||||
R: FormatRule<T, C>,
|
R: FormatRule<T, C>,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut Formatter<C>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<C>) -> FormatResult<()> {
|
||||||
self.rule.fmt(&self.item, f)
|
self.rule.fmt(&self.item, f)
|
||||||
}
|
}
|
||||||
|
@ -671,6 +672,7 @@ impl<T, R, O, C> FormatOwnedWithRule<T, R, C>
|
||||||
where
|
where
|
||||||
R: FormatRuleWithOptions<T, C, Options = O>,
|
R: FormatRuleWithOptions<T, C, Options = O>,
|
||||||
{
|
{
|
||||||
|
#[must_use]
|
||||||
pub fn with_options(mut self, options: O) -> Self {
|
pub fn with_options(mut self, options: O) -> Self {
|
||||||
self.rule = self.rule.with_options(options);
|
self.rule = self.rule.with_options(options);
|
||||||
self
|
self
|
||||||
|
@ -729,7 +731,7 @@ where
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn write<Context>(
|
pub fn write<Context>(
|
||||||
output: &mut dyn Buffer<Context = Context>,
|
output: &mut dyn Buffer<Context = Context>,
|
||||||
args: Arguments<Context>,
|
args: Arguments<Context>,
|
||||||
|
@ -790,9 +792,9 @@ where
|
||||||
|
|
||||||
/// This structure stores the state that is relevant for the formatting of the whole document.
|
/// This structure stores the state that is relevant for the formatting of the whole document.
|
||||||
///
|
///
|
||||||
/// This structure is different from [crate::Formatter] in that the formatting infrastructure
|
/// This structure is different from [`crate::Formatter`] in that the formatting infrastructure
|
||||||
/// creates a new [crate::Formatter] for every [crate::write!] call, whereas this structure stays alive
|
/// creates a new [`crate::Formatter`] for every [`crate::write`!] call, whereas this structure stays alive
|
||||||
/// for the whole process of formatting a root with [crate::format!].
|
/// for the whole process of formatting a root with [`crate::format`!].
|
||||||
pub struct FormatState<Context> {
|
pub struct FormatState<Context> {
|
||||||
context: Context,
|
context: Context,
|
||||||
|
|
||||||
|
@ -815,7 +817,7 @@ impl<Context> FormatState<Context> {
|
||||||
pub fn new(context: Context) -> Self {
|
pub fn new(context: Context) -> Self {
|
||||||
Self {
|
Self {
|
||||||
context,
|
context,
|
||||||
group_id_builder: Default::default(),
|
group_id_builder: UniqueGroupIdBuilder::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +836,7 @@ impl<Context> FormatState<Context> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new group id that is unique to this document. The passed debug name is used in the
|
/// Creates a new group id that is unique to this document. The passed debug name is used in the
|
||||||
/// [std::fmt::Debug] of the document if this is a debug build.
|
/// [`std::fmt::Debug`] of the document if this is a debug build.
|
||||||
/// The name is unused for production builds and has no meaning on the equality of two group ids.
|
/// The name is unused for production builds and has no meaning on the equality of two group ids.
|
||||||
pub fn group_id(&self, debug_name: &'static str) -> GroupId {
|
pub fn group_id(&self, debug_name: &'static str) -> GroupId {
|
||||||
self.group_id_builder.group_id(debug_name)
|
self.group_id_builder.group_id(debug_name)
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/// Constructs the parameters for other formatting macros.
|
/// Constructs the parameters for other formatting macros.
|
||||||
///
|
///
|
||||||
/// This macro functions by taking a list of objects implementing [crate::Format]. It canonicalize the
|
/// This macro functions by taking a list of objects implementing [`crate::Format`]. It canonicalize the
|
||||||
/// arguments into a single type.
|
/// arguments into a single type.
|
||||||
///
|
///
|
||||||
/// This macro produces a value of type [crate::Arguments]. This value can be passed to
|
/// This macro produces a value of type [`crate::Arguments`]. This value can be passed to
|
||||||
/// the macros within [crate]. All other formatting macros ([`format!`](crate::format!),
|
/// the macros within [crate]. All other formatting macros ([`format!`](crate::format!),
|
||||||
/// [`write!`](crate::write!)) are proxied through this one. This macro avoids heap allocations.
|
/// [`write!`](crate::write!)) are proxied through this one. This macro avoids heap allocations.
|
||||||
///
|
///
|
||||||
|
@ -41,7 +41,7 @@ macro_rules! format_args {
|
||||||
///
|
///
|
||||||
/// This macro accepts a 'buffer' and a list of format arguments. Each argument will be formatted
|
/// This macro accepts a 'buffer' and a list of format arguments. Each argument will be formatted
|
||||||
/// and the result will be passed to the buffer. The writer may be any value with a `write_fmt` method;
|
/// and the result will be passed to the buffer. The writer may be any value with a `write_fmt` method;
|
||||||
/// generally this comes from an implementation of the [crate::Buffer] trait.
|
/// generally this comes from an implementation of the [`crate::Buffer`] trait.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -116,8 +116,8 @@ macro_rules! dbg_write {
|
||||||
|
|
||||||
/// Creates the Format IR for a value.
|
/// Creates the Format IR for a value.
|
||||||
///
|
///
|
||||||
/// The first argument `format!` receives is the [crate::FormatContext] that specify how elements must be formatted.
|
/// The first argument `format!` receives is the [`crate::FormatContext`] that specify how elements must be formatted.
|
||||||
/// Additional parameters passed get formatted by using their [crate::Format] implementation.
|
/// Additional parameters passed get formatted by using their [`crate::Format`] implementation.
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
|
@ -314,13 +314,13 @@ macro_rules! format {
|
||||||
/// ## Behavior
|
/// ## Behavior
|
||||||
/// This IR is similar to Prettier's `conditionalGroup`. The printer measures each variant, except the [`MostExpanded`], in [`Flat`] mode
|
/// This IR is similar to Prettier's `conditionalGroup`. The printer measures each variant, except the [`MostExpanded`], in [`Flat`] mode
|
||||||
/// to find the first variant that fits and prints this variant in [`Flat`] mode. If no variant fits, then
|
/// to find the first variant that fits and prints this variant in [`Flat`] mode. If no variant fits, then
|
||||||
/// the printer falls back to printing the [`MostExpanded`] variant in `[`Expanded`] mode.
|
/// the printer falls back to printing the [`MostExpanded`] variant in [`Expanded`] mode.
|
||||||
///
|
///
|
||||||
/// The definition of *fits* differs to groups in that the printer only tests if it is possible to print
|
/// The definition of *fits* differs to groups in that the printer only tests if it is possible to print
|
||||||
/// the content up to the first non-soft line break without exceeding the configured print width.
|
/// the content up to the first non-soft line break without exceeding the configured print width.
|
||||||
/// This definition differs from groups as that non-soft line breaks make group expand.
|
/// This definition differs from groups as that non-soft line breaks make group expand.
|
||||||
///
|
///
|
||||||
/// [crate::BestFitting] acts as a "break" boundary, meaning that it is considered to fit
|
/// [`crate::BestFitting`] acts as a "break" boundary, meaning that it is considered to fit
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// [`Flat`]: crate::format_element::PrintMode::Flat
|
/// [`Flat`]: crate::format_element::PrintMode::Flat
|
||||||
|
@ -329,6 +329,7 @@ macro_rules! format {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! best_fitting {
|
macro_rules! best_fitting {
|
||||||
($least_expanded:expr, $($tail:expr),+ $(,)?) => {{
|
($least_expanded:expr, $($tail:expr),+ $(,)?) => {{
|
||||||
|
#[allow(unsafe_code)]
|
||||||
unsafe {
|
unsafe {
|
||||||
$crate::BestFitting::from_arguments_unchecked($crate::format_args!($least_expanded, $($tail),+))
|
$crate::BestFitting::from_arguments_unchecked($crate::format_args!($least_expanded, $($tail),+))
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ pub(super) struct StackFrame {
|
||||||
|
|
||||||
/// Stores arguments passed to `print_element` call, holding the state specific to printing an element.
|
/// Stores arguments passed to `print_element` call, holding the state specific to printing an element.
|
||||||
/// E.g. the `indent` depends on the token the Printer's currently processing. That's why
|
/// E.g. the `indent` depends on the token the Printer's currently processing. That's why
|
||||||
/// it must be stored outside of the [PrinterState] that stores the state common to all elements.
|
/// it must be stored outside of the [`PrinterState`] that stores the state common to all elements.
|
||||||
///
|
///
|
||||||
/// The state is passed by value, which is why it's important that it isn't storing any heavy
|
/// The state is passed by value, which is why it's important that it isn't storing any heavy
|
||||||
/// data structures. Such structures should be stored on the [PrinterState] instead.
|
/// data structures. Such structures should be stored on the [`PrinterState`] instead.
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub(super) struct PrintElementArgs {
|
pub(super) struct PrintElementArgs {
|
||||||
indent: Indention,
|
indent: Indention,
|
||||||
|
@ -39,15 +39,15 @@ impl PrintElementArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn mode(&self) -> PrintMode {
|
pub(super) fn mode(self) -> PrintMode {
|
||||||
self.mode
|
self.mode
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn measure_mode(&self) -> MeasureMode {
|
pub(super) fn measure_mode(self) -> MeasureMode {
|
||||||
self.measure_mode
|
self.measure_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn indention(&self) -> Indention {
|
pub(super) fn indention(self) -> Indention {
|
||||||
self.indent
|
self.indent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +92,9 @@ impl Default for PrintElementArgs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call stack that stores the [PrintElementCallArgs].
|
/// Call stack that stores the [`PrintElementCallArgs`].
|
||||||
///
|
///
|
||||||
/// New [PrintElementCallArgs] are pushed onto the stack for every [`start`](Tag::is_start) [`Tag`](FormatElement::Tag)
|
/// New [`PrintElementCallArgs`] are pushed onto the stack for every [`start`](Tag::is_start) [`Tag`](FormatElement::Tag)
|
||||||
/// and popped when reaching the corresponding [`end`](Tag::is_end) [`Tag`](FormatElement::Tag).
|
/// and popped when reaching the corresponding [`end`](Tag::is_end) [`Tag`](FormatElement::Tag).
|
||||||
pub(super) trait CallStack {
|
pub(super) trait CallStack {
|
||||||
type Stack: Stack<StackFrame> + Debug;
|
type Stack: Stack<StackFrame> + Debug;
|
||||||
|
@ -158,7 +158,7 @@ pub(super) trait CallStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [PrintElementArgs] for the current stack frame.
|
/// Returns the [`PrintElementArgs`] for the current stack frame.
|
||||||
fn top(&self) -> PrintElementArgs {
|
fn top(&self) -> PrintElementArgs {
|
||||||
self.stack()
|
self.stack()
|
||||||
.top()
|
.top()
|
||||||
|
@ -166,7 +166,7 @@ pub(super) trait CallStack {
|
||||||
.args
|
.args
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [TagKind] of the current stack frame or [None] if this is the root stack frame.
|
/// Returns the [`TagKind`] of the current stack frame or [None] if this is the root stack frame.
|
||||||
fn top_kind(&self) -> Option<TagKind> {
|
fn top_kind(&self) -> Option<TagKind> {
|
||||||
match self
|
match self
|
||||||
.stack()
|
.stack()
|
||||||
|
@ -179,16 +179,16 @@ pub(super) trait CallStack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new stack frame for a [FormatElement::Tag] of `kind` with `args` as the call arguments.
|
/// Creates a new stack frame for a [`FormatElement::Tag`] of `kind` with `args` as the call arguments.
|
||||||
fn push(&mut self, kind: TagKind, args: PrintElementArgs) {
|
fn push(&mut self, kind: TagKind, args: PrintElementArgs) {
|
||||||
self.stack_mut().push(StackFrame {
|
self.stack_mut().push(StackFrame {
|
||||||
kind: StackFrameKind::Tag(kind),
|
kind: StackFrameKind::Tag(kind),
|
||||||
args,
|
args,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call stack used for printing the [FormatElement]s
|
/// Call stack used for printing the [`FormatElement`]s
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(super) struct PrintCallStack(Vec<StackFrame>);
|
pub(super) struct PrintCallStack(Vec<StackFrame>);
|
||||||
|
|
||||||
|
@ -215,7 +215,7 @@ impl CallStack for PrintCallStack {
|
||||||
|
|
||||||
/// Call stack used for measuring if some content fits on the line.
|
/// Call stack used for measuring if some content fits on the line.
|
||||||
///
|
///
|
||||||
/// The stack is a view on top of the [PrintCallStack] because the stack frames are still necessary for printing.
|
/// The stack is a view on top of the [`PrintCallStack`] because the stack frames are still necessary for printing.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(super) struct FitsCallStack<'print> {
|
pub(super) struct FitsCallStack<'print> {
|
||||||
stack: StackedStack<'print, StackFrame>,
|
stack: StackedStack<'print, StackFrame>,
|
||||||
|
|
|
@ -84,6 +84,7 @@ impl<'a> Printer<'a> {
|
||||||
queue: &mut PrintQueue<'a>,
|
queue: &mut PrintQueue<'a>,
|
||||||
element: &'a FormatElement,
|
element: &'a FormatElement,
|
||||||
) -> PrintResult<()> {
|
) -> PrintResult<()> {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Tag::*;
|
use Tag::*;
|
||||||
|
|
||||||
let args = stack.top();
|
let args = stack.top();
|
||||||
|
@ -94,7 +95,7 @@ impl<'a> Printer<'a> {
|
||||||
FormatElement::DynamicText { text } => self.print_text(text, None),
|
FormatElement::DynamicText { text } => self.print_text(text, None),
|
||||||
FormatElement::SourceCodeSlice { slice, .. } => {
|
FormatElement::SourceCodeSlice { slice, .. } => {
|
||||||
let text = slice.text(self.source_code);
|
let text = slice.text(self.source_code);
|
||||||
self.print_text(text, Some(slice.range()))
|
self.print_text(text, Some(slice.range()));
|
||||||
}
|
}
|
||||||
FormatElement::Line(line_mode) => {
|
FormatElement::Line(line_mode) => {
|
||||||
if args.mode().is_flat()
|
if args.mode().is_flat()
|
||||||
|
@ -221,6 +222,8 @@ impl<'a> Printer<'a> {
|
||||||
|
|
||||||
FormatElement::Tag(StartVerbatim(kind)) => {
|
FormatElement::Tag(StartVerbatim(kind)) => {
|
||||||
if let VerbatimKind::Verbatim { length } = kind {
|
if let VerbatimKind::Verbatim { length } = kind {
|
||||||
|
// SAFETY: Ruff only supports formatting files <= 4GB
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
self.state.verbatim_markers.push(TextRange::at(
|
self.state.verbatim_markers.push(TextRange::at(
|
||||||
TextSize::from(self.state.buffer.len() as u32),
|
TextSize::from(self.state.buffer.len() as u32),
|
||||||
*length,
|
*length,
|
||||||
|
@ -291,7 +294,7 @@ impl<'a> Printer<'a> {
|
||||||
kind: TagKind,
|
kind: TagKind,
|
||||||
mode: GroupMode,
|
mode: GroupMode,
|
||||||
args: PrintElementArgs,
|
args: PrintElementArgs,
|
||||||
queue: &mut PrintQueue<'a>,
|
queue: &PrintQueue<'a>,
|
||||||
stack: &mut PrintCallStack,
|
stack: &mut PrintCallStack,
|
||||||
) -> PrintResult<PrintMode> {
|
) -> PrintResult<PrintMode> {
|
||||||
let group_mode = match mode {
|
let group_mode = match mode {
|
||||||
|
@ -384,7 +387,7 @@ impl<'a> Printer<'a> {
|
||||||
|
|
||||||
if let Some(last) = self.state.source_markers.last() {
|
if let Some(last) = self.state.source_markers.last() {
|
||||||
if last != &marker {
|
if last != &marker {
|
||||||
self.state.source_markers.push(marker)
|
self.state.source_markers.push(marker);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.state.source_markers.push(marker);
|
self.state.source_markers.push(marker);
|
||||||
|
@ -411,10 +414,11 @@ impl<'a> Printer<'a> {
|
||||||
queue.push(suffix);
|
queue.push(suffix);
|
||||||
}
|
}
|
||||||
LineSuffixEntry::Args(args) => {
|
LineSuffixEntry::Args(args) => {
|
||||||
stack.push(TagKind::LineSuffix, args);
|
|
||||||
const LINE_SUFFIX_END: &FormatElement =
|
const LINE_SUFFIX_END: &FormatElement =
|
||||||
&FormatElement::Tag(Tag::EndLineSuffix);
|
&FormatElement::Tag(Tag::EndLineSuffix);
|
||||||
|
|
||||||
|
stack.push(TagKind::LineSuffix, args);
|
||||||
|
|
||||||
queue.push(LINE_SUFFIX_END);
|
queue.push(LINE_SUFFIX_END);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -437,7 +441,7 @@ impl<'a> Printer<'a> {
|
||||||
self.state.measured_group_fits = true;
|
self.state.measured_group_fits = true;
|
||||||
let normal_variants = &variants[..variants.len() - 1];
|
let normal_variants = &variants[..variants.len() - 1];
|
||||||
|
|
||||||
for variant in normal_variants.iter() {
|
for variant in normal_variants {
|
||||||
// Test if this variant fits and if so, use it. Otherwise try the next
|
// Test if this variant fits and if so, use it. Otherwise try the next
|
||||||
// variant.
|
// variant.
|
||||||
|
|
||||||
|
@ -614,7 +618,7 @@ impl<'a> Printer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Semantic alias for [Self::print_entry] for fill items.
|
/// Semantic alias for [`Self::print_entry`] for fill items.
|
||||||
fn print_fill_item(
|
fn print_fill_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
queue: &mut PrintQueue<'a>,
|
queue: &mut PrintQueue<'a>,
|
||||||
|
@ -624,7 +628,7 @@ impl<'a> Printer<'a> {
|
||||||
self.print_entry(queue, stack, args)
|
self.print_entry(queue, stack, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Semantic alias for [Self::print_entry] for fill separators.
|
/// Semantic alias for [`Self::print_entry`] for fill separators.
|
||||||
fn print_fill_separator(
|
fn print_fill_separator(
|
||||||
&mut self,
|
&mut self,
|
||||||
queue: &mut PrintQueue<'a>,
|
queue: &mut PrintQueue<'a>,
|
||||||
|
@ -636,7 +640,7 @@ impl<'a> Printer<'a> {
|
||||||
|
|
||||||
/// Fully print an element (print the element itself and all its descendants)
|
/// Fully print an element (print the element itself and all its descendants)
|
||||||
///
|
///
|
||||||
/// Unlike [print_element], this function ensures the entire element has
|
/// Unlike [`print_element`], this function ensures the entire element has
|
||||||
/// been printed when it returns and the queue is back to its original state
|
/// been printed when it returns and the queue is back to its original state
|
||||||
fn print_entry(
|
fn print_entry(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -703,9 +707,11 @@ impl<'a> Printer<'a> {
|
||||||
} else {
|
} else {
|
||||||
self.state.buffer.push(char);
|
self.state.buffer.push(char);
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
let char_width = if char == '\t' {
|
let char_width = if char == '\t' {
|
||||||
self.options.tab_width as u32
|
u32::from(self.options.tab_width)
|
||||||
} else {
|
} else {
|
||||||
|
// SAFETY: A u32 is sufficient to represent the width of a file <= 4GB
|
||||||
char.width().unwrap_or(0) as u32
|
char.width().unwrap_or(0) as u32
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -791,7 +797,7 @@ enum Indention {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Indention {
|
impl Indention {
|
||||||
const fn is_empty(&self) -> bool {
|
const fn is_empty(self) -> bool {
|
||||||
matches!(self, Indention::Level(0))
|
matches!(self, Indention::Level(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,27 +807,27 @@ impl Indention {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the indention level
|
/// Returns the indention level
|
||||||
fn level(&self) -> u16 {
|
fn level(self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
Indention::Level(count) => *count,
|
Indention::Level(count) => count,
|
||||||
Indention::Align { level: indent, .. } => *indent,
|
Indention::Align { level: indent, .. } => indent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of trailing align spaces or 0 if none
|
/// Returns the number of trailing align spaces or 0 if none
|
||||||
fn align(&self) -> u8 {
|
fn align(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Indention::Level(_) => 0,
|
Indention::Level(_) => 0,
|
||||||
Indention::Align { align, .. } => (*align).into(),
|
Indention::Align { align, .. } => align.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increments the level by one.
|
/// Increments the level by one.
|
||||||
///
|
///
|
||||||
/// The behaviour depends on the [`indent_style`][IndentStyle] if this is an [Indent::Align]:
|
/// The behaviour depends on the [`indent_style`][IndentStyle] if this is an [`Indent::Align`]:
|
||||||
/// - **Tabs**: `align` is converted into an indent. This results in `level` increasing by two: once for the align, once for the level increment
|
/// - **Tabs**: `align` is converted into an indent. This results in `level` increasing by two: once for the align, once for the level increment
|
||||||
/// - **Spaces**: Increments the `level` by one and keeps the `align` unchanged.
|
/// - **Spaces**: Increments the `level` by one and keeps the `align` unchanged.
|
||||||
/// Keeps any the current value is [Indent::Align] and increments the level by one.
|
/// Keeps any the current value is [`Indent::Align`] and increments the level by one.
|
||||||
fn increment_level(self, indent_style: IndentStyle) -> Self {
|
fn increment_level(self, indent_style: IndentStyle) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Indention::Level(count) => Indention::Level(count + 1),
|
Indention::Level(count) => Indention::Level(count + 1),
|
||||||
|
@ -838,8 +844,8 @@ impl Indention {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decrements the indent by one by:
|
/// Decrements the indent by one by:
|
||||||
/// - Reducing the level by one if this is [Indent::Level]
|
/// - Reducing the level by one if this is [`Indent::Level`]
|
||||||
/// - Removing the `align` if this is [Indent::Align]
|
/// - Removing the `align` if this is [`Indent::Align`]
|
||||||
///
|
///
|
||||||
/// No-op if the level is already zero.
|
/// No-op if the level is already zero.
|
||||||
fn decrement(self) -> Self {
|
fn decrement(self) -> Self {
|
||||||
|
@ -851,7 +857,7 @@ impl Indention {
|
||||||
|
|
||||||
/// Adds an `align` of `count` spaces to the current indention.
|
/// Adds an `align` of `count` spaces to the current indention.
|
||||||
///
|
///
|
||||||
/// It increments the `level` value if the current value is [Indent::IndentAlign].
|
/// It increments the `level` value if the current value is [`Indent::IndentAlign`].
|
||||||
fn set_align(self, count: NonZeroU8) -> Self {
|
fn set_align(self, count: NonZeroU8) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Indention::Level(indent_count) => Indention::Align {
|
Indention::Level(indent_count) => Indention::Align {
|
||||||
|
@ -955,9 +961,9 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests if the content of a `Fill` item fits in [PrintMode::Flat].
|
/// Tests if the content of a `Fill` item fits in [`PrintMode::Flat`].
|
||||||
///
|
///
|
||||||
/// Returns `Err` if the top element of the queue is not a [Tag::StartEntry]
|
/// Returns `Err` if the top element of the queue is not a [`Tag::StartEntry`]
|
||||||
/// or if the document has any mismatching start/end tags.
|
/// or if the document has any mismatching start/end tags.
|
||||||
fn fill_item_fits(&mut self) -> PrintResult<bool> {
|
fn fill_item_fits(&mut self) -> PrintResult<bool> {
|
||||||
self.fill_entry_fits(PrintMode::Flat)
|
self.fill_entry_fits(PrintMode::Flat)
|
||||||
|
@ -965,17 +971,17 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
|
|
||||||
/// Tests if the content of a `Fill` separator fits with `mode`.
|
/// Tests if the content of a `Fill` separator fits with `mode`.
|
||||||
///
|
///
|
||||||
/// Returns `Err` if the top element of the queue is not a [Tag::StartEntry]
|
/// Returns `Err` if the top element of the queue is not a [`Tag::StartEntry`]
|
||||||
/// or if the document has any mismatching start/end tags.
|
/// or if the document has any mismatching start/end tags.
|
||||||
fn fill_separator_fits(&mut self, mode: PrintMode) -> PrintResult<bool> {
|
fn fill_separator_fits(&mut self, mode: PrintMode) -> PrintResult<bool> {
|
||||||
self.fill_entry_fits(mode)
|
self.fill_entry_fits(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests if the elements between the [Tag::StartEntry] and [Tag::EndEntry]
|
/// Tests if the elements between the [`Tag::StartEntry`] and [`Tag::EndEntry`]
|
||||||
/// of a fill item or separator fits with `mode`.
|
/// of a fill item or separator fits with `mode`.
|
||||||
///
|
///
|
||||||
/// Returns `Err` if the queue isn't positioned at a [Tag::StartEntry] or if
|
/// Returns `Err` if the queue isn't positioned at a [`Tag::StartEntry`] or if
|
||||||
/// the matching [Tag::EndEntry] is missing.
|
/// the matching [`Tag::EndEntry`] is missing.
|
||||||
fn fill_entry_fits(&mut self, mode: PrintMode) -> PrintResult<bool> {
|
fn fill_entry_fits(&mut self, mode: PrintMode) -> PrintResult<bool> {
|
||||||
let start_entry = self.queue.top();
|
let start_entry = self.queue.top();
|
||||||
|
|
||||||
|
@ -997,6 +1003,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
|
|
||||||
/// Tests if the passed element fits on the current line or not.
|
/// Tests if the passed element fits on the current line or not.
|
||||||
fn fits_element(&mut self, element: &'a FormatElement) -> PrintResult<Fits> {
|
fn fits_element(&mut self, element: &'a FormatElement) -> PrintResult<Fits> {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
use Tag::*;
|
use Tag::*;
|
||||||
|
|
||||||
let args = self.stack.top();
|
let args = self.stack.top();
|
||||||
|
@ -1093,7 +1100,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatElement::Tag(StartGroup(group)) => {
|
FormatElement::Tag(StartGroup(group)) => {
|
||||||
return self.fits_group(TagKind::Group, group.mode(), group.id(), args);
|
return Ok(self.fits_group(TagKind::Group, group.mode(), group.id(), args));
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatElement::Tag(StartConditionalGroup(group)) => {
|
FormatElement::Tag(StartConditionalGroup(group)) => {
|
||||||
|
@ -1108,10 +1115,14 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if condition.mode == print_mode {
|
if condition.mode == print_mode {
|
||||||
return self.fits_group(TagKind::ConditionalGroup, group.mode(), None, args);
|
return Ok(self.fits_group(
|
||||||
} else {
|
TagKind::ConditionalGroup,
|
||||||
self.stack.push(TagKind::ConditionalGroup, args);
|
group.mode(),
|
||||||
|
None,
|
||||||
|
args,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
self.stack.push(TagKind::ConditionalGroup, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatElement::Tag(StartConditionalContent(condition)) => {
|
FormatElement::Tag(StartConditionalContent(condition)) => {
|
||||||
|
@ -1183,14 +1194,14 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
TagKind::FitsExpanded,
|
TagKind::FitsExpanded,
|
||||||
args.with_print_mode(PrintMode::Expanded)
|
args.with_print_mode(PrintMode::Expanded)
|
||||||
.with_measure_mode(MeasureMode::AllLines),
|
.with_measure_mode(MeasureMode::AllLines),
|
||||||
)
|
);
|
||||||
} else {
|
} else {
|
||||||
if propagate_expand.get() && args.mode().is_flat() {
|
if propagate_expand.get() && args.mode().is_flat() {
|
||||||
return Ok(Fits::No);
|
return Ok(Fits::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
// As usual
|
// As usual
|
||||||
self.stack.push(TagKind::FitsExpanded, args)
|
self.stack.push(TagKind::FitsExpanded, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1227,17 +1238,17 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
mode: GroupMode,
|
mode: GroupMode,
|
||||||
id: Option<GroupId>,
|
id: Option<GroupId>,
|
||||||
args: PrintElementArgs,
|
args: PrintElementArgs,
|
||||||
) -> PrintResult<Fits> {
|
) -> Fits {
|
||||||
if self.must_be_flat && !mode.is_flat() {
|
if self.must_be_flat && !mode.is_flat() {
|
||||||
return Ok(Fits::No);
|
return Fits::No;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue printing groups in expanded mode if measuring a `best_fitting` element where
|
// Continue printing groups in expanded mode if measuring a `best_fitting` element where
|
||||||
// a group expands.
|
// a group expands.
|
||||||
let print_mode = if !mode.is_flat() {
|
let print_mode = if mode.is_flat() {
|
||||||
PrintMode::Expanded
|
|
||||||
} else {
|
|
||||||
args.mode()
|
args.mode()
|
||||||
|
} else {
|
||||||
|
PrintMode::Expanded
|
||||||
};
|
};
|
||||||
|
|
||||||
self.stack.push(kind, args.with_print_mode(print_mode));
|
self.stack.push(kind, args.with_print_mode(print_mode));
|
||||||
|
@ -1246,30 +1257,32 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
self.group_modes_mut().insert_print_mode(id, print_mode);
|
self.group_modes_mut().insert_print_mode(id, print_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Fits::Maybe)
|
Fits::Maybe
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fits_text(&mut self, text: &str, args: PrintElementArgs) -> Fits {
|
fn fits_text(&mut self, text: &str, args: PrintElementArgs) -> Fits {
|
||||||
let indent = std::mem::take(&mut self.state.pending_indent);
|
let indent = std::mem::take(&mut self.state.pending_indent);
|
||||||
self.state.line_width +=
|
self.state.line_width += u32::from(indent.level())
|
||||||
indent.level() as u32 * self.options().indent_width() as u32 + indent.align() as u32;
|
* u32::from(self.options().indent_width())
|
||||||
|
+ u32::from(indent.align());
|
||||||
|
|
||||||
for c in text.chars() {
|
for c in text.chars() {
|
||||||
let char_width = match c {
|
let char_width = match c {
|
||||||
'\t' => self.options().tab_width as u32,
|
'\t' => u32::from(self.options().tab_width),
|
||||||
'\n' => {
|
'\n' => {
|
||||||
if self.must_be_flat {
|
if self.must_be_flat {
|
||||||
return Fits::No;
|
return Fits::No;
|
||||||
} else {
|
}
|
||||||
match args.measure_mode() {
|
match args.measure_mode() {
|
||||||
MeasureMode::FirstLine => return Fits::Yes,
|
MeasureMode::FirstLine => return Fits::Yes,
|
||||||
MeasureMode::AllLines => {
|
MeasureMode::AllLines => {
|
||||||
self.state.line_width = 0;
|
self.state.line_width = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
// SAFETY: A u32 is sufficient to format files <= 4GB
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
c => c.width().unwrap_or(0) as u32,
|
c => c.width().unwrap_or(0) as u32,
|
||||||
};
|
};
|
||||||
self.state.line_width += char_width;
|
self.state.line_width += char_width;
|
||||||
|
@ -1352,9 +1365,10 @@ enum Fits {
|
||||||
|
|
||||||
impl From<bool> for Fits {
|
impl From<bool> for Fits {
|
||||||
fn from(value: bool) -> Self {
|
fn from(value: bool) -> Self {
|
||||||
match value {
|
if value {
|
||||||
true => Fits::Yes,
|
Fits::Yes
|
||||||
false => Fits::No,
|
} else {
|
||||||
|
Fits::No
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1418,7 +1432,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(r#"["a", "b", "c", "d"]"#, result.as_code())
|
assert_eq!(r#"["a", "b", "c", "d"]"#, result.as_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1447,7 +1461,7 @@ mod tests {
|
||||||
b
|
b
|
||||||
a"#,
|
a"#,
|
||||||
formatted.as_code()
|
formatted.as_code()
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1489,13 +1503,13 @@ two lines`,
|
||||||
"b",
|
"b",
|
||||||
]"#,
|
]"#,
|
||||||
result.as_code()
|
result.as_code()
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn it_breaks_a_group_if_it_contains_a_hard_line_break() {
|
fn it_breaks_a_group_if_it_contains_a_hard_line_break() {
|
||||||
let result = format(&group(&format_args![text("a"), block_indent(&text("b"))]));
|
let result = format(&group(&format_args![text("a"), block_indent(&text("b"))]));
|
||||||
|
|
||||||
assert_eq!("a\n b\n", result.as_code())
|
assert_eq!("a\n b\n", result.as_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1559,7 +1573,7 @@ two lines`,
|
||||||
text("b"),
|
text("b"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!("a\nb", result.as_code())
|
assert_eq!("a\nb", result.as_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1572,7 +1586,7 @@ two lines`,
|
||||||
text("b"),
|
text("b"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!("a\n\n\n\nb", result.as_code())
|
assert_eq!("a\n\n\n\nb", result.as_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1586,7 +1600,7 @@ two lines`,
|
||||||
text("b"),
|
text("b"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!("a\n\n\nb", result.as_code())
|
assert_eq!("a\n\n\nb", result.as_code());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1648,7 +1662,7 @@ two lines`,
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
printed.as_code(),
|
printed.as_code(),
|
||||||
"1, 2, 3,\n723493294,\n[5],\n[\n\t123456789\n]"
|
"1, 2, 3,\n723493294,\n[5],\n[\n\t123456789\n]"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1678,7 +1692,7 @@ two lines`,
|
||||||
&line_suffix(&format_args![space(), text("// trailing")])
|
&line_suffix(&format_args![space(), text("// trailing")])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_eq!(printed.as_code(), "[1, 2, 3]; // trailing")
|
assert_eq!(printed.as_code(), "[1, 2, 3]; // trailing");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{FormatOptions, IndentStyle, LineWidth};
|
use crate::{FormatOptions, IndentStyle, LineWidth};
|
||||||
|
|
||||||
/// Options that affect how the [crate::Printer] prints the format tokens
|
/// Options that affect how the [`crate::Printer`] prints the format tokens
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct PrinterOptions {
|
pub struct PrinterOptions {
|
||||||
/// Width of a single tab character (does it equal 2, 4, ... spaces?)
|
/// Width of a single tab character (does it equal 2, 4, ... spaces?)
|
||||||
|
@ -33,7 +33,7 @@ impl Default for PrintWidth {
|
||||||
|
|
||||||
impl From<LineWidth> for PrintWidth {
|
impl From<LineWidth> for PrintWidth {
|
||||||
fn from(width: LineWidth) -> Self {
|
fn from(width: LineWidth) -> Self {
|
||||||
Self(u16::from(width) as u32)
|
Self(u32::from(u16::from(width)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,11 +61,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrinterOptions {
|
impl PrinterOptions {
|
||||||
|
#[must_use]
|
||||||
pub fn with_print_width(mut self, width: PrintWidth) -> Self {
|
pub fn with_print_width(mut self, width: PrintWidth) -> Self {
|
||||||
self.print_width = width;
|
self.print_width = width;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn with_indent(mut self, style: IndentStyle) -> Self {
|
pub fn with_indent(mut self, style: IndentStyle) -> Self {
|
||||||
self.indent_style = style;
|
self.indent_style = style;
|
||||||
|
|
||||||
|
@ -114,7 +116,7 @@ impl Default for PrinterOptions {
|
||||||
PrinterOptions {
|
PrinterOptions {
|
||||||
tab_width: 2,
|
tab_width: 2,
|
||||||
print_width: PrintWidth::default(),
|
print_width: PrintWidth::default(),
|
||||||
indent_style: Default::default(),
|
indent_style: IndentStyle::default(),
|
||||||
line_ending: LineEnding::LineFeed,
|
line_ending: LineEnding::LineFeed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::fmt::Debug;
|
||||||
use std::iter::FusedIterator;
|
use std::iter::FusedIterator;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
/// Queue of [FormatElement]s.
|
/// Queue of [`FormatElement`]s.
|
||||||
pub(super) trait Queue<'a> {
|
pub(super) trait Queue<'a> {
|
||||||
type Stack: Stack<&'a [FormatElement]>;
|
type Stack: Stack<&'a [FormatElement]>;
|
||||||
|
|
||||||
|
@ -40,19 +40,19 @@ pub(super) trait Queue<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the next element, not traversing into [FormatElement::Interned].
|
/// Returns the next element, not traversing into [`FormatElement::Interned`].
|
||||||
fn top_with_interned(&self) -> Option<&'a FormatElement> {
|
fn top_with_interned(&self) -> Option<&'a FormatElement> {
|
||||||
self.stack()
|
self.stack()
|
||||||
.top()
|
.top()
|
||||||
.map(|top_slice| &top_slice[self.next_index()])
|
.map(|top_slice| &top_slice[self.next_index()])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the next element, recursively resolving the first element of [FormatElement::Interned].
|
/// Returns the next element, recursively resolving the first element of [`FormatElement::Interned`].
|
||||||
fn top(&self) -> Option<&'a FormatElement> {
|
fn top(&self) -> Option<&'a FormatElement> {
|
||||||
let mut top = self.top_with_interned();
|
let mut top = self.top_with_interned();
|
||||||
|
|
||||||
while let Some(FormatElement::Interned(interned)) = top {
|
while let Some(FormatElement::Interned(interned)) = top {
|
||||||
top = interned.first()
|
top = interned.first();
|
||||||
}
|
}
|
||||||
|
|
||||||
top
|
top
|
||||||
|
@ -60,7 +60,7 @@ pub(super) trait Queue<'a> {
|
||||||
|
|
||||||
/// Queues a single element to process before the other elements in this queue.
|
/// Queues a single element to process before the other elements in this queue.
|
||||||
fn push(&mut self, element: &'a FormatElement) {
|
fn push(&mut self, element: &'a FormatElement) {
|
||||||
self.extend_back(std::slice::from_ref(element))
|
self.extend_back(std::slice::from_ref(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queues a slice of elements to process before the other elements in this queue.
|
/// Queues a slice of elements to process before the other elements in this queue.
|
||||||
|
@ -73,7 +73,7 @@ pub(super) trait Queue<'a> {
|
||||||
let next_index = self.next_index();
|
let next_index = self.next_index();
|
||||||
let stack = self.stack_mut();
|
let stack = self.stack_mut();
|
||||||
if let Some(top) = stack.pop() {
|
if let Some(top) = stack.pop() {
|
||||||
stack.push(&top[next_index..])
|
stack.push(&top[next_index..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.push(slice);
|
stack.push(slice);
|
||||||
|
@ -150,14 +150,14 @@ impl<'a> Queue<'a> for PrintQueue<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_next_index(&mut self, index: usize) {
|
fn set_next_index(&mut self, index: usize) {
|
||||||
self.next_index = index
|
self.next_index = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue for measuring if an element fits on the line.
|
/// Queue for measuring if an element fits on the line.
|
||||||
///
|
///
|
||||||
/// The queue is a view on top of the [PrintQueue] because no elements should be removed
|
/// The queue is a view on top of the [`PrintQueue`] because no elements should be removed
|
||||||
/// from the [PrintQueue] while measuring.
|
/// from the [`PrintQueue`] while measuring.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct FitsQueue<'a, 'print> {
|
pub(super) struct FitsQueue<'a, 'print> {
|
||||||
|
@ -203,9 +203,9 @@ impl<'a, 'print> Queue<'a> for FitsQueue<'a, 'print> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator that calls [Queue::pop] until it reaches the end of the document.
|
/// Iterator that calls [`Queue::pop`] until it reaches the end of the document.
|
||||||
///
|
///
|
||||||
/// The iterator traverses into the content of any [FormatElement::Interned].
|
/// The iterator traverses into the content of any [`FormatElement::Interned`].
|
||||||
pub(super) struct QueueIterator<'a, 'q, Q: Queue<'a>> {
|
pub(super) struct QueueIterator<'a, 'q, Q: Queue<'a>> {
|
||||||
queue: &'q mut Q,
|
queue: &'q mut Q,
|
||||||
lifetime: PhantomData<&'a ()>,
|
lifetime: PhantomData<&'a ()>,
|
||||||
|
@ -252,32 +252,31 @@ where
|
||||||
type Item = &'a FormatElement;
|
type Item = &'a FormatElement;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self.depth {
|
if self.depth == 0 {
|
||||||
0 => None,
|
None
|
||||||
_ => {
|
} else {
|
||||||
let mut top = self.queue.pop();
|
let mut top = self.queue.pop();
|
||||||
|
|
||||||
while let Some(FormatElement::Interned(interned)) = top {
|
while let Some(FormatElement::Interned(interned)) = top {
|
||||||
self.queue.extend_back(interned);
|
self.queue.extend_back(interned);
|
||||||
top = self.queue.pop();
|
top = self.queue.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
match top.expect("Missing end signal.") {
|
match top.expect("Missing end signal.") {
|
||||||
element @ FormatElement::Tag(tag) if tag.kind() == self.kind => {
|
element @ FormatElement::Tag(tag) if tag.kind() == self.kind => {
|
||||||
if tag.is_start() {
|
if tag.is_start() {
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
} else {
|
} else {
|
||||||
self.depth -= 1;
|
self.depth -= 1;
|
||||||
|
|
||||||
if self.depth == 0 {
|
if self.depth == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(element)
|
|
||||||
}
|
}
|
||||||
element => Some(element),
|
|
||||||
|
Some(element)
|
||||||
}
|
}
|
||||||
|
element => Some(element),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +286,7 @@ impl<'a, Q> FusedIterator for QueueContentIterator<'a, '_, Q> where Q: Queue<'a>
|
||||||
|
|
||||||
/// A predicate determining when to end measuring if some content fits on the line.
|
/// A predicate determining when to end measuring if some content fits on the line.
|
||||||
///
|
///
|
||||||
/// Called for every [`element`](FormatElement) in the [FitsQueue] when measuring if a content
|
/// Called for every [`element`](FormatElement) in the [`FitsQueue`] when measuring if a content
|
||||||
/// fits on the line. The measuring of the content ends after the first element [`element`](FormatElement) for which this
|
/// fits on the line. The measuring of the content ends after the first element [`element`](FormatElement) for which this
|
||||||
/// predicate returns `true` (similar to a take while iterator except that it takes while the predicate returns `false`).
|
/// predicate returns `true` (similar to a take while iterator except that it takes while the predicate returns `false`).
|
||||||
pub(super) trait FitsEndPredicate {
|
pub(super) trait FitsEndPredicate {
|
||||||
|
@ -303,7 +302,7 @@ impl FitsEndPredicate for AllPredicate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Filter that takes all elements between two matching [Tag::StartEntry] and [Tag::EndEntry] tags.
|
/// Filter that takes all elements between two matching [`Tag::StartEntry`] and [`Tag::EndEntry`] tags.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum SingleEntryPredicate {
|
pub(super) enum SingleEntryPredicate {
|
||||||
Entry { depth: usize },
|
Entry { depth: usize },
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl<T> Stack<T> for Vec<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, value: T) {
|
fn push(&mut self, value: T) {
|
||||||
self.push(value)
|
self.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top(&self) -> Option<&T> {
|
fn top(&self) -> Option<&T> {
|
||||||
|
|
|
@ -715,23 +715,19 @@ pub fn walk_pattern<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, pattern: &'a P
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(
|
pub fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(visitor: &V, expr_context: &'a ExprContext) {}
|
||||||
visitor: &mut V,
|
|
||||||
expr_context: &'a ExprContext,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn walk_bool_op<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, bool_op: &'a BoolOp) {}
|
pub fn walk_bool_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, bool_op: &'a BoolOp) {}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn walk_operator<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, operator: &'a Operator) {}
|
pub fn walk_operator<'a, V: Visitor<'a> + ?Sized>(visitor: &V, operator: &'a Operator) {}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn walk_unary_op<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, unary_op: &'a UnaryOp) {}
|
pub fn walk_unary_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, unary_op: &'a UnaryOp) {}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn walk_cmp_op<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, cmp_op: &'a CmpOp) {}
|
pub fn walk_cmp_op<'a, V: Visitor<'a> + ?Sized>(visitor: &V, cmp_op: &'a CmpOp) {}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, alias: &'a Alias) {}
|
pub fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &V, alias: &'a Alias) {}
|
||||||
|
|
|
@ -341,7 +341,7 @@ impl AsciiEscape<'_> {
|
||||||
let mut single_count = 0;
|
let mut single_count = 0;
|
||||||
let mut double_count = 0;
|
let mut double_count = 0;
|
||||||
|
|
||||||
for ch in source.iter() {
|
for ch in source {
|
||||||
let incr = match ch {
|
let incr = match ch {
|
||||||
b'\'' => {
|
b'\'' => {
|
||||||
single_count += 1;
|
single_count += 1;
|
||||||
|
@ -425,7 +425,7 @@ impl<'a> Escape for AsciiEscape<'a> {
|
||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
fn write_body_slow(&self, formatter: &mut impl std::fmt::Write) -> std::fmt::Result {
|
fn write_body_slow(&self, formatter: &mut impl std::fmt::Write) -> std::fmt::Result {
|
||||||
for ch in self.source.iter() {
|
for ch in self.source {
|
||||||
Self::write_char(*ch, self.layout().quote, formatter)?;
|
Self::write_char(*ch, self.layout().quote, formatter)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -775,7 +775,7 @@ type X[T] \
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_type_as_identifier() {
|
fn test_type_as_identifier() {
|
||||||
let source = r#"\
|
let source = r"\
|
||||||
type *a + b, c # ((type * a) + b), c
|
type *a + b, c # ((type * a) + b), c
|
||||||
type *(a + b), c # (type * (a + b)), c
|
type *(a + b), c # (type * (a + b)), c
|
||||||
type (*a + b, c) # type ((*(a + b)), c)
|
type (*a + b, c) # type ((*(a + b)), c)
|
||||||
|
@ -806,7 +806,7 @@ type (
|
||||||
type = 1
|
type = 1
|
||||||
type = x = 1
|
type = x = 1
|
||||||
x = type = 1
|
x = type = 1
|
||||||
"#;
|
";
|
||||||
insta::assert_debug_snapshot!(parse_suite(source, "<test>").unwrap());
|
insta::assert_debug_snapshot!(parse_suite(source, "<test>").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,7 +863,7 @@ y = 100(no)
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_match_as_identifier() {
|
fn test_match_as_identifier() {
|
||||||
let source = r#"\
|
let source = r"\
|
||||||
match *a + b, c # ((match * a) + b), c
|
match *a + b, c # ((match * a) + b), c
|
||||||
match *(a + b), c # (match * (a + b)), c
|
match *(a + b), c # (match * (a + b)), c
|
||||||
match (*a + b, c) # match ((*(a + b)), c)
|
match (*a + b, c) # match ((*(a + b)), c)
|
||||||
|
@ -885,7 +885,7 @@ match match:
|
||||||
pass
|
pass
|
||||||
match = lambda query: query == event
|
match = lambda query: query == event
|
||||||
print(match(12))
|
print(match(12))
|
||||||
"#;
|
";
|
||||||
insta::assert_debug_snapshot!(parse_suite(source, "<test>").unwrap());
|
insta::assert_debug_snapshot!(parse_suite(source, "<test>").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,7 +1124,7 @@ class Abcd:
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ipython_escape_commands() {
|
fn test_ipython_escape_commands() {
|
||||||
let parse_ast = parse(
|
let parse_ast = parse(
|
||||||
r#"
|
r"
|
||||||
# Normal Python code
|
# Normal Python code
|
||||||
(
|
(
|
||||||
a
|
a
|
||||||
|
@ -1189,7 +1189,7 @@ foo[0]??
|
||||||
foo[0][1]?
|
foo[0][1]?
|
||||||
foo.bar[0].baz[1]??
|
foo.bar[0].baz[1]??
|
||||||
foo.bar[0].baz[2].egg??
|
foo.bar[0].baz[2].egg??
|
||||||
"#
|
"
|
||||||
.trim(),
|
.trim(),
|
||||||
Mode::Jupyter,
|
Mode::Jupyter,
|
||||||
"<test>",
|
"<test>",
|
||||||
|
|
|
@ -387,7 +387,7 @@ impl<'a> StringParser<'a> {
|
||||||
'{' => {
|
'{' => {
|
||||||
if !constant_piece.is_empty() {
|
if !constant_piece.is_empty() {
|
||||||
spec_constructor.push(Expr::from(ast::ExprConstant {
|
spec_constructor.push(Expr::from(ast::ExprConstant {
|
||||||
value: constant_piece.drain(..).collect::<String>().into(),
|
value: std::mem::take(&mut constant_piece).into(),
|
||||||
kind: None,
|
kind: None,
|
||||||
range: self.range(start_location),
|
range: self.range(start_location),
|
||||||
}));
|
}));
|
||||||
|
@ -408,7 +408,7 @@ impl<'a> StringParser<'a> {
|
||||||
}
|
}
|
||||||
if !constant_piece.is_empty() {
|
if !constant_piece.is_empty() {
|
||||||
spec_constructor.push(Expr::from(ast::ExprConstant {
|
spec_constructor.push(Expr::from(ast::ExprConstant {
|
||||||
value: constant_piece.drain(..).collect::<String>().into(),
|
value: std::mem::take(&mut constant_piece).into(),
|
||||||
kind: None,
|
kind: None,
|
||||||
range: self.range(start_location),
|
range: self.range(start_location),
|
||||||
}));
|
}));
|
||||||
|
@ -446,7 +446,7 @@ impl<'a> StringParser<'a> {
|
||||||
}
|
}
|
||||||
if !content.is_empty() {
|
if !content.is_empty() {
|
||||||
values.push(Expr::from(ast::ExprConstant {
|
values.push(Expr::from(ast::ExprConstant {
|
||||||
value: content.drain(..).collect::<String>().into(),
|
value: std::mem::take(&mut content).into(),
|
||||||
kind: None,
|
kind: None,
|
||||||
range: self.range(start_location),
|
range: self.range(start_location),
|
||||||
}));
|
}));
|
||||||
|
@ -1003,7 +1003,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_escape_char_in_byte_literal() {
|
fn test_escape_char_in_byte_literal() {
|
||||||
// backslash does not escape
|
// backslash does not escape
|
||||||
let source = r##"b"omkmok\Xaa""##; // spell-checker:ignore omkmok
|
let source = r#"b"omkmok\Xaa""#; // spell-checker:ignore omkmok
|
||||||
let parse_ast = parse_suite(source, "<test>").unwrap();
|
let parse_ast = parse_suite(source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
@ -1024,7 +1024,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_escape_octet() {
|
fn test_escape_octet() {
|
||||||
let source = r##"b'\43a\4\1234'"##;
|
let source = r"b'\43a\4\1234'";
|
||||||
let parse_ast = parse_suite(source, "<test>").unwrap();
|
let parse_ast = parse_suite(source, "<test>").unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
|
@ -877,8 +877,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn single_quoted_multiline_string_containing_comment() {
|
fn single_quoted_multiline_string_containing_comment() {
|
||||||
let test_case = tokenize(
|
let test_case = tokenize(
|
||||||
r#"'This string contains a hash looking like a comment\
|
r"'This string contains a hash looking like a comment\
|
||||||
# This is not a comment'"#,
|
# This is not a comment'",
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_debug_snapshot!(test_case.tokenize_reverse());
|
assert_debug_snapshot!(test_case.tokenize_reverse());
|
||||||
|
@ -928,14 +928,14 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_with_escaped_quote() {
|
fn string_with_escaped_quote() {
|
||||||
let test_case = tokenize(r#"'a string \' # containing a hash ' # finally a comment"#);
|
let test_case = tokenize(r"'a string \' # containing a hash ' # finally a comment");
|
||||||
|
|
||||||
assert_debug_snapshot!(test_case.tokenize_reverse());
|
assert_debug_snapshot!(test_case.tokenize_reverse());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn string_with_double_escaped_backslash() {
|
fn string_with_double_escaped_backslash() {
|
||||||
let test_case = tokenize(r#"'a string \\' # a comment '"#);
|
let test_case = tokenize(r"'a string \\' # a comment '");
|
||||||
|
|
||||||
assert_debug_snapshot!(test_case.tokenize_reverse());
|
assert_debug_snapshot!(test_case.tokenize_reverse());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue