轻量级标记语言 markdown 现今不仅在程序员范围内流行,很多的其它行业人员也对 markdown 青睐有加。因此现在的 web 应用中,富文本编辑器越来越多的支持 markdown 语法格式,以及即时渲染功能。在存储时,数据库中存入轻量级标记语言 markdown 文档,方便后续导出再做它用的排版。也可以直接数据库中存入渲染后的 html 文档,对 API 调用者提供方便(如格式和验证等)。
Rust 中,对于将 markdown 渲染为 html 方面,目前成熟度较高的 crate 主要有 2 个:markdown.rs
和 pulldown-cmark
。功能都非常完善和强大:支持解析文档注脚(footnote)、github 风格的表格、github 风格的任务列表,以及删除线效果(strikethrough)等,但要主要支持是选择性地。
性能方面,或许测试体量不足,笔者测试感觉差别不大。前者 markdown.rs
稍微简单易用一些。后者 pulldown-cmark
专注于 CommonMark
,默认提供命令行工具。采用拉取解析(pull parse)模式,其为 Rust 开发的书籍工具 mdBook
所使用。
我们下面通过实例体验一下,这些代码都是完整可用于生产环境的。
markdown.rs
markdown.rs 使用非常简单:
代码语言:javascript复制use markdown;
// 如果您没有异步库 async-std 依赖项,
// 请替换下述前 2 行代码为
// fn main() {
#[async_std::main]
async fn main() {
let html: String = markdown::to_html("__我是 *markdown*__");
assert_eq!(&html, "<p><strong>我是 <em>markdown</em></strong></p>n")
}
也可以通过读入 markdown 文件来解析。如我们有一个 markdown 文档 code.md
:
# Rust 代码
这是 Tide 中对 **cookie** 进行增、删的例子。
``` Rust
use tide::http::Cookie;
use tide::{Request, Response, StatusCode};
/// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter.
async fn insert_cookie(_req: Request<()>) -> tide::Result {
let mut res = Response::new(StatusCode::Ok);
res.insert_cookie(Cookie::new("hello", "world"));
Ok(res)
}
async fn remove_cookie(_req: Request<()>) -> tide::Result {
let mut res = Response::new(StatusCode::Ok);
res.remove_cookie(Cookie::named("hello"));
Ok(res)
}
```
我们通过 Rust 标准库的文件模块读入 code.md
并将其转换为 html。
use markdown;
use std::path::Path;
// 如果您没有异步库 async-std 依赖项,
// 请替换下述前 2 行代码为
// fn main() {
#[async_std::main]
async fn main() {
let md = Path::new("./code.md");
let html = markdown::file_to_html(md);
println!("{:#?}", &html);
}
输出的 html 为:
代码语言:javascript复制<h1>Rust 代码</h1>
<p>这是 Tide 中对 <strong>cookie</strong> 进行增、删的例子。</p>
<pre><code class="language-Rust">use tide::http::Cookie;
use tide::{Request, Response, StatusCode};
/// Tide will use the the `Cookies`'s `Extract` implementation to build this parameter.
async fn insert_cookie(_req: Request<()>) -> tide::Result {
let mut res = Response::new(StatusCode::Ok);
res.insert_cookie(Cookie::new("hello", "world"));
Ok(res)
}
async fn remove_cookie(_req: Request<()>) -> tide::Result {
let mut res = Response::new(StatusCode::Ok);
res.remove_cookie(Cookie::named("hello"));
Ok(res)
}
</code></pre>
若我们在其顶部引入 highlight.js
代码高亮库和 night-owl.css
样式,即可达到生产环境使用的效果。
当然,也可以通过 markdown.rs
渲染 markdown 文档为 html 后,直接通过 file 模块将其存为文件。
pulldown-cmark
pulldown-cmark
是为 CommonMark 实现的拉取模式的解析器,通过事件迭代来驱动推送。笔者在生产环境中主要以 pulldown-cmark
来进行 markdown 文档到 html 的渲染。pulldown-cmark
的代码稍微复杂一些,但特性也更丰富一些。
比如删除线(strikethrough)效果并非 CommonMark 标准的一部分,而是 github 风格的 markdown 语法,因此我们必须明确地启用它。
代码语言:javascript复制use pulldown_cmark::{Parser, Options, html};
let markdown_input = "各位,请查看~~删除线~~*效果*的示例。";
// 设定解析器选项,包括 5 个等级,
// `ENABLE_STRIKETHROUGH` 为第三等级,包括删除线效果。
let mut options = Options::empty();
options.insert(Options::ENABLE_STRIKETHROUGH);
let parser = Parser::new_ext(markdown_input, options);
// 写入字符串缓冲区
let mut html_output = String::new();
html::push_html(&mut html_output, parser);
// 检查输出是否符合预期
let expected_html = "<p>各位,请查看<del>删除线</del><em>效果</em>的示例。</p>n";
assert_eq!(expected_html, &html_output);
文章的开始提到,pulldown-cmark
默认提供命令行工具。因此,对于 markdown 文件的读入解析和渲染,一种是通过命令行。在服务器端代码中,还可以直接将文件读入到字符串,然后进行解析渲染为 html。
本文主要介绍 markdown 渲染为 html,对于 html 渲染为 markdown,也是同样简单的,都是如同 markdown.rs
的实现方法,一行代码即可。
谢谢您的阅读。