diff --git a/rinja_derive/src/generator.rs b/rinja_derive/src/generator.rs index b9664f8ee..dd32ae908 100644 --- a/rinja_derive/src/generator.rs +++ b/rinja_derive/src/generator.rs @@ -15,7 +15,7 @@ use quote::quote; use crate::config::WhitespaceHandling; use crate::heritage::{Context, Heritage}; use crate::input::{Source, TemplateInput}; -use crate::{CompileError, CRATE}; +use crate::{CompileError, MsgValidEscapers, CRATE}; pub(crate) struct Generator<'a> { // The template input state: original struct AST and attributes @@ -1429,7 +1429,10 @@ impl<'a> Generator<'a> { }) .ok_or_else(|| { ctx.generate_error( - &format!("invalid escaper '{name}' for `escape` filter"), + &format!( + "invalid escaper '{name}' for `escape` filter. {}", + MsgValidEscapers(&self.input.config.escapers), + ), node, ) })?, diff --git a/rinja_derive/src/input.rs b/rinja_derive/src/input.rs index 7a8692970..a86ee0fb7 100644 --- a/rinja_derive/src/input.rs +++ b/rinja_derive/src/input.rs @@ -10,7 +10,7 @@ use quote::ToTokens; use syn::punctuated::Punctuated; use crate::config::{get_template_source, Config}; -use crate::CompileError; +use crate::{CompileError, MsgValidEscapers}; pub(crate) struct TemplateInput<'a> { pub(crate) ast: &'a syn::DeriveInput, @@ -87,7 +87,10 @@ impl TemplateInput<'_> { .then_some(path.as_ref()) }) .ok_or_else(|| { - CompileError::no_file_info(format!("no escaper defined for extension '{escaping}'")) + CompileError::no_file_info(format!( + "no escaper defined for extension '{escaping}'. {}", + MsgValidEscapers(&config.escapers), + )) })?; let mime_type = diff --git a/rinja_derive/src/lib.rs b/rinja_derive/src/lib.rs index d8df48867..beb137a03 100644 --- a/rinja_derive/src/lib.rs +++ b/rinja_derive/src/lib.rs @@ -8,6 +8,7 @@ mod input; #[cfg(test)] mod tests; +use std::borrow::Cow; use std::collections::HashMap; use std::fmt; use std::path::Path; @@ -231,6 +232,21 @@ impl fmt::Display for FileInfo<'_> { } } +struct MsgValidEscapers<'a>(&'a [(Vec>, Cow<'a, str>)]); + +impl fmt::Display for MsgValidEscapers<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut exts = self + .0 + .iter() + .flat_map(|(exts, _)| exts) + .map(|x| format!("{x:?}")) + .collect::>(); + exts.sort(); + write!(f, "The available extensions are: {}", exts.join(", ")) + } +} + // This is used by the code generator to decide whether a named filter is part of // Rinja or should refer to a local `filters` module. It should contain all the // filters shipped with Rinja, even the optional ones (since optional inclusion diff --git a/testing/tests/ui/no-such-escaper.stderr b/testing/tests/ui/no-such-escaper.stderr index 277fc0450..12fbeac5c 100644 --- a/testing/tests/ui/no-such-escaper.stderr +++ b/testing/tests/ui/no-such-escaper.stderr @@ -1,4 +1,4 @@ -error: invalid escaper 'latex' for `escape` filter +error: invalid escaper 'latex' for `escape` filter. The available extensions are: "", "htm", "html", "j2", "jinja", "jinja2", "md", "none", "svg", "txt", "xml", "yml" --> LocalEscaper.html:1:38 "text|escape(\"latex\")}}`." --> tests/ui/no-such-escaper.rs:3:10 @@ -8,7 +8,7 @@ error: invalid escaper 'latex' for `escape` filter | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: no escaper defined for extension 'tex' +error: no escaper defined for extension 'tex'. The available extensions are: "", "htm", "html", "j2", "jinja", "jinja2", "md", "none", "svg", "txt", "xml", "yml" --> tests/ui/no-such-escaper.rs:12:10 | 12 | #[derive(Template)]