mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-11 22:28:27 +00:00
Add tab width option (#6848)
This commit is contained in:
parent
f91bacbb94
commit
9d77552e18
20 changed files with 345 additions and 44 deletions
|
@ -43,7 +43,10 @@ where
|
|||
// 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
|
||||
// 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 {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
|
||||
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::{self as ast, ExprConstant, ExprFString, Ranged};
|
||||
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
|
||||
/// [`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)
|
||||
fn count_indentation_like_black(line: &str) -> TextSize {
|
||||
let tab_width: u32 = 8;
|
||||
fn count_indentation_like_black(line: &str, tab_width: TabWidth) -> TextSize {
|
||||
let mut indentation = TextSize::default();
|
||||
for char in line.chars() {
|
||||
if char == '\t' {
|
||||
// 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() {
|
||||
indentation += char.text_len();
|
||||
} else {
|
||||
|
@ -868,7 +869,7 @@ fn format_docstring(string_part: &FormatStringPart, f: &mut PyFormatter) -> Form
|
|||
.clone()
|
||||
// We don't want to count whitespace-only lines as miss-indented
|
||||
.filter(|line| !line.trim().is_empty())
|
||||
.map(count_indentation_like_black)
|
||||
.map(|line| count_indentation_like_black(line, f.options().tab_width()))
|
||||
.min()
|
||||
.unwrap_or_default();
|
||||
|
||||
|
@ -943,7 +944,8 @@ fn format_docstring_line(
|
|||
// 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
|
||||
// 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();
|
||||
dynamic_text(&in_docstring_indent, Some(offset)).fmt(f)?;
|
||||
} else {
|
||||
|
@ -976,12 +978,23 @@ fn format_docstring_line(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::expression::string::count_indentation_like_black;
|
||||
use ruff_formatter::TabWidth;
|
||||
|
||||
#[test]
|
||||
fn test_indentation_like_black() {
|
||||
assert_eq!(count_indentation_like_black("\t \t \t").to_u32(), 24);
|
||||
assert_eq!(count_indentation_like_black("\t \t").to_u32(), 24);
|
||||
assert_eq!(count_indentation_like_black("\t\t\t").to_u32(), 24);
|
||||
assert_eq!(count_indentation_like_black(" ").to_u32(), 4);
|
||||
let tab_width = TabWidth::try_from(8).unwrap();
|
||||
assert_eq!(
|
||||
count_indentation_like_black("\t \t \t", tab_width).to_u32(),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
@ -24,6 +24,10 @@ pub struct PyFormatOptions {
|
|||
#[cfg_attr(feature = "serde", serde(default = "default_line_width"))]
|
||||
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).
|
||||
quote_style: QuoteStyle,
|
||||
|
||||
|
@ -39,12 +43,17 @@ fn default_indent_style() -> IndentStyle {
|
|||
IndentStyle::Space(4)
|
||||
}
|
||||
|
||||
fn default_tab_width() -> TabWidth {
|
||||
TabWidth::try_from(4).unwrap()
|
||||
}
|
||||
|
||||
impl Default for PyFormatOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
source_type: PySourceType::default(),
|
||||
indent_style: default_indent_style(),
|
||||
line_width: default_line_width(),
|
||||
tab_width: default_tab_width(),
|
||||
quote_style: QuoteStyle::default(),
|
||||
magic_trailing_comma: MagicTrailingComma::default(),
|
||||
}
|
||||
|
@ -106,13 +115,17 @@ impl FormatOptions for PyFormatOptions {
|
|||
self.indent_style
|
||||
}
|
||||
|
||||
fn tab_width(&self) -> TabWidth {
|
||||
self.tab_width
|
||||
}
|
||||
|
||||
fn line_width(&self) -> LineWidth {
|
||||
self.line_width
|
||||
}
|
||||
|
||||
fn as_print_options(&self) -> PrinterOptions {
|
||||
PrinterOptions {
|
||||
tab_width: 4,
|
||||
tab_width: self.tab_width,
|
||||
print_width: self.line_width.into(),
|
||||
line_ending: LineEnding::LineFeed,
|
||||
indent_style: self.indent_style,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue