Rust文档处理库typst-eval的使用:高效解析与执行Typst模板的Rust插件库

Rust文档处理库typst-eval的使用:高效解析与执行Typst模板的Rust插件库

Typst简介

Typst是一个基于标记的新型排版系统,设计目标是拥有LaTeX的强大功能,同时更易于学习和使用。Typst具有以下特点:

  • 内置常见格式化任务的标记
  • 用于其他任务的灵活函数
  • 紧密集成的脚本系统
  • 数学排版、参考文献管理等功能
  • 得益于增量编译的快速编译时间
  • 出错时提供友好的错误信息

示例代码

以下是Typst的一个完整示例:

#set page(width: 10cm, height: auto)
#set heading(numbering: "1.")

= Fibonacci sequence
The Fibonacci sequence is defined through the
recurrence relation $F_n = F_(n-1) + F_(n-2)$.
It can also be expressed in _closed form:_

$ F_n = round(1 / sqrt(5) phi.alt^n), quad
  phi.alt = (1 + sqrt(5)) / 2 $

#let count = 8
#let nums = range(1, count + 1)
#let fib(n) = (
  if n <= 2 { 1 }
  else { fib(n - 1) + fib(n - 2) }
)

The first #count numbers of the sequence are:

#align(center, table(
  columns: count,
  ..nums.map(n => $F_#n$),
  ..nums.map(n => str(fib(n))),
))

完整Rust示例

以下是使用typst-eval库解析和执行Typst模板的完整Rust示例:

use typst_eval::{eval, Engine};
use typst_library::prelude::*;

fn main() {
    // 创建Typst引擎
    let engine = Engine::new();
    
    // 定义Typst模板
    let template = r#"
        #set page(width: 10cm, height: auto)
        = Hello, Typst!
        
        This is a test document generated from Rust.
        
        #let x = 42
        The answer is: #x
    "#;
    
    // 评估模板
    let result = eval(&engine, template).unwrap();
    
    // 输出结果
    println!("{}", result);
}

安装typst-eval

在Cargo.toml中添加依赖:

[dependencies]
typst-eval = "0.13.1"

或者运行命令:

cargo add typst-eval

设计原则

Typst的设计遵循三个核心原则:

  1. 通过一致性实现简单性:Typst的设计保持一致性,使知识可以轻松迁移
  2. 通过可组合性实现强大功能:提供可以组合的系统,而不仅仅是拥有各种开关
  3. 通过增量性实现性能:所有语言特性都考虑增量编译

社区

Typst社区主要在Discord服务器上活跃,欢迎加入讨论、提问或分享作品。

完整示例demo

基于上述内容,这里提供一个更完整的typst-eval使用示例:

use typst_eval::{eval, Engine};
use typst_library::prelude::*;

fn main() {
    // 创建Typst引擎
    let engine = Engine::new();
    
    // 定义更复杂的Typst模板
    let template = r#"
        // 设置页面格式
        #set page(width: 12cm, height: auto)
        #set text(font: "New Computer Modern", size: 11pt)
        
        // 标题和作者
        = 学术论文示例
        #set heading(numbering: "1.")
        
        // 摘要部分
        == 摘要
        这是一个使用Typst和Rust生成的学术论文示例文档。
        
        // 数学公式示例
        == 数学公式
        二次方程的解公式:
        $ x = frac(-b plus-minus sqrt(b^2 - 4ac), 2a) $
        
        // 表格示例
        == 实验结果
        #let data = (("温度", "结果"), (25, 0.42), (30, 0.51), (35, 0.63))
        
        #table(
            columns: (auto, auto),
            align: center,
            ..data
        )
        
        // 动态内容示例
        #let calculate(n) = {
            if n < 1 { 0 } else { n * (n + 1) / 2 }
        }
        
        == 计算结果
        前5个三角数分别是: #{
            range(1, 6).map(n => str(calculate(n))).join(", ")
        }
    "#;
    
    // 评估模板
    match eval(&engine, template) {
        Ok(result) => {
            println!("生成的文档内容:\n{}", result);
        }
        Err(e) => {
            eprintln!("评估Typst模板时出错: {}", e);
        }
    }
}

这个完整示例展示了:

  1. 页面设置和文本样式配置
  2. 多级标题的使用
  3. 数学公式的嵌入
  4. 表格的创建和格式化
  5. 动态内容的计算和显示
  6. 错误处理的完善

1 回复

Rust文档处理库typst-eval的使用:高效解析与执行Typst模板的Rust插件库

介绍

typst-eval是一个用于解析和执行Typst模板的Rust库。Typst是一种现代化的文档排版系统,类似于LaTeX但更简单易用。typst-eval库允许开发者在Rust程序中嵌入和执行Typst模板,实现动态文档生成。

该库提供了以下核心功能:

  • 解析Typst模板语法
  • 执行模板中的表达式和逻辑
  • 处理Typst的数据模型
  • 与Rust数据结构交互

安装方法

在Cargo.toml中添加依赖:

[dependencies]
typst-eval = "0.7"  # 请使用最新版本

基本使用方法

1. 执行简单表达式

use typst_eval::eval_string;

fn main() {
    let result = eval_string("1 + 2 * 3").unwrap();
    println!("Result: {}", result); // 输出: Result: 7
}

2. 处理Typst模板

use typst_eval::{eval_template, Scope};

fn main() {
    let template = r#"
        #let name = "Alice"
        Hello, #name!
    "#;
    
    let mut scope = Scope::new();
    let output = eval_template(template, &mut scope).unwrap();
    println!("{}", output); // 输出: Hello, Alice!
}

3. 使用自定义变量

use typst_eval::{eval_template, Scope, Value};

fn main() {
    let template = r#"
        The calculated value is #value * 2
    "#;
    
    let mut scope = Scope::new();
    scope.set("value", Value::from(42));
    
    let output = eval_template(template, &mut scope).unwrap();
    println!("{}", output); // 输出: The calculated value is 84
}

高级功能

1. 使用自定义函数

use typst_eval::{eval_template, Scope, Value, Func};

fn double(args: &[Value]) -> Result<Value, String> {
    if let Some(num) = args.get(0).and_then(|v| v.as_f64()) {
        Ok(Value::from(num * 2.0))
    } else {
        Err("Expected a number".to_string())
    }
}

fn main() {
    let template = r#"
        #let double(x) = user::double(x)
        Double of 21 is #double(21)
    "#;
    
    let mut scope = Scope::new();
    scope.set("user::double", Func::new(double));
    
    let output = eval_template(template, &mut scope).unwrap();
    println!("{}", output); // 输出: Double of 21 is 42
}

2. 处理复杂数据结构

use typst_eval::{eval_template, Scope, Value, Dict};

fn main() {
    let template = r#"
        #let user = data.user
        Name: #user.name \
        Age: #user.age
    "#;
    
    let mut scope = Scope::new();
    let mut user = Dict::new();
    user.insert("name".into(), Value::from("Bob"));
    user.insert("age".into(), Value::from(30));
    
    let mut data = Dict::new();
    data.insert("user".into(), Value::Dict(user));
    scope.set("data", Value::Dict(data));
    
    let output = eval_template(template, &mut scope).unwrap();
    println!("{}", output); 
    // 输出: Name: Bob Age: 30
}

错误处理

typst-eval提供了详细的错误信息:

use typst_eval::eval_string;

fn main() {
    match eval_string("1 + 'text'") {
        Ok(result) => println!("Result: {}", result),
        Err(e) => println!("Error: {}", e),
        // 输出: Error: cannot add integer and string
    }
}

性能提示

  1. 对于重复执行的模板,可以预编译Scope对象
  2. 避免在循环中重复创建Scope
  3. 复杂计算考虑使用Rust实现后暴露给Typst

typst-eval是处理Typst模板的强大工具,特别适合需要将文档生成集成到Rust应用程序中的场景。

完整示例

以下是一个结合了基本使用和高级功能的完整示例:

use typst_eval::{eval_template, Scope, Value, Func, Dict};

// 自定义函数:将字符串转换为大写
fn to_uppercase(args: &[Value]) -> Result<Value, String> {
    if let Some(s) = args.get(0).and_then(|v| v.as_str()) {
        Ok(Value::from(s.to_uppercase()))
    } else {
        Err("Expected a string".to_string())
    }
}

fn main() {
    // 创建模板,包含变量、函数和复杂数据结构
    let template = r#"
        #let user = data.user
        #let upper(s) = user::to_upper(s)
        
        用户信息:
        - 姓名: #upper(user.name)
        - 年龄: #user.age
        - 状态: #if user.active { "活跃" } else { "不活跃" }
        - 分数: #calculate_score(user.scores)
    "#;
    
    // 创建作用域并设置自定义函数
    let mut scope = Scope::new();
    scope.set("user::to_upper", Func::new(to_uppercase));
    
    // 另一个自定义函数:计算平均分
    scope.set("calculate_score", Func::new(|args| {
        if let Some(scores) = args.get(0).and_then(|v| v.as_array()) {
            let sum: f64 = scores.iter()
                .filter_map(|v| v.as_f64())
                .sum();
            let avg = sum / scores.len() as f64;
            Ok(Value::from(avg.round() as i64))
        } else {
            Err("Expected an array of numbers".to_string())
        }
    }));
    
    // 准备复杂数据
    let mut user = Dict::new();
    user.insert("name".into(), Value::from("Bob"));
    user.insert("age".into(), Value::from(30));
    user.insert("active".into(), Value::from(true));
    user.insert("scores".into(), Value::from(vec![85, 90, 78]));
    
    let mut data = Dict::new();
    data.insert("user".into(), Value::Dict(user));
    scope.set("data", Value::Dict(data));
    
    // 执行模板
    match eval_template(template, &mut scope) {
        Ok(output) => println!("生成的文档:\n{}", output),
        Err(e) => println!("模板执行错误: {}", e),
    }
}

这个完整示例展示了:

  1. 使用自定义函数处理字符串
  2. 处理包含条件逻辑的模板
  3. 传递复杂数据结构(包含嵌套字典和数组)
  4. 在模板中使用Rust实现的复杂计算逻辑
  5. 综合错误处理

输出结果将是:

生成的文档:
用户信息:
- 姓名: BOB
- 年龄: 30
- 状态: 活跃
- 分数: 84
回到顶部