Skip to content

Commit

Permalink
derive: use config span in error message
Browse files Browse the repository at this point in the history
  • Loading branch information
Kijewski committed Jul 29, 2024
1 parent c3639ec commit 3b2c074
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 49 deletions.
66 changes: 37 additions & 29 deletions rinja_derive/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::{env, fs};
use once_map::sync::OnceMap;
use parser::node::Whitespace;
use parser::{ParseError, Parsed, Syntax};
use proc_macro2::Span;
#[cfg(feature = "config")]
use serde::Deserialize;

Expand Down Expand Up @@ -71,6 +72,7 @@ impl Config {
source: &str,
config_path: Option<&str>,
template_whitespace: Option<&str>,
config_span: Option<Span>,
) -> Result<&'static Config, CompileError> {
static CACHE: OnceLock<OnceMap<OwnedConfigKey, Arc<Config>>> = OnceLock::new();

Expand All @@ -80,9 +82,9 @@ impl Config {
config_path: config_path.map(Cow::Borrowed),
template_whitespace: template_whitespace.map(Cow::Borrowed),
},
(),
config_span,
ConfigKey::to_owned,
|_, key| match Config::new_uncached(key.clone()) {
|config_span, key| match Config::new_uncached(key.clone(), config_span) {
Ok(config) => Ok((Arc::clone(&config), config)),
Err(err) => Err(err),
},
Expand All @@ -94,7 +96,10 @@ impl Config {
}

impl Config {
fn new_uncached(key: OwnedConfigKey) -> Result<Arc<Config>, CompileError> {
fn new_uncached(
key: OwnedConfigKey,
config_span: Option<Span>,
) -> Result<Arc<Config>, CompileError> {
// SAFETY: the resulting `Config` will keep a reference to the `key`
let eternal_key =
unsafe { transmute::<&ConfigKey<'_>, &'static ConfigKey<'static>>(key.borrow()) };
Expand Down Expand Up @@ -152,7 +157,7 @@ impl Config {
let name = raw_s.name;
match syntaxes.entry(name.to_string()) {
Entry::Vacant(entry) => {
entry.insert(SyntaxAndCache::new(raw_s.try_into()?));
entry.insert(SyntaxAndCache::new(raw_s.to_syntax(config_span)?));
}
Entry::Occupied(_) => {
return Err(CompileError::new(
Expand Down Expand Up @@ -300,10 +305,8 @@ impl<'a> SyntaxAndCache<'a> {
}
}

impl<'a> TryInto<Syntax<'a>> for RawSyntax<'a> {
type Error = CompileError;

fn try_into(self) -> Result<Syntax<'a>, Self::Error> {
impl<'a> RawSyntax<'a> {
fn to_syntax(&self, config_span: Option<Span>) -> Result<Syntax<'a>, CompileError> {
let default = Syntax::default();
let syntax = Syntax {
block_start: self.block_start.unwrap_or(default.block_start),
Expand All @@ -325,12 +328,12 @@ impl<'a> TryInto<Syntax<'a>> for RawSyntax<'a> {
if s.len() < 2 {
return Err(CompileError::no_file_info(
format!("delimiters must be at least two characters long: {s:?}"),
None,
config_span,
));
} else if s.chars().any(|c| c.is_whitespace()) {
return Err(CompileError::no_file_info(
format!("delimiters may not contain white spaces: {s:?}"),
None,
config_span,
));
}
}
Expand All @@ -345,7 +348,7 @@ impl<'a> TryInto<Syntax<'a>> for RawSyntax<'a> {
format!(
"a delimiter may not be the prefix of another delimiter: {s1:?} vs {s2:?}",
),
None,
config_span,
));
}
}
Expand Down Expand Up @@ -477,7 +480,7 @@ mod tests {
fn test_default_config() {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
root.push("templates");
let config = Config::new("", None, None).unwrap();
let config = Config::new("", None, None, None).unwrap();
assert_eq!(config.dirs, vec![root]);
}

Expand All @@ -486,7 +489,7 @@ mod tests {
fn test_config_dirs() {
let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
root.push("tpl");
let config = Config::new("[general]\ndirs = [\"tpl\"]", None, None).unwrap();
let config = Config::new("[general]\ndirs = [\"tpl\"]", None, None, None).unwrap();
assert_eq!(config.dirs, vec![root]);
}

Expand All @@ -500,7 +503,7 @@ mod tests {

#[test]
fn find_absolute() {
let config = Config::new("", None, None).unwrap();
let config = Config::new("", None, None, None).unwrap();
let root = config.find_template("a.html", None, None).unwrap();
let path = config
.find_template("sub/b.html", Some(&root), None)
Expand All @@ -511,22 +514,22 @@ mod tests {
#[test]
#[should_panic]
fn find_relative_nonexistent() {
let config = Config::new("", None, None).unwrap();
let config = Config::new("", None, None, None).unwrap();
let root = config.find_template("a.html", None, None).unwrap();
config.find_template("c.html", Some(&root), None).unwrap();
}

#[test]
fn find_relative() {
let config = Config::new("", None, None).unwrap();
let config = Config::new("", None, None, None).unwrap();
let root = config.find_template("sub/b.html", None, None).unwrap();
let path = config.find_template("c.html", Some(&root), None).unwrap();
assert_eq_rooted(&path, "sub/c.html");
}

#[test]
fn find_relative_sub() {
let config = Config::new("", None, None).unwrap();
let config = Config::new("", None, None, None).unwrap();
let root = config.find_template("sub/b.html", None, None).unwrap();
let path = config
.find_template("sub1/d.html", Some(&root), None)
Expand All @@ -551,7 +554,7 @@ mod tests {
"#;

let default_syntax = Syntax::default();
let config = Config::new(raw_config, None, None).unwrap();
let config = Config::new(raw_config, None, None, None).unwrap();
assert_eq!(config.default_syntax, "foo");

let foo = config.syntaxes.get("foo").unwrap();
Expand Down Expand Up @@ -583,7 +586,7 @@ mod tests {
"#;

let default_syntax = Syntax::default();
let config = Config::new(raw_config, None, None).unwrap();
let config = Config::new(raw_config, None, None, None).unwrap();
assert_eq!(config.default_syntax, "foo");

let foo = config.syntaxes.get("foo").unwrap();
Expand Down Expand Up @@ -620,7 +623,7 @@ mod tests {
default_syntax = "emoji"
"#;

let config = Config::new(raw_config, None, None).unwrap();
let config = Config::new(raw_config, None, None, None).unwrap();
assert_eq!(config.default_syntax, "emoji");

let foo = config.syntaxes.get("emoji").unwrap();
Expand Down Expand Up @@ -648,7 +651,7 @@ mod tests {
name = "too_short"
block_start = "<"
"#;
let config = Config::new(raw_config, None, None);
let config = Config::new(raw_config, None, None, None);
assert_eq!(
expect_err(config).msg,
r#"delimiters must be at least two characters long: "<""#,
Expand All @@ -659,7 +662,7 @@ mod tests {
name = "contains_ws"
block_start = " {{ "
"#;
let config = Config::new(raw_config, None, None);
let config = Config::new(raw_config, None, None, None);
assert_eq!(
expect_err(config).msg,
r#"delimiters may not contain white spaces: " {{ ""#,
Expand All @@ -672,7 +675,7 @@ mod tests {
expr_start = "{{$"
comment_start = "{{#"
"#;
let config = Config::new(raw_config, None, None);
let config = Config::new(raw_config, None, None, None);
assert_eq!(
expect_err(config).msg,
r#"a delimiter may not be the prefix of another delimiter: "{{" vs "{{$""#,
Expand All @@ -687,7 +690,7 @@ mod tests {
syntax = [{ name = "default" }]
"#;

let _config = Config::new(raw_config, None, None).unwrap();
let _config = Config::new(raw_config, None, None, None).unwrap();
}

#[cfg(feature = "config")]
Expand All @@ -699,7 +702,7 @@ mod tests {
{ name = "foo", block_start = "%%" } ]
"#;

let _config = Config::new(raw_config, None, None).unwrap();
let _config = Config::new(raw_config, None, None, None).unwrap();
}

#[cfg(feature = "config")]
Expand All @@ -711,7 +714,7 @@ mod tests {
default_syntax = "foo"
"#;

let _config = Config::new(raw_config, None, None).unwrap();
let _config = Config::new(raw_config, None, None, None).unwrap();
}

#[cfg(feature = "config")]
Expand All @@ -725,6 +728,7 @@ mod tests {
"#,
None,
None,
None,
)
.unwrap();
assert_eq!(
Expand Down Expand Up @@ -753,11 +757,12 @@ mod tests {
"#,
None,
None,
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Suppress);

let config = Config::new(r#""#, None, None).unwrap();
let config = Config::new(r#""#, None, None, None).unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Preserve);

let config = Config::new(
Expand All @@ -767,6 +772,7 @@ mod tests {
"#,
None,
None,
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Preserve);
Expand All @@ -778,6 +784,7 @@ mod tests {
"#,
None,
None,
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Minimize);
Expand All @@ -796,17 +803,18 @@ mod tests {
"#,
None,
Some("minimize"),
None,
)
.unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Minimize);

let config = Config::new(r#""#, None, Some("minimize")).unwrap();
let config = Config::new(r#""#, None, Some("minimize"), None).unwrap();
assert_eq!(config.whitespace, WhitespaceHandling::Minimize);
}

#[test]
fn test_config_whitespace_error() {
let config = Config::new(r#""#, None, Some("trim"));
let config = Config::new(r#""#, None, Some("trim"), None);
if let Err(err) = config {
assert_eq!(err.msg, "invalid value for `whitespace`: \"trim\"");
} else {
Expand Down
4 changes: 3 additions & 1 deletion rinja_derive/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ pub(crate) struct TemplateArgs {
config: Option<String>,
pub(crate) whitespace: Option<String>,
pub(crate) template_span: Option<Span>,
pub(crate) config_span: Option<Span>,
}

impl TemplateArgs {
Expand Down Expand Up @@ -399,6 +400,7 @@ impl TemplateArgs {
set_template_str_attr(ident, value, &mut args.syntax)?;
} else if ident == "config" {
set_template_str_attr(ident, value, &mut args.config)?;
args.config_span = Some(ident.span())
} else if ident == "whitespace" {
set_template_str_attr(ident, value, &mut args.whitespace)?;
} else {
Expand Down Expand Up @@ -629,7 +631,7 @@ mod tests {

#[test]
fn get_source() {
let path = Config::new("", None, None)
let path = Config::new("", None, None, None)
.and_then(|config| config.find_template("b.html", None, None))
.unwrap();
assert_eq!(get_template_source(&path, None).unwrap(), "bar".into());
Expand Down
9 changes: 7 additions & 2 deletions rinja_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ pub fn derive_template(input: TokenStream12) -> TokenStream12 {

fn build_skeleton(ast: &syn::DeriveInput) -> Result<String, CompileError> {
let template_args = TemplateArgs::fallback();
let config = Config::new("", None, None)?;
let config = Config::new("", None, None, None)?;
let input = TemplateInput::new(ast, config, &template_args)?;
let mut contexts = HashMap::new();
let parsed = parser::Parsed::default();
Expand Down Expand Up @@ -153,7 +153,12 @@ fn build_template_inner(
) -> Result<String, CompileError> {
let config_path = template_args.config_path();
let s = read_config_file(config_path)?;
let config = Config::new(&s, config_path, template_args.whitespace.as_deref())?;
let config = Config::new(
&s,
config_path,
template_args.whitespace.as_deref(),
template_args.config_span,
)?;
let input = TemplateInput::new(ast, config, template_args)?;

let mut templates = HashMap::new();
Expand Down
4 changes: 4 additions & 0 deletions testing/delim-clash.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[[syntax]]
name = "delim-clash"
block_start = "<<<"
expr_start = "<<<<"
3 changes: 3 additions & 0 deletions testing/delim-too-short.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[[syntax]]
name = "delim-too-short"
block_start = "<"
2 changes: 2 additions & 0 deletions testing/folder-config.toml/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
!.gitignore
Loading

0 comments on commit 3b2c074

Please sign in to comment.