diff --git a/Cargo.lock b/Cargo.lock index ec3a755..1167be8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,13 +71,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -198,7 +198,6 @@ dependencies = [ "axum-sqlx-tx", "chrono", "dotenv", - "highlight-pulldown", "horrorshow", "once_cell", "pulldown-cmark", @@ -206,6 +205,7 @@ dependencies = [ "serde", "shared_data", "sitewriter", + "syntect", "tokio", "tower", "tower-sessions", @@ -681,7 +681,7 @@ checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -724,15 +724,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - [[package]] name = "getrandom" version = "0.2.11" @@ -1116,7 +1107,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1178,17 +1169,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "highlight-pulldown" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eb649350bc7d5e1b8770777d0ae848357ae685f09c112b8b9102a10acffa5d6" -dependencies = [ - "pulldown-cmark", - "syntect", - "thiserror", -] - [[package]] name = "hkdf" version = "0.12.4" @@ -1300,9 +1280,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +checksum = "bdea9aac0dbe5a9240d68cfd9501e2db94222c6dc06843e06640b9e07f0fdc67" dependencies = [ "bytes", "futures-channel", @@ -1313,8 +1293,6 @@ dependencies = [ "pin-project-lite", "socket2", "tokio", - "tower", - "tower-service", "tracing", ] @@ -1374,7 +1352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" dependencies = [ "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1417,21 +1395,6 @@ version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -1667,7 +1630,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1695,23 +1658,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "plist" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" -dependencies = [ - "base64 0.21.5", - "indexmap", - "line-wrap", - "quick-xml 0.31.0", - "serde", - "time", -] +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "powerfmt" @@ -1732,7 +1681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -1771,9 +1720,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" +checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] @@ -1802,7 +1751,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" dependencies = [ "bitflags 1.3.2", - "getopts", "memchr", "unicase", ] @@ -1970,12 +1918,6 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - [[package]] name = "same-file" version = "1.0.6" @@ -2040,7 +1982,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2329,9 +2271,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.41" +version = "2.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" +checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" dependencies = [ "proc-macro2", "quote", @@ -2356,13 +2298,11 @@ dependencies = [ "fnv", "once_cell", "onig", - "plist", "regex-syntax", "serde", "serde_json", "thiserror", "walkdir", - "yaml-rust", ] [[package]] @@ -2395,14 +2335,14 @@ checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] name = "time" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" dependencies = [ "deranged", "itoa", @@ -2420,9 +2360,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" dependencies = [ "time-core", ] @@ -2444,9 +2384,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.0" +version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d45b238a16291a4e1584e61820b8ae57d696cc5015c459c229ccc6990cc1c" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", @@ -2467,7 +2407,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2525,7 +2465,6 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] @@ -2621,7 +2560,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -2675,12 +2614,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -2763,7 +2696,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "wasm-bindgen-shared", ] @@ -2797,7 +2730,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3011,15 +2944,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "yew" version = "0.21.0" @@ -3057,7 +2981,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] @@ -3087,25 +3011,25 @@ checksum = "42bfd190a07ca8cfde7cd4c52b3ac463803dc07323db8c34daa697e86365978c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] [[package]] name = "zerocopy" -version = "0.7.31" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c4061bedbb353041c12f413700357bec76df2c7e2ca8e4df8bac24c6bf68e3d" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.31" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3c129550b3e6de3fd0ba67ba5c81818f9805e58b8d7fee80a3a59d2c9fc601a" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.41", + "syn 2.0.42", ] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index bbb826f..496c7e6 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -17,7 +17,7 @@ tower = { version = "0.4.13", default-features = false } axum-auth = { version = "0.7.0", default-features = false, features = ["auth-basic"] } argon2 = { version = "0.5.2", features = ["std"] } tower-sessions = "0.7.0" -highlight-pulldown = "0.2.2" +syntect = { version = "5.1.0", default-features = false, features = ["default-themes", "parsing", "default-syntaxes", "html", "regex-onig"] } horrorshow = { version = "0.8.4", default-features = false, features = ["std", "ops"] } once_cell = { version = "1.19.0", default-features = false } rss = { version = "2.0.6", default-features = false } diff --git a/backend/src/main.rs b/backend/src/main.rs index 41cab0d..949a991 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -22,7 +22,6 @@ use tower_sessions::{ use serde::Deserialize; use axum_sqlx_tx::Tx; use images::{upload_asset, get_asset}; -use pulldown_cmark as md; use shared_data::{ Post, PostReq, @@ -47,6 +46,7 @@ mod home; mod post_list; mod post; mod robots; +mod md_to_html; #[macro_export] macro_rules! print_and_ret{ @@ -434,20 +434,7 @@ struct SqlPostDetails { // Returns an err string or (Text, HTML, Title, Tags) fn post_details(payload: PostReq) -> SqlPostDetails { let PostReq { content, title, tags, draft } = payload; - let parser = md::Parser::new_ext(&content, md::Options::all()); - - // This only errors on an unknown theme, so we can safely unwrap here - let events = highlight_pulldown::highlight_with_theme(parser, "base16-ocean.dark").unwrap(); - - let mut html = String::new(); - - // So it would be smart to sanitize the html to make sure that XSS and stuff like that isn't - // supported but it's my website and I think it's fun to have the option of doing fun little - // stuff with javascript if I would so like, and this input is already trusted (since only - // logged-in users can access this API and I am the only user) so I don't see the need to - // sanitize very strongly - md::html::push_html(&mut html, events.into_iter()); - + let html = md_to_html::md_to_html(&content); SqlPostDetails { content, html, title, draft, tags: tags.join(",") } } diff --git a/backend/src/md_to_html.rs b/backend/src/md_to_html.rs new file mode 100644 index 0000000..20d7537 --- /dev/null +++ b/backend/src/md_to_html.rs @@ -0,0 +1,79 @@ +use syntect::{ + highlighting::{Color, ThemeSet}, + parsing::SyntaxSet, + html::{append_highlighted_html_for_styled_line, IncludeBackground}, + easy::HighlightLines, + util::LinesWithEndings, +}; +use pulldown_cmark::{Event, Tag, CodeBlockKind, CowStr}; + +pub fn md_to_html(input: &str) -> String { + let events = pulldown_cmark::Parser::new_ext(input, pulldown_cmark::Options::all()); + + // This only errors on an unknown theme, so we can safely unwrap here + let themeset = ThemeSet::load_defaults(); + let theme = themeset.themes + .get("base16-ocean.dark") + .unwrap(); + let syntax_set = SyntaxSet::load_defaults_newlines(); + + // kinda reimplimenting highlight_pulldown::PulldownHighlighter::highlight + // so that we can do
 instead of just 
+	let mut in_code_block = false;
+	let mut syntax = syntax_set.find_syntax_plain_text();
+	let mut to_highlight = String::new();
+
+	let events = events.flat_map(|ev| match ev {
+		Event::Start(Tag::CodeBlock(kind)) => {
+			if let CodeBlockKind::Fenced(lang) = kind {
+				if let Some(syn) = syntax_set.find_syntax_by_token(&lang) {
+					syntax = syn;
+				}
+			}
+			in_code_block = true;
+			None
+		},
+		Event::End(Tag::CodeBlock(_)) => {
+			let mut highlighter = HighlightLines::new(syntax, theme);
+			let color = theme.settings.background.unwrap_or(Color::BLACK);
+			let lang = syntax.name.to_lowercase();
+			let mut output = format!(
+				"
\n",
+				color.r, color.g, color.b,
+			);
+
+			for line in LinesWithEndings::from(&to_highlight) {
+				// if we fail to highlight, it's kinda whatever
+				if let Ok(regions) = highlighter.highlight_line(line, &syntax_set) {
+					_ = append_highlighted_html_for_styled_line(
+						®ions[..], 
+						IncludeBackground::IfDifferent(color),
+						&mut output
+					)
+				}
+			}
+
+			output.push_str("
\n"); + + to_highlight.clear(); + in_code_block = false; + Some(Event::Html(CowStr::from(output))) + }, + Event::Text(t) if in_code_block => { + to_highlight.push_str(&t); + None + }, + e => Some(e) + }); + + let mut html = String::new(); + + // So it would be smart to sanitize the html to make sure that XSS and stuff like that isn't + // supported but it's my website and I think it's fun to have the option of doing fun little + // stuff with javascript if I would so like, and this input is already trusted (since only + // logged-in users can access this API and I am the only user) so I don't see the need to + // sanitize very strongly + pulldown_cmark::html::push_html(&mut html, events); + + html +} diff --git a/shared_data/src/lib.rs b/shared_data/src/lib.rs index e579687..85b7680 100644 --- a/shared_data/src/lib.rs +++ b/shared_data/src/lib.rs @@ -114,7 +114,7 @@ pre { overflow: auto; -webkit-text-size-adjust: 140%; } -pre > span, code { +pre span, code { font-family: Courier; } ";