add: use pulldown-cmark instead
This commit is contained in:
parent
3f70a8f465
commit
fe2e61118a
5 changed files with 68 additions and 56 deletions
53
Cargo.lock
generated
53
Cargo.lock
generated
|
@ -955,6 +955,15 @@ dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getopts"
|
||||||
|
version = "0.2.23"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
|
@ -1743,15 +1752,6 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "markdown"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a5cab8f2cadc416a82d2e783a1946388b31654d391d1c7d92cc1f03e295b1deb"
|
|
||||||
dependencies = [
|
|
||||||
"unicode-id",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "markup5ever"
|
name = "markup5ever"
|
||||||
version = "0.35.0"
|
version = "0.35.0"
|
||||||
|
@ -2355,6 +2355,25 @@ dependencies = [
|
||||||
"syn 2.0.101",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.9.1",
|
||||||
|
"getopts",
|
||||||
|
"memchr",
|
||||||
|
"pulldown-cmark-escape",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pulldown-cmark-escape"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "qoi"
|
name = "qoi"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
@ -3334,12 +3353,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tetratto-shared"
|
name = "tetratto-shared"
|
||||||
version = "12.0.1"
|
version = "12.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ammonia",
|
"ammonia",
|
||||||
"chrono",
|
"chrono",
|
||||||
"hex_fmt",
|
"hex_fmt",
|
||||||
"markdown",
|
"pulldown-cmark",
|
||||||
"rand 0.9.1",
|
"rand 0.9.1",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
@ -3871,12 +3890,6 @@ version = "0.3.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-id"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
@ -3898,6 +3911,12 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
|
@ -36,12 +36,13 @@ pub(crate) type InnerState = (DataManager, Tera, Client, Option<StripeClient>);
|
||||||
pub(crate) type State = Arc<RwLock<InnerState>>;
|
pub(crate) type State = Arc<RwLock<InnerState>>;
|
||||||
|
|
||||||
fn render_markdown(value: &Value, _: &HashMap<String, Value>) -> tera::Result<Value> {
|
fn render_markdown(value: &Value, _: &HashMap<String, Value>) -> tera::Result<Value> {
|
||||||
Ok(
|
Ok(tetratto_shared::markdown::render_markdown(
|
||||||
tetratto_shared::markdown::render_markdown(&CustomEmoji::replace(value.as_str().unwrap()))
|
&CustomEmoji::replace(value.as_str().unwrap()),
|
||||||
|
true,
|
||||||
|
)
|
||||||
.replace("\\@", "@")
|
.replace("\\@", "@")
|
||||||
.replace("%5C@", "@")
|
.replace("%5C@", "@")
|
||||||
.into(),
|
.into())
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_emojis(value: &Value, _: &HashMap<String, Value>) -> tera::Result<Value> {
|
fn render_emojis(value: &Value, _: &HashMap<String, Value>) -> tera::Result<Value> {
|
||||||
|
|
|
@ -267,7 +267,7 @@ pub async fn delete_by_dir_request(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn render_markdown_request(Json(req): Json<RenderMarkdown>) -> impl IntoResponse {
|
pub async fn render_markdown_request(Json(req): Json<RenderMarkdown>) -> impl IntoResponse {
|
||||||
tetratto_shared::markdown::render_markdown(&CustomEmoji::replace(&req.content))
|
tetratto_shared::markdown::render_markdown(&CustomEmoji::replace(&req.content), true)
|
||||||
.replace("\\@", "@")
|
.replace("\\@", "@")
|
||||||
.replace("%5C@", "@")
|
.replace("%5C@", "@")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tetratto-shared"
|
name = "tetratto-shared"
|
||||||
description = "Shared stuff for Tetratto"
|
description = "Shared stuff for Tetratto"
|
||||||
version = "12.0.1"
|
version = "12.0.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
@ -10,8 +10,8 @@ license.workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ammonia = "4.1.1"
|
ammonia = "4.1.1"
|
||||||
chrono = "0.4.41"
|
chrono = "0.4.41"
|
||||||
markdown = "1.0.0"
|
|
||||||
hex_fmt = "0.3.0"
|
hex_fmt = "0.3.0"
|
||||||
|
pulldown-cmark = "0.13.0"
|
||||||
rand = "0.9.1"
|
rand = "0.9.1"
|
||||||
serde = { version = "1.0.219", features = ["derive"] }
|
serde = { version = "1.0.219", features = ["derive"] }
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
|
|
|
@ -1,37 +1,24 @@
|
||||||
use ammonia::Builder;
|
use ammonia::Builder;
|
||||||
use markdown::{to_html_with_options, Options, CompileOptions, ParseOptions, Constructs};
|
use pulldown_cmark::{Parser, Options, html::push_html};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
/// Render markdown input into HTML
|
/// Render markdown input into HTML
|
||||||
pub fn render_markdown(input: &str) -> String {
|
pub fn render_markdown(input: &str, proxy_images: bool) -> String {
|
||||||
let input = &parse_alignment(input);
|
let input = &parse_alignment(input);
|
||||||
let options = Options {
|
|
||||||
compile: CompileOptions {
|
|
||||||
allow_any_img_src: false,
|
|
||||||
allow_dangerous_html: true,
|
|
||||||
allow_dangerous_protocol: true,
|
|
||||||
gfm_task_list_item_checkable: false,
|
|
||||||
gfm_tagfilter: false,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
parse: ParseOptions {
|
|
||||||
constructs: Constructs {
|
|
||||||
math_flow: true,
|
|
||||||
math_text: true,
|
|
||||||
..Constructs::gfm()
|
|
||||||
},
|
|
||||||
gfm_strikethrough_single_tilde: false,
|
|
||||||
math_text_single_dollar: false,
|
|
||||||
mdx_expression_parse: None,
|
|
||||||
mdx_esm_parse: None,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let html = match to_html_with_options(input, &options) {
|
let mut options = Options::empty();
|
||||||
Ok(h) => h,
|
options.insert(Options::ENABLE_STRIKETHROUGH);
|
||||||
Err(e) => e.to_string(),
|
options.insert(Options::ENABLE_GFM);
|
||||||
};
|
options.insert(Options::ENABLE_FOOTNOTES);
|
||||||
|
options.insert(Options::ENABLE_TABLES);
|
||||||
|
options.insert(Options::ENABLE_HEADING_ATTRIBUTES);
|
||||||
|
options.insert(Options::ENABLE_SUBSCRIPT);
|
||||||
|
options.insert(Options::ENABLE_SUPERSCRIPT);
|
||||||
|
|
||||||
|
let parser = Parser::new_ext(input, options);
|
||||||
|
|
||||||
|
let mut html = String::new();
|
||||||
|
push_html(&mut html, parser);
|
||||||
|
|
||||||
let mut allowed_attributes = HashSet::new();
|
let mut allowed_attributes = HashSet::new();
|
||||||
allowed_attributes.insert("id");
|
allowed_attributes.insert("id");
|
||||||
|
@ -43,7 +30,7 @@ pub fn render_markdown(input: &str) -> String {
|
||||||
allowed_attributes.insert("align");
|
allowed_attributes.insert("align");
|
||||||
allowed_attributes.insert("src");
|
allowed_attributes.insert("src");
|
||||||
|
|
||||||
Builder::default()
|
let output = Builder::default()
|
||||||
.generic_attributes(allowed_attributes)
|
.generic_attributes(allowed_attributes)
|
||||||
.add_tags(&[
|
.add_tags(&[
|
||||||
"video", "source", "img", "b", "span", "p", "i", "strong", "em", "a", "align",
|
"video", "source", "img", "b", "span", "p", "i", "strong", "em", "a", "align",
|
||||||
|
@ -53,11 +40,16 @@ pub fn render_markdown(input: &str) -> String {
|
||||||
.add_url_schemes(&["atto"])
|
.add_url_schemes(&["atto"])
|
||||||
.clean(&html)
|
.clean(&html)
|
||||||
.to_string()
|
.to_string()
|
||||||
.replace(
|
.replace("<video loading=", "<video controls loading=");
|
||||||
|
|
||||||
|
if proxy_images {
|
||||||
|
output.replace(
|
||||||
"src=\"http",
|
"src=\"http",
|
||||||
"loading=\"lazy\" src=\"/api/v1/util/proxy?url=http",
|
"loading=\"lazy\" src=\"/api/v1/util/proxy?url=http",
|
||||||
)
|
)
|
||||||
.replace("<video loading=", "<video controls loading=")
|
} else {
|
||||||
|
output
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_alignment_line(line: &str, output: &mut String, buffer: &mut String, is_in_pre: bool) {
|
fn parse_alignment_line(line: &str, output: &mut String, buffer: &mut String, is_in_pre: bool) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue