annotate_snippets/snippet.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
//! Structures used as an input for the library.
//!
//! Example:
//!
//! ```
//! use 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,
}
}
}