Skip to content

Commit

Permalink
Merge pull request #98 from epage/footer
Browse files Browse the repository at this point in the history
fix!: Generalize footer to be any Message
  • Loading branch information
Muscraft authored Mar 12, 2024
2 parents 0d1364d + 535e146 commit 6c23a41
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 113 deletions.
4 changes: 2 additions & 2 deletions examples/footer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use annotate_snippets::{Label, Level, Renderer, Snippet};
use annotate_snippets::{Level, Renderer, Snippet};

fn main() {
let message =
Expand All @@ -13,7 +13,7 @@ fn main() {
"expected struct `annotate_snippets::snippet::Slice`, found reference",
)),
)
.footer(Label::note(
.footer(Level::Note.title(
"expected type: `snippet::Annotation`\n found type: `__&__snippet::Annotation`",
));

Expand Down
116 changes: 64 additions & 52 deletions src/renderer/display_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,39 +106,12 @@ impl<'a> DisplayList<'a> {
const WARNING_TXT: &'static str = "warning";

pub(crate) fn new(
snippet::Message {
level,
id,
title,
footer,
snippets,
}: snippet::Message<'a>,
message: snippet::Message<'a>,
stylesheet: &'a Stylesheet,
anonymized_line_numbers: bool,
margin: Option<Margin>,
) -> DisplayList<'a> {
let mut body = vec![];

body.push(format_title(
snippet::Label {
level,
label: title,
},
id,
));

for (idx, snippet) in snippets.into_iter().enumerate() {
body.append(&mut format_slice(
snippet,
idx == 0,
!footer.is_empty(),
margin,
));
}

for annotation in footer {
body.append(&mut format_footer(annotation));
}
let body = format_message(message, margin, true);

Self {
body,
Expand Down Expand Up @@ -725,40 +698,64 @@ impl<'a> Iterator for CursorLines<'a> {
}
}

fn format_label(
label: Option<&str>,
style: Option<DisplayTextStyle>,
) -> Vec<DisplayTextFragment<'_>> {
let mut result = vec![];
if let Some(label) = label {
let element_style = style.unwrap_or(DisplayTextStyle::Regular);
result.push(DisplayTextFragment {
content: label,
style: element_style,
});
fn format_message(
snippet::Message {
level,
id,
title,
footer,
snippets,
}: snippet::Message<'_>,
margin: Option<Margin>,
primary: bool,
) -> Vec<DisplayLine<'_>> {
let mut body = vec![];

if !snippets.is_empty() || primary {
body.push(format_title(level, id, title));
} else {
body.extend(format_footer(level, id, title));
}
result

for (idx, snippet) in snippets.into_iter().enumerate() {
body.extend(format_snippet(
snippet,
idx == 0,
!footer.is_empty(),
margin,
));
}

for annotation in footer {
body.extend(format_message(annotation, margin, false));
}

body
}

fn format_title<'a>(title: snippet::Label<'a>, id: Option<&'a str>) -> DisplayLine<'a> {
fn format_title<'a>(level: crate::Level, id: Option<&'a str>, label: &'a str) -> DisplayLine<'a> {
DisplayLine::Raw(DisplayRawLine::Annotation {
annotation: Annotation {
annotation_type: DisplayAnnotationType::from(title.level),
annotation_type: DisplayAnnotationType::from(level),
id,
label: format_label(Some(title.label), Some(DisplayTextStyle::Emphasis)),
label: format_label(Some(label), Some(DisplayTextStyle::Emphasis)),
},
source_aligned: false,
continuation: false,
})
}

fn format_footer(footer: snippet::Label<'_>) -> Vec<DisplayLine<'_>> {
fn format_footer<'a>(
level: crate::Level,
id: Option<&'a str>,
label: &'a str,
) -> Vec<DisplayLine<'a>> {
let mut result = vec![];
for (i, line) in footer.label.lines().enumerate() {
for (i, line) in label.lines().enumerate() {
result.push(DisplayLine::Raw(DisplayRawLine::Annotation {
annotation: Annotation {
annotation_type: DisplayAnnotationType::from(footer.level),
id: None,
annotation_type: DisplayAnnotationType::from(level),
id,
label: format_label(Some(line), None),
},
source_aligned: true,
Expand All @@ -768,7 +765,22 @@ fn format_footer(footer: snippet::Label<'_>) -> Vec<DisplayLine<'_>> {
result
}

fn format_slice(
fn format_label(
label: Option<&str>,
style: Option<DisplayTextStyle>,
) -> Vec<DisplayTextFragment<'_>> {
let mut result = vec![];
if let Some(label) = label {
let element_style = style.unwrap_or(DisplayTextStyle::Regular);
result.push(DisplayTextFragment {
content: label,
style: element_style,
});
}
result
}

fn format_snippet(
snippet: snippet::Snippet<'_>,
is_first: bool,
has_footer: bool,
Expand All @@ -777,14 +789,14 @@ fn format_slice(
let main_range = snippet.annotations.first().map(|x| x.range.start);
let origin = snippet.origin;
let need_empty_header = origin.is_some() || is_first;
let mut body = format_body(snippet, need_empty_header, has_footer, margin);
let body = format_body(snippet, need_empty_header, has_footer, margin);
let header = format_header(origin, main_range, &body, is_first);
let mut result = vec![];

if let Some(header) = header {
result.push(header);
}
result.append(&mut body);
result.extend(body);
result
}

Expand Down Expand Up @@ -1444,7 +1456,7 @@ mod tests {
fn test_format_label() {
let input = snippet::Level::Error
.title("")
.footer(snippet::Label::error("This __is__ a title"));
.footer(snippet::Level::Error.title("This __is__ a title"));
let output = from_display_lines(vec![
DisplayLine::Raw(DisplayRawLine::Annotation {
annotation: Annotation {
Expand Down
41 changes: 3 additions & 38 deletions src/snippet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub struct Message<'a> {
pub(crate) id: Option<&'a str>,
pub(crate) title: &'a str,
pub(crate) snippets: Vec<Snippet<'a>>,
pub(crate) footer: Vec<Label<'a>>,
pub(crate) footer: Vec<Message<'a>>,
}

impl<'a> Message<'a> {
Expand All @@ -39,52 +39,17 @@ impl<'a> Message<'a> {
self
}

pub fn footer(mut self, footer: Label<'a>) -> Self {
pub fn footer(mut self, footer: Message<'a>) -> Self {
self.footer.push(footer);
self
}

pub fn footers(mut self, footer: impl IntoIterator<Item = Label<'a>>) -> Self {
pub fn footers(mut self, footer: impl IntoIterator<Item = Message<'a>>) -> Self {
self.footer.extend(footer);
self
}
}

pub struct Label<'a> {
pub(crate) level: Level,
pub(crate) label: &'a str,
}

impl<'a> Label<'a> {
pub fn new(level: Level, label: &'a str) -> Self {
Self { level, label }
}
pub fn error(label: &'a str) -> Self {
Self::new(Level::Error, label)
}

pub fn warning(label: &'a str) -> Self {
Self::new(Level::Warning, label)
}

pub fn info(label: &'a str) -> Self {
Self::new(Level::Info, label)
}

pub fn note(label: &'a str) -> Self {
Self::new(Level::Note, label)
}

pub fn help(label: &'a str) -> Self {
Self::new(Level::Help, label)
}

pub fn label(mut self, label: &'a str) -> Self {
self.label = label;
self
}
}

/// Structure containing the slice of text to be annotated and
/// basic information about the location of the slice.
///
Expand Down
24 changes: 3 additions & 21 deletions tests/fixtures/deserialize.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use serde::{Deserialize, Deserializer, Serialize};
use std::ops::Range;

use annotate_snippets::{renderer::Margin, Annotation, Label, Level, Message, Renderer, Snippet};
use annotate_snippets::{renderer::Margin, Annotation, Level, Message, Renderer, Snippet};

#[derive(Deserialize)]
pub struct Fixture<'a> {
Expand All @@ -20,10 +20,9 @@ pub struct MessageDef<'a> {
#[serde(default)]
#[serde(borrow)]
pub id: Option<&'a str>,
#[serde(deserialize_with = "deserialize_labels")]
#[serde(default)]
#[serde(borrow)]
pub footer: Vec<Label<'a>>,
pub footer: Vec<MessageDef<'a>>,
#[serde(deserialize_with = "deserialize_snippets")]
#[serde(borrow)]
pub snippets: Vec<Snippet<'a>>,
Expand All @@ -43,28 +42,11 @@ impl<'a> From<MessageDef<'a>> for Message<'a> {
message = message.id(id);
}
message = message.snippets(snippets);
message = message.footers(footer);
message = message.footers(footer.into_iter().map(Into::into));
message
}
}

fn deserialize_labels<'de, D>(deserializer: D) -> Result<Vec<Label<'de>>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrapper<'a>(
#[serde(with = "LabelDef")]
#[serde(borrow)]
LabelDef<'a>,
);

let v = Vec::deserialize(deserializer)?;
Ok(v.into_iter()
.map(|Wrapper(a)| Label::new(a.level, a.label))
.collect())
}

fn deserialize_snippets<'de, D>(deserializer: D) -> Result<Vec<Snippet<'de>>, D::Error>
where
D: Deserializer<'de>,
Expand Down

0 comments on commit 6c23a41

Please sign in to comment.