utkarshkukreti / markup.rs

A blazing fast, type-safe template engine for Rust.
Apache License 2.0
363 stars 15 forks source link

Support raw as a default mode #4

Open mmstick opened 5 years ago

mmstick commented 5 years ago

Currently, the define!() macro assumes XML-like rules, and there's likely a bit of overhead in parsing every string in that manner. I have use for templating for a wide range of formats which are not XML-like in nature, such as INI, TOML, or any other custom formats. Peppering the define!() with markup::raw() seems wrong.

As an example, this is what I've come up with for generating desktop entry files. There are no escape rules, outside of \; for in keys that take multiple values.

markup::define! {
    DesktopEntry<'a>(
        name: &'a str,
        generic_name: Option<&'a str>,
        icon: &'a str,
        comment: Option<&'a str>,
        hidden: bool,
        no_display: bool,
        kind: DesktopType<'a>
    ) {
        "[Desktop Entry]\n"
        "Type=" {markup::raw(kind.type_str())} "\n"
        "Name=" {markup::raw(name)} "\n"

        @if let Some(generic) = (generic_name) {
            "GenericName=" {markup::raw(generic)} "\n"

            "X-GNOME-FullName=" {markup::raw(name)} " " {markup::raw(generic)} "\n"
        }

        "Icon=" {icon} "\n"

        @if let Some(comment) = (comment) {
            "Comment=" {markup::raw(comment)} "\n"
        }

        @if *(hidden) {
            "Hidden=true\n"
        }

        @if *(no_display) {
            "NoDisplay=true\n"
        }

        @if let DesktopType::Application(app) = (kind) {
            "Categories=" {markup::raw(app.categories)} "\n"

            @if !app.keywords.is_empty() {
                "Keywords=" { '\"' }
                @for keyword in app.keywords.iter() {
                    {markup::raw(keyword)} ";"
                }
                { markup::raw("\"\n") }
            }

            @if !app.mime_types.is_empty() {
                "MimeType=" { '\"' }
                @for mime in app.mime_types {
                    {markup::raw(mime)} ";"
                }
                { markup::raw("\"\n") }
            }

            @if app.terminal {
                "Terminal=true\n"
            }

            @if app.startup_notify {
                "StartupNotify=true\n"
            }

            "Exec=" {markup::raw(app.exec)} "\n"

            @if let Some(path) = (app.path) {
                "Path=" {markup::raw(path)} "\n"
            }
        } else if let DesktopType::Link { url } = (kind) {
            "Link=" {markup::raw(url)} "\n"
        }
    }
}
utkarshkukreti commented 5 years ago

Never thought someone would use this for generating non HTML/XML data! I added auto escaping like most HTML/XML templating languages do -- to prevent accidental XSS attacks. You could shorten markup::raw to r like this:

use markup::raw as r;

...

"Type=" {r(kind.type_str())} "\n"

Just 3 extra characters now. Maybe that is good enough?

inferrna commented 4 years ago

I tried to use this for code generation via build.rs and was disappoint of escaping. I'd suggest you to add new macro, called define_raw! for example, to make it usable not only for HTML/XML.