ruff_linter,ruff_python_parser: migrate to updated annotate-snippets

This is pretty much just moving to the new API and taking care to use
byte offsets. This is *almost* enough. The next commit will fix a bug
involving the handling of unprintable characters as a result of
switching to byte offsets.
This commit is contained in:
Andrew Gallant 2024-12-20 14:19:32 -05:00 committed by Andrew Gallant
parent 1b97677779
commit 84179aaa96
6 changed files with 43 additions and 99 deletions

25
Cargo.lock generated
View file

@ -57,16 +57,6 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7" checksum = "c7021ce4924a3f25f802b2cccd1af585e39ea1a363a1aa2e72afe54b67a3a7a7"
[[package]]
name = "annotate-snippets"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e"
dependencies = [
"unicode-width 0.1.13",
"yansi-term",
]
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.6.18" version = "0.6.18"
@ -326,7 +316,7 @@ version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5b5db619f3556839cb2223ae86ff3f9a09da2c5013be42bc9af08c9589bf70c" checksum = "a5b5db619f3556839cb2223ae86ff3f9a09da2c5013be42bc9af08c9589bf70c"
dependencies = [ dependencies = [
"annotate-snippets 0.6.1", "annotate-snippets",
] ]
[[package]] [[package]]
@ -2837,7 +2827,6 @@ name = "ruff_linter"
version = "0.9.1" version = "0.9.1"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"annotate-snippets 0.9.2",
"anyhow", "anyhow",
"bitflags 2.7.0", "bitflags 2.7.0",
"chrono", "chrono",
@ -2861,6 +2850,7 @@ dependencies = [
"pyproject-toml", "pyproject-toml",
"quick-junit", "quick-junit",
"regex", "regex",
"ruff_annotate_snippets",
"ruff_cache", "ruff_cache",
"ruff_diagnostics", "ruff_diagnostics",
"ruff_index", "ruff_index",
@ -3020,13 +3010,13 @@ dependencies = [
name = "ruff_python_parser" name = "ruff_python_parser"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"annotate-snippets 0.9.2",
"anyhow", "anyhow",
"bitflags 2.7.0", "bitflags 2.7.0",
"bstr", "bstr",
"compact_str", "compact_str",
"insta", "insta",
"memchr", "memchr",
"ruff_annotate_snippets",
"ruff_python_ast", "ruff_python_ast",
"ruff_python_trivia", "ruff_python_trivia",
"ruff_source_file", "ruff_source_file",
@ -4651,15 +4641,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
[[package]]
name = "yansi-term"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "yoke" name = "yoke"
version = "0.7.4" version = "0.7.4"

View file

@ -44,7 +44,6 @@ red_knot_test = { path = "crates/red_knot_test" }
red_knot_workspace = { path = "crates/red_knot_workspace", default-features = false } red_knot_workspace = { path = "crates/red_knot_workspace", default-features = false }
aho-corasick = { version = "1.1.3" } aho-corasick = { version = "1.1.3" }
annotate-snippets = { version = "0.9.2", features = ["color"] }
anstream = { version = "0.6.18" } anstream = { version = "0.6.18" }
anstyle = { version = "1.0.10" } anstyle = { version = "1.0.10" }
anyhow = { version = "1.0.80" } anyhow = { version = "1.0.80" }

View file

@ -13,6 +13,7 @@ license = { workspace = true }
[lib] [lib]
[dependencies] [dependencies]
ruff_annotate_snippets = { workspace = true }
ruff_cache = { workspace = true } ruff_cache = { workspace = true }
ruff_diagnostics = { workspace = true, features = ["serde"] } ruff_diagnostics = { workspace = true, features = ["serde"] }
ruff_index = { workspace = true } ruff_index = { workspace = true }
@ -30,7 +31,6 @@ ruff_source_file = { workspace = true, features = ["serde"] }
ruff_text_size = { workspace = true } ruff_text_size = { workspace = true }
aho-corasick = { workspace = true } aho-corasick = { workspace = true }
annotate-snippets = { workspace = true, features = ["color"] }
anyhow = { workspace = true } anyhow = { workspace = true }
bitflags = { workspace = true } bitflags = { workspace = true }
chrono = { workspace = true } chrono = { workspace = true }

View file

@ -2,10 +2,9 @@ use std::borrow::Cow;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::io::Write; use std::io::Write;
use annotate_snippets::display_list::{DisplayList, FormatOptions};
use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation};
use bitflags::bitflags; use bitflags::bitflags;
use colored::Colorize; use colored::Colorize;
use ruff_annotate_snippets::{Level, Renderer, Snippet};
use ruff_notebook::NotebookIndex; use ruff_notebook::NotebookIndex;
use ruff_source_file::{OneIndexed, SourceLocation}; use ruff_source_file::{OneIndexed, SourceLocation};
@ -186,12 +185,8 @@ pub(super) struct MessageCodeFrame<'a> {
impl Display for MessageCodeFrame<'_> { impl Display for MessageCodeFrame<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let suggestion = self.message.suggestion(); let suggestion = self.message.suggestion();
let footer = if suggestion.is_some() { let footers = if let Some(suggestion) = suggestion {
vec![Annotation { vec![Level::Help.title(suggestion)]
id: None,
label: suggestion,
annotation_type: AnnotationType::Help,
}]
} else { } else {
Vec::new() Vec::new()
}; };
@ -257,22 +252,12 @@ impl Display for MessageCodeFrame<'_> {
let source_text = source.text.show_nonprinting(); let source_text = source.text.show_nonprinting();
let start_char = source.text[TextRange::up_to(source.annotation_range.start())]
.chars()
.count();
let char_length = source.text[source.annotation_range].chars().count();
let label = self let label = self
.message .message
.rule() .rule()
.map_or_else(String::new, |rule| rule.noqa_code().to_string()); .map_or_else(String::new, |rule| rule.noqa_code().to_string());
let snippet = Snippet { let line_start = self.notebook_index.map_or_else(
title: None,
slices: vec![Slice {
source: &source_text,
line_start: self.notebook_index.map_or_else(
|| start_index.get(), || start_index.get(),
|notebook_index| { |notebook_index| {
notebook_index notebook_index
@ -280,28 +265,24 @@ impl Display for MessageCodeFrame<'_> {
.unwrap_or(OneIndexed::MIN) .unwrap_or(OneIndexed::MIN)
.get() .get()
}, },
), );
annotations: vec![SourceAnnotation {
label: &label,
annotation_type: AnnotationType::Error,
range: (start_char, start_char + char_length),
}],
// The origin (file name, line number, and column number) is already encoded
// in the `label`.
origin: None,
fold: false,
}],
footer,
opt: FormatOptions {
#[cfg(test)]
color: false,
#[cfg(not(test))]
color: colored::control::SHOULD_COLORIZE.should_colorize(),
..FormatOptions::default()
},
};
writeln!(f, "{message}", message = DisplayList::from(snippet)) let span = usize::from(source.annotation_range.start())
..usize::from(source.annotation_range.end());
let annotation = Level::Error.span(span).label(&label);
let snippet = Snippet::source(&source_text)
.line_start(line_start)
.annotation(annotation)
.fold(false);
let message = Level::None.title("").snippet(snippet).footers(footers);
let renderer = if !cfg!(test) && colored::control::SHOULD_COLORIZE.should_colorize() {
Renderer::styled()
} else {
Renderer::plain()
};
let rendered = renderer.render(message);
writeln!(f, "{rendered}")
} }
} }

