From 84179aaa96aa9cd6774fc632f66acdf2a12f9fe3 Mon Sep 17 00:00:00 2001 From: Andrew Gallant Date: Fri, 20 Dec 2024 14:19:32 -0500 Subject: [PATCH] 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. --- Cargo.lock | 25 +------ Cargo.toml | 1 - crates/ruff_linter/Cargo.toml | 2 +- crates/ruff_linter/src/message/text.rs | 73 ++++++++------------- crates/ruff_python_parser/Cargo.toml | 2 +- crates/ruff_python_parser/tests/fixtures.rs | 39 ++++------- 6 files changed, 43 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47f0d77eeb..4844058c68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,16 +57,6 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "anstream" version = "0.6.18" @@ -326,7 +316,7 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5b5db619f3556839cb2223ae86ff3f9a09da2c5013be42bc9af08c9589bf70c" dependencies = [ - "annotate-snippets 0.6.1", + "annotate-snippets", ] [[package]] @@ -2837,7 +2827,6 @@ name = "ruff_linter" version = "0.9.1" dependencies = [ "aho-corasick", - "annotate-snippets 0.9.2", "anyhow", "bitflags 2.7.0", "chrono", @@ -2861,6 +2850,7 @@ dependencies = [ "pyproject-toml", "quick-junit", "regex", + "ruff_annotate_snippets", "ruff_cache", "ruff_diagnostics", "ruff_index", @@ -3020,13 +3010,13 @@ dependencies = [ name = "ruff_python_parser" version = "0.0.0" dependencies = [ - "annotate-snippets 0.9.2", "anyhow", "bitflags 2.7.0", "bstr", "compact_str", "insta", "memchr", + "ruff_annotate_snippets", "ruff_python_ast", "ruff_python_trivia", "ruff_source_file", @@ -4651,15 +4641,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" 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]] name = "yoke" version = "0.7.4" diff --git a/Cargo.toml b/Cargo.toml index b484f1eb1b..de13bcf836 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,6 @@ red_knot_test = { path = "crates/red_knot_test" } red_knot_workspace = { path = "crates/red_knot_workspace", default-features = false } aho-corasick = { version = "1.1.3" } -annotate-snippets = { version = "0.9.2", features = ["color"] } anstream = { version = "0.6.18" } anstyle = { version = "1.0.10" } anyhow = { version = "1.0.80" } diff --git a/crates/ruff_linter/Cargo.toml b/crates/ruff_linter/Cargo.toml index 17cd6c717a..969104a7f4 100644 --- a/crates/ruff_linter/Cargo.toml +++ b/crates/ruff_linter/Cargo.toml @@ -13,6 +13,7 @@ license = { workspace = true } [lib] [dependencies] +ruff_annotate_snippets = { workspace = true } ruff_cache = { workspace = true } ruff_diagnostics = { workspace = true, features = ["serde"] } ruff_index = { workspace = true } @@ -30,7 +31,6 @@ ruff_source_file = { workspace = true, features = ["serde"] } ruff_text_size = { workspace = true } aho-corasick = { workspace = true } -annotate-snippets = { workspace = true, features = ["color"] } anyhow = { workspace = true } bitflags = { workspace = true } chrono = { workspace = true } diff --git a/crates/ruff_linter/src/message/text.rs b/crates/ruff_linter/src/message/text.rs index 7b3c417e48..98c7dddc36 100644 --- a/crates/ruff_linter/src/message/text.rs +++ b/crates/ruff_linter/src/message/text.rs @@ -2,10 +2,9 @@ use std::borrow::Cow; use std::fmt::{Display, Formatter}; use std::io::Write; -use annotate_snippets::display_list::{DisplayList, FormatOptions}; -use annotate_snippets::snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation}; use bitflags::bitflags; use colored::Colorize; +use ruff_annotate_snippets::{Level, Renderer, Snippet}; use ruff_notebook::NotebookIndex; use ruff_source_file::{OneIndexed, SourceLocation}; @@ -186,12 +185,8 @@ pub(super) struct MessageCodeFrame<'a> { impl Display for MessageCodeFrame<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let suggestion = self.message.suggestion(); - let footer = if suggestion.is_some() { - vec![Annotation { - id: None, - label: suggestion, - annotation_type: AnnotationType::Help, - }] + let footers = if let Some(suggestion) = suggestion { + vec![Level::Help.title(suggestion)] } else { Vec::new() }; @@ -257,51 +252,37 @@ impl Display for MessageCodeFrame<'_> { 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 .message .rule() .map_or_else(String::new, |rule| rule.noqa_code().to_string()); - let snippet = Snippet { - title: None, - slices: vec![Slice { - source: &source_text, - line_start: self.notebook_index.map_or_else( - || start_index.get(), - |notebook_index| { - notebook_index - .cell_row(start_index) - .unwrap_or(OneIndexed::MIN) - .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() + let line_start = self.notebook_index.map_or_else( + || start_index.get(), + |notebook_index| { + notebook_index + .cell_row(start_index) + .unwrap_or(OneIndexed::MIN) + .get() }, - }; + ); - 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}") } } diff --git a/crates/ruff_python_parser/Cargo.toml b/crates/ruff_python_parser/Cargo.toml index a74a93143e..d6b8425bc3 100644 --- a/crates/ruff_python_parser/Cargo.toml +++ b/crates/ruff_python_parser/Cargo.toml @@ -28,9 +28,9 @@ unicode_names2 = { workspace = true } unicode-normalization = { workspace = true } [dev-dependencies] +ruff_annotate_snippets = { workspace = true } ruff_source_file = { workspace = true } -annotate-snippets = { workspace = true } anyhow = { workspace = true } insta = { workspace = true, features = ["glob"] } walkdir = { workspace = true } diff --git a/crates/ruff_python_parser/tests/fixtures.rs b/crates/ruff_python_parser/tests/fixtures.rs index 893695fa94..e8516b6a64 100644 --- a/crates/ruff_python_parser/tests/fixtures.rs +++ b/crates/ruff_python_parser/tests/fixtures.rs @@ -3,9 +3,7 @@ use std::fmt::{Formatter, Write}; use std::fs; use std::path::Path; -use annotate_snippets::display_list::{DisplayList, FormatOptions}; -use annotate_snippets::snippet::{AnnotationType, Slice, Snippet, SourceAnnotation}; - +use ruff_annotate_snippets::{Level, Renderer, Snippet}; use ruff_python_ast::visitor::source_order::{walk_module, SourceOrderVisitor, TraversalSignal}; use ruff_python_ast::{AnyNodeRef, Mod}; use ruff_python_parser::{parse_unchecked, Mode, ParseErrorType, Token}; @@ -203,33 +201,18 @@ impl std::fmt::Display for CodeFrame<'_> { .source_code .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 snippet = Snippet { - title: None, - slices: vec![Slice { - source, - line_start: start_index.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: Vec::new(), - opt: FormatOptions::default(), - }; - - writeln!(f, "{message}", message = DisplayList::from(snippet)) + let span = usize::from(annotation_range.start())..usize::from(annotation_range.end()); + let annotation = Level::Error.span(span).label(&label); + let snippet = Snippet::source(source) + .line_start(start_index.get()) + .annotation(annotation) + .fold(false); + let message = Level::None.title("").snippet(snippet); + let renderer = Renderer::plain(); + let rendered = renderer.render(message); + writeln!(f, "{rendered}") } }