Introduce IndentWidth (#7301)

This commit is contained in:
Micha Reiser 2023-09-13 14:52:24 +02:00 committed by GitHub
parent e122a96d27
commit 2d9b39871f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 187 additions and 199 deletions

View file

@ -361,7 +361,7 @@ where
f.write_element(FormatElement::Text {
text: self.text.to_string().into_boxed_str(),
text_width: TextWidth::from_text(self.text, f.options().tab_width()),
text_width: TextWidth::from_text(self.text, f.options().indent_width()),
});
Ok(())
@ -393,8 +393,10 @@ where
let slice = source_code.slice(self.range);
debug_assert_no_newlines(slice.text(source_code));
let text_width =
TextWidth::from_text(slice.text(source_code), f.context().options().tab_width());
let text_width = TextWidth::from_text(
slice.text(source_code),
f.context().options().indent_width(),
);
f.write_element(FormatElement::SourceCodeSlice { slice, text_width });
@ -917,8 +919,10 @@ where
/// use ruff_formatter::prelude::*;
///
/// # fn main() -> FormatResult<()> {
/// use ruff_formatter::IndentWidth;
/// let context = SimpleFormatContext::new(SimpleFormatOptions {
/// indent_style: IndentStyle::Space(4),
/// indent_style: IndentStyle::Space,
/// indent_width: IndentWidth::try_from(4).unwrap(),
/// ..SimpleFormatOptions::default()
/// });
///

View file

@ -10,7 +10,7 @@ use unicode_width::UnicodeWidthChar;
use crate::format_element::tag::{GroupMode, LabelId, Tag};
use crate::source_code::SourceCodeSlice;
use crate::{TabWidth, TagKind};
use crate::{IndentWidth, TagKind};
use ruff_text_size::TextSize;
/// Language agnostic IR for formatting source code.
@ -432,12 +432,12 @@ pub enum TextWidth {
}
impl TextWidth {
pub fn from_text(text: &str, tab_width: TabWidth) -> TextWidth {
pub fn from_text(text: &str, indent_width: IndentWidth) -> TextWidth {
let mut width = 0u32;
for c in text.chars() {
let char_width = match c {
'\t' => tab_width.value(),
'\t' => indent_width.value(),
'\n' => return TextWidth::Multiline,
#[allow(clippy::cast_possible_truncation)]
c => c.width().unwrap_or(0) as u32,

View file

@ -9,7 +9,7 @@ use crate::prelude::*;
use crate::source_code::SourceCode;
use crate::{
format, write, BufferExtensions, Format, FormatContext, FormatElement, FormatOptions,
FormatResult, Formatter, IndentStyle, LineWidth, PrinterOptions, TabWidth,
FormatResult, Formatter, IndentStyle, IndentWidth, LineWidth, PrinterOptions,
};
use super::tag::Tag;
@ -213,11 +213,11 @@ struct IrFormatOptions;
impl FormatOptions for IrFormatOptions {
fn indent_style(&self) -> IndentStyle {
IndentStyle::Space(2)
IndentStyle::Space
}
fn tab_width(&self) -> TabWidth {
TabWidth::default()
fn indent_width(&self) -> IndentWidth {
IndentWidth::default()
}
fn line_width(&self) -> LineWidth {
@ -227,7 +227,7 @@ impl FormatOptions for IrFormatOptions {
fn as_print_options(&self) -> PrinterOptions {
PrinterOptions {
line_width: self.line_width(),
indent_style: IndentStyle::Space(2),
indent_style: IndentStyle::Space,
..PrinterOptions::default()
}
}

View file

@ -52,23 +52,20 @@ pub use crate::diagnostics::{ActualStart, FormatError, InvalidDocumentError, Pri
pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS};
pub use group_id::GroupId;
use ruff_text_size::{TextRange, TextSize};
use std::str::FromStr;
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[derive(Default)]
pub enum IndentStyle {
/// Tab
/// Use tabs to indent code.
#[default]
Tab,
/// Space, with its quantity
Space(u8),
/// Use [`IndentWidth`] spaces to indent code.
Space,
}
impl IndentStyle {
pub const DEFAULT_SPACES: u8 = 2;
/// Returns `true` if this is an [`IndentStyle::Tab`].
pub const fn is_tab(&self) -> bool {
matches!(self, IndentStyle::Tab)
@ -76,58 +73,42 @@ impl IndentStyle {
/// Returns `true` if this is an [`IndentStyle::Space`].
pub const fn is_space(&self) -> bool {
matches!(self, IndentStyle::Space(_))
}
}
impl FromStr for IndentStyle {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"tab" | "Tabs" => Ok(Self::Tab),
"space" | "Spaces" => Ok(Self::Space(IndentStyle::DEFAULT_SPACES)),
// TODO: replace this error with a diagnostic
v => {
let v = v.strip_prefix("Spaces, size: ").unwrap_or(v);
u8::from_str(v)
.map(Self::Space)
.map_err(|_| "Value not supported for IndentStyle")
}
}
matches!(self, IndentStyle::Space)
}
}
impl std::fmt::Display for IndentStyle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndentStyle::Tab => std::write!(f, "Tab"),
IndentStyle::Space(size) => std::write!(f, "Spaces, size: {size}"),
IndentStyle::Tab => std::write!(f, "tab"),
IndentStyle::Space => std::write!(f, "space"),
}
}
}
/// The visual width of a `\t` character.
/// The visual width of a indentation.
///
/// Determines the visual width of a tab character (`\t`) and the number of
/// spaces per indent when using [`IndentStyle::Space`].
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct TabWidth(NonZeroU8);
pub struct IndentWidth(NonZeroU8);
impl TabWidth {
impl IndentWidth {
/// Return the numeric value for this [`LineWidth`]
pub const fn value(&self) -> u32 {
self.0.get() as u32
}
}
impl Default for TabWidth {
impl Default for IndentWidth {
fn default() -> Self {
Self(NonZeroU8::new(2).unwrap())
}
}
impl TryFrom<u8> for TabWidth {
impl TryFrom<u8> for IndentWidth {
type Error = TryFromIntError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
@ -196,16 +177,8 @@ pub trait FormatOptions {
/// The indent style.
fn indent_style(&self) -> IndentStyle;
/// The visual width of a tab character.
fn tab_width(&self) -> TabWidth;
/// The visual width of an indent
fn indent_width(&self) -> u32 {
match self.indent_style() {
IndentStyle::Tab => self.tab_width().value(),
IndentStyle::Space(spaces) => u32::from(spaces),
}
}
fn indent_width(&self) -> IndentWidth;
/// What's the max width of a line. Defaults to 80.
fn line_width(&self) -> LineWidth;
@ -250,6 +223,7 @@ impl FormatContext for SimpleFormatContext {
#[derive(Debug, Default, Eq, PartialEq, Clone)]
pub struct SimpleFormatOptions {
pub indent_style: IndentStyle,
pub indent_width: IndentWidth,
pub line_width: LineWidth,
}
@ -258,8 +232,8 @@ impl FormatOptions for SimpleFormatOptions {
self.indent_style
}
fn tab_width(&self) -> TabWidth {
TabWidth::default()
fn indent_width(&self) -> IndentWidth {
self.indent_width
}
fn line_width(&self) -> LineWidth {
@ -270,6 +244,7 @@ impl FormatOptions for SimpleFormatOptions {
PrinterOptions {
line_width: self.line_width,
indent_style: self.indent_style,
indent_width: self.indent_width,
source_map_generation: SourceMapGeneration::Enabled,
..PrinterOptions::default()
}

View file

@ -367,7 +367,7 @@ impl<'a> Printer<'a> {
if !self.state.pending_indent.is_empty() {
let (indent_char, repeat_count) = match self.options.indent_style() {
IndentStyle::Tab => ('\t', 1),
IndentStyle::Space(count) => (' ', count),
IndentStyle::Space => (' ', self.options.indent_width()),
};
let indent = std::mem::take(&mut self.state.pending_indent);
@ -764,7 +764,7 @@ impl<'a> Printer<'a> {
#[allow(clippy::cast_possible_truncation)]
let char_width = if char == '\t' {
self.options.tab_width.value()
self.options.indent_width.value()
} else {
// SAFETY: A u32 is sufficient to represent the width of a file <= 4GB
char.width().unwrap_or(0) as u32
@ -1347,7 +1347,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
} else {
for c in text.chars() {
let char_width = match c {
'\t' => self.options().tab_width.value(),
'\t' => self.options().indent_width.value(),
'\n' => {
if self.must_be_flat {
return Fits::No;
@ -1501,7 +1501,7 @@ mod tests {
use crate::printer::{LineEnding, Printer, PrinterOptions};
use crate::source_code::SourceCode;
use crate::{
format_args, write, Document, FormatState, IndentStyle, LineWidth, Printed, TabWidth,
format_args, write, Document, FormatState, IndentStyle, IndentWidth, LineWidth, Printed,
VecBuffer,
};
@ -1509,7 +1509,7 @@ mod tests {
format_with_options(
root,
PrinterOptions {
indent_style: IndentStyle::Space(2),
indent_style: IndentStyle::Space,
..PrinterOptions::default()
},
)
@ -1653,7 +1653,7 @@ two lines`,
fn it_use_the_indent_character_specified_in_the_options() {
let options = PrinterOptions {
indent_style: IndentStyle::Tab,
tab_width: TabWidth::try_from(4).unwrap(),
indent_width: IndentWidth::try_from(4).unwrap(),
line_width: LineWidth::try_from(19).unwrap(),
..PrinterOptions::default()
};

View file

@ -1,10 +1,13 @@
use crate::{FormatOptions, IndentStyle, LineWidth, TabWidth};
use crate::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
/// Options that affect how the [`crate::Printer`] prints the format tokens
#[derive(Clone, Debug, Eq, PartialEq, Default)]
pub struct PrinterOptions {
/// Width of a single tab character (does it equal 2, 4, ... spaces?)
pub tab_width: TabWidth,
pub indent_width: IndentWidth,
/// Whether the printer should use tabs or spaces to indent code.
pub indent_style: IndentStyle,
/// What's the max width of a line. Defaults to 80
pub line_width: LineWidth,
@ -12,9 +15,6 @@ pub struct PrinterOptions {
/// The type of line ending to apply to the printed input
pub line_ending: LineEnding,
/// Whether the printer should use tabs or spaces to indent code and if spaces, by how many.
pub indent_style: IndentStyle,
/// Whether the printer should build a source map that allows mapping positions in the source document
/// to positions in the formatted document.
pub source_map_generation: SourceMapGeneration,
@ -46,8 +46,8 @@ impl PrinterOptions {
}
#[must_use]
pub fn with_tab_width(mut self, width: TabWidth) -> Self {
self.tab_width = width;
pub fn with_tab_width(mut self, width: IndentWidth) -> Self {
self.indent_width = width;
self
}
@ -58,10 +58,7 @@ impl PrinterOptions {
/// Width of an indent in characters.
pub(super) const fn indent_width(&self) -> u32 {
match self.indent_style {
IndentStyle::Tab => self.tab_width.value(),
IndentStyle::Space(count) => count as u32,
}
self.indent_width.value()
}
}