Error on zero tab width (#6429)

## Summary

Error if `tab-size` is set to zero (it is used as a divisor). Closes
#6423.

Also fixes a typo.

## Test Plan

Running ruff with a config

```toml
[tool.ruff]
tab-size = 0
```

returns an error message to the user saying that `tab-size` must be
greater than zero.
This commit is contained in:
Tom Kuson 2023-08-08 21:51:37 +01:00 committed by GitHub
parent 55d6fd53cd
commit 1b9fed8397
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 27 additions and 19 deletions

View file

@ -1,4 +1,5 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::num::NonZeroU8;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use ruff_macros::CacheKey; use ruff_macros::CacheKey;
@ -83,7 +84,7 @@ impl LineWidth {
} }
fn update(mut self, chars: impl Iterator<Item = char>) -> Self { fn update(mut self, chars: impl Iterator<Item = char>) -> Self {
let tab_size: usize = self.tab_size.into(); let tab_size: usize = self.tab_size.as_usize();
for c in chars { for c in chars {
match c { match c {
'\t' => { '\t' => {
@ -144,22 +145,22 @@ impl PartialOrd<LineLength> for LineWidth {
/// The size of a tab. /// The size of a tab.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, CacheKey)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, CacheKey)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct TabSize(pub u8); pub struct TabSize(pub NonZeroU8);
impl TabSize {
fn as_usize(self) -> usize {
self.0.get() as usize
}
}
impl Default for TabSize { impl Default for TabSize {
fn default() -> Self { fn default() -> Self {
Self(4) Self(NonZeroU8::new(4).unwrap())
} }
} }
impl From<u8> for TabSize { impl From<NonZeroU8> for TabSize {
fn from(tab_size: u8) -> Self { fn from(tab_size: NonZeroU8) -> Self {
Self(tab_size) Self(tab_size)
} }
} }
impl From<TabSize> for usize {
fn from(tab_size: TabSize) -> Self {
tab_size.0 as usize
}
}

View file

@ -293,12 +293,10 @@ impl Display for MessageCodeFrame<'_> {
} }
fn replace_whitespace(source: &str, annotation_range: TextRange) -> SourceCode { fn replace_whitespace(source: &str, annotation_range: TextRange) -> SourceCode {
static TAB_SIZE: TabSize = TabSize(4); // TODO(jonathan): use `tab-size`
let mut result = String::new(); let mut result = String::new();
let mut last_end = 0; let mut last_end = 0;
let mut range = annotation_range; let mut range = annotation_range;
let mut line_width = LineWidth::new(TAB_SIZE); let mut line_width = LineWidth::new(TabSize::default());
for (index, c) in source.char_indices() { for (index, c) in source.char_indices() {
let old_width = line_width.get(); let old_width = line_width.get();

View file

@ -6,6 +6,7 @@ pub(crate) mod helpers;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::num::NonZeroU8;
use std::path::Path; use std::path::Path;
use anyhow::Result; use anyhow::Result;
@ -204,7 +205,7 @@ mod tests {
let diagnostics = test_path( let diagnostics = test_path(
Path::new("pycodestyle/E501_2.py"), Path::new("pycodestyle/E501_2.py"),
&settings::Settings { &settings::Settings {
tab_size: tab_size.into(), tab_size: NonZeroU8::new(tab_size).unwrap().into(),
..settings::Settings::for_rule(Rule::LineTooLong) ..settings::Settings::for_rule(Rule::LineTooLong)
}, },
)?; )?;

View file

@ -312,13 +312,13 @@ pub struct Options {
"# "#
)] )]
/// The line length to use when enforcing long-lines violations (like /// The line length to use when enforcing long-lines violations (like
/// `E501`). /// `E501`). Must be greater than `0`.
pub line_length: Option<LineLength>, pub line_length: Option<LineLength>,
#[option( #[option(
default = "4", default = "4",
value_type = "int", value_type = "int",
example = r#" example = r#"
tab_size = 8 tab-size = 8
"# "#
)] )]
/// The tabulation size to calculate line length. /// The tabulation size to calculate line length.

View file

@ -2,6 +2,7 @@ use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher; use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::num::NonZeroU8;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -205,6 +206,13 @@ impl CacheKey for i8 {
} }
} }
impl CacheKey for NonZeroU8 {
#[inline]
fn cache_key(&self, state: &mut CacheKeyHasher) {
state.write_u8(self.get());
}
}
macro_rules! impl_cache_key_tuple { macro_rules! impl_cache_key_tuple {
() => ( () => (
impl CacheKey for () { impl CacheKey for () {

4
ruff.schema.json generated
View file

@ -376,7 +376,7 @@
] ]
}, },
"line-length": { "line-length": {
"description": "The line length to use when enforcing long-lines violations (like `E501`).", "description": "The line length to use when enforcing long-lines violations (like `E501`). Must be greater than `0`.",
"anyOf": [ "anyOf": [
{ {
"$ref": "#/definitions/LineLength" "$ref": "#/definitions/LineLength"
@ -2741,7 +2741,7 @@
"description": "The size of a tab.", "description": "The size of a tab.",
"type": "integer", "type": "integer",
"format": "uint8", "format": "uint8",
"minimum": 0.0 "minimum": 1.0
}, },
"Version": { "Version": {
"type": "string" "type": "string"