Add tab width option (#6848)

This commit is contained in:
Micha Reiser 2023-08-26 12:29:58 +02:00 committed by GitHub
parent f91bacbb94
commit 9d77552e18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 345 additions and 44 deletions

View file

@ -4,7 +4,7 @@ use crate::prelude::tag::GroupMode;
use crate::prelude::*; use crate::prelude::*;
use crate::printer::LineEnding; use crate::printer::LineEnding;
use crate::source_code::SourceCode; use crate::source_code::SourceCode;
use crate::{format, write}; use crate::{format, write, TabWidth};
use crate::{ use crate::{
BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter, BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter,
IndentStyle, LineWidth, PrinterOptions, IndentStyle, LineWidth, PrinterOptions,
@ -215,13 +215,17 @@ impl FormatOptions for IrFormatOptions {
IndentStyle::Space(2) IndentStyle::Space(2)
} }
fn tab_width(&self) -> TabWidth {
TabWidth::default()
}
fn line_width(&self) -> LineWidth { fn line_width(&self) -> LineWidth {
LineWidth(80) LineWidth(80)
} }
fn as_print_options(&self) -> PrinterOptions { fn as_print_options(&self) -> PrinterOptions {
PrinterOptions { PrinterOptions {
tab_width: 2, tab_width: TabWidth::default(),
print_width: self.line_width().into(), print_width: self.line_width().into(),
line_ending: LineEnding::LineFeed, line_ending: LineEnding::LineFeed,
indent_style: IndentStyle::Space(2), indent_style: IndentStyle::Space(2),

View file

@ -51,7 +51,7 @@ pub use crate::diagnostics::{ActualStart, FormatError, InvalidDocumentError, Pri
pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS}; pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS};
pub use group_id::GroupId; pub use group_id::GroupId;
use ruff_text_size::{TextRange, TextSize}; use ruff_text_size::{TextRange, TextSize};
use std::num::ParseIntError; use std::num::{NonZeroU8, ParseIntError, TryFromIntError};
use std::str::FromStr; use std::str::FromStr;
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
@ -108,6 +108,33 @@ impl std::fmt::Display for IndentStyle {
} }
} }
/// The visual width of a `\t` character.
#[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);
impl TabWidth {
/// Return the numeric value for this [`LineWidth`]
pub const fn value(&self) -> u32 {
self.0.get() as u32
}
}
impl Default for TabWidth {
fn default() -> Self {
Self(NonZeroU8::new(2).unwrap())
}
}
impl TryFrom<u8> for TabWidth {
type Error = TryFromIntError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
NonZeroU8::try_from(value).map(Self)
}
}
/// Validated value for the `line_width` formatter options /// Validated value for the `line_width` formatter options
/// ///
/// The allowed range of values is 1..=320 /// The allowed range of values is 1..=320
@ -213,6 +240,17 @@ pub trait FormatOptions {
/// The indent style. /// The indent style.
fn indent_style(&self) -> IndentStyle; 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),
}
}
/// What's the max width of a line. Defaults to 80. /// What's the max width of a line. Defaults to 80.
fn line_width(&self) -> LineWidth; fn line_width(&self) -> LineWidth;
@ -264,6 +302,10 @@ impl FormatOptions for SimpleFormatOptions {
self.indent_style self.indent_style
} }
fn tab_width(&self) -> TabWidth {
TabWidth::default()
}
fn line_width(&self) -> LineWidth { fn line_width(&self) -> LineWidth {
self.line_width self.line_width
} }
@ -271,6 +313,7 @@ impl FormatOptions for SimpleFormatOptions {
fn as_print_options(&self) -> PrinterOptions { fn as_print_options(&self) -> PrinterOptions {
PrinterOptions::default() PrinterOptions::default()
.with_indent(self.indent_style) .with_indent(self.indent_style)
.with_tab_width(self.tab_width())
.with_print_width(self.line_width.into()) .with_print_width(self.line_width.into())
} }
} }

View file

@ -732,7 +732,7 @@ impl<'a> Printer<'a> {
#[allow(clippy::cast_possible_truncation)] #[allow(clippy::cast_possible_truncation)]
let char_width = if char == '\t' { let char_width = if char == '\t' {
u32::from(self.options.tab_width) self.options.tab_width.value()
} else { } else {
// SAFETY: A u32 is sufficient to represent the width of a file <= 4GB // 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
@ -1283,13 +1283,12 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
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 += u32::from(indent.level()) self.state.line_width +=
* u32::from(self.options().indent_width()) u32::from(indent.level()) * self.options().indent_width() + u32::from(indent.align());
+ 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' => u32::from(self.options().tab_width), '\t' => self.options().tab_width.value(),
'\n' => { '\n' => {
if self.must_be_flat { if self.must_be_flat {
return Fits::No; return Fits::No;
@ -1428,7 +1427,9 @@ mod tests {
use crate::prelude::*; use crate::prelude::*;
use crate::printer::{LineEnding, PrintWidth, Printer, PrinterOptions}; use crate::printer::{LineEnding, PrintWidth, Printer, PrinterOptions};
use crate::source_code::SourceCode; use crate::source_code::SourceCode;
use crate::{format_args, write, Document, FormatState, IndentStyle, Printed, VecBuffer}; use crate::{
format_args, write, Document, FormatState, IndentStyle, Printed, TabWidth, VecBuffer,
};
fn format(root: &dyn Format<SimpleFormatContext>) -> Printed { fn format(root: &dyn Format<SimpleFormatContext>) -> Printed {
format_with_options( format_with_options(
@ -1578,7 +1579,7 @@ two lines`,
fn it_use_the_indent_character_specified_in_the_options() { fn it_use_the_indent_character_specified_in_the_options() {
let options = PrinterOptions { let options = PrinterOptions {
indent_style: IndentStyle::Tab, indent_style: IndentStyle::Tab,
tab_width: 4, tab_width: TabWidth::try_from(4).unwrap(),
print_width: PrintWidth::new(19), print_width: PrintWidth::new(19),
..PrinterOptions::default() ..PrinterOptions::default()
}; };

View file

@ -1,10 +1,10 @@
use crate::{FormatOptions, IndentStyle, LineWidth}; use crate::{FormatOptions, IndentStyle, LineWidth, TabWidth};
/// 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, Default)]
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?)
pub tab_width: u8, pub tab_width: TabWidth,
/// What's the max width of a line. Defaults to 80 /// What's the max width of a line. Defaults to 80
pub print_width: PrintWidth, pub print_width: PrintWidth,
@ -74,23 +74,31 @@ impl PrinterOptions {
self self
} }
#[must_use]
pub fn with_tab_width(mut self, width: TabWidth) -> Self {
self.tab_width = width;
self
}
pub(crate) fn indent_style(&self) -> IndentStyle { pub(crate) fn indent_style(&self) -> IndentStyle {
self.indent_style self.indent_style
} }
/// Width of an indent in characters. /// Width of an indent in characters.
pub(super) const fn indent_width(&self) -> u8 { pub(super) const fn indent_width(&self) -> u32 {
match self.indent_style { match self.indent_style {
IndentStyle::Tab => self.tab_width, IndentStyle::Tab => self.tab_width.value(),
IndentStyle::Space(count) => count, IndentStyle::Space(count) => count as u32,
} }
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq, Default)]
pub enum LineEnding { pub enum LineEnding {
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos /// Line Feed only (\n), common on Linux and macOS as well as inside git repos
#[default]
LineFeed, LineFeed,
/// Carriage Return + Line Feed characters (\r\n), common on Windows /// Carriage Return + Line Feed characters (\r\n), common on Windows
@ -110,14 +118,3 @@ impl LineEnding {
} }
} }
} }
impl Default for PrinterOptions {
fn default() -> Self {
PrinterOptions {
tab_width: 2,
print_width: PrintWidth::default(),
indent_style: IndentStyle::default(),
line_ending: LineEnding::LineFeed,
}
}
}

View file

@ -0,0 +1,3 @@
{
"tab_width": 8
}

View file

@ -2,14 +2,21 @@
{ {
"indent_style": { "indent_style": {
"Space": 4 "Space": 4
} },
"tab_width": 8
}, },
{ {
"indent_style": { "indent_style": {
"Space": 2 "Space": 2
} },
"tab_width": 8
}, },
{ {
"indent_style": "Tab" "indent_style": "Tab",
"tab_width": 8
},
{
"indent_style": "Tab",
"tab_width": 4
} }
] ]

View file

@ -0,0 +1,8 @@
[
{
"tab_width": 2
},
{
"tab_width": 4
}
]

View file

@ -0,0 +1,8 @@
# Fits with tab width 2
1 + " 012345678901234567890123456789012345678901234567890123456789012345678901234567890"
# Fits with tab width 4
1 + " 0123456789012345678901234567890123456789012345678901234567890123456789012345678"
# Fits with tab width 8
1 + " 012345678901234567890123456789012345678901234567890123456789012345678901234"

View file

@ -43,7 +43,10 @@ where
// of 5 characters to avoid it exceeding the line width by 1 reduces the readability. // of 5 characters to avoid it exceeding the line width by 1 reduces the readability.
// * The text is know to never fit: The text can never fit even when parenthesizing if it is longer // * The text is know to never fit: The text can never fit even when parenthesizing if it is longer
// than the configured line width (minus indent). // than the configured line width (minus indent).
text_len > 5 && text_len < context.options().line_width().value() as usize text_len > 5
&& text_len
<= context.options().line_width().value() as usize
- context.options().indent_width() as usize
} }
pub(crate) trait NeedsParentheses { pub(crate) trait NeedsParentheses {

View file

@ -2,7 +2,7 @@ use std::borrow::Cow;
use bitflags::bitflags; use bitflags::bitflags;
use ruff_formatter::{format_args, write, FormatError}; use ruff_formatter::{format_args, write, FormatError, FormatOptions, TabWidth};
use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::node::AnyNodeRef;
use ruff_python_ast::{self as ast, ExprConstant, ExprFString, Ranged}; use ruff_python_ast::{self as ast, ExprConstant, ExprFString, Ranged};
use ruff_python_parser::lexer::{lex_starts_at, LexicalError, LexicalErrorType}; use ruff_python_parser::lexer::{lex_starts_at, LexicalError, LexicalErrorType};
@ -682,13 +682,14 @@ fn normalize_string(
/// to the next multiple of 8. This is effectively a port of /// to the next multiple of 8. This is effectively a port of
/// [`str.expandtabs`](https://docs.python.org/3/library/stdtypes.html#str.expandtabs), /// [`str.expandtabs`](https://docs.python.org/3/library/stdtypes.html#str.expandtabs),
/// which black [calls with the default tab width of 8](https://github.com/psf/black/blob/c36e468794f9256d5e922c399240d49782ba04f1/src/black/strings.py#L61) /// which black [calls with the default tab width of 8](https://github.com/psf/black/blob/c36e468794f9256d5e922c399240d49782ba04f1/src/black/strings.py#L61)
fn count_indentation_like_black(line: &str) -> TextSize { fn count_indentation_like_black(line: &str, tab_width: TabWidth) -> TextSize {
let tab_width: u32 = 8;
let mut indentation = TextSize::default(); let mut indentation = TextSize::default();
for char in line.chars() { for char in line.chars() {
if char == '\t' { if char == '\t' {
// Pad to the next multiple of tab_width // Pad to the next multiple of tab_width
indentation += TextSize::from(tab_width - (indentation.to_u32().rem_euclid(tab_width))); indentation += TextSize::from(
tab_width.value() - (indentation.to_u32().rem_euclid(tab_width.value())),
);
} else if char.is_whitespace() { } else if char.is_whitespace() {
indentation += char.text_len(); indentation += char.text_len();
} else { } else {
@ -868,7 +869,7 @@ fn format_docstring(string_part: &FormatStringPart, f: &mut PyFormatter) -> Form
.clone() .clone()
// We don't want to count whitespace-only lines as miss-indented // We don't want to count whitespace-only lines as miss-indented
.filter(|line| !line.trim().is_empty()) .filter(|line| !line.trim().is_empty())
.map(count_indentation_like_black) .map(|line| count_indentation_like_black(line, f.options().tab_width()))
.min() .min()
.unwrap_or_default(); .unwrap_or_default();
@ -943,7 +944,8 @@ fn format_docstring_line(
// overindented, in which case we strip the additional whitespace (see example in // overindented, in which case we strip the additional whitespace (see example in
// [`format_docstring`] doc comment). We then prepend the in-docstring indentation to the // [`format_docstring`] doc comment). We then prepend the in-docstring indentation to the
// string. // string.
let indent_len = count_indentation_like_black(trim_end) - stripped_indentation; let indent_len =
count_indentation_like_black(trim_end, f.options().tab_width()) - stripped_indentation;
let in_docstring_indent = " ".repeat(indent_len.to_usize()) + trim_end.trim_start(); let in_docstring_indent = " ".repeat(indent_len.to_usize()) + trim_end.trim_start();
dynamic_text(&in_docstring_indent, Some(offset)).fmt(f)?; dynamic_text(&in_docstring_indent, Some(offset)).fmt(f)?;
} else { } else {
@ -976,12 +978,23 @@ fn format_docstring_line(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::expression::string::count_indentation_like_black; use crate::expression::string::count_indentation_like_black;
use ruff_formatter::TabWidth;
#[test] #[test]
fn test_indentation_like_black() { fn test_indentation_like_black() {
assert_eq!(count_indentation_like_black("\t \t \t").to_u32(), 24); let tab_width = TabWidth::try_from(8).unwrap();
assert_eq!(count_indentation_like_black("\t \t").to_u32(), 24); assert_eq!(
assert_eq!(count_indentation_like_black("\t\t\t").to_u32(), 24); count_indentation_like_black("\t \t \t", tab_width).to_u32(),
assert_eq!(count_indentation_like_black(" ").to_u32(), 4); 24
);
assert_eq!(
count_indentation_like_black("\t \t", tab_width).to_u32(),
24
);
assert_eq!(
count_indentation_like_black("\t\t\t", tab_width).to_u32(),
24
);
assert_eq!(count_indentation_like_black(" ", tab_width).to_u32(), 4);
} }
} }

View file

@ -1,5 +1,5 @@
use ruff_formatter::printer::{LineEnding, PrinterOptions}; use ruff_formatter::printer::{LineEnding, PrinterOptions};
use ruff_formatter::{FormatOptions, IndentStyle, LineWidth}; use ruff_formatter::{FormatOptions, IndentStyle, LineWidth, TabWidth};
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use std::path::Path; use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
@ -24,6 +24,10 @@ pub struct PyFormatOptions {
#[cfg_attr(feature = "serde", serde(default = "default_line_width"))] #[cfg_attr(feature = "serde", serde(default = "default_line_width"))]
line_width: LineWidth, line_width: LineWidth,
/// The visual width of a tab character.
#[cfg_attr(feature = "serde", serde(default = "default_tab_width"))]
tab_width: TabWidth,
/// The preferred quote style to use (single vs double quotes). /// The preferred quote style to use (single vs double quotes).
quote_style: QuoteStyle, quote_style: QuoteStyle,
@ -39,12 +43,17 @@ fn default_indent_style() -> IndentStyle {
IndentStyle::Space(4) IndentStyle::Space(4)
} }
fn default_tab_width() -> TabWidth {
TabWidth::try_from(4).unwrap()
}
impl Default for PyFormatOptions { impl Default for PyFormatOptions {
fn default() -> Self { fn default() -> Self {
Self { Self {
source_type: PySourceType::default(), source_type: PySourceType::default(),
indent_style: default_indent_style(), indent_style: default_indent_style(),
line_width: default_line_width(), line_width: default_line_width(),
tab_width: default_tab_width(),
quote_style: QuoteStyle::default(), quote_style: QuoteStyle::default(),
magic_trailing_comma: MagicTrailingComma::default(), magic_trailing_comma: MagicTrailingComma::default(),
} }
@ -106,13 +115,17 @@ impl FormatOptions for PyFormatOptions {
self.indent_style self.indent_style
} }
fn tab_width(&self) -> TabWidth {
self.tab_width
}
fn line_width(&self) -> LineWidth { fn line_width(&self) -> LineWidth {
self.line_width self.line_width
} }
fn as_print_options(&self) -> PrinterOptions { fn as_print_options(&self) -> PrinterOptions {
PrinterOptions { PrinterOptions {
tab_width: 4, tab_width: self.tab_width,
print_width: self.line_width.into(), print_width: self.line_width.into(),
line_ending: LineEnding::LineFeed, line_ending: LineEnding::LineFeed,
indent_style: self.indent_style, indent_style: self.indent_style,

View file

@ -253,9 +253,11 @@ impl fmt::Display for DisplayPyOptions<'_> {
f, f,
r#"indent-style = {indent_style} r#"indent-style = {indent_style}
line-width = {line_width} line-width = {line_width}
tab-width = {tab_width}
quote-style = {quote_style:?} quote-style = {quote_style:?}
magic-trailing-comma = {magic_trailing_comma:?}"#, magic-trailing-comma = {magic_trailing_comma:?}"#,
indent_style = self.0.indent_style(), indent_style = self.0.indent_style(),
tab_width = self.0.tab_width().value(),
line_width = self.0.line_width().value(), line_width = self.0.line_width().value(),
quote_style = self.0.quote_style(), quote_style = self.0.quote_style(),
magic_trailing_comma = self.0.magic_trailing_comma() magic_trailing_comma = self.0.magic_trailing_comma()

View file

@ -113,6 +113,7 @@ class TabbedIndent:
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 8
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -225,6 +226,7 @@ class TabbedIndent:
``` ```
indent-style = Spaces, size: 2 indent-style = Spaces, size: 2
line-width = 88 line-width = 88
tab-width = 8
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -337,6 +339,7 @@ class TabbedIndent:
``` ```
indent-style = Tab indent-style = Tab
line-width = 88 line-width = 88
tab-width = 8
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -445,4 +448,117 @@ class TabbedIndent:
``` ```
### Output 4
```
indent-style = Tab
line-width = 88
tab-width = 4
quote-style = Double
magic-trailing-comma = Respect
```
```py
def single_line_backslashes1():
"""content\ """
return
def single_line_backslashes2():
"""content\\"""
return
def single_line_backslashes3():
"""content\\\ """
return
def multiline_backslashes1():
"""This is a docstring with
some lines of text\ """
return
def multiline_backslashes2():
"""This is a docstring with
some lines of text\\"""
return
def multiline_backslashes3():
"""This is a docstring with
some lines of text\\\ """
return
def multiple_negatively_indented_docstring_lines():
"""a
b
c
d
e
"""
def overindentend_docstring():
"""a
over-indented
"""
def comment_before_docstring():
# don't lose this function comment ...
"""Does nothing.
But it has comments
""" # ... neither lose this function comment
class CommentBeforeDocstring:
# don't lose this class comment ...
"""Empty class.
But it has comments
""" # ... neither lose this class comment
class IndentMeSome:
def doc_string_without_linebreak_after_colon(self):
"""This is somewhat strange
a
b
We format this a is the docstring had started properly indented on the next
line if the target indentation. This may we incorrect since source and target
indentation can be incorrect, but this is also an edge case.
"""
class IgnoreImplicitlyConcatenatedStrings:
"""""" ""
def docstring_that_ends_with_quote_and_a_line_break1():
"""
he said "the news of my death have been greatly exaggerated"
"""
def docstring_that_ends_with_quote_and_a_line_break2():
"""he said "the news of my death have been greatly exaggerated" """
def docstring_that_ends_with_quote_and_a_line_break3():
"""he said "the news of my death have been greatly exaggerated" """
class TabbedIndent:
def tabbed_indent(self):
"""check for correct tabbed formatting
^^^^^^^^^^
Normal indented line
- autor
"""
```

View file

@ -131,6 +131,7 @@ test_particular = [
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -279,6 +280,7 @@ test_particular = [
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Single quote-style = Single
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```

View file

@ -143,6 +143,7 @@ x = (b"""aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa""" b"""bbbbbbbbbbbbbbbbbbbbbbbbbbb
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -312,6 +313,7 @@ x = (
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Single quote-style = Single
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```

View file

@ -30,6 +30,7 @@ def test():
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -61,6 +62,7 @@ def test():
``` ```
indent-style = Spaces, size: 2 indent-style = Spaces, size: 2
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```

View file

@ -66,6 +66,7 @@ formatted;
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -135,6 +136,7 @@ formatted
``` ```
indent-style = Spaces, size: 1 indent-style = Spaces, size: 1
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -204,6 +206,7 @@ formatted
``` ```
indent-style = Tab indent-style = Tab
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```

View file

@ -26,6 +26,7 @@ not_fixed
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -52,6 +53,7 @@ not_fixed
``` ```
indent-style = Spaces, size: 2 indent-style = Spaces, size: 2
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -78,6 +80,7 @@ not_fixed
``` ```
indent-style = Tab indent-style = Tab
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```

View file

@ -44,6 +44,7 @@ with (a,): # magic trailing comma
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Respect magic-trailing-comma = Respect
``` ```
@ -95,6 +96,7 @@ with (
``` ```
indent-style = Spaces, size: 4 indent-style = Spaces, size: 4
line-width = 88 line-width = 88
tab-width = 4
quote-style = Double quote-style = Double
magic-trailing-comma = Ignore magic-trailing-comma = Ignore
``` ```

View file

@ -0,0 +1,69 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/tab_width.py
---
## Input
```py
# Fits with tab width 2
1 + " 012345678901234567890123456789012345678901234567890123456789012345678901234567890"
# Fits with tab width 4
1 + " 0123456789012345678901234567890123456789012345678901234567890123456789012345678"
# Fits with tab width 8
1 + " 012345678901234567890123456789012345678901234567890123456789012345678901234"
```
## Outputs
### Output 1
```
indent-style = Spaces, size: 4
line-width = 88
tab-width = 2
quote-style = Double
magic-trailing-comma = Respect
```
```py
# Fits with tab width 2
(
1
+ " 012345678901234567890123456789012345678901234567890123456789012345678901234567890"
)
# Fits with tab width 4
1 + " 0123456789012345678901234567890123456789012345678901234567890123456789012345678"
# Fits with tab width 8
1 + " 012345678901234567890123456789012345678901234567890123456789012345678901234"
```
### Output 2
```
indent-style = Spaces, size: 4
line-width = 88
tab-width = 4
quote-style = Double
magic-trailing-comma = Respect
```
```py
# Fits with tab width 2
(
1
+ " 012345678901234567890123456789012345678901234567890123456789012345678901234567890"
)
# Fits with tab width 4
(
1
+ " 0123456789012345678901234567890123456789012345678901234567890123456789012345678"
)
# Fits with tab width 8
1 + " 012345678901234567890123456789012345678901234567890123456789012345678901234"
```