Skip to content

Commit

Permalink
Truncate SyntaxErrors before newline character (#4124)
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaReiser authored May 10, 2023
1 parent b8bb9e8 commit d66ce76
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 5 deletions.
80 changes: 76 additions & 4 deletions crates/ruff/src/logging.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::fmt::{Display, Formatter};
use std::fmt::{Display, Formatter, Write};
use std::path::Path;
use std::sync::Mutex;

Expand All @@ -9,7 +9,7 @@ use fern;
use log::Level;
use once_cell::sync::Lazy;
use ruff_python_ast::source_code::SourceCode;
use rustpython_parser::ParseError;
use rustpython_parser::{ParseError, ParseErrorType};

pub(crate) static WARNINGS: Lazy<Mutex<Vec<&'static str>>> = Lazy::new(Mutex::default);

Expand Down Expand Up @@ -150,12 +150,84 @@ impl Display for DisplayParseError<'_> {
write!(
f,
"{header} {path}{colon}{row}{colon}{column}{colon} {inner}",
header = "Failed to parse ".bold(),
header = "Failed to parse".bold(),
path = fs::relativize_path(Path::new(&self.error.source_path)).bold(),
row = source_location.row,
column = source_location.column,
colon = ":".cyan(),
inner = &self.error.error
inner = &DisplayParseErrorType(&self.error.error)
)
}
}

pub(crate) struct DisplayParseErrorType<'a>(&'a ParseErrorType);

impl<'a> DisplayParseErrorType<'a> {
pub(crate) fn new(error: &'a ParseErrorType) -> Self {
Self(error)
}
}

impl Display for DisplayParseErrorType<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.0 {
ParseErrorType::Eof => write!(f, "Expected token but reached end of file."),
ParseErrorType::ExtraToken(ref tok) => write!(
f,
"Got extraneous token: {tok}",
tok = TruncateAtNewline(&tok)
),
ParseErrorType::InvalidToken => write!(f, "Got invalid token"),
ParseErrorType::UnrecognizedToken(ref tok, ref expected) => {
if let Some(expected) = expected.as_ref() {
write!(
f,
"expected '{expected}', but got {tok}",
tok = TruncateAtNewline(&tok)
)
} else {
write!(f, "unexpected token {tok}", tok = TruncateAtNewline(&tok))
}
}
ParseErrorType::Lexical(ref error) => write!(f, "{error}"),
}
}
}

/// Truncates the display text before the first newline character to avoid line breaks.
struct TruncateAtNewline<'a>(&'a dyn Display);

impl Display for TruncateAtNewline<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
struct TruncateAdapter<'a> {
inner: &'a mut dyn std::fmt::Write,
after_new_line: bool,
}

impl std::fmt::Write for TruncateAdapter<'_> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
if self.after_new_line {
Ok(())
} else {
if let Some(end) = s.find(['\n', '\r']) {
self.inner.write_str(&s[..end])?;
self.inner.write_str("\u{23ce}...")?;
self.after_new_line = true;
Ok(())
} else {
self.inner.write_str(s)
}
}
}
}

write!(
TruncateAdapter {
inner: f,
after_new_line: false,
},
"{}",
self.0
)
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/ruff/src/rules/pycodestyle/rules/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ruff_text_size::{TextLen, TextRange, TextSize};
use rustpython_parser::ParseError;

use crate::logging::DisplayParseErrorType;
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::source_code::Locator;
Expand Down Expand Up @@ -50,7 +51,7 @@ pub fn syntax_error(

diagnostics.push(Diagnostic::new(
SyntaxError {
message: parse_error.error.to_string(),
message: format!("{}", DisplayParseErrorType::new(&parse_error.error)),
},
TextRange::at(parse_error.location, len),
));
Expand Down

0 comments on commit d66ce76

Please sign in to comment.