Skip to content

Commit

Permalink
fix: more accurate spans on parent templates
Browse files Browse the repository at this point in the history
  • Loading branch information
0b10011 committed Jan 25, 2025
1 parent ee2d6ad commit 27c71a2
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 70 deletions.
8 changes: 3 additions & 5 deletions oxiplate-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,8 @@ fn parse_source_tokens(
template_type: &TemplateType,
) -> (Span, proc_macro2::TokenStream, Option<PathBuf>) {
match template_type {
TemplateType::Inline | TemplateType::Extends => {
parse_source_tokens_for_inline_or_extends(attr)
}
TemplateType::Path => parse_source_tokens_for_path(attr),
TemplateType::Inline => parse_source_tokens_for_inline_or_extends(attr),
TemplateType::Path | TemplateType::Extends => parse_source_tokens_for_path(attr),
}
}

Expand Down Expand Up @@ -312,7 +310,7 @@ fn parse_fields(
Some(name) => {
if !is_extending {
field_names.push(name);
} else if *name == "_data" {
} else if *name == "oxiplate_extends_data" {
data_type = field.ty.clone();
} else {
blocks.push(name.to_string());
Expand Down
1 change: 1 addition & 0 deletions oxiplate-derive/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ impl<'a> Source<'a> {
// Customize the range to map properly to the literal.
let mut range = Range { start, end };

// Uses the span from the included file.
if self.original.origin.is_some() {
return self
.original
Expand Down
6 changes: 4 additions & 2 deletions oxiplate-derive/src/syntax/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ impl ToTokens for Expression<'_> {
match scope {
IdentifierScope::Local => quote_spanned! {span=> #identifier },
IdentifierScope::Parent => quote_spanned! {span=> self.#identifier },
IdentifierScope::Data => quote_spanned! {span=> self._data.#identifier },
IdentifierScope::Data => {
quote_spanned! {span=> self.oxiplate_extends_data.#identifier }
}
}
}
IdentifierOrFunction::Function(identifier, parens) => {
Expand All @@ -187,7 +189,7 @@ impl ToTokens for Expression<'_> {
quote_spanned! {span=> self.#identifier #parens }
}
IdentifierScope::Data => {
quote_spanned! {span=> self._data.#identifier #parens }
quote_spanned! {span=> self.oxiplate_extends_data.#identifier #parens }
}
}
}
Expand Down
33 changes: 14 additions & 19 deletions oxiplate-derive/src/syntax/statement/extends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use nom::combinator::cut;
use nom::error::context;
use nom::sequence::tuple;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens, TokenStreamExt};
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
use syn::Type;

use super::super::expression::keyword;
Expand Down Expand Up @@ -85,15 +85,8 @@ impl ToTokens for Extends<'_> {
fn to_tokens(&self, tokens: &mut TokenStream) {
let Extends { path, template, .. } = self;

let span = path.span();
let path = path.as_str();
let path = ::std::path::PathBuf::from(
::std::env::var("CARGO_MANIFEST_DIR_OVERRIDE")
.or(::std::env::var("CARGO_MANIFEST_DIR"))
.unwrap(),
)
.join(option_env!("OXIP_TEMPLATE_DIR").unwrap_or("templates"))
.join(path);
let path = path.to_string_lossy();

let data_type = &self.data_type;
// FIXME: Should also include local vars here I think
Expand All @@ -113,42 +106,42 @@ impl ToTokens for Extends<'_> {
}
}
if self.is_extending {
tokens.append_all(quote! {
tokens.append_all(quote_spanned! {span=>
#template
#[derive(::oxiplate::Oxiplate)]
#[oxiplate_extends = include_str!(#path)]
#[oxiplate_extends = #path]
struct ExtendingTemplate<'a, F>
where
F: Fn(fn(f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result, &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result,
{
_data: &'a #data_type,
oxiplate_extends_data: &'a #data_type,
#(#inherited_blocks: &'a F,)*
#(#new_blocks: &'a F,)*
}

let template = ExtendingTemplate {
_data: &self._data,
oxiplate_extends_data: &self.oxiplate_extends_data,
#(#inherited_blocks: &self.#inherited_blocks,)*
#(#new_blocks: &#new_blocks,)*
};
});
} else {
tokens.append_all(quote! {
tokens.append_all(quote_spanned! {span=>
#template
#[derive(::oxiplate::Oxiplate)]
#[oxiplate_extends = include_str!(#path)]
#[oxiplate_extends = #path]
struct Template<'a, F>
where
F: Fn(fn(f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result, &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result,
{
// FIXME: Need to pass #extending and #extending_generics down to next level (type alias doesn't help because generics need to be passed sometimes)
_data: &'a #data_type,
oxiplate_extends_data: &'a #data_type,
#(#inherited_blocks: &'a F,)*
#(#new_blocks: &'a F,)*
}

let template = Template {
_data: self,
oxiplate_extends_data: self,
#(#inherited_blocks: &#inherited_blocks,)*
#(#new_blocks: &#new_blocks,)*
};
Expand All @@ -161,7 +154,7 @@ impl ToTokens for Extends<'_> {
}

pub(super) fn parse_extends(input: Source) -> Res<Source, Statement> {
let (input, _extends_keyword) = keyword("extends")(input)?;
let (input, extends_keyword) = keyword("extends")(input)?;

let (input, (_, _, path, _)) = cut(tuple((
context("Expected space after 'extends'", take_while1(is_whitespace)),
Expand All @@ -177,6 +170,8 @@ pub(super) fn parse_extends(input: Source) -> Res<Source, Statement> {
let data_type = input.original.data_type.clone();
let blocks = input.original.blocks.clone();

let source = extends_keyword.0;

Ok((
input,
Statement {
Expand All @@ -188,7 +183,7 @@ pub(super) fn parse_extends(input: Source) -> Res<Source, Statement> {
template: Template(vec![]),
}
.into(),
source: path,
source,
},
))
}
3 changes: 3 additions & 0 deletions oxiplate/templates/extends-with-empty-content.html.oxip
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% extends "extends-wrapper.html.oxip" %}
{% block content -%}
{%- endblock %}
11 changes: 5 additions & 6 deletions oxiplate/tests/broken/extends-extends.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
error: Only block statements are allowed here, along with comments and whitespace.
--> tests/broken/extends-extends.rs:4:77
--> tests/broken/extends-extends.rs:4:68
|
4 | #[oxiplate_inline = r#"{% extends "extends-wrapper.html.oxip" %}{% extends "extends-wrapper.html.oxip" %}"#]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^

error[E0392]: type parameter `F` is never used
--> tests/broken/extends-extends.rs:3:10
--> tests/broken/extends-extends.rs:4:36
|
3 | #[derive(Oxiplate)]
| ^^^^^^^^ unused type parameter
4 | #[oxiplate_inline = r#"{% extends "extends-wrapper.html.oxip" %}{% extends "extends-wrapper.html.oxip" %}"#]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ unused type parameter
|
= help: consider removing `F`, referring to it in a field, or using a marker such as `PhantomData`
= note: this error originates in the derive macro `Oxiplate` (in Nightly builds, run with -Z macro-backtrace for more info)
12 changes: 12 additions & 0 deletions oxiplate/tests/broken/extends/extends.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use oxiplate_derive::Oxiplate;

#[derive(Oxiplate)]
#[oxiplate = "extends-with-empty-content.html.oxip"]
struct AbsoluteData {}

fn main() {
// Intentionally missing the "title" field used by the parent template
let data = AbsoluteData {};

panic!("{data}");
}
12 changes: 12 additions & 0 deletions oxiplate/tests/broken/extends/extends.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0609]: no field `title` on type `&'a AbsoluteData`
--> templates/extends-wrapper.html.oxip
|
| <title>{{ title }}</title>
| ^^^^^ unknown field
|
::: tests/broken/extends/extends.rs:3:10
|
3 | #[derive(Oxiplate)]
| -------- in this derive macro expansion
|
= note: this error originates in the derive macro `Oxiplate` (in Nightly builds, run with -Z macro-backtrace for more info)
2 changes: 1 addition & 1 deletion oxiplate/tests/expansion/expected/broken.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn broken() {
}
let tests = trybuild::TestCases::new();
tests.pass("tests/broken-verify/with-group.rs");
tests.compile_fail("tests/broken/*.rs");
tests.compile_fail("tests/broken/**/*.rs");
}
#[rustc_main]
#[coverage(off)]
Expand Down
15 changes: 8 additions & 7 deletions oxiplate/tests/expansion/expected/extends-lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ impl<'a> ::std::fmt::Display for AbsoluteData<'a> {
)?;
Ok(())
};
#[oxiplate_extends = "{% extends \"extends-wrapper.html.oxip\" %}\n\n{% block content -%}\n Some test content.\n{%- endblock %}\n"]
#[oxiplate_extends = "extends-inner-wrapper.html.oxip"]
struct Template<'a, F>
where
F: Fn(
fn(f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result,
&mut ::std::fmt::Formatter<'_>,
) -> ::std::fmt::Result,
{
_data: &'a AbsoluteData<'a>,
oxiplate_extends_data: &'a AbsoluteData<'a>,
content: &'a F,
}
impl<'a, F> ::std::fmt::Display for Template<'a, F>
Expand All @@ -40,15 +40,15 @@ impl<'a> ::std::fmt::Display for AbsoluteData<'a> {
{
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
let content = self.content;
#[oxiplate_extends = "<!DOCTYPE html>\n<title>{{ title }}</title>\n{% block content -%}test{%- endblock %}\n"]
#[oxiplate_extends = "extends-wrapper.html.oxip"]
struct ExtendingTemplate<'a, F>
where
F: Fn(
fn(f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result,
&mut ::std::fmt::Formatter<'_>,
) -> ::std::fmt::Result,
{
_data: &'a &'a AbsoluteData<'a>,
oxiplate_extends_data: &'a &'a AbsoluteData<'a>,
content: &'a F,
}
impl<'a, F> ::std::fmt::Display for ExtendingTemplate<'a, F>
Expand All @@ -64,7 +64,8 @@ impl<'a> ::std::fmt::Display for AbsoluteData<'a> {
) -> ::std::fmt::Result {
f.write_fmt(
format_args!(
"<!DOCTYPE html>\n<title>{0}</title>\n", self._data.title
"<!DOCTYPE html>\n<title>{0}</title>\n", self
.oxiplate_extends_data.title
),
)?;
let content = |
Expand All @@ -79,15 +80,15 @@ impl<'a> ::std::fmt::Display for AbsoluteData<'a> {
}
}
let template = ExtendingTemplate {
_data: &self._data,
oxiplate_extends_data: &self.oxiplate_extends_data,
content: &self.content,
};
f.write_fmt(format_args!("{0}", template))?;
Ok(())
}
}
let template = Template {
_data: self,
oxiplate_extends_data: self,
content: &content,
};
f.write_fmt(format_args!("{0}", template))?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ impl ::std::fmt::Display for AbsoluteData {
)?;
Ok(())
};
#[oxiplate_extends = "{% extends \"extends-nested-different-blocks-layout.html.oxip\" %}\n{% block body -%}\n <main>\n {%- block content -%}{%- endblock -%}\n </main>\n{%- endblock %}"]
#[oxiplate_extends = "extends-nested-different-blocks-wrapper.html.oxip"]
struct Template<'a, F>
where
F: Fn(
fn(f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result,
&mut ::std::fmt::Formatter<'_>,
) -> ::std::fmt::Result,
{
_data: &'a AbsoluteData,
oxiplate_extends_data: &'a AbsoluteData,
content: &'a F,
}
impl<'a, F> ::std::fmt::Display for Template<'a, F>
Expand All @@ -53,15 +53,15 @@ impl ::std::fmt::Display for AbsoluteData {
f.write_str("</main>")?;
Ok(())
};
#[oxiplate_extends = "<DOCTYPE html>\n<head>\n <title>{{ title }}</title>\n</head>\n<body>\n {%- block body -%}{%- endblock -%}\n</body>\n"]
#[oxiplate_extends = "extends-nested-different-blocks-layout.html.oxip"]
struct ExtendingTemplate<'a, F>
where
F: Fn(
fn(f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result,
&mut ::std::fmt::Formatter<'_>,
) -> ::std::fmt::Result,
{
_data: &'a &'a AbsoluteData,
oxiplate_extends_data: &'a &'a AbsoluteData,
body: &'a F,
}
impl<'a, F> ::std::fmt::Display for ExtendingTemplate<'a, F>
Expand All @@ -78,7 +78,7 @@ impl ::std::fmt::Display for AbsoluteData {
f.write_fmt(
format_args!(
"<DOCTYPE html>\n<head>\n <title>{0}</title>\n</head>\n<body>",
self._data.title
self.oxiplate_extends_data.title
),
)?;
let body = |
Expand All @@ -90,15 +90,15 @@ impl ::std::fmt::Display for AbsoluteData {
}
}
let template = ExtendingTemplate {
_data: &self._data,
oxiplate_extends_data: &self.oxiplate_extends_data,
body: &body,
};
f.write_fmt(format_args!("{0}", template))?;
Ok(())
}
}
let template = Template {
_data: self,
oxiplate_extends_data: self,
content: &content,
};
f.write_fmt(format_args!("{0}", template))?;
Expand Down
Loading

0 comments on commit 27c71a2

Please sign in to comment.