Skip to content

Commit

Permalink
derive: add option to specify rinja path
Browse files Browse the repository at this point in the history
  • Loading branch information
Kijewski committed Feb 4, 2025
1 parent 30e6641 commit e2a40c1
Show file tree
Hide file tree
Showing 17 changed files with 269 additions and 81 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
for PKG in \
examples/actix-web-app examples/axum-app examples/poem-app examples/rocket-app examples/salvo-app examples/warp-app fuzzing \
rinja rinja_derive rinja_derive_standalone rinja_parser \
testing testing-alloc testing-no-std
testing testing-alloc testing-no-std testing-renamed
do
cd "$PKG"
echo "Testing: $PKG"
Expand Down Expand Up @@ -118,7 +118,7 @@ jobs:
for PKG in \
examples/actix-web-app examples/axum-app examples/poem-app examples/rocket-app examples/salvo-app examples/warp-app fuzzing \
rinja rinja_derive rinja_derive_standalone rinja_parser \
testing testing-alloc testing-no-std
testing testing-alloc testing-no-std testing-renamed
do
cd "$PKG"
cargo sort --check --check-format --grouped
Expand Down Expand Up @@ -161,7 +161,7 @@ jobs:
package: [
examples/actix-web-app, examples/axum-app, examples/poem-app, examples/rocket-app, examples/salvo-app, examples/warp-app, fuzzing,
rinja, rinja_derive, rinja_derive_standalone, rinja_parser,
testing, testing-alloc, testing-no-std,
testing, testing-alloc, testing-no-std, testing-renamed,
]
runs-on: ubuntu-latest
steps:
Expand Down
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ members = [
"rinja_parser",
"testing",
"testing-alloc",
"testing-no-std"
"testing-no-std",
"testing-renamed"
]
resolver = "2"
49 changes: 38 additions & 11 deletions book/src/creating_templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ code generation process takes some options that can be specified through
the `template()` attribute. The following sub-attributes are currently
recognized:

* `path` (as `path = "foo.html"`): sets the path to the template file. The
* `path` (e.g. `path = "foo.html"`): sets the path to the template file. The
path is interpreted as relative to the configured template directories
(by default, this is a `templates` directory next to your `Cargo.toml`).
The file name extension is used to infer an escape mode (see below). In
Expand All @@ -43,7 +43,7 @@ recognized:
struct HelloTemplate<'a> { ... }
```

* `source` (as `source = "{{ foo }}"`): directly sets the template source.
* `source` (e.g. `source = "{{ foo }}"`): directly sets the template source.
This can be useful for test cases or short templates. The generated path
is undefined, which generally makes it impossible to refer to this
template from other templates. If `source` is specified, `ext` must also
Expand All @@ -56,10 +56,10 @@ recognized:
}
```

* `in_doc` (as `in_doc = true`):
* `in_doc` (e.g. `in_doc = true`):
please see the section ["documentation as template code"](#documentation-as-template-code).

* `ext` (as `ext = "txt"`): lets you specify the content type as a file
* `ext` (e.g. `ext = "txt"`): lets you specify the content type as a file
extension. This is used to infer an escape mode (see below), and some
web framework integrations use it to determine the content type.
Cannot be used together with `path`.
Expand All @@ -71,7 +71,7 @@ recognized:
}
```

* `print` (as `print = "code"`): enable debugging by printing nothing
* `print` (e.g. `print = "code"`): enable debugging by printing nothing
(`none`), the parsed syntax tree (`ast`), the generated code (`code`)
or `all` for both. The requested data will be printed to stdout at
compile time.
Expand All @@ -81,7 +81,7 @@ recognized:
struct HelloTemplate<'a> { ... }
```

