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的设计遵循三个核心原则:
- 通过一致性实现简单性:Typst的设计保持一致性,使知识可以轻松迁移
- 通过可组合性实现强大功能:提供可以组合的系统,而不仅仅是拥有各种开关
- 通过增量性实现性能:所有语言特性都考虑增量编译
社区
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 回复
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
}
}
性能提示
- 对于重复执行的模板,可以预编译Scope对象
- 避免在循环中重复创建Scope
- 复杂计算考虑使用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),
}
}
这个完整示例展示了:
- 使用自定义函数处理字符串
- 处理包含条件逻辑的模板
- 传递复杂数据结构(包含嵌套字典和数组)
- 在模板中使用Rust实现的复杂计算逻辑
- 综合错误处理
输出结果将是:
生成的文档:
用户信息:
- 姓名: BOB
- 年龄: 30
- 状态: 活跃
- 分数: 84