mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +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
|
@ -4,7 +4,7 @@ use crate::prelude::tag::GroupMode;
|
|||
use crate::prelude::*;
|
||||
use crate::printer::LineEnding;
|
||||
use crate::source_code::SourceCode;
|
||||
use crate::{format, write};
|
||||
use crate::{format, write, TabWidth};
|
||||
use crate::{
|
||||
BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter,
|
||||
IndentStyle, LineWidth, PrinterOptions,
|
||||
|
@ -215,13 +215,17 @@ impl FormatOptions for IrFormatOptions {
|
|||
IndentStyle::Space(2)
|
||||
}
|
||||
|
||||
fn tab_width(&self) -> TabWidth {
|
||||
TabWidth::default()
|
||||
}
|
||||
|
||||
fn line_width(&self) -> LineWidth {
|
||||
LineWidth(80)
|
||||
}
|
||||
|
||||
fn as_print_options(&self) -> PrinterOptions {
|
||||
PrinterOptions {
|
||||
tab_width: 2,
|
||||
tab_width: TabWidth::default(),
|
||||
print_width: self.line_width().into(),
|
||||
line_ending: LineEnding::LineFeed,
|
||||
indent_style: IndentStyle::Space(2),
|
||||
|
|
|
@ -51,7 +51,7 @@ 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::num::ParseIntError;
|
||||
use std::num::{NonZeroU8, ParseIntError, TryFromIntError};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[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
|
||||
///
|
||||
/// The allowed range of values is 1..=320
|
||||
|
@ -213,6 +240,17 @@ 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),
|
||||
}
|
||||
}
|
||||
|
||||
/// What's the max width of a line. Defaults to 80.
|
||||
fn line_width(&self) -> LineWidth;
|
||||
|
||||
|
@ -264,6 +302,10 @@ impl FormatOptions for SimpleFormatOptions {
|
|||
self.indent_style
|
||||
}
|
||||
|
||||
fn tab_width(&self) -> TabWidth {
|
||||
TabWidth::default()
|
||||
}
|
||||
|
||||
fn line_width(&self) -> LineWidth {
|
||||
self.line_width
|
||||
}
|
||||
|
@ -271,6 +313,7 @@ impl FormatOptions for SimpleFormatOptions {
|
|||
fn as_print_options(&self) -> PrinterOptions {
|
||||
PrinterOptions::default()
|
||||
.with_indent(self.indent_style)
|
||||
.with_tab_width(self.tab_width())
|
||||
.with_print_width(self.line_width.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -732,7 +732,7 @@ impl<'a> Printer<'a> {
|
|||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
let char_width = if char == '\t' {
|
||||
u32::from(self.options.tab_width)
|
||||
self.options.tab_width.value()
|
||||
} else {
|
||||
// SAFETY: A u32 is sufficient to represent the width of a file <= 4GB
|
||||
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 {
|
||||
let indent = std::mem::take(&mut self.state.pending_indent);
|
||||
self.state.line_width += u32::from(indent.level())
|
||||
* u32::from(self.options().indent_width())
|
||||
+ u32::from(indent.align());
|
||||
self.state.line_width +=
|
||||
u32::from(indent.level()) * self.options().indent_width() + u32::from(indent.align());
|
||||
|
||||
for c in text.chars() {
|
||||
let char_width = match c {
|
||||
'\t' => u32::from(self.options().tab_width),
|
||||
'\t' => self.options().tab_width.value(),
|
||||
'\n' => {
|
||||
if self.must_be_flat {
|
||||
return Fits::No;
|
||||
|
@ -1428,7 +1427,9 @@ mod tests {
|
|||
use crate::prelude::*;
|
||||
use crate::printer::{LineEnding, PrintWidth, Printer, PrinterOptions};
|
||||
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 {
|
||||
format_with_options(
|
||||
|
@ -1578,7 +1579,7 @@ two lines`,
|
|||
fn it_use_the_indent_character_specified_in_the_options() {
|
||||
let options = PrinterOptions {
|
||||
indent_style: IndentStyle::Tab,
|
||||
tab_width: 4,
|
||||
tab_width: TabWidth::try_from(4).unwrap(),
|
||||
print_width: PrintWidth::new(19),
|
||||
..PrinterOptions::default()
|
||||
};
|
||||
|
|
|
@ -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
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub struct PrinterOptions {
|
||||
/// 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
|
||||
pub print_width: PrintWidth,
|
||||
|
@ -74,23 +74,31 @@ impl PrinterOptions {
|
|||
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 {
|
||||
self.indent_style
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
IndentStyle::Tab => self.tab_width,
|
||||
IndentStyle::Space(count) => count,
|
||||
IndentStyle::Tab => self.tab_width.value(),
|
||||
IndentStyle::Space(count) => count as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Default)]
|
||||
pub enum LineEnding {
|
||||
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos
|
||||
#[default]
|
||||
LineFeed,
|
||||
|
||||
/// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue