Rust铁路图生成库railroad的使用,可高效创建语法图和流程图的可视化工具

Rust铁路图生成库railroad的使用,可高效创建语法图和流程图的可视化工具

railroad是一个用于创建语法铁路图(railroad diagram)的Rust库,可以生成可缩放矢量图形(SVG)。铁路图是一种表示上下文无关语法的方式,每个图表都有唯一的起点和终点,描述的语言中的所有内容都表示为这些点之间的可能路径之一。

基本使用

使用这个库时,通过实现Node的基元来创建图表。通过将简单元素包装成更复杂的结构来组合成更复杂的结构。

use railroad::*;

let mut seq = Sequence::default();
seq.push(Box::new(Start) as Box<dyn Node>)
   .push(Box::new(Terminal::new("BEGIN".to_owned())))
   .push(Box::new(NonTerminal::new("syntax".to_owned())))
   .push(Box::new(End));

let mut dia = Diagram::new(seq);

dia.add_element(svg::Element::new("style")
                .set("type", "text/css")
                .text(DEFAULT_CSS));

println!("{}", dia);

完整示例

下面是一个更完整的示例,展示如何创建更复杂的语法图:

use railroad::*;

fn main() {
    // 创建一个选择结构(或分支)
    let mut choice = Choice::new(0);
    choice.push(Box::new(Terminal::new("if".to_owned())));
    choice.push(Box::new(Terminal::new("unless".to_owned())));
    
    // 创建一个可选结构
    let optional = Optional::new(
        Box::new(NonTerminal::new("condition".to_owned()))
    );
    
    // 创建一个序列
    let mut seq = Sequence::default();
    seq.push(Box::new(Start));
    seq.push(Box::new(choice));
    seq.push(Box::new(optional));
    seq.push(Box::new(Terminal::new("then".to_owned())));
    seq.push(Box::new(NonTerminal::new("expression".to_owned())));
    seq.push(Box::new(End));
    
    // 创建图表并添加样式
    let mut dia = Diagram::new(seq);
    dia.add_element(
        svg::Element::new("style")
            .set("type", "text/css")
            .text(DEFAULT_CSS)
    );
    
    // 输出SVG
    println!("{}", dia);
}

调试功能

当向这个库添加新的Node基元时,可以使用examples/visual.rs快速生成特殊情况并检查它们是否正确渲染。使用visual-debug功能可以在渲染的图表中添加参考线和SVG代码中的额外信息。

安装

在项目中添加以下依赖到Cargo.toml:

railroad = "0.3.3"

或者运行:

cargo add railroad

railroad库采用MIT许可证,是一个轻量级(24.6 KiB)的Rust库,非常适合用于生成语法图、流程图等可视化工具。

完整示例demo

下面是一个更详细的示例,展示如何创建一个SQL SELECT语句的铁路图:

use railroad::*;

fn main() {
    // 创建SELECT子句
    let select_clause = {
        let mut seq = Sequence::default();
        seq.push(Box::new(Terminal::new("SELECT".to_owned())));
        seq.push(Box::new(NonTerminal::new("columns".to_owned())));
        seq
    };
    
    // 创建FROM子句
    let from_clause = {
        let mut seq = Sequence::default();
        seq.push(Box::new(Terminal::new("FROM".to_owned())));
        seq.push(Box::new(NonTerminal::new("tables".to_owned())));
        seq
    };
    
    // 创建WHERE子句(可选)
    let where_clause = Optional::new(
        Box::new({
            let mut seq = Sequence::default();
            seq.push(Box::new(Terminal::new("WHERE".to_owned())));
            seq.push(Box::new(NonTerminal::new("condition".to_owned())));
            seq
        })
    );
    
    // 创建GROUP BY子句(可选)
    let group_by_clause = Optional::new(
        Box::new({
            let mut seq = Sequence::default();
            seq.push(Box::new(Terminal::new("GROUP BY".to_owned())));
            seq.push(Box::new(NonTerminal::new("columns".to_owned())));
            seq
        })
    );
    
    // 创建完整的SQL语句
    let mut sql_stmt = Sequence::default();
    sql_stmt.push(Box::new(Start));
    sql_stmt.push(Box::new(select_clause));
    sql_stmt.push(Box::new(from_clause));
    sql_stmt.push(Box::new(where_clause));
    sql_stmt.push(Box::new(group_by_clause));
    sql_stmt.push(Box::new(End));
    
    // 创建图表并添加样式
    let mut diagram = Diagram::new(sql_stmt);
    diagram.add_element(
        svg::Element::new("style")
            .set("type", "text/css")
            .text(DEFAULT_CSS)
    );
    
    // 输出SVG
    println!("{}", diagram);
}

这个示例展示了如何创建一个包含多个可选子句的SQL SELECT语句的铁路图。代码中使用了Sequence来组合多个元素,并使用Optional来表示可选的子句。


1 回复

Rust铁路图生成库railroad使用指南

railroad是一个用于生成语法图和流程图的Rust库,它能够创建类似铁路轨道图(railroad diagram)的可视化图表,常用于编程语言文档中的语法表示。

安装

在Cargo.toml中添加依赖:

[dependencies]
railroad = "0.3"

基本用法

1. 创建简单流程图

use railroad::*;

let diagram = Diagram::new(
    Sequence::new(vec![
        Terminal::new("Start".into()),
        Box::new(Choice::new(0, vec![
            Terminal::new("Option 1".into()),
            Terminal::new("Option 2".into()),
        ])),
        Terminal::new("End".into()),
    ])
);

// 输出SVG
let svg = diagram.to_svg().to_string();
println!("{}", svg);

2. 语法图示例

use railroad::*;

// 创建一个简单的赋值语句语法图
let assignment = Diagram::new(
    Sequence::new(vec![
        NonTerminal::new("identifier".into()),
        Terminal::new("=".into()),
        Box::new(Choice::new(0, vec![
            NonTerminal::new("expression".into()),
            NonTerminal::new("function_call".into()),
        ])),
        Terminal::new(";".into()),
    ])
);

let svg = assignment.to_svg().to_string();

主要组件

railroad提供了多种组件来构建图表:

  • Terminal: 矩形框,表示终结符
  • NonTerminal: 圆角矩形,表示非终结符
  • Comment: 小字体文本,用于注释
  • Sequence: 顺序连接多个元素
  • Choice: 分支选择(类似或关系)
  • Optional: 可选元素
  • OneOrMore: 一个或多个重复
  • ZeroOrMore: 零个或多个重复
  • Stack: 垂直堆叠元素

高级用法

自定义样式

use railroad::*;

let mut style = StyleSheet::default();
style.symbol.terminal.border_radius = 5.0;
style.symbol.non_terminal.fill = Some("#e6f3ff".into());

let diagram = Diagram::with_style(
    Sequence::new(vec![
        Terminal::new("Start".into()),
        NonTerminal::new("Process".into()),
        Terminal::new("End".into()),
    ]),
    style
);

复杂语法图示例

use railroad::*;

let if_statement = Diagram::new(
    Sequence::new(vec![
        Terminal::new("if".into()),
        Terminal::new("(".into()),
        NonTerminal::new("condition".into()),
        Terminal::new(")".into()),
        NonTerminal::new("statement".into()),
        Box::new(Optional::new(
            Sequence::new(vec![
                Terminal::new("else".into()),
                NonTerminal::new("statement".into()),
            ])
        )),
    ])
);

输出选项

railroad支持多种输出方式:

// 输出SVG字符串
let svg_string = diagram.to_svg().to_string();

// 写入文件
use std::fs::File;
use std::io::Write;

let mut file = File::create("diagram.svg").unwrap();
file.write_all(diagram.to_svg().to_string().as_bytes()).unwrap();

实际应用场景

  1. 编程语言文档中的语法描述
  2. 复杂流程的可视化
  3. 正则表达式语法图解
  4. 数据格式规范描述

railroad库特别适合需要自动生成语法图的场景,可以轻松集成到文档生成流程中。

完整示例

下面是一个完整的函数调用语法图示例:

use railroad::*;

fn main() {
    // 创建函数调用语法图
    let function_call = Diagram::new(
        Sequence::new(vec![
            NonTerminal::new("function_name".into()),
            Terminal::new("(".into()),
            Box::new(Optional::new(
                Sequence::new(vec![
                    NonTerminal::new("argument".into()),
                    Box::new(ZeroOrMore::new(
                        Sequence::new(vec![
                            Terminal::new(",".into()),
                            NonTerminal::new("argument".into()),
                        ])
                    ))
                ])
            )),
            Terminal::new(")".into()),
            Terminal::new(";".into()),
        ])
    );

    // 自定义样式
    let mut style = StyleSheet::default();
    style.symbol.terminal.fill = Some("#f0f0f0".into());
    style.symbol.non_terminal.fill = Some("#e6f3ff".into());
    style.symbol.comment.font_size = 10.0;
    
    // 应用样式
    let styled_diagram = Diagram::with_style(function_call, style);
    
    // 输出到文件
    let mut file = std::fs::File::create("function_call.svg").unwrap();
    file.write_all(styled_diagram.to_svg().to_string().as_bytes()).unwrap();
    
    println!("SVG diagram saved to function_call.svg");
}

这个示例展示了如何:

  1. 创建函数调用语法图
  2. 使用Optional和ZeroOrMore组件表示可选参数和多个参数
  3. 自定义图表样式
  4. 将生成的SVG图表保存到文件
回到顶部