Skip to content

Commit

Permalink
derive: use source/path as error source span
Browse files Browse the repository at this point in the history
  • Loading branch information
Kijewski committed Jul 29, 2024
1 parent fa8c936 commit ec9cffd
Show file tree
Hide file tree
Showing 44 changed files with 306 additions and 219 deletions.
25 changes: 15 additions & 10 deletions rinja_derive/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ impl Config {
&self,
path: &str,
start_at: Option<&Path>,
file_info: Option<FileInfo<'_>>,
) -> Result<Arc<Path>, CompileError> {
if let Some(root) = start_at {
let relative = root.with_file_name(path);
Expand All @@ -213,12 +214,12 @@ impl Config {
}
}

Err(CompileError::no_file_info(
Err(CompileError::new(
format!(
"template {:?} not found in directories {:?}",
path, self.dirs
),
None,
file_info,
))
}
}
Expand Down Expand Up @@ -500,32 +501,36 @@ mod tests {
#[test]
fn find_absolute() {
let config = Config::new("", None, None).unwrap();
let root = config.find_template("a.html", None).unwrap();
let path = config.find_template("sub/b.html", Some(&root)).unwrap();
let root = config.find_template("a.html", None, None).unwrap();
let path = config
.find_template("sub/b.html", Some(&root), None)
.unwrap();
assert_eq_rooted(&path, "sub/b.html");
}

#[test]
#[should_panic]
fn find_relative_nonexistent() {
let config = Config::new("", None, None).unwrap();
let root = config.find_template("a.html", None).unwrap();
config.find_template("c.html", Some(&root)).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 root = config.find_template("sub/b.html", None).unwrap();
let path = config.find_template("c.html", Some(&root)).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 root = config.find_template("sub/b.html", None).unwrap();
let path = config.find_template("sub1/d.html", Some(&root)).unwrap();
let root = config.find_template("sub/b.html", None, None).unwrap();
let path = config
.find_template("sub1/d.html", Some(&root), None)
.unwrap();
assert_eq_rooted(&path, "sub/sub1/d.html");
}

Expand Down
15 changes: 11 additions & 4 deletions rinja_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::config::WhitespaceHandling;
use crate::heritage::{Context, Heritage};
use crate::html::write_escaped_str;
use crate::input::{Source, TemplateInput};
use crate::{CompileError, MsgValidEscapers, CRATE};
use crate::{CompileError, FileInfo, MsgValidEscapers, CRATE};

#[derive(Clone, Copy, PartialEq, Debug)]
enum EvaluatedResult {
Expand Down Expand Up @@ -78,7 +78,13 @@ impl<'a> Generator<'a> {
pub(crate) fn build(mut self, ctx: &Context<'a>) -> Result<String, CompileError> {
let mut buf = Buffer::new();

self.impl_template(ctx, &mut buf)?;
if let Err(mut err) = self.impl_template(ctx, &mut buf) {
if err.span.is_some() {
err.span = self.input.source_span;
}
return Err(err);
}

self.impl_display(&mut buf);

#[cfg(feature = "with-actix-web")]
Expand Down Expand Up @@ -907,14 +913,15 @@ impl<'a> Generator<'a> {
&mut self,
ctx: &Context<'a>,
buf: &mut Buffer,
i: &'a Include<'_>,
i: &'a WithSpan<'_, Include<'_>>,
) -> Result<usize, CompileError> {
self.flush_ws(i.ws);
self.write_buf_writable(ctx, buf)?;
let file_info = ctx.path.map(|path| FileInfo::of(i, path, ctx.parsed));
let path = self
.input
.config
.find_template(i.path, Some(&self.input.path))?;
.find_template(i.path, Some(&self.input.path), file_info)?;

// We clone the context of the child in order to preserve their macros and imports.
// But also add all the imports and macros from this template that don't override the
Expand Down
16 changes: 12 additions & 4 deletions rinja_derive/src/heritage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ pub(crate) struct Context<'a> {
pub(crate) blocks: HashMap<&'a str, &'a BlockDef<'a>>,
pub(crate) macros: HashMap<&'a str, &'a Macro<'a>>,
pub(crate) imports: HashMap<&'a str, Arc<Path>>,
path: Option<&'a Path>,
parsed: &'a Parsed,
pub(crate) path: Option<&'a Path>,
pub(crate) parsed: &'a Parsed,
}

impl Context<'_> {
Expand Down Expand Up @@ -84,15 +84,23 @@ impl Context<'_> {
Some(FileInfo::of(e, path, parsed)),
));
}
extends = Some(config.find_template(e.path, Some(path))?);
extends = Some(config.find_template(
e.path,
Some(path),
Some(FileInfo::of(e, &path, &parsed)),
)?);
}
Node::Macro(m) => {
ensure_top(top, m, path, parsed, "macro")?;
macros.insert(m.name, &**m);
}
Node::Import(import) => {
ensure_top(top, import, path, parsed, "import")?;
let path = config.find_template(import.path, Some(path))?;
let path = config.find_template(
import.path,
Some(path),
Some(FileInfo::of(import, &path, &parsed)),
)?;
imports.insert(import.scope, path);
}
Node::BlockDef(b) => {
Expand Down
45 changes: 32 additions & 13 deletions rinja_derive/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::sync::{Arc, OnceLock};
use mime::Mime;
use once_map::OnceMap;
use parser::{Node, Parsed};
use proc_macro2::Span;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;

Expand All @@ -18,6 +19,7 @@ pub(crate) struct TemplateInput<'a> {
pub(crate) config: &'a Config,
pub(crate) syntax: &'a SyntaxAndCache<'a>,
pub(crate) source: &'a Source,
pub(crate) source_span: Option<Span>,
pub(crate) block: Option<&'a str>,
pub(crate) print: Print,
pub(crate) escaper: &'a str,
Expand All @@ -42,18 +44,19 @@ impl TemplateInput<'_> {
print,
escaping,
ext,
ext_span,
syntax,
..
} = args;

// Validate the `source` and `ext` value together, since they are
// related. In case `source` was used instead of `path`, the value
// of `ext` is merged into a synthetic `path` value here.
let source = source
let &(ref source, source_span) = source
.as_ref()
.expect("template path or source not found in attributes");
let path = match (&source, &ext) {
(Source::Path(path), _) => config.find_template(path, None)?,
(Source::Path(path), _) => config.find_template(path, None, None)?,
(&Source::Source(_), Some(ext)) => {
PathBuf::from(format!("{}.{}", ast.ident, ext)).into()
}
Expand Down Expand Up @@ -95,7 +98,7 @@ impl TemplateInput<'_> {
"no escaper defined for extension '{escaping}'. {}",
MsgValidEscapers(&config.escapers),
),
None,
*ext_span,
)
})?;

