1use std::fmt;
23use proc_macro2::{Span, TokenStream as TokenStream2};
4use quote::ToTokens;
56/// An error with an optional span. Most errors will have a span, the only exception is on a
7/// [`Error::Parse`], which can occur in the [`get_args_and_format_string()`] function.
8///
9/// [`get_args_and_format_string()`]: crate::format_args::get_args_and_format_string()
10#[derive(Debug, Clone)]
11pub struct SpanError {
12pub err: Error,
13pub span: Option<Span>,
14}
1516impl SpanError {
17/// Creates a new `SpanError`.
18pub fn new(err: Error, span: Option<Span>) -> Self {
19Self { err, span }
20 }
21}
2223/// Manual implementation because [`Span`] is not [`PartialEq`] and can be ignored when comparing.
24impl PartialEq for SpanError {
25fn eq(&self, other: &SpanError) -> bool {
26self.err == other.err
27 }
28}
2930impl From<Error> for SpanError {
31fn from(err: Error) -> SpanError {
32 SpanError { err, span: None }
33 }
34}
3536impl ToTokens for SpanError {
37fn to_tokens(&self, tokens: &mut TokenStream2) {
38let span = self.span.unwrap_or_else(Span::call_site);
39let token_stream_err = syn::Error::new(span, self.err.clone()).to_compile_error();
40 token_stream_err.to_tokens(tokens);
41 }
42}
4344/// All possible errors which can occur when calling one of the public macros.
45#[derive(Debug, PartialEq, Clone)]
46pub enum Error {
47/// Error during the initial parsing of the macro arguments.
48Parse(String),
49/// The first macro argument is not a string literal.
50MustBeStringLiteral,
51/// Unable to parse a tag.
52UnableToParseTag(String),
53/// An error occured while parsing a color tag.
54ParseTag(String),
55/// A "{" character has not been closed in the format string.
56UnclosedPlaceholder,
57/// A "<" character has not been closed in the format string.
58UnclosedTag,
59/// Trying to close a previous tag, while there are no open tag.
60NoTagToClose,
61/// Trying to close a previous tag which does not match, like `<red>...</blue>`.
62MismatchCloseTag(String, String),
63/// Only one argument is allowed for the `cstr!()` and `untagged!()` macros.
64#[cfg(not(feature = "terminfo"))]
65TooManyArgs,
66/// Only one argument is allowed for the '`untagged!()` macro.
67#[cfg(feature = "terminfo")]
68TooManyArgs,
69}
7071impl fmt::Display for Error {
72fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73let msg = match self {
74Self::Parse(msg) => msg.clone(),
75Self::MustBeStringLiteral => "Format string must be a string literal".to_owned(),
76Self::UnableToParseTag(tag) => format!("Unable to parse the tag {}", tag),
77Self::ParseTag(detail) => detail.clone(),
78Self::UnclosedPlaceholder => "Unclosed placeholder".to_owned(),
79Self::UnclosedTag => "Unclosed color tag".to_owned(),
80Self::NoTagToClose => "No color tag to close".to_owned(),
81Self::MismatchCloseTag(tag1, tag2) => {
82format!("Mismatch close tag between {} and {}", tag1, tag2)
83 }
84Self::TooManyArgs => "Too many arguments".to_owned(),
85 };
86write!(f, "{}", msg)
87 }
88}