Run commands

This can be already done without any features, but with an extra step (writing rust service).

This is done using load_data(url=...) function.

For example, how to generate svg formulas in .md files.

Step 0. Install tex2svg

sudo apt install nodejs npm
sudo npm install --global mathjax-node-cli

Commands are taken from here.

Step 1. Create Rust service

Cargo.toml:

[package]
name = "zola_ext"
version = "0.1.0"
edition = "2018"

[dependencies]
rocket = "0.5.0-rc.1"
base64 = "0.13.0"

main.rs

use rocket::*;
use std::hash::Hash;
use std::process::Command;

const PATH: &str = "/home/zorax/my/zola/static";

fn calculate_hash<T: Hash>(t: &T) -> u64 {
    use std::collections::hash_map::DefaultHasher;
    use std::hash::Hasher;

    let mut s = DefaultHasher::new();
    t.hash(&mut s);
    s.finish()
}

#[get("/tex2svg/<formula>")]
fn tex2svg(formula: &str) -> Option<String> {
    let formula = String::from_utf8(base64::decode(formula).ok()?).ok()?;
    let file = format!("formulas/h{}.svg", calculate_hash(&formula));
    let full_file = format!("{}/{}", PATH, file);
    if !std::path::Path::new(&full_file).exists() {
        let result = Command::new("tex2svg").args(&[&formula]).output().ok()?;
        if result.stdout.is_empty() {
            return None;
        }
        std::fs::write(&full_file, result.stdout).ok()?;
    }
    Some(format!("{{\"file\": \"{}\"}}", file))
}

#[launch]
fn rocket() -> Rocket<Build> {
    let config = Config {
        port: 1234,
        ..Config::debug_default()
    };
    rocket::custom(&config).mount("/", routes![tex2svg])
}

Modify PATH variable to /static directory of your zola site.

This code already does:

  • Use a hash of input to generate a file.
  • Don’t run the command when a file exists.

Notice that you can return information in json format to zola.

Also, base64 is just convenient to escape.

Unfortunately, if you return Result<String, BadRequest<String>> from tex2svg, the error will not be shown in zola, only that it is 403. So, you need to print an error by yourself in this app.

Step 2. Create shortcode

templates/shortcodes/formula.html:

{% set formula =  formula | base64_encode %}
{% set url = "http://127.0.0.1:1234/tex2svg/" ~ formula %}
{% set result = load_data(url=url, format="json") %}
<img src="{{"/" ~ result.file}}">

Step 3. Use

Write this in any your .md file:

{{ formula(formula="\sin^2{\theta} + \cos^2{\theta} = 1") }}

And this will just work.

2 Likes