From acb2d1991c5c93fa65e7070e210190df2cedf238 Mon Sep 17 00:00:00 2001 From: Adrian Hedqvist Date: Sun, 18 Jun 2023 11:34:08 +0200 Subject: [PATCH] Code hilighting --- Cargo.lock | 145 +++++++++++++++++++++++++++++++++++++- Cargo.toml | 1 + posts/foldertest/index.md | 8 +++ src/hilighting.rs | 15 ++++ src/main.rs | 2 + src/markdown.rs | 55 +++++++++++++++ src/post.rs | 10 +-- templates/index.html | 3 +- 8 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 src/hilighting.rs create mode 100644 src/markdown.rs diff --git a/Cargo.lock b/Cargo.lock index ab505d0..f096aca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,6 +174,21 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -302,7 +317,7 @@ dependencies = [ "js-sys", "num-traits", "serde", - "time", + "time 0.1.45", "wasm-bindgen", "winapi", ] @@ -949,6 +964,21 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +[[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.1.4" @@ -1081,6 +1111,28 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "opentelemetry" version = "0.18.0" @@ -1344,6 +1396,20 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "plist" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" +dependencies = [ + "base64 0.21.2", + "indexmap", + "line-wrap", + "quick-xml", + "serde", + "time 0.3.22", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1407,6 +1473,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "quick-xml" +version = "0.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.28" @@ -1519,6 +1594,12 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[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" @@ -1698,6 +1779,29 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "syntect" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c454c27d9d7d9a84c7803aaa3c50cd088d2906fe3c6e42da3209aa623576a8" +dependencies = [ + "bincode", + "bitflags", + "flate2", + "fnv", + "lazy_static", + "once_cell", + "onig", + "plist", + "regex-syntax 0.6.29", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + [[package]] name = "tera" version = "1.19.0" @@ -1761,6 +1865,33 @@ dependencies = [ "winapi", ] +[[package]] +name = "time" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + [[package]] name = "tokio" version = "1.28.2" @@ -1867,7 +1998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d1d42a9b3f3ec46ba828e8d376aec14592ea199f70a06a548587ecd1c4ab658" dependencies = [ "async-compression", - "base64", + "base64 0.20.0", "bitflags", "bytes", "futures-core", @@ -2230,6 +2361,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", + "syntect", "tera", "tokio", "toml", @@ -2421,6 +2553,15 @@ 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 = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index e0e9386..a02ed35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ regex = "1.7.2" serde = "1.0.144" serde_derive = "1.0.144" serde_json = "1.0.85" +syntect = "5.0.0" tera = { version = "1.17.0", features = ["builtins"] } tokio = { version = "1.19.2", features = ["full"] } toml = "0.7.3" diff --git a/posts/foldertest/index.md b/posts/foldertest/index.md index 7c3a5b0..8515882 100644 --- a/posts/foldertest/index.md +++ b/posts/foldertest/index.md @@ -12,3 +12,11 @@ here have a squid kid miku to test relative paths: modified post test, see if docker skips build using its cache if only a post has changed. + +code hilighting test: + +```rs +fn main() { + println!("Hello world!") +} +``` diff --git a/src/hilighting.rs b/src/hilighting.rs new file mode 100644 index 0000000..60a3e74 --- /dev/null +++ b/src/hilighting.rs @@ -0,0 +1,15 @@ +use syntect::{highlighting::ThemeSet, parsing::SyntaxSet}; +use tracing::error; + +pub fn hilight(content: &str, lang: &str) -> color_eyre::Result { + let ss = SyntaxSet::load_defaults_newlines(); + let s = ss.find_syntax_by_extension(lang).unwrap_or_else(|| { + error!("Syntax not found for language: {}", lang); + ss.find_syntax_plain_text() + }); + let ts = ThemeSet::load_defaults(); + let theme = ts.themes.first_key_value().unwrap().1; // TODO + + let res = syntect::html::highlighted_html_for_string(content, &ss, s, theme)?; + Ok(res) +} diff --git a/src/main.rs b/src/main.rs index 413212a..754d4f4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,6 +14,8 @@ use tracing_subscriber::{prelude::*, EnvFilter}; mod feed; mod handlers; +mod hilighting; +mod markdown; mod post; mod tag; diff --git a/src/markdown.rs b/src/markdown.rs new file mode 100644 index 0000000..bc567cf --- /dev/null +++ b/src/markdown.rs @@ -0,0 +1,55 @@ +use color_eyre::Result; +use pulldown_cmark::Event; +use pulldown_cmark::Tag; +use pulldown_cmark::{Options, Parser}; + +use crate::hilighting; + +pub fn render_markdown_to_html(markdown: &str) -> Result { + let options = Options::all(); + let mut content_html = String::new(); + let parser = Parser::new_ext(markdown, options); + + let mut code_block = false; + let mut code_lang = None; + let mut code_accumulator = String::new(); + let mut events = Vec::new(); + for event in parser { + match event { + Event::Text(text) => { + if code_block { + code_accumulator.push_str(&text); + } + else { + events.push(Event::Text(text)); + } + } + Event::Start(Tag::CodeBlock(kind)) => { + code_block = true; + if let pulldown_cmark::CodeBlockKind::Fenced(lang) = kind { + code_lang = Some(lang); + } + } + Event::End(Tag::CodeBlock(_)) => { + code_block = false; + + let lang = code_lang.take().unwrap_or("".into()); + let res = hilighting::hilight(&code_accumulator, &lang).unwrap(); + + events.push(Event::Html(res.into())); + + code_accumulator.clear(); + } + _ => events.push(event), + } + } + + events.retain(|e| match e { + Event::Text(t) | Event::Html(t) => !t.is_empty(), + _ => true, + }); + + pulldown_cmark::html::push_html(&mut content_html, events.into_iter()); + + Ok(content_html) +} diff --git a/src/post.rs b/src/post.rs index 47e1b06..580e81e 100644 --- a/src/post.rs +++ b/src/post.rs @@ -11,7 +11,7 @@ use tokio::fs; use tracing::{instrument, log::*}; -use crate::{AppState, WebsiteError}; +use crate::{AppState, WebsiteError, markdown}; #[derive(Deserialize, Debug, Default)] pub struct TomlFrontMatter { @@ -103,12 +103,8 @@ pub async fn load_post(slug: &str) -> color_eyre::eyre::Result { let tomlfm = tomlfm.expect("Missing frontmatter"); let content = content.map(|c| { - let options = Options::all(); - let mut content_html = String::new(); - let parser = Parser::new_ext(&c, options); - html::push_html(&mut content_html, parser); - content_html - }); + markdown::render_markdown_to_html(&c) + }).transpose()?; Ok(Post::new( slug.to_string(), diff --git a/templates/index.html b/templates/index.html index b26941c..f777895 100644 --- a/templates/index.html +++ b/templates/index.html @@ -12,9 +12,10 @@
  • ✅ app metrics (page hits, etc)
  • ✅ tests
  • ✅ page aliases (redirects, for back-compat with old routes)
  • -
  • ⬜ sass compilation (using rsass? grass?)
  • ✅ rss/atom/jsonfeed (atom is good enough for now)
  • ✅ proper error handling (i guess??)
  • +
  • ✅ code hilighting? (good enough for now, gotta figure out themes n' stuff later)
  • +
  • ⬜ sass compilation (using rsass? grass?)
  • ⬜ fancy styling
  • ⬜ other pages???
  • ⬜ graphviz to svg rendering??