mirror of https://github.com/zkat/miette.git
feat(protocol): new SourceSpans with labels
This commit is contained in:
parent
36b86df9f5
commit
acfeb9c5b0
|
|
@ -104,8 +104,8 @@ fn pretend_this_is_main() -> Result<(), MyBad> {
|
||||||
Err(MyBad {
|
Err(MyBad {
|
||||||
src: Arc::new(src),
|
src: Arc::new(src),
|
||||||
filename: "bad_file.rs".into(),
|
filename: "bad_file.rs".into(),
|
||||||
snip: (0, (len - 1)).into(),
|
snip: (0, len).into(),
|
||||||
bad_bit: (9, 12).into(),
|
bad_bit: (9, 3).into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -16,25 +16,21 @@ pub struct Snippets(Vec<Snippet>);
|
||||||
struct Snippet {
|
struct Snippet {
|
||||||
message: Option<MemberOrString>,
|
message: Option<MemberOrString>,
|
||||||
highlights: Vec<Highlight>,
|
highlights: Vec<Highlight>,
|
||||||
source_name: MemberOrString,
|
|
||||||
source: syn::Member,
|
source: syn::Member,
|
||||||
snippet: syn::Member,
|
snippet: syn::Member,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Highlight {
|
struct Highlight {
|
||||||
highlight: syn::Member,
|
highlight: syn::Member,
|
||||||
label: Option<MemberOrString>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SnippetAttr {
|
struct SnippetAttr {
|
||||||
source: syn::Member,
|
source: syn::Member,
|
||||||
source_name: MemberOrString,
|
|
||||||
message: Option<MemberOrString>,
|
message: Option<MemberOrString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HighlightAttr {
|
struct HighlightAttr {
|
||||||
snippet: syn::Member,
|
snippet: syn::Member,
|
||||||
label: Option<MemberOrString>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MemberOrString {
|
enum MemberOrString {
|
||||||
|
|
@ -82,15 +78,8 @@ impl Parse for SnippetAttr {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let src_name = iter
|
|
||||||
.next()
|
|
||||||
.ok_or_else(|| syn::Error::new(span, "Expected a source name."))?;
|
|
||||||
let message = iter.next();
|
let message = iter.next();
|
||||||
Ok(SnippetAttr {
|
Ok(SnippetAttr { source, message })
|
||||||
source,
|
|
||||||
source_name: src_name,
|
|
||||||
message,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,8 +96,7 @@ impl Parse for HighlightAttr {
|
||||||
"must be an identifier that refers to something with a #[snippet] attribute.",
|
"must be an identifier that refers to something with a #[snippet] attribute.",
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
let label = iter.next();
|
Ok(HighlightAttr { snippet })
|
||||||
Ok(HighlightAttr { snippet, label })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -137,18 +125,13 @@ impl Snippets {
|
||||||
span: field.span(),
|
span: field.span(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
let SnippetAttr {
|
let SnippetAttr { source, message } = attr.parse_args::<SnippetAttr>()?;
|
||||||
source,
|
|
||||||
message,
|
|
||||||
source_name,
|
|
||||||
} = attr.parse_args::<SnippetAttr>()?;
|
|
||||||
// TODO: useful error when source refers to a field that doesn't exist.
|
// TODO: useful error when source refers to a field that doesn't exist.
|
||||||
snippets.insert(
|
snippets.insert(
|
||||||
snippet.clone(),
|
snippet.clone(),
|
||||||
Snippet {
|
Snippet {
|
||||||
message,
|
message,
|
||||||
highlights: Vec::new(),
|
highlights: Vec::new(),
|
||||||
source_name,
|
|
||||||
source,
|
source,
|
||||||
snippet,
|
snippet,
|
||||||
},
|
},
|
||||||
|
|
@ -160,7 +143,7 @@ impl Snippets {
|
||||||
for (i, field) in fields.iter().enumerate() {
|
for (i, field) in fields.iter().enumerate() {
|
||||||
for attr in &field.attrs {
|
for attr in &field.attrs {
|
||||||
if attr.path.is_ident("highlight") {
|
if attr.path.is_ident("highlight") {
|
||||||
let HighlightAttr { snippet, label } = attr.parse_args::<HighlightAttr>()?;
|
let HighlightAttr { snippet } = attr.parse_args::<HighlightAttr>()?;
|
||||||
if let Some(snippet) = snippets.get_mut(&snippet) {
|
if let Some(snippet) = snippets.get_mut(&snippet) {
|
||||||
let member = if let Some(ident) = field.ident.clone() {
|
let member = if let Some(ident) = field.ident.clone() {
|
||||||
syn::Member::Named(ident)
|
syn::Member::Named(ident)
|
||||||
|
|
@ -170,10 +153,7 @@ impl Snippets {
|
||||||
span: field.span(),
|
span: field.span(),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
snippet.highlights.push(Highlight {
|
snippet.highlights.push(Highlight { highlight: member });
|
||||||
label,
|
|
||||||
highlight: member,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
return Err(syn::Error::new(snippet.span(), "Highlight must refer to an existing field with a #[snippet(...)] attribute."));
|
return Err(syn::Error::new(snippet.span(), "Highlight must refer to an existing field with a #[snippet(...)] attribute."));
|
||||||
}
|
}
|
||||||
|
|
@ -218,18 +198,6 @@ impl Snippets {
|
||||||
source: self.#src_ident.clone(),
|
source: self.#src_ident.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Source name
|
|
||||||
let src_name = match &snippet.source_name {
|
|
||||||
MemberOrString::String(str) => {
|
|
||||||
quote! {
|
|
||||||
source_name: #str.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberOrString::Member(member) => quote! {
|
|
||||||
source_name: self.#member.clone(),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Context
|
// Context
|
||||||
let context = &snippet.snippet;
|
let context = &snippet.snippet;
|
||||||
let context = quote! {
|
let context = quote! {
|
||||||
|
|
@ -238,9 +206,9 @@ impl Snippets {
|
||||||
|
|
||||||
// Highlights
|
// Highlights
|
||||||
let highlights = snippet.highlights.iter().map(|highlight| {
|
let highlights = snippet.highlights.iter().map(|highlight| {
|
||||||
let Highlight { highlight, label } = highlight;
|
let Highlight { highlight } = highlight;
|
||||||
quote! {
|
quote! {
|
||||||
(#label.into(), self.#highlight.clone())
|
self.#highlight.clone()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let highlights = quote! {
|
let highlights = quote! {
|
||||||
|
|
@ -253,7 +221,6 @@ impl Snippets {
|
||||||
quote! {
|
quote! {
|
||||||
miette::DiagnosticSnippet {
|
miette::DiagnosticSnippet {
|
||||||
#msg
|
#msg
|
||||||
#src_name
|
|
||||||
#src_ident
|
#src_ident
|
||||||
#context
|
#context
|
||||||
#highlights
|
#highlights
|
||||||
|
|
@ -314,26 +281,6 @@ impl Snippets {
|
||||||
source: #src_ident.clone(),
|
source: #src_ident.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Source name
|
|
||||||
let src_name = match &snippet.source_name {
|
|
||||||
MemberOrString::String(str) => {
|
|
||||||
quote! {
|
|
||||||
source_name: #str.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MemberOrString::Member(m) => {
|
|
||||||
let m = match m {
|
|
||||||
syn::Member::Named(id) => id.clone(),
|
|
||||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
|
||||||
format_ident!("_{}", index)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
quote! {
|
|
||||||
source_name: #m.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Context
|
// Context
|
||||||
let context = match &snippet.snippet {
|
let context = match &snippet.snippet {
|
||||||
syn::Member::Named(id) => id.clone(),
|
syn::Member::Named(id) => id.clone(),
|
||||||
|
|
@ -347,7 +294,7 @@ impl Snippets {
|
||||||
|
|
||||||
// Highlights
|
// Highlights
|
||||||
let highlights = snippet.highlights.iter().map(|highlight| {
|
let highlights = snippet.highlights.iter().map(|highlight| {
|
||||||
let Highlight { highlight, label } = highlight;
|
let Highlight { highlight } = highlight;
|
||||||
let m = match highlight {
|
let m = match highlight {
|
||||||
syn::Member::Named(id) => id.clone(),
|
syn::Member::Named(id) => id.clone(),
|
||||||
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
syn::Member::Unnamed(syn::Index { index, .. }) => {
|
||||||
|
|
@ -355,7 +302,7 @@ impl Snippets {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
quote! {
|
quote! {
|
||||||
(#label.into(), #m.clone())
|
#m.clone()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let highlights = quote! {
|
let highlights = quote! {
|
||||||
|
|
@ -368,7 +315,6 @@ impl Snippets {
|
||||||
quote! {
|
quote! {
|
||||||
miette::DiagnosticSnippet {
|
miette::DiagnosticSnippet {
|
||||||
#msg
|
#msg
|
||||||
#src_name
|
|
||||||
#src_ident
|
#src_ident
|
||||||
#context
|
#context
|
||||||
#highlights
|
#highlights
|
||||||
|
|
|
||||||
|
|
@ -174,8 +174,6 @@ A snippet from a [Source] to be displayed with a message and possibly some highl
|
||||||
pub struct DiagnosticSnippet {
|
pub struct DiagnosticSnippet {
|
||||||
/// Explanation of this specific diagnostic snippet.
|
/// Explanation of this specific diagnostic snippet.
|
||||||
pub message: Option<String>,
|
pub message: Option<String>,
|
||||||
/// The "filename" for this snippet.
|
|
||||||
pub source_name: String,
|
|
||||||
/// A [Source] that can be used to read the actual text of a source.
|
/// A [Source] that can be used to read the actual text of a source.
|
||||||
pub source: Arc<dyn Source>,
|
pub source: Arc<dyn Source>,
|
||||||
/// The primary [SourceSpan] where this diagnostic is located.
|
/// The primary [SourceSpan] where this diagnostic is located.
|
||||||
|
|
@ -183,7 +181,7 @@ pub struct DiagnosticSnippet {
|
||||||
/// Additional [SourceSpan]s that mark specific sections of the span, for
|
/// Additional [SourceSpan]s that mark specific sections of the span, for
|
||||||
/// example, to underline specific text within the larger span. They're
|
/// example, to underline specific text within the larger span. They're
|
||||||
/// paired with labels that should be applied to those sections.
|
/// paired with labels that should be applied to those sections.
|
||||||
pub highlights: Option<Vec<(String, SourceSpan)>>,
|
pub highlights: Option<Vec<SourceSpan>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -191,35 +189,65 @@ Span within a [Source] with an associated message.
|
||||||
*/
|
*/
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SourceSpan {
|
pub struct SourceSpan {
|
||||||
|
/// An optional label for this span. Rendered differently depending on
|
||||||
|
/// context.
|
||||||
|
label: Option<String>,
|
||||||
/// The start of the span.
|
/// The start of the span.
|
||||||
pub start: SourceOffset,
|
offset: SourceOffset,
|
||||||
/// The (exclusive) end of the span.
|
/// The total length of the span. Think of this as an offset from `start`.
|
||||||
pub end: SourceOffset,
|
length: SourceOffset,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SourceSpan {
|
impl SourceSpan {
|
||||||
pub fn new(start: SourceOffset, end: SourceOffset) -> Self {
|
pub fn new(start: SourceOffset, length: SourceOffset) -> Self {
|
||||||
assert!(
|
Self {
|
||||||
start.offset() <= end.offset(),
|
label: None,
|
||||||
"Starting offset must come before the end offset."
|
offset: start,
|
||||||
);
|
length,
|
||||||
Self { start, end }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_labeled(label: impl AsRef<str>, start: SourceOffset, length: SourceOffset) -> Self {
|
||||||
|
Self {
|
||||||
|
label: Some(label.as_ref().into()),
|
||||||
|
offset: start,
|
||||||
|
length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self) -> usize {
|
||||||
|
self.offset.offset()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn label(&self) -> Option<&str> {
|
||||||
|
self.label.as_ref().map(|x| &x[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.end.offset() - self.start.offset() + 1
|
self.length.offset()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.start.offset() == self.end.offset()
|
self.length.offset() == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(ByteOffset, ByteOffset)> for SourceSpan {
|
impl From<(ByteOffset, ByteOffset)> for SourceSpan {
|
||||||
fn from((start, end): (ByteOffset, ByteOffset)) -> Self {
|
fn from((start, len): (ByteOffset, ByteOffset)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
start: start.into(),
|
label: None,
|
||||||
end: end.into(),
|
offset: start.into(),
|
||||||
|
length: len.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<str>> From<(T, ByteOffset, ByteOffset)> for SourceSpan {
|
||||||
|
fn from((label, start, len): (T, ByteOffset, ByteOffset)) -> Self {
|
||||||
|
Self {
|
||||||
|
label: Some(label.as_ref().into()),
|
||||||
|
offset: start.into(),
|
||||||
|
length: len.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ impl MietteReporter {
|
||||||
snippet: &DiagnosticSnippet,
|
snippet: &DiagnosticSnippet,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
use fmt::Write as _;
|
use fmt::Write as _;
|
||||||
write!(f, "[{}]", snippet.source_name)?;
|
if let Some(source_name) = snippet.context.label() {
|
||||||
|
write!(f, "[{}]", source_name)?;
|
||||||
|
}
|
||||||
if let Some(msg) = &snippet.message {
|
if let Some(msg) = &snippet.message {
|
||||||
write!(f, " {}:", msg)?;
|
write!(f, " {}:", msg)?;
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +38,7 @@ impl MietteReporter {
|
||||||
let context = std::str::from_utf8(context_data.data()).expect("Bad utf8 detected");
|
let context = std::str::from_utf8(context_data.data()).expect("Bad utf8 detected");
|
||||||
let mut line = context_data.line();
|
let mut line = context_data.line();
|
||||||
let mut column = context_data.column();
|
let mut column = context_data.column();
|
||||||
let mut offset = snippet.context.start.offset();
|
let mut offset = snippet.context.offset();
|
||||||
let mut line_offset = offset;
|
let mut line_offset = offset;
|
||||||
let mut iter = context.chars().peekable();
|
let mut iter = context.chars().peekable();
|
||||||
let mut line_str = String::new();
|
let mut line_str = String::new();
|
||||||
|
|
@ -71,20 +73,22 @@ impl MietteReporter {
|
||||||
writeln!(indented(f), "{: <2} | {}", line, line_str)?;
|
writeln!(indented(f), "{: <2} | {}", line, line_str)?;
|
||||||
line_str.clear();
|
line_str.clear();
|
||||||
if let Some(highlights) = highlights {
|
if let Some(highlights) = highlights {
|
||||||
for (label, span) in highlights {
|
for span in highlights {
|
||||||
if span.start.offset() >= line_offset && span.end.offset() < offset {
|
if span.offset() >= line_offset && (span.offset() + span.len()) < offset {
|
||||||
// Highlight only covers one line.
|
// Highlight only covers one line.
|
||||||
write!(indented(f), "{: <2} | ", "⫶")?;
|
write!(indented(f), "{: <2} | ", "⫶")?;
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{} ",
|
"{}{} ",
|
||||||
" ".repeat(span.start.offset() - line_offset),
|
" ".repeat(span.offset() - line_offset),
|
||||||
"^".repeat(span.len())
|
"^".repeat(span.len())
|
||||||
)?;
|
)?;
|
||||||
writeln!(f, "{}", label)?;
|
if let Some(label) = span.label() {
|
||||||
} else if span.start.offset() < offset
|
writeln!(f, "{}", label)?;
|
||||||
&& span.start.offset() >= line_offset
|
}
|
||||||
&& span.end.offset() >= offset
|
} else if span.offset() < offset
|
||||||
|
&& span.offset() >= line_offset
|
||||||
|
&& (span.offset() + span.len()) >= offset
|
||||||
{
|
{
|
||||||
// Multiline highlight.
|
// Multiline highlight.
|
||||||
todo!("Multiline highlights.");
|
todo!("Multiline highlights.");
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ impl Source for String {
|
||||||
let mut start_column = 0usize;
|
let mut start_column = 0usize;
|
||||||
let mut iter = self.chars().peekable();
|
let mut iter = self.chars().peekable();
|
||||||
while let Some(char) = iter.next() {
|
while let Some(char) = iter.next() {
|
||||||
if offset < span.start.offset() {
|
if offset < span.offset() {
|
||||||
match char {
|
match char {
|
||||||
'\r' => {
|
'\r' => {
|
||||||
if iter.next_if_eq(&'\n').is_some() {
|
if iter.next_if_eq(&'\n').is_some() {
|
||||||
|
|
@ -29,9 +29,9 @@ impl Source for String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if offset >= span.end.offset() {
|
if offset >= span.offset() + span.len() - 1 {
|
||||||
return Ok(Box::new(MietteSpanContents::new(
|
return Ok(Box::new(MietteSpanContents::new(
|
||||||
&self.as_bytes()[span.start.offset()..=span.end.offset()],
|
&self.as_bytes()[span.offset()..span.offset() + span.len()],
|
||||||
start_line,
|
start_line,
|
||||||
start_column,
|
start_column,
|
||||||
)));
|
)));
|
||||||
|
|
@ -50,10 +50,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn basic() -> Result<(), MietteError> {
|
fn basic() -> Result<(), MietteError> {
|
||||||
let src = String::from("foo\n");
|
let src = String::from("foo\n");
|
||||||
let contents = src.read_span(&SourceSpan {
|
let contents = src.read_span(&(0, 4).into())?;
|
||||||
start: 0.into(),
|
|
||||||
end: 3.into(),
|
|
||||||
})?;
|
|
||||||
assert_eq!("foo\n", std::str::from_utf8(contents.data()).unwrap());
|
assert_eq!("foo\n", std::str::from_utf8(contents.data()).unwrap());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -61,10 +58,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn middle() -> Result<(), MietteError> {
|
fn middle() -> Result<(), MietteError> {
|
||||||
let src = String::from("foo\nbar\nbaz\n");
|
let src = String::from("foo\nbar\nbaz\n");
|
||||||
let contents = src.read_span(&SourceSpan {
|
let contents = src.read_span(&(4, 4).into())?;
|
||||||
start: 4.into(),
|
|
||||||
end: 7.into(),
|
|
||||||
})?;
|
|
||||||
assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap());
|
assert_eq!("bar\n", std::str::from_utf8(contents.data()).unwrap());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -72,10 +66,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn with_crlf() -> Result<(), MietteError> {
|
fn with_crlf() -> Result<(), MietteError> {
|
||||||
let src = String::from("foo\r\nbar\r\nbaz\r\n");
|
let src = String::from("foo\r\nbar\r\nbaz\r\n");
|
||||||
let contents = src.read_span(&SourceSpan {
|
let contents = src.read_span(&(5, 5).into())?;
|
||||||
start: 5.into(),
|
|
||||||
end: 9.into(),
|
|
||||||
})?;
|
|
||||||
assert_eq!("bar\r\n", std::str::from_utf8(contents.data()).unwrap());
|
assert_eq!("bar\r\n", std::str::from_utf8(contents.data()).unwrap());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,8 +183,8 @@ fn test_snippet_named_struct() {
|
||||||
// / [my_snippet]: hi this is where the thing went wrong.
|
// / [my_snippet]: hi this is where the thing went wrong.
|
||||||
// 1 | hello
|
// 1 | hello
|
||||||
// 2 | world
|
// 2 | world
|
||||||
#[snippet(src, "my_snippet.rs", "hi this is where the thing went wrong")]
|
#[snippet(src, "hi this is where the thing went wrong")]
|
||||||
snip: SourceSpan,
|
snip: SourceSpan, // Defines filename using `label`
|
||||||
|
|
||||||
// "Highlights" are the specific highlights _inside_ the snippet.
|
// "Highlights" are the specific highlights _inside_ the snippet.
|
||||||
// These will be used to underline/point to specific sections of the
|
// These will be used to underline/point to specific sections of the
|
||||||
|
|
@ -196,9 +196,9 @@ fn test_snippet_named_struct() {
|
||||||
// | ^^^^ ^^^^ - var 2
|
// | ^^^^ ^^^^ - var 2
|
||||||
// | |
|
// | |
|
||||||
// | var 1
|
// | var 1
|
||||||
#[highlight(snip, "var 1")]
|
#[highlight(snip)]
|
||||||
var1: SourceSpan,
|
var1: SourceSpan, // label from SourceSpan is used, if any.
|
||||||
#[highlight(snip, "var 2")]
|
#[highlight(snip)]
|
||||||
var2: SourceSpan,
|
var2: SourceSpan,
|
||||||
|
|
||||||
// Now with member source names
|
// Now with member source names
|
||||||
|
|
@ -216,15 +216,14 @@ fn test_snippet_unnamed_struct() {
|
||||||
#[diagnostic(code(foo::bar::baz))]
|
#[diagnostic(code(foo::bar::baz))]
|
||||||
struct Foo(
|
struct Foo(
|
||||||
Arc<String>,
|
Arc<String>,
|
||||||
#[snippet(0, "my_snippet.rs", "hi")] SourceSpan,
|
#[snippet(0, "hi")] SourceSpan,
|
||||||
#[highlight(1, "var 1")] SourceSpan,
|
#[highlight(1)] SourceSpan,
|
||||||
#[highlight(1, "var 2")] SourceSpan,
|
#[highlight(1)] SourceSpan,
|
||||||
// referenced source name
|
// referenced source name
|
||||||
String,
|
String,
|
||||||
String,
|
#[snippet(0, 4)] SourceSpan,
|
||||||
#[snippet(0, 4, 5)] SourceSpan,
|
#[highlight(5)] SourceSpan,
|
||||||
#[highlight(6, "var 3")] SourceSpan,
|
#[highlight(5)] SourceSpan,
|
||||||
#[highlight(6, "var 4")] SourceSpan,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use std::{fmt, sync::Arc};
|
use std::{fmt, sync::Arc};
|
||||||
|
|
||||||
use miette::{
|
use miette::{Diagnostic, DiagnosticReporter, DiagnosticSnippet, MietteError, MietteReporter};
|
||||||
Diagnostic, DiagnosticReporter, DiagnosticSnippet, MietteError, MietteReporter, SourceSpan,
|
|
||||||
};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error)]
|
#[derive(Error)]
|
||||||
|
|
@ -51,19 +49,9 @@ fn fancy() -> Result<(), MietteError> {
|
||||||
let err = MyBad {
|
let err = MyBad {
|
||||||
snippets: vec![DiagnosticSnippet {
|
snippets: vec![DiagnosticSnippet {
|
||||||
message: Some("This is the part that broke".into()),
|
message: Some("This is the part that broke".into()),
|
||||||
source_name: "bad_file.rs".into(),
|
|
||||||
source: Arc::new(src),
|
source: Arc::new(src),
|
||||||
highlights: Some(vec![(
|
highlights: Some(vec![("this bit here", 9, 4).into()]),
|
||||||
"this bit here".into(),
|
context: ("bad_file.rs", 0, len).into(),
|
||||||
SourceSpan {
|
|
||||||
start: 9.into(),
|
|
||||||
end: 12.into(),
|
|
||||||
},
|
|
||||||
)]),
|
|
||||||
context: SourceSpan {
|
|
||||||
start: 0.into(),
|
|
||||||
end: (len - 1).into(),
|
|
||||||
},
|
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
let out = format!("{:?}", err);
|
let out = format!("{:?}", err);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue