Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error defining template in macro #59

Open
alvra opened this issue May 9, 2021 · 6 comments
Open

Error defining template in macro #59

alvra opened this issue May 9, 2021 · 6 comments

Comments

@alvra
Copy link

alvra commented May 9, 2021

Defining a template in a macro currently fails, while doing the same thing without a macro works as expected.

A minimal example to reproduce this:

use sailfish::TemplateOnce;

macro_rules! template {
    ($name:ident, $path:literal, { $($field:ident: $type:ty),* } ) => {
        #[derive(TemplateOnce)]
        #[template(path=$path)]
        struct $name {
            $($field: $type,)*
        }
    }
}

template!(SimpleTemplate, "index.html", {});

fn main() {
    let template = SimpleTemplate {};
    let result = template.render_once().unwrap();
    println!("{}", result)
}

Error:

error[E0425]: cannot find value `__sf_buf` in this scope
 --> .../target/debug/build/sailfish-compiler-8fa5b2a3e77dde90/out/templates/index-1cd25f105bd4f9f0:2:27
  |
2 |     __sf_rt::render_text!(__sf_buf, "<p>Hello world</p>");
  |                           ^^^^^^^^ not found in this scope

This is the file where the error occurs (templates/index-1cd25f105bd4f9f0):

{
    __sf_rt::render_text!(__sf_buf, "<p>Hello world</p>");
}

I would expect this to give the same result as this:

#[derive(TemplateOnce)]
#[template(path="index.html")]
struct SimpleTemplate {}
@mpfaff
Copy link

mpfaff commented Sep 1, 2023

I'm running into this issue too. Did you ever get it working?

@alvra
Copy link
Author

alvra commented Sep 1, 2023

@mpfaff Nope, but I'm not using sailfish anymore though

@mpfaff
Copy link

mpfaff commented Sep 1, 2023

Darn. The ability to embed full rust expressions in the templates is a killer feature for me. Do you know of any other template engines that come close in terms of keeping the logic and computation in the templates? I've just looked at Askama and Tera, and Tera looks like the more promising of the two.

@alvra
Copy link
Author

alvra commented Sep 2, 2023

No experience with Tera, but I'm a happy Askama user. It has match statements (which are pretty essential in Rust IMO) and converts templates to Rust at compile time. It seems that Tera doesn't support either of these, but compiling templates at run-time does make development easier since you don't need to recompile for a template change. That is my main issue with Askama.

I don't have any experience with an engine that allows you to embed actual Rust, but there are some interesting macros if you're only rendering html, like maud and typed-html.

@wangziling
Copy link

wangziling commented Nov 30, 2023

Hmmm... I meet this issue as well...
Sailfish version: sailfish = "0.8.3"
Rust version: 1.74.0 (79e9716c9 2023-11-13)

Refer to the example simple.rs, and the simple.stpl.

Origin:

use sailfish::TemplateOnce;

#[derive(TemplateOnce)]
#[template(path = "simple.stpl")]
struct Simple {
    messages: Vec<String>,
}

fn main() {
    let messages = vec![String::from("Message 1"), String::from("<Message 2>")];
    println!("{}", Simple { messages }.render_once().unwrap());
}

Modified:

use sailfish::TemplateOnce;

macro_rules! template {
    ($name:ident, $path:literal, { $($field:ident: $type:ty),* } ) => {
        #[derive(TemplateOnce)]
        #[template(path=$path)]
        struct $name {
            $($field: $type,)*
        }
    }
}

template!(Simple, "simple.stpl", { messages: Vec<String> });

fn main() {
    let messages = vec![String::from("Message 1"), String::from("<Message 2>")];
    println!("{}", Simple { messages }.render_once().unwrap());
}

With cargo expand, the results between these two are TOTALLY the SAME:

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
use sailfish::TemplateOnce;
#[template(path = "simple.stpl")]
struct Simple {
    messages: Vec<String>,
}
impl sailfish::TemplateOnce for Simple {
    fn render_once(self) -> sailfish::RenderResult {
        use sailfish::runtime::{Buffer, SizeHint};
        static SIZE_HINT: SizeHint = SizeHint::new();
        let mut buf = Buffer::with_capacity(SIZE_HINT.get());
        self.render_once_to(&mut buf)?;
        SIZE_HINT.update(buf.len());
        Ok(buf.into_string())
    }
    fn render_once_to(
        self,
        __sf_buf: &mut sailfish::runtime::Buffer,
    ) -> std::result::Result<(), sailfish::runtime::RenderError> {
        b"<!DOCTYPE html>\n<html>\n  <body>\n    <%# This is a comment %>\n    <% for (i, msg) in messages.iter().enumerate() { %>\n      <% if i == 0 { %>\n        <h1>Hello, world!</h1>\n      <% } %>\n      <div><%= *msg %></div>\n    <% } %>\n  </body>\n</html>\n";
        use sailfish::runtime as __sf_rt;
        let Simple { messages } = self;
        {
            __sf_buf.push_str("<!DOCTYPE html>\n<html>\n  <body>\n    \n    ");
            for (i, msg) in messages.iter().enumerate() {
                __sf_buf.push_str("\n      ");
                if i == 0 {
                    __sf_buf.push_str("\n        <h1>Hello, world!</h1>\n      ");
                }
                __sf_buf.push_str("\n      <div>");
                ::sailfish::runtime::Render::render_escaped(&(*msg), __sf_buf)?;
                __sf_buf.push_str("</div>\n    ");
            }
            __sf_buf.push_str("\n  </body>\n</html>");
        };
        Ok(())
    }
}
impl sailfish::private::Sealed for Simple {}
fn main() {
    let messages = <[_]>::into_vec(
        #[rustc_box]
        ::alloc::boxed::Box::new([
            String::from("Message 1"),
            String::from("<Message 2>"),
        ]),
    );
    {
        ::std::io::_print(
            format_args!("{0}\n", Simple { messages }.render_once().unwrap()),
        );
    };
}

Hmmm... Cannot figure why caused the latter one panic.

@wangziling
Copy link

wangziling commented Nov 30, 2023

I have used the proc_macro_attribute to addsome new fields to a struct which has derived TemplateOnce. Instead of using decl_macro implementation.

It works. But lack of flexibility just yet.

image

image

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants