crates: vendor annotate-snippets crate

This merely adds the crate to our repository. Some cosmetic changes are
made to make it work in our repo and follow our conventions, such as
changing the name to `ruff_annotate_snippets`. We retain the original
license information. We do drop some things, such as benchmarks, but
keep tests and examples.
This commit is contained in:
Andrew Gallant 2024-12-20 12:55:16 -05:00 committed by Andrew Gallant
parent 4f3209a3ec
commit 9c27c57b5b
58 changed files with 6171 additions and 8 deletions

View file

@ -0,0 +1,157 @@
//! Structures used as an input for the library.
//!
//! Example:
//!
//! ```
//! use ruff_annotate_snippets::*;
//!
//! Level::Error.title("mismatched types")
//! .snippet(Snippet::source("Foo").line_start(51).origin("src/format.rs"))
//! .snippet(Snippet::source("Faa").line_start(129).origin("src/display.rs"));
//! ```
use std::ops::Range;
/// Primary structure provided for formatting
///
/// See [`Level::title`] to create a [`Message`]
#[derive(Debug)]
pub struct Message<'a> {
pub(crate) level: Level,
pub(crate) id: Option<&'a str>,
pub(crate) title: &'a str,
pub(crate) snippets: Vec<Snippet<'a>>,
pub(crate) footer: Vec<Message<'a>>,
}
impl<'a> Message<'a> {
pub fn id(mut self, id: &'a str) -> Self {
self.id = Some(id);
self
}
pub fn snippet(mut self, slice: Snippet<'a>) -> Self {
self.snippets.push(slice);
self
}
pub fn snippets(mut self, slice: impl IntoIterator<Item = Snippet<'a>>) -> Self {
self.snippets.extend(slice);
self
}
pub fn footer(mut self, footer: Message<'a>) -> Self {
self.footer.push(footer);
self
}
pub fn footers(mut self, footer: impl IntoIterator<Item = Message<'a>>) -> Self {
self.footer.extend(footer);
self
}
}
/// Structure containing the slice of text to be annotated and
/// basic information about the location of the slice.
///
/// One `Snippet` is meant to represent a single, continuous,
/// slice of source code that you want to annotate.
#[derive(Debug)]
pub struct Snippet<'a> {
pub(crate) origin: Option<&'a str>,
pub(crate) line_start: usize,
pub(crate) source: &'a str,
pub(crate) annotations: Vec<Annotation<'a>>,
pub(crate) fold: bool,
}
impl<'a> Snippet<'a> {
pub fn source(source: &'a str) -> Self {
Self {
origin: None,
line_start: 1,
source,
annotations: vec![],
fold: false,
}
}
pub fn line_start(mut self, line_start: usize) -> Self {
self.line_start = line_start;
self
}
pub fn origin(mut self, origin: &'a str) -> Self {
self.origin = Some(origin);
self
}
pub fn annotation(mut self, annotation: Annotation<'a>) -> Self {
self.annotations.push(annotation);
self
}
pub fn annotations(mut self, annotation: impl IntoIterator<Item = Annotation<'a>>) -> Self {
self.annotations.extend(annotation);
self
}
/// Hide lines without [`Annotation`]s
pub fn fold(mut self, fold: bool) -> Self {
self.fold = fold;
self
}
}
/// An annotation for a [`Snippet`].
///
/// See [`Level::span`] to create a [`Annotation`]
#[derive(Debug)]
pub struct Annotation<'a> {
/// The byte range of the annotation in the `source` string
pub(crate) range: Range<usize>,
pub(crate) label: Option<&'a str>,
pub(crate) level: Level,
}
impl<'a> Annotation<'a> {
pub fn label(mut self, label: &'a str) -> Self {
self.label = Some(label);
self
}
}
/// Types of annotations.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Level {
/// Error annotations are displayed using red color and "^" character.
Error,
/// Warning annotations are displayed using blue color and "-" character.
Warning,
Info,
Note,
Help,
}
impl Level {
pub fn title(self, title: &str) -> Message<'_> {
Message {
level: self,
id: None,
title,
snippets: vec![],
footer: vec![],
}
}
/// Create a [`Annotation`] with the given span for a [`Snippet`]
pub fn span<'a>(self, span: Range<usize>) -> Annotation<'a> {
Annotation {
range: span,
label: None,
level: self,
}
}
}