Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
|
ac7ce64408 | |
|
d496efe835 |
|
@ -17,6 +17,15 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
|
@ -32,6 +41,16 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi-to-html"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d73c455ae09fa2223a75114789f30ad605e9e297f79537953523366c05995f5f"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.15"
|
||||
|
@ -168,15 +187,39 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "blog-thing"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ansi-to-html",
|
||||
"axum",
|
||||
"chrono",
|
||||
"clap",
|
||||
"markdown",
|
||||
"syntect",
|
||||
"tokio",
|
||||
"two-face",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -272,6 +315,40 @@ version = "0.8.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -326,6 +403,12 @@ version = "0.31.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
|
@ -442,6 +525,16 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
|
@ -469,6 +562,12 @@ version = "0.2.159"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
|
@ -523,6 +622,12 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
|
@ -550,6 +655,28 @@ dependencies = [
|
|||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[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 = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
|
@ -568,12 +695,37 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"indexmap",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
|
@ -583,6 +735,15 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
|
@ -592,6 +753,35 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
|
@ -610,6 +800,15 @@ version = "1.0.18"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
|
@ -715,6 +914,79 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
|
||||
|
||||
[[package]]
|
||||
name = "syntect"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"bitflags",
|
||||
"flate2",
|
||||
"fnv",
|
||||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.40.0"
|
||||
|
@ -789,6 +1061,17 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "two-face"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ccd4843ea031c609fe9c16cae00e9657bad8a9f735a3cc2e420955d802b4268"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"serde",
|
||||
"syntect",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-id"
|
||||
version = "0.3.5"
|
||||
|
@ -807,6 +1090,16 @@ version = "0.2.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -868,6 +1161,15 @@ version = "0.2.93"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
|
@ -949,3 +1251,12 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -4,8 +4,11 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
ansi-to-html = "0.2.1"
|
||||
axum = "0.7.7"
|
||||
chrono = "0.4.38"
|
||||
clap = { version = "4.5.18", features = ["derive", "env"] }
|
||||
markdown = "1.0.0-alpha.21"
|
||||
syntect = "5.2.0"
|
||||
tokio = { version = "1.40.0", features = [ "rt-multi-thread" ] }
|
||||
two-face = "0.4.0"
|
||||
|
|
256
src/main.rs
256
src/main.rs
|
@ -5,14 +5,24 @@ use axum::{
|
|||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||
use clap::Parser;
|
||||
use markdown::ParseOptions;
|
||||
use std::{collections::HashMap, path::PathBuf, sync::Arc};
|
||||
use syntect::{
|
||||
highlighting::{Theme, ThemeSet},
|
||||
html::highlighted_html_for_string,
|
||||
parsing::{SyntaxSet, SyntaxSetBuilder},
|
||||
};
|
||||
use two_face::theme::EmbeddedLazyThemeSet;
|
||||
|
||||
#[derive(Debug)]
|
||||
// #[derive(Debug)]
|
||||
struct BlogState {
|
||||
templates: HashMap<String, Cached<Template>>,
|
||||
posts: HashMap<String, Cached<Post>>,
|
||||
|
||||
ps: SyntaxSet,
|
||||
ts: EmbeddedLazyThemeSet,
|
||||
|
||||
config: Config,
|
||||
}
|
||||
type AppState = State<Arc<BlogState>>;
|
||||
|
@ -77,25 +87,198 @@ struct Post {
|
|||
embed_template_name: Option<String>,
|
||||
}
|
||||
|
||||
trait ToHtml {
|
||||
fn is_directive(&self) -> bool;
|
||||
fn to_html(&self, ps: &SyntaxSet, theme: &Theme) -> String;
|
||||
fn template(&self) -> Option<String>;
|
||||
}
|
||||
|
||||
impl ToHtml for markdown::mdast::Node {
|
||||
fn to_html(&self, ps: &SyntaxSet, theme: &Theme) -> String {
|
||||
let mut s = String::new();
|
||||
|
||||
if self.is_directive() {
|
||||
return s;
|
||||
}
|
||||
|
||||
match self {
|
||||
markdown::mdast::Node::Root(root) => {
|
||||
for child in &root.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
}
|
||||
markdown::mdast::Node::Blockquote(block_quote) => {
|
||||
s += "<blockquote>";
|
||||
for child in &block_quote.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</blockquote>";
|
||||
}
|
||||
markdown::mdast::Node::FootnoteDefinition(_) => {}
|
||||
markdown::mdast::Node::MdxJsxFlowElement(_) => {}
|
||||
markdown::mdast::Node::List(list) => {
|
||||
s += "<ul>";
|
||||
for child in &list.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</ul>";
|
||||
}
|
||||
markdown::mdast::Node::MdxjsEsm(_) => {}
|
||||
markdown::mdast::Node::Toml(_) => {}
|
||||
markdown::mdast::Node::Yaml(_) => {}
|
||||
markdown::mdast::Node::Break(_) => {}
|
||||
markdown::mdast::Node::InlineCode(inline_code) => {
|
||||
s += &format!(
|
||||
"<code>{}</code>",
|
||||
&ansi_to_html::convert(&inline_code.value).unwrap()
|
||||
);
|
||||
}
|
||||
markdown::mdast::Node::InlineMath(_) => {}
|
||||
markdown::mdast::Node::Delete(_) => {}
|
||||
markdown::mdast::Node::Emphasis(emphasis) => {
|
||||
s += "<em>";
|
||||
for child in &emphasis.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</em>";
|
||||
}
|
||||
markdown::mdast::Node::MdxTextExpression(_) => {}
|
||||
markdown::mdast::Node::FootnoteReference(_) => {}
|
||||
markdown::mdast::Node::Html(_) => {}
|
||||
markdown::mdast::Node::Image(image) => {
|
||||
if image.url.ends_with(".mp4") {
|
||||
s += &format!("<video controls src={}>", image.url);
|
||||
} else {
|
||||
s += &format!("<img src={}>", image.url);
|
||||
}
|
||||
}
|
||||
markdown::mdast::Node::ImageReference(_) => {}
|
||||
markdown::mdast::Node::MdxJsxTextElement(_) => {}
|
||||
markdown::mdast::Node::Link(link) => {
|
||||
s += &format!("<a href={}>", link.url);
|
||||
for child in &link.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</a>";
|
||||
}
|
||||
markdown::mdast::Node::LinkReference(_) => {}
|
||||
markdown::mdast::Node::Strong(strong) => {
|
||||
s += "<b>";
|
||||
for child in &strong.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</b>";
|
||||
}
|
||||
markdown::mdast::Node::Text(text) => s += &ansi_to_html::convert(&text.value).unwrap(),
|
||||
markdown::mdast::Node::Code(code) => {
|
||||
if let Some(syntax) = code
|
||||
.lang
|
||||
.as_ref()
|
||||
.and_then(|lang| ps.find_syntax_by_extension(&lang))
|
||||
{
|
||||
println!("{:?}", code.lang);
|
||||
let escaped = highlighted_html_for_string(&code.value, &ps, syntax, theme)
|
||||
.expect("generate html");
|
||||
|
||||
s += &escaped;
|
||||
} else {
|
||||
s += "<pre><code>";
|
||||
s += &ansi_to_html::convert(&code.value).unwrap();
|
||||
s += "</code></pre>";
|
||||
}
|
||||
}
|
||||
markdown::mdast::Node::Math(_) => {}
|
||||
markdown::mdast::Node::MdxFlowExpression(_) => {}
|
||||
markdown::mdast::Node::Heading(heading) => {
|
||||
s += &format!("<h{}>", heading.depth);
|
||||
for child in &heading.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += &format!("</h{}>", heading.depth);
|
||||
}
|
||||
markdown::mdast::Node::Table(_) => {}
|
||||
markdown::mdast::Node::ThematicBreak(_) => {
|
||||
s += "<hr>";
|
||||
}
|
||||
markdown::mdast::Node::TableRow(_) => {}
|
||||
markdown::mdast::Node::TableCell(_) => {}
|
||||
markdown::mdast::Node::ListItem(item) => {
|
||||
s += "<li>";
|
||||
for child in &item.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</li>";
|
||||
}
|
||||
markdown::mdast::Node::Definition(_) => {}
|
||||
markdown::mdast::Node::Paragraph(paragraph) => {
|
||||
s += "<p>";
|
||||
for child in ¶graph.children {
|
||||
s += &child.to_html(ps, theme);
|
||||
}
|
||||
s += "</p>";
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
fn is_directive(&self) -> bool {
|
||||
self.children()
|
||||
.and_then(|children| children.first())
|
||||
.map(|first| match first {
|
||||
markdown::mdast::Node::Text(text) => {
|
||||
if text.value.starts_with("%{") && text.value.ends_with("}") {
|
||||
text.value.chars().filter(|x| *x == '}').count() == 1
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.is_some_and(|x| x)
|
||||
}
|
||||
|
||||
fn template(&self) -> Option<String> {
|
||||
self.children()
|
||||
.and_then(|children| children.first())
|
||||
.and_then(|first| match first {
|
||||
markdown::mdast::Node::Paragraph(_) => first.template(),
|
||||
markdown::mdast::Node::Text(text) => {
|
||||
if text.value.starts_with("%{") {
|
||||
text.value[2..].split('}').next().map(String::from)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Post {
|
||||
fn to_html(&self, templates: &HashMap<String, Cached<Template>>) -> String {
|
||||
fn to_html(
|
||||
&self,
|
||||
templates: &HashMap<String, Cached<Template>>,
|
||||
ps: &SyntaxSet,
|
||||
ts: &Theme,
|
||||
) -> String {
|
||||
let mut s = String::with_capacity(self.content.len());
|
||||
if let Some(template) = self
|
||||
.embed_template_name
|
||||
.as_ref()
|
||||
.and_then(|name| templates.get(name))
|
||||
{
|
||||
|
||||
let ast = markdown::to_mdast(&self.content, &ParseOptions::default()).unwrap();
|
||||
let template_name = ast.template();
|
||||
|
||||
if let Some(template) = template_name.and_then(|name| templates.get(&name)) {
|
||||
if template.data.index > 0 {
|
||||
s += &template.data.content[0..template.data.index];
|
||||
}
|
||||
|
||||
s += &markdown::to_html(&self.content);
|
||||
s += &ast.to_html(ps, ts);
|
||||
|
||||
if template.data.index > 0 {
|
||||
s += &template.data.content[template.data.index + 3..]
|
||||
}
|
||||
} else {
|
||||
s += &markdown::to_html(&self.content);
|
||||
s += &ast.to_html(ps, ts);
|
||||
}
|
||||
|
||||
s
|
||||
|
@ -105,7 +288,8 @@ impl Post {
|
|||
impl From<String> for Post {
|
||||
fn from(value: String) -> Self {
|
||||
let template_name = if value.starts_with("%{") {
|
||||
value[2..].split('}').next().map(Into::into)
|
||||
// value[2..].split('}').next().map(Into::into)
|
||||
None
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -132,13 +316,25 @@ struct Config {
|
|||
#[tokio::main]
|
||||
async fn main() {
|
||||
let config = Config::parse();
|
||||
|
||||
let mut builder = two_face::syntax::extra_newlines().into_builder();
|
||||
builder
|
||||
.add_from_folder(format!("{}/syntaxes", &config.blog_dir), true)
|
||||
.expect("load syntaxes");
|
||||
let ps = builder.build();
|
||||
|
||||
let mut blog_state = BlogState {
|
||||
templates: HashMap::new(),
|
||||
posts: HashMap::new(),
|
||||
ps,
|
||||
ts: two_face::theme::extra(),
|
||||
config,
|
||||
};
|
||||
|
||||
for dir in std::fs::read_dir(&blog_state.config.blog_dir).unwrap().flatten() {
|
||||
for dir in std::fs::read_dir(&blog_state.config.blog_dir)
|
||||
.unwrap()
|
||||
.flatten()
|
||||
{
|
||||
if dir.file_type().unwrap().is_file() {
|
||||
let file_name = dir.file_name().into_string().unwrap();
|
||||
let Some((file_name, extension)) = file_name.split_once('.') else {
|
||||
|
@ -169,7 +365,9 @@ async fn main() {
|
|||
.route("/:post", get(blog_post))
|
||||
.route("/images/:image", get(image))
|
||||
.with_state(Arc::new(blog_state));
|
||||
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port)).await.unwrap();
|
||||
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
axum::serve(listener, app).await.unwrap();
|
||||
}
|
||||
|
@ -177,7 +375,15 @@ async fn main() {
|
|||
async fn home_page(State(state): AppState) -> Result<Html<String>, Html<String>> {
|
||||
match state.posts.get("home") {
|
||||
Some(post) => match post.data() {
|
||||
Ok(content) => Ok(Html(content.to_html(&state.templates))),
|
||||
Ok(content) => Ok(Html(
|
||||
content.to_html(
|
||||
&state.templates,
|
||||
&state.ps,
|
||||
state
|
||||
.ts
|
||||
.get(two_face::theme::EmbeddedThemeName::GruvboxDark),
|
||||
),
|
||||
)),
|
||||
Err(e) => Err(Html(e.to_string())),
|
||||
},
|
||||
None => Err(Html("<h1>404 - Not Found</h1>".to_string())),
|
||||
|
@ -190,7 +396,15 @@ async fn blog_post(
|
|||
) -> Result<Html<String>, Html<String>> {
|
||||
match state.posts.get(&post) {
|
||||
Some(post) => match post.data() {
|
||||
Ok(content) => Ok(Html(content.to_html(&state.templates))),
|
||||
Ok(content) => Ok(Html(
|
||||
content.to_html(
|
||||
&state.templates,
|
||||
&state.ps,
|
||||
state
|
||||
.ts
|
||||
.get(two_face::theme::EmbeddedThemeName::GruvboxDark),
|
||||
),
|
||||
)),
|
||||
Err(e) => Err(Html(e.to_string())),
|
||||
},
|
||||
None => Err(not_found_page(state)),
|
||||
|
@ -199,7 +413,7 @@ async fn blog_post(
|
|||
|
||||
async fn image(State(state): AppState, Path(image_path): Path<String>) -> impl IntoResponse {
|
||||
match std::fs::read(format!("{}/images/{image_path}", state.config.blog_dir)) {
|
||||
Ok(contents) => Ok(([(header::CONTENT_TYPE, "image/png")], contents)),
|
||||
Ok(contents) => Ok(([(header::CONTENT_TYPE, "image/png;video/mp4")], contents)),
|
||||
Err(e) => {
|
||||
eprintln!("{e:#?}");
|
||||
Err(StatusCode::NOT_FOUND)
|
||||
|
@ -210,7 +424,15 @@ async fn image(State(state): AppState, Path(image_path): Path<String>) -> impl I
|
|||
fn not_found_page(state: Arc<BlogState>) -> Html<String> {
|
||||
match state.posts.get("404") {
|
||||
Some(post) => match post.data() {
|
||||
Ok(content) => Html(content.to_html(&state.templates)),
|
||||
Ok(content) => Html(
|
||||
content.to_html(
|
||||
&state.templates,
|
||||
&state.ps,
|
||||
state
|
||||
.ts
|
||||
.get(two_face::theme::EmbeddedThemeName::GruvboxDark),
|
||||
),
|
||||
),
|
||||
Err(e) => Html(e.to_string()),
|
||||
},
|
||||
None => Html("<h1>404 - Not Found</h1>".to_string()),
|
||||
|
|
Loading…
Reference in New Issue