|
1 | 1 | #![allow(dead_code, unused_imports, unused_variables)]
|
2 | 2 |
|
| 3 | +use itertools::Itertools; |
3 | 4 | use rustpython_parser::ast::Location;
|
4 |
| -use rustpython_parser::Tok; |
5 | 5 |
|
6 |
| -use ruff_diagnostics::DiagnosticKind; |
7 | 6 | use ruff_diagnostics::Fix;
|
8 | 7 | use ruff_diagnostics::Violation;
|
9 | 8 | use ruff_diagnostics::{AlwaysAutofixableViolation, Diagnostic};
|
10 | 9 | use ruff_macros::{derive_message_formats, violation};
|
11 | 10 | use ruff_python_ast::types::Range;
|
12 | 11 |
|
13 |
| -use crate::registry::AsRule; |
14 |
| -use crate::rules::pycodestyle::helpers::{is_keyword_token, is_singleton_token}; |
15 |
| - |
16 | 12 | #[violation]
|
17 | 13 | pub struct MissingWhitespace {
|
18 | 14 | pub token: String,
|
@@ -40,21 +36,26 @@ pub fn missing_whitespace(
|
40 | 36 | indent_level: usize,
|
41 | 37 | ) -> Vec<Diagnostic> {
|
42 | 38 | let mut diagnostics = vec![];
|
43 |
| - for (idx, char) in line.chars().enumerate() { |
44 |
| - if idx + 1 == line.len() { |
45 |
| - break; |
| 39 | + |
| 40 | + let mut num_lsqb = 0; |
| 41 | + let mut num_rsqb = 0; |
| 42 | + let mut prev_lsqb = None; |
| 43 | + let mut prev_lbrace = None; |
| 44 | + for (idx, (char, next_char)) in line.chars().tuple_windows().enumerate() { |
| 45 | + if char == '[' { |
| 46 | + num_lsqb += 1; |
| 47 | + prev_lsqb = Some(idx); |
| 48 | + } else if char == ']' { |
| 49 | + num_rsqb += 1; |
| 50 | + } else if char == '{' { |
| 51 | + prev_lbrace = Some(idx); |
46 | 52 | }
|
47 |
| - let next_char = line.chars().nth(idx + 1).unwrap(); |
48 | 53 |
|
49 |
| - if ",;:".contains(char) && !char::is_whitespace(next_char) { |
50 |
| - let before = &line[..idx]; |
51 |
| - if char == ':' |
52 |
| - && before.matches('[').count() > before.matches(']').count() |
53 |
| - && before.rfind('{') < before.rfind('[') |
54 |
| - { |
| 54 | + if (char == ',' || char == ';' || char == ':') && !char::is_whitespace(next_char) { |
| 55 | + if char == ':' && num_lsqb > num_rsqb && prev_lsqb > prev_lbrace { |
55 | 56 | continue; // Slice syntax, no space required
|
56 | 57 | }
|
57 |
| - if char == ',' && ")]".contains(next_char) { |
| 58 | + if char == ',' && (next_char == ')' || next_char == ']') { |
58 | 59 | continue; // Allow tuple with only one element: (3,)
|
59 | 60 | }
|
60 | 61 | if char == ':' && next_char == '=' {
|
|
0 commit comments