* `block` (as `block = "block_name"`): renders the block by itself.
* `block` (e.g. `block = "block_name"`): renders the block by itself.
Expressions outside of the block are not required by the struct, and
inheritance is also supported. This can be useful when you need to
decompose your template for partial rendering, without needing to
Expand All @@ -92,7 +92,7 @@ recognized:
struct HelloTemplate<'a> { ... }
```

* `escape` (as `escape = "none"`): override the template's extension used for
* `escape` (e.g. `escape = "none"`): override the template's extension used for
the purpose of determining the escaper for this template. See the section
on configuring custom escapers for more information.
```rust
Expand All @@ -101,7 +101,7 @@ recognized:
struct HelloTemplate<'a> { ... }
```

* `syntax` (as `syntax = "foo"`): set the syntax name for a parser defined
* `syntax` (e.g. `syntax = "foo"`): set the syntax name for a parser defined
in the configuration file. The default syntax , "default", is the one
provided by Rinja.
```rust
Expand All @@ -110,14 +110,41 @@ recognized:
struct HelloTemplate<'a> { ... }
```

* `config` (as `config = "config_file_path"`): set the path for the config file
* `config` (e.g. `config = "config_file_path"`): set the path for the config file
to be used. The path is interpreted as relative to your crate root.
```rust
#[derive(Template)]
#[template(path = "hello.html", config = "config.toml")]
struct HelloTemplate<'a> { ... }
```

* `rinja` (e.g. `rinja = rinja`):
If you are using rinja in a subproject, a library or a [macro][book-macro], it might be
necessary to specify the [path][book-tree] where to find the module `rinja`:

[book-macro]: https://doc.rust-lang.org/book/ch19-06-macros.html
[book-tree]: https://doc.rust-lang.org/book/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html

```rust,ignore
#[doc(hidden)]
use rinja as __rinja;
#[macro_export]
macro_rules! new_greeter {
($name:ident) => {
#[derive(Debug, $crate::rinja::Template)]
#[template(
ext = "txt",
source = "Hello, world!",
rinja = $crate::__rinja
)]
struct $name;
}
}
new_greeter!(HelloWorld);
assert_eq!(HelloWorld.to_string(), Ok("Hello, world."));
```
## Templating `enum`s

You can add derive `Template`s for `struct`s and `enum`s.
Expand Down Expand Up @@ -200,8 +227,8 @@ enum AreaWithBlocks {
## Documentation as template code
[#documentation-as-template-code]: #documentation-as-template-code

As an alternative to supplying the code template code in an external file (as `path` argument),
or as a string (as `source` argument), you can also enable the `"code-in-doc"` feature.
As an alternative to supplying the code template code in an external file (e.g. `path` argument),
or as a string (e.g. `source` argument), you can also enable the `"code-in-doc"` feature.
With this feature, you can specify the template code directly in the documentation
of the template item.

Expand Down
5 changes: 0 additions & 5 deletions rinja_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,6 @@ pub(crate) fn template_to_string(
heritage: Option<&Heritage<'_, '_>>,
tmpl_kind: TmplKind,
) -> Result<usize, CompileError> {
if tmpl_kind == TmplKind::Struct {
buf.write("const _: () = { extern crate rinja as rinja;");
}

let generator = Generator::new(
input,
contexts,
Expand All @@ -49,7 +45,6 @@ pub(crate) fn template_to_string(

if tmpl_kind == TmplKind::Struct {
impl_everything(input.ast, buf);
buf.write("};");
}
Ok(size_hint)
}
Expand Down
42 changes: 40 additions & 2 deletions rinja_derive/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use proc_macro2::Span;
use rustc_hash::FxBuildHasher;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::{Attribute, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Meta, Token};
use syn::{Attribute, Expr, ExprLit, ExprPath, Ident, Lit, LitBool, LitStr, Meta, Token};

use crate::config::{Config, SyntaxAndCache};
use crate::{CompileError, FileInfo, MsgValidEscapers, OnceMap};
Expand Down Expand Up @@ -329,9 +329,21 @@ impl AnyTemplateArgs {
has_default_impl: needs_default_impl > 0,
})
}

pub(crate) fn take_crate_name(&mut self) -> Option<ExprPath> {
match self {
AnyTemplateArgs::Struct(template_args) => template_args.crate_name.take(),
AnyTemplateArgs::Enum { enum_args, .. } => {
if let Some(PartialTemplateArgs { crate_name, .. }) = enum_args {
crate_name.take()
} else {
None
}
}
}
}
}

#[derive(Debug)]
pub(crate) struct TemplateArgs {
pub(crate) source: (Source, Option<Span>),
block: Option<String>,
Expand All @@ -341,6 +353,7 @@ pub(crate) struct TemplateArgs {
ext_span: Option<Span>,
syntax: Option<String>,
config: Option<String>,
crate_name: Option<ExprPath>,
pub(crate) whitespace: Option<Whitespace>,
pub(crate) template_span: Option<Span>,
pub(crate) config_span: Option<Span>,
Expand Down Expand Up @@ -389,6 +402,7 @@ impl TemplateArgs {
ext_span: args.ext.as_ref().map(|value| value.span()),
syntax: args.syntax.map(|value| value.value()),
config: args.config.as_ref().map(|value| value.value()),
crate_name: args.crate_name,
whitespace: args.whitespace,
template_span: Some(args.template.span()),
config_span: args.config.as_ref().map(|value| value.span()),
Expand All @@ -405,6 +419,7 @@ impl TemplateArgs {
ext_span: None,
syntax: None,
config: None,
crate_name: None,
whitespace: None,
template_span: None,
config_span: None,
Expand Down Expand Up @@ -676,6 +691,7 @@ pub(crate) struct PartialTemplateArgs {
pub(crate) syntax: Option<LitStr>,
pub(crate) config: Option<LitStr>,
pub(crate) whitespace: Option<Whitespace>,
pub(crate) crate_name: Option<ExprPath>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -735,6 +751,7 @@ const _: () = {
syntax: None,
config: None,
whitespace: None,
crate_name: None,
};
let mut has_data = false;

Expand Down Expand Up @@ -776,6 +793,12 @@ const _: () = {
None => unreachable!("not possible in syn::Meta::NameValue(…)"),
};

if ident == "rinja" {
ensure_only_once(ident, &mut this.crate_name)?;
this.crate_name = Some(get_exprpath(ident, pair.value)?);
continue;
}

let value = get_lit(ident, pair.value)?;

if ident == "path" {
Expand Down Expand Up @@ -918,6 +941,21 @@ const _: () = {
}
}

fn get_exprpath(name: &Ident, mut expr: Expr) -> Result<ExprPath, CompileError> {
loop {
match expr {
Expr::Path(path) => return Ok(path),
Expr::Group(group) => expr = *group.expr,
v => {
return Err(CompileError::no_file_info(
format!("template attribute `{name}` expects a path or identifier"),
Some(v.span()),
));
}
}
}
}

fn ensure_source_only_once(
name: &Ident,
source: &Option<PartialTemplateArgsSource>,
Expand Down
4 changes: 1 addition & 3 deletions rinja_derive/src/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ pub(crate) fn build_template_enum(
unreachable!();
};

buf.write("const _: () = { extern crate rinja as rinja;");
impl_everything(enum_ast, buf);

let enum_id = &enum_ast.ident;
Expand Down Expand Up @@ -368,8 +367,7 @@ pub(crate) fn build_template_enum(
buf.write(format_args!(
"\
const SIZE_HINT: rinja::helpers::core::primitive::usize = {biggest_size_hint}usize;\
}}\
}};",
}}",
));
Ok(biggest_size_hint)
}
Expand Down
Loading

0 comments on commit e2a40c1

Please sign in to comment.