Expand Down Expand Up @@ -127,6 +130,7 @@ impl TemplateInput<'_> {
config,
syntax,
source,
source_span,
block: block.as_deref(),
print: *print,
escaper,
Expand Down Expand Up @@ -189,7 +193,11 @@ impl TemplateInput<'_> {

match n {
Node::Extends(extends) if top => {
let extends = self.config.find_template(extends.path, Some(&path))?;
let extends = self.config.find_template(
extends.path,
Some(&path),
Some(FileInfo::of(extends, &path, &parsed)),
)?;
let dependency_path = (path.clone(), extends.clone());
if path == extends {
// We add the path into the graph to have a better looking error.
Expand All @@ -205,14 +213,22 @@ impl TemplateInput<'_> {
nested.push(&m.nodes);
}
Node::Import(import) if top => {
let import = self.config.find_template(import.path, Some(&path))?;
let import = self.config.find_template(
import.path,
Some(&path),
Some(FileInfo::of(import, &path, &parsed)),
)?;
add_to_check(import)?;
}
Node::FilterBlock(f) => {
nested.push(&f.nodes);
}
Node::Include(include) => {
let include = self.config.find_template(include.path, Some(&path))?;
let include = self.config.find_template(
include.path,
Some(&path),
Some(FileInfo::of(include, &path, &parsed)),
)?;
add_to_check(include)?;
}
Node::BlockDef(b) => {
Expand Down Expand Up @@ -260,15 +276,16 @@ impl TemplateInput<'_> {

#[derive(Debug, Default)]
pub(crate) struct TemplateArgs {
source: Option<Source>,
pub(crate) source: Option<(Source, Option<Span>)>,
block: Option<String>,
print: Print,
escaping: Option<String>,
ext: Option<String>,
ext_span: Option<Span>,
syntax: Option<String>,
config: Option<String>,
pub(crate) whitespace: Option<String>,
pub(crate) span: Option<proc_macro2::Span>,
pub(crate) template_span: Option<Span>,
}

impl TemplateArgs {
Expand Down Expand Up @@ -305,7 +322,7 @@ impl TemplateArgs {
.ok_or_else(|| CompileError::no_file_info("no attribute 'template' found", None))?;

let mut args = Self {
span,
template_span: span,
..Self::default()
};
// Loop over the meta attributes and find everything that we
Expand Down Expand Up @@ -348,6 +365,7 @@ impl TemplateArgs {

if ident == "path" {
source_or_path(ident, value, &mut args.source, Source::Path)?;
args.ext_span = Some(ident.span());
} else if ident == "source" {
source_or_path(ident, value, &mut args.source, |s| Source::Source(s.into()))?;
} else if ident == "block" {
Expand Down Expand Up @@ -376,6 +394,7 @@ impl TemplateArgs {
set_template_str_attr(ident, value, &mut args.escaping)?;
} else if ident == "ext" {
set_template_str_attr(ident, value, &mut args.ext)?;
args.ext_span = Some(ident.span());
} else if ident == "syntax" {
set_template_str_attr(ident, value, &mut args.syntax)?;
} else if ident == "config" {
Expand All @@ -395,7 +414,7 @@ impl TemplateArgs {

pub(crate) fn fallback() -> Self {
Self {
source: Some(Source::Source("".into())),
source: Some((Source::Source("".into()), None)),
ext: Some("txt".to_string()),
..Self::default()
}
Expand All @@ -409,7 +428,7 @@ impl TemplateArgs {
fn source_or_path(
name: &syn::Ident,
value: &syn::ExprLit,
dest: &mut Option<Source>,
dest: &mut Option<(Source, Option<Span>)>,
ctor: fn(String) -> Source,
) -> Result<(), CompileError> {
if dest.is_some() {
Expand All @@ -418,7 +437,7 @@ fn source_or_path(
Some(name.span()),
))
} else if let syn::Lit::Str(s) = &value.lit {
*dest = Some(ctor(s.value()));
*dest = Some((ctor(s.value()), Some(name.span())));
Ok(())
} else {
Err(CompileError::no_file_info(
Expand Down Expand Up @@ -611,7 +630,7 @@ mod tests {
#[test]
fn get_source() {
let path = Config::new("", None, None)
.and_then(|config| config.find_template("b.html", None))
.and_then(|config| config.find_template("b.html", None, None))
.unwrap();
assert_eq!(get_template_source(&path, None).unwrap(), "bar".into());
}
Expand Down
6 changes: 5 additions & 1 deletion rinja_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ pub(crate) fn build_template(ast: &syn::DeriveInput) -> Result<String, CompileEr
let mut result = build_template_inner(ast, &template_args);
if let Err(err) = &mut result {
if err.span.is_none() {
err.span = template_args.span;
err.span = template_args
.source
.as_ref()
.and_then(|(_, span)| *span)
.or(template_args.template_span);
}
}
result
Expand Down
1 change: 1 addition & 0 deletions testing/templates/latex-file.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
empty.
1 change: 1 addition & 0 deletions testing/templates/transclude-there.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{% include "transclude-missing.html" %}
Loading

0 comments on commit ec9cffd

Please sign in to comment.