Skip to content

Commit

Permalink
Tweak message; remove locator
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Mar 12, 2024
1 parent d13c6b9 commit 2d4e2fe
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 36 deletions.
2 changes: 1 addition & 1 deletion crates/ruff_linter/src/checkers/tokens.rs
Expand Up @@ -204,7 +204,7 @@ pub(crate) fn check_tokens(
}

if settings.rules.enabled(Rule::TooManyNewlinesAtEndOfFile) {
pycodestyle::rules::too_many_newlines_at_end_of_file(&mut diagnostics, tokens, locator);
pycodestyle::rules::too_many_newlines_at_end_of_file(&mut diagnostics, tokens);
}

diagnostics.retain(|diagnostic| settings.rules.enabled(diagnostic.kind.rule()));
Expand Down
Expand Up @@ -42,7 +42,7 @@ pub(crate) fn no_newline_at_end_of_file(
) -> Option<Diagnostic> {
let source = locator.contents();

// Ignore empty and BOM only files
// Ignore empty and BOM only files.
if source.is_empty() || source == "\u{feff}" {
return None;
}
Expand Down
Expand Up @@ -2,15 +2,15 @@ use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_parser::lexer::LexResult;
use ruff_python_parser::Tok;
use ruff_source_file::Locator;
use ruff_text_size::{TextRange, TextSize};

/// ## What it does
/// Checks for files with too many new lines at the end of the file.
/// Checks for files with multiple trailing blank lines.
///
/// ## Why is this bad?
/// Trailing blank lines are superfluous.
/// However the last line should end with a new line.
/// Trailing blank lines in a file are superfluous.
///
/// However, the last line of the file should end with a newline.
///
/// ## Example
/// ```python
Expand All @@ -22,44 +22,56 @@ use ruff_text_size::{TextRange, TextSize};
/// spam(1)\n
/// ```
#[violation]
pub struct TooManyNewlinesAtEndOfFile;
pub struct TooManyNewlinesAtEndOfFile {
num_trailing_newlines: u32,
}

impl AlwaysFixableViolation for TooManyNewlinesAtEndOfFile {
#[derive_message_formats]
fn message(&self) -> String {
format!("Too many newlines at the end of file")
let TooManyNewlinesAtEndOfFile {
num_trailing_newlines,
} = self;

// We expect a single trailing newline; so two trailing newlines is one too many, three
// trailing newlines is two too many, etc.
if *num_trailing_newlines > 2 {
format!("Too many newlines at end of file")
} else {
format!("Extra newline at end of file")
}
}

fn fix_title(&self) -> String {
"Remove extraneous trailing newlines".to_string()
let TooManyNewlinesAtEndOfFile {
num_trailing_newlines,
} = self;
if *num_trailing_newlines > 2 {
"Remove trailing newlines".to_string()
} else {
"Remove trailing newline".to_string()
}
}
}

/// W391
pub(crate) fn too_many_newlines_at_end_of_file(
diagnostics: &mut Vec<Diagnostic>,
lxr: &[LexResult],
locator: &Locator,
) {
let source = locator.contents();
let mut num_trailing_newlines = 0u32;
let mut start: Option<TextSize> = None;
let mut end: Option<TextSize> = None;

// Ignore empty and BOM only files
if source.is_empty() || source == "\u{feff}" {
return;
}

let mut count = 0;
let mut start_pos: Option<TextSize> = None;
let mut end_pos: Option<TextSize> = None;

for &(ref tok, range) in lxr.iter().rev().flatten() {
// Count the number of trailing newlines.
for (tok, range) in lxr.iter().rev().flatten() {
match tok {
Tok::NonLogicalNewline | Tok::Newline => {
if count == 0 {
end_pos = Some(range.end());
if num_trailing_newlines == 0 {
end = Some(range.end());
}
start_pos = Some(range.end());
count += 1;
start = Some(range.end());
num_trailing_newlines += 1;
}
Tok::Dedent => continue,
_ => {
Expand All @@ -68,12 +80,20 @@ pub(crate) fn too_many_newlines_at_end_of_file(
}
}

if count > 1 {
let start = start_pos.unwrap();
let end = end_pos.unwrap();
let range = TextRange::new(start, end);
let mut diagnostic = Diagnostic::new(TooManyNewlinesAtEndOfFile, range);
diagnostic.set_fix(Fix::safe_edit(Edit::deletion(start, end)));
diagnostics.push(diagnostic);
if num_trailing_newlines == 0 || num_trailing_newlines == 1 {
return;
}

let range = match (start, end) {
(Some(start), Some(end)) => TextRange::new(start, end),
_ => return,
};
let mut diagnostic = Diagnostic::new(
TooManyNewlinesAtEndOfFile {
num_trailing_newlines,
},
range,
);
diagnostic.set_fix(Fix::safe_edit(Edit::range_deletion(range)));
diagnostics.push(diagnostic);
}
@@ -1,14 +1,14 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
W391_0.py:14:1: W391 [*] Too many newlines at the end of file
W391_0.py:14:1: W391 [*] Extra newline at end of file
|
12 | foo()
13 | bar()
14 |
| ^ W391
|
= help: Remove extraneous trailing newlines
= help: Remove trailing newline

Safe fix
11 11 | if __name__ == '__main__':
Expand Down
@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
W391_2.py:14:1: W391 [*] Too many newlines at the end of file
W391_2.py:14:1: W391 [*] Too many newlines at end of file
|
12 | foo()
13 | bar()
Expand All @@ -10,7 +10,7 @@ W391_2.py:14:1: W391 [*] Too many newlines at the end of file
16 | |
17 | |
|
= help: Remove extraneous trailing newlines
= help: Remove trailing newlines

Safe fix
11 11 | if __name__ == '__main__':
Expand Down

0 comments on commit 2d4e2fe

Please sign in to comment.