View file

@ -28,9 +28,9 @@ unicode_names2 = { workspace = true }
unicode-normalization = { workspace = true } unicode-normalization = { workspace = true }
[dev-dependencies] [dev-dependencies]
ruff_annotate_snippets = { workspace = true }
ruff_source_file = { workspace = true } ruff_source_file = { workspace = true }
annotate-snippets = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
insta = { workspace = true, features = ["glob"] } insta = { workspace = true, features = ["glob"] }
walkdir = { workspace = true } walkdir = { workspace = true }

View file

@ -3,9 +3,7 @@ use std::fmt::{Formatter, Write};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use annotate_snippets::display_list::{DisplayList, FormatOptions}; use ruff_annotate_snippets::{Level, Renderer, Snippet};
use annotate_snippets::snippet::{AnnotationType, Slice, Snippet, SourceAnnotation};
use ruff_python_ast::visitor::source_order::{walk_module, SourceOrderVisitor, TraversalSignal}; use ruff_python_ast::visitor::source_order::{walk_module, SourceOrderVisitor, TraversalSignal};
use ruff_python_ast::{AnyNodeRef, Mod}; use ruff_python_ast::{AnyNodeRef, Mod};
use ruff_python_parser::{parse_unchecked, Mode, ParseErrorType, Token}; use ruff_python_parser::{parse_unchecked, Mode, ParseErrorType, Token};
@ -203,33 +201,18 @@ impl std::fmt::Display for CodeFrame<'_> {
.source_code .source_code
.slice(TextRange::new(start_offset, end_offset)); .slice(TextRange::new(start_offset, end_offset));
let start_char = source[TextRange::up_to(annotation_range.start())]
.chars()
.count();
let char_length = source[annotation_range].chars().count();
let label = format!("Syntax Error: {error}", error = self.error); let label = format!("Syntax Error: {error}", error = self.error);
let snippet = Snippet { let span = usize::from(annotation_range.start())..usize::from(annotation_range.end());
title: None, let annotation = Level::Error.span(span).label(&label);
slices: vec![Slice { let snippet = Snippet::source(source)
source, .line_start(start_index.get())
line_start: start_index.get(), .annotation(annotation)
annotations: vec![SourceAnnotation { .fold(false);
label: &label, let message = Level::None.title("").snippet(snippet);
annotation_type: AnnotationType::Error, let renderer = Renderer::plain();
range: (start_char, start_char + char_length), let rendered = renderer.render(message);
}], writeln!(f, "{rendered}")
// The origin (file name, line number, and column number) is already encoded
// in the `label`.
origin: None,
fold: false,
}],
footer: Vec::new(),
opt: FormatOptions::default(),
};
writeln!(f, "{message}", message = DisplayList::from(snippet))
} }
} }