commit 0841f6158dd1a5f9dc1ec2c70f7e69b72bac811f Author: Price Hiller Date: Sun Aug 27 20:17:16 2023 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0f9d898 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +out diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b6dbc7e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1404 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[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 = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blog" +version = "0.1.0" +dependencies = [ + "anyhow", + "chrono", + "clap", + "comrak", + "lazy_static", + "serde", + "serde_json", + "serde_yaml", + "syntect", + "tera", +] + +[[package]] +name = "bstr" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "winapi", +] + +[[package]] +name = "chrono-tz" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58549f1842da3080ce63002102d5bc954c7bc843d4f47818e642abdc36253552" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + +[[package]] +name = "clap" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "comrak" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482aa5695bca086022be453c700a40c02893f1ba7098a2c88351de55341ae894" +dependencies = [ + "clap", + "entities", + "memchr", + "once_cell", + "regex", + "shell-words", + "slug", + "syntect", + "typed-arena", + "unicode_categories", + "xdg", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "globset" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libm" +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.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "num-traits" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +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 = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pest" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666d00490d4ac815001da55838c500eafb0320019bbaa44444137c48b443a853" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56af0a30af74d0445c0bf6d9d051c979b516a1a5af790d251daee76005420a48" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", + "uncased", +] + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "plist" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdc0001cfea3db57a2e24bc0d818e9e20e554b5f97fabb9bc231dc240269ae06" +dependencies = [ + "base64", + "indexmap 1.9.3", + "line-wrap", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "regex" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" + +[[package]] +name = "rustix" +version = "0.37.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +dependencies = [ + "indexmap 2.0.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syntect" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02b4b303bf8d08bfeb0445cba5068a3d306b6baece1d5582171a9bf49188f91" +dependencies = [ + "bincode", + "bitflags", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax", + "serde", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "tera" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ab29bb4f3e256ae6ad5c3e2775aa1f8829f2c0c101fc407bfd3a6df15c60c5" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk", + "humansize", + "lazy_static", + "percent-encoding", + "pest", + "pest_derive", + "rand", + "regex", + "serde", + "serde_json", + "slug", + "thread_local", + "unic-segment", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix", + "windows-sys", +] + +[[package]] +name = "thiserror" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" +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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" +dependencies = [ + "time-core", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uncased" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b9bc53168a4be7402ab86c3aad243a84dd7381d09be0eddc81280c1da95ca68" +dependencies = [ + "version_check", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2f1909d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "blog" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +comrak = "0.18.0" +syntect = "5.1.0" +anyhow = "1.0.75" +clap = { version = "4.4.0", features = ["derive"] } +chrono = { version = "0.4.26", default-features = false, features = ["clock", "serde"] } +serde = { version = "1.0.188", features = ["derive"]} +serde_yaml = "0.9.25" +serde_json = "1.0.105" +lazy_static = "1.4.0" +tera = "1.19.0" diff --git a/assets/Kanagawa.tmTheme b/assets/Kanagawa.tmTheme new file mode 100644 index 0000000..133bc1a --- /dev/null +++ b/assets/Kanagawa.tmTheme @@ -0,0 +1,636 @@ + + + + + + + + + name + kanagawa + settings + + + settings + + background + #1F1F28 + foreground + #dcd7ba + lineHighlight + #363646 + selection + #223249 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #727169 + + + + name + String + scope + string + settings + + foreground + #98bb6c + + + + name + Number + scope + constant.numeric + settings + + foreground + #d27e99 + + + + name + Built-in constant + scope + constant.language + settings + + foreground + #7fb4ca + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #ffa066 + + + + name + Variable + scope + variable + settings + + foreground + #dcd7ba + + + + name + Keyword + scope + keyword + settings + + foreground + #FF5D62 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #7aa89f + + + + name + Storage type + scope + storage.type + settings + + foreground + #957FB8 + + + + name + Function argument + scope + variable.parameter + settings + + foreground + #FFA066 + + + + name + Tag name + scope + entity.name.tag + settings + + foreground + #7aa89f + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #7fb4ca + + + + name + Punctuation Definition Entity + scope + punctuation.definition.entity + settings + + foreground + #9CABCA + + + + name + Entity Other Attribute-Name + scope + entity.other.attribute-name + settings + + foreground + #e6c384 + + + + name + Class Name + scope + entity.name + settings + + foreground + #7aa89f + + + + name + Punctuation Comment + scope + punctuation.definition.comment + settings + + fontStyle + italic + foreground + #727169 + + + + name + Brackets/Braces + scope + brace + settings + + foreground + #9cabca + + + + name + Constant + scope + constant.language + settings + + foreground + #ffa066 + + + + name + Built In Types + scope + type.built-ins + settings + + foreground + #7fb4ca + + + + name + Import Types + scope + type.import + settings + + foreground + #E6C384 + + + + name + Class Inheritance + scope + class.inheritance + settings + + foreground + #7aa89f + + + + name + Section Embedded + scope + section.embedded + settings + + foreground + #9cabca + + + + name + Punctuation + scope + punctuation + settings + + foreground + #9cabca + + + + name + Types + scope + type + settings + + foreground + #7aa89f + + + + name + Support Constant + scope + support.constant + settings + + foreground + #e6c384 + + + + name + Support Class + scope + support.class + settings + + foreground + #7aa89f + + + + name + Property Name + scope + property-name + settings + + foreground + #e6c384 + + + + name + Storage Modifier Lifetime Rust + scope + storage.modifier.lifetime.rust + settings + + foreground + #7aa89f + + + + name + Storage Modifier + scope + storage.modifier + settings + + foreground + #7aa89f + + + + name + Generic + scope + generic + settings + + foreground + #7aa89f + + + + name + Macro + scope + macro + settings + + foreground + #FF5D62 + + + + name + Support Macro + scope + support.macro + settings + + foreground + #FF5D62 + + + + name + Path + scope + meta.path + settings + + foreground + #e6c384 + + + + name + Variable Language + scope + variable.language + settings + + foreground + #FF5D62 + + + + name + keyword.control.flow + scope + keyword.control.flow + settings + + foreground + #957FB8 + + + + name + keyword.operator.logical + scope + keyword.operator.logical + settings + + foreground + #e6c384 + + + + name + keyword.operator.arithmetic + scope + keyword.operator.arithmetic + settings + + foreground + #e6c384 + + + + name + punctuation.definition.string + scope + punctuation.definition.string + settings + + foreground + #98bb6c + + + + name + support.constant.property-value + scope + support.constant.property-value + settings + + foreground + #98bb6c + + + + name + keyword.other.unit + scope + keyword.other.unit + settings + + foreground + #98bb6c + + + + name + keyword.operator + scope + keyword.operator + settings + + foreground + #e6c384 + + + + name + variable.annotation + scope + variable.annotation + settings + + foreground + #FF5D62 + + + + name + Support + scope + support + settings + + foreground + #7aa89f + + + + name + variable.other.member + scope + variable.other.member + settings + + foreground + #e6c384 + + + + name + Generic + scope + meta.generic + settings + + foreground + #7aa89f + + + + name + meta.function.return-type + scope + meta.function.return-type + settings + + foreground + #7aa89f + + + + name + meta.property + scope + meta.property + settings + + foreground + #e6c384 + + + + name + support.function + scope + support.function + settings + + foreground + #7e9cd8 + + + + name + variable.type + scope + variable.type + settings + + foreground + #7aa89f + + + + name + meta.function-call + scope + meta.function-call + settings + + foreground + #7e9cd8 + + + + name + entity.name.function + scope + entity.name.function + settings + + foreground + #7e9cd8 + + + + name + meta.function-call.arguments + scope + meta.function-call.arguments + settings + + foreground + #dcd7ba + + + + name + variable.parameter + scope + variable.parameter + settings + + foreground + #b8b4d0 + + + + name + variable.function + scope + variable.function + settings + + foreground + #7e9cd8 + + + + uuid + D8D5E82E-3D5B-46B5-B38E-8C841C21347D + colorSpaceName + sRGB + semanticClass + theme.dark.kanagawa + + \ No newline at end of file diff --git a/assets/style/article.css b/assets/style/article.css new file mode 100644 index 0000000..e62f30b --- /dev/null +++ b/assets/style/article.css @@ -0,0 +1,127 @@ +/* Article Specific Styling Below */ +article { + display: flex; + max-width: min(700px, 100vw); + padding-left: 3px; + padding-left: 3px; + align-self: center; + flex-direction: column; +} + +article > p > img { + margin-left: 50%; + transform: translateX(-50%); + max-height: 75vh; + max-width: min(90vw, 800px); +} + +.article-name { + color: var(--springGreen); + font-weight: bold; +} + +.article-summary { + font-size: 1.2rem; +} + +.article-tags > ul { + display: flex; + justify-items: flex-start; + gap: 8px; + padding: 0; + margin: 0; + text-align: center; +} + +.article-tags a { + color: unset; + background-color: color-mix(in srgb, var() 25%, transparent); +} +.article-tags > ul > li { + width: auto; + display: inline; + float: none; +} + +.article-tags > ul > li:not(:last-child)::after { + content: " ⦁"; +} + +.article-dates { + color: var(--fujiGray); + display: flex; + gap: 10px; + justify-content: space-evenly; + font-size: 0.9rem; +} + +.article-published::before { + content: "Published: "; +} + +.article-last-updated::before { + content: "Last Updated: "; +} + +.articles-container { + width: min(600px, 90vw); +} + +.articles-container > ul { + margin: 0; + padding: 0; +} +.articles-container > ul > li { + list-style-type: none; + margin: 10px +} + +.article-frontmatter { + background-color: var(--winterGreen); + font-family: sans-serif; + border-radius: 10px; + padding: 10px; +} + +.article-frontmatter:hover { + background-color: color-mix(in srgb, var(--autumnGreen) 35%, transparent); + transition-duration: 0.25s; +} + +.article-frontmatter > a { + text-decoration: none; + color: var(--fujiWhite); +} + +.article-frontmatter > a:hover { + font-weight: unset; + text-decoration: none; + background-color: unset; + color: var(--fujiWhite); +} + +.article-frontmatter > a > .article-name { + font-size: 1.5rem; +} + +.article-frontmatter > a > .article-dates { + justify-content: flex-start; +} + +.article-frontmatter-tags > ul { + gap: 8px; + padding-left: 0; +} + +.article-frontmatter-tags a { + color: unset; + background-color: color-mix(in srgb, var() 25%, transparent); +} + +.article-frontmatter-tags > ul > li { + display: inline; +} + +.article-frontmatter-tags > ul > li:not(:last-child)::after { + content: " ⦁"; +} diff --git a/assets/style/style.css b/assets/style/style.css new file mode 100644 index 0000000..5bfc961 --- /dev/null +++ b/assets/style/style.css @@ -0,0 +1,236 @@ +/* Yo, you're looking at my horrid CSS. Judge, let me know what I'm doing wrong because I sure as shit am NOT a web dev. +* Though maybe someday? For now, this is my cobbled together mess based on Mozilla's web developer documentation and a +* fuckton of fiddling. */ + +/* TODO: Split this up and improve some of our organization of classes. Ideally the delivered css should be no more than +* 4k in size so the article content can take up 10k. Stay within the TCP first roundtrip size to speed up loading. +* Granted the style SHOULD get cached so it's not that big of a deal, but something to resolve. +* +* TODO: Regardless of the size of this beast, I need to deduplicate some of the functionality of these classes. Lots of +* things are unecessarily repated that could be consolidated. <- DO THIS PART FIRST, IGNORE SIZE */ +:root { + --fujiWhite: #dcd7ba; + --oldWhite: #c8c093; + --sumiInk0: #16161d; + --sumiInk1: #1f1f28; + --sumiInk2: #2a2a37; + --sumiInk3: #363646; + --sumiInk4: #54546d; + --waveBlue1: #223249; + --waveBlue2: #2d4f67; + --winterGreen: #2b3328; + --winterYellow: #49443c; + --winterRed: #43242b; + --winterBlue: #252535; + --autumnGreen: #76946a; + --autumnRed: #c34043; + --autumnYellow: #dca561; + --samuraiRed: #e82424; + --roninYellow: #ff9e3b; + --waveAqua1: #6a9589; + --dragonBlue: #658594; + --fujiGray: #727169; + --springViolet1: #938aa9; + --oniViolet: #957fb8; + --crystalBlue: #7e9cd8; + --springViolet2: #9cabca; + --springBlue: #7fb4ca; + --lightBlue: #a3d4d5; + --waveAqua2: #7aa89f; + --springGreen: #98bb6c; + --boatYellow1: #938056; + --boatYellow2: #c0a36e; + --carpYellow: #e6c384; + --sakuraPink: #d27e99; + --waveRed: #e46876; + --peachRed: #ff5d62; + --surimiOrange: #ffa066; + --navbar-height: 40px; + --navbar-bg-color: var(--sumiInk4); + --navbar-border-color: var(--sumiInk3); +} + +::selection { + background: color-mix(in srgb, var(--lightBlue) 25%, transparent); +} + +/* This ensures the page uses full width at all times. We have to do this because some elements (our images in +* particular) are wider than their parents and we couldn't use flex for that causing some alignment issues when the +* webpage was too narrow (Mobile devices). */ +html, +body { + max-width: 100%; + overflow-x: hidden; +} + +html { + background-color: var(--sumiInk0); + color: var(--fujiWhite); +} + +body { + padding-top: var(--navbar-height); + line-height: 1.6; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +nav { + display: flex; + flex-direction: row; + align-self: center; + background-color: color-mix(in srgb, var(--navbar-bg-color) 20%, transparent); + backdrop-filter: blur(12px); + /* HACK: Fucken safari doesn't support `backdrop-filter`, webkit has its own. D o g s h i t. */ + -webkit-backdrop-filter: blur(12px); + font-size: 1.1rem; + font-family: sans-serif; + height: var(--navbar-height); + position: fixed; + top: 0; + width: 300px; + border-bottom-width: 2px; + border-bottom-style: solid; + border-bottom-color: var(--sumiInk3); + border-right-style: solid; + border-right-color: var(--sumiInk3); + border-bottom-right-radius: 10px; + border-left-style: solid; + border-left-color: var(--sumiInk3); + border-bottom-left-radius: 10px; + /* Set the navbar to have highest priority so it shows above all other elements */ +} + +nav a:link, +nav a:visited { + color: var(--fujiWhite); + background-color: unset; + text-decoration: none; +} + +nav a:hover, +nav a:visited:hover { + color: unset; + background-color: unset; +} + +.nav-item { + width: 100%; +} + +.nav-item:not(:last-child) { + border-right: 2px solid var(--sumiInk3); +} + +.nav-item:hover { + color: var(--fujiWhite); + transition-duration: 0.3s; + background-color: color-mix(in srgb, var(--navbar-bg-color) 40%, transparent); +} + +.nav-item a { + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} + +img { + padding: 10px; + overflow: scroll; + max-height: 75vh; + max-width: min(95vw, 125%); +} + +h1, +h2, +h3, +h4, +h5, +h6 { + line-height: 0; + font-family: sans-serif; +} + +a:link { + color: var(--crystalBlue); +} + +a:hover, +a:visited:hover { + color: var(--fujiWhite); + background-color: color-mix(in srgb, var(--crystalBlue) 50%, transparent); + text-decoration-color: var(--crystalBlue); +} + +a:visited { + color: var(--oniViolet); +} + +blockquote { + background-color: var(--sumiInk1); + padding: 10px; + border-left-width: 5px; + border-left-style: solid; + border-left-color: var(--sumiInk4); +} + +blockquote > p { + margin: 0; +} + +pre { + border-radius: 4px; + overflow: auto; + outline-style: solid; + outline-color: var(--sumiInk2); + outline-width: 2.5px; + width: min(90vw, 800px); + font-size: 0.85rem; + transition-duration: 0.25s; + align-self: center; + padding: 5px; +} + +pre:hover { + outline-color: var(--sumiInk3); + /* NOTE: We have to set important because Comrak's default syntax adapter will ALWAYS set a color for the background + * here, no way to avoid it unless we want to rewrite chunks of the syntax adapter. Currently I'm too lazy to + * investigate that.*/ + background-color: var(--sumiInk2) !important; +} + +code { + border-radius: 6px; + padding: 2px; + font-family: monospace; +} + +p > code { + background-color: var(--sumiInk3); +} + +.page-info { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + font-family: sans-serif; +} + +.page-title { + font-size: 2rem; + font-style: bold; + font-family: sans-serif; +} + +.page-detail { + font-size: 0.95rem; + max-width: min(600px, 95vw); +} + +hr { + margin: 30px; +} diff --git a/assets/style/tags.css b/assets/style/tags.css new file mode 100644 index 0000000..35a86bf --- /dev/null +++ b/assets/style/tags.css @@ -0,0 +1,19 @@ +/* Tags.html */ +.tags { + max-width: min(750px, 90vw); +} + +.tags > ul { + margin: 0; + padding: 0; +} + +.tags > ul > li { + display: inline; + font-family: sans-serif; + font-size: 1.5rem; +} + +.tags > ul > li:not(:last-child)::after { + content: " ⦁"; +} diff --git a/assets/templates/article-frontmatter.html b/assets/templates/article-frontmatter.html new file mode 100644 index 0000000..31f37e4 --- /dev/null +++ b/assets/templates/article-frontmatter.html @@ -0,0 +1,19 @@ +{% macro gen(frontmatter, link) %} +
+ +
{{ frontmatter.name }}
+
{{ frontmatter.summary }}
+ +
+ +
+ +
+{% endmacro gen %} diff --git a/assets/templates/article.html b/assets/templates/article.html new file mode 100644 index 0000000..e4238f5 --- /dev/null +++ b/assets/templates/article.html @@ -0,0 +1,36 @@ + + + + + {{ article_title }} + + + + + + +{% include "nav.html" %} + + +
+
{{ article_title }}
+
{{ article_summary }}
+ + +
+
+
+ {{ article_content }} +
+ + + diff --git a/assets/templates/articles.html b/assets/templates/articles.html new file mode 100644 index 0000000..ee11ab6 --- /dev/null +++ b/assets/templates/articles.html @@ -0,0 +1,29 @@ +{% import "article-frontmatter.html" as front_matter_macro %} + + + + Articles + + + + + + {% include "nav.html" %} + +
+
Articles
+
Grimoire of brain damage
+
+
+ +
+ + diff --git a/assets/templates/footer.html b/assets/templates/footer.html new file mode 100644 index 0000000..e69de29 diff --git a/assets/templates/nav.html b/assets/templates/nav.html new file mode 100644 index 0000000..301f5cc --- /dev/null +++ b/assets/templates/nav.html @@ -0,0 +1,5 @@ + diff --git a/assets/templates/tag-articles.html b/assets/templates/tag-articles.html new file mode 100644 index 0000000..8e84705 --- /dev/null +++ b/assets/templates/tag-articles.html @@ -0,0 +1,31 @@ +{% import "article-frontmatter.html" as front_matter_macro %} + + + + Tags + + + + + + {% include "nav.html" %} + + +
+
{{ tag }}
+
Articles tagged {{ tag }}
+
+
+ +
+ + diff --git a/assets/templates/tags.html b/assets/templates/tags.html new file mode 100644 index 0000000..e62f2d2 --- /dev/null +++ b/assets/templates/tags.html @@ -0,0 +1,24 @@ + + + + + Tags + + + + + + +{% include "nav.html" %} + + +
+ +
+ + + diff --git a/posts/assets/out.png b/posts/assets/out.png new file mode 100644 index 0000000..2d1fb3d Binary files /dev/null and b/posts/assets/out.png differ diff --git a/posts/example.md b/posts/example.md new file mode 100644 index 0000000..588cf34 --- /dev/null +++ b/posts/example.md @@ -0,0 +1,398 @@ +--- +name: Example Article +summary: This is an example summary for quick detail to be parsed into frontmatter shit +tags: + - example + - nope +category: + - example + - nope +published: 2023-07-24 +updated: 2023-07-24 +--- + +# Heading + +Content + +## Sub Heading + +More content + +```lua +local my_table = { + string = "Nah", + boolean = true, + arr = { + "nah", + "yes", + true, + false, + nil + }, +} +``` + +```rust +use std::collections::BTreeMap; + +use comrak::plugins::syntect::SyntectAdapterBuilder; +use comrak::{markdown_to_html_with_plugins, ComrakOptions, ComrakPlugins}; +use syntect::highlighting::ThemeSet; + +#[derive(debug)] +fn main() { + let theme = ThemeSet::load_from_reader(&mut std::io::Cursor::new(include_bytes!("../TwoDark.tmTheme"))).unwrap(); + let mut t = BTreeMap::new(); + t.insert(String::from("TwoDark"), theme); + let mut theme_set= ThemeSet::new(); + theme_set.themes = t; + let adapter = SyntectAdapterBuilder::new().theme("TwoDark").theme_set(theme_set).build(); + let options = ComrakOptions::default(); + let mut plugins = ComrakPlugins::default(); + + // Hello World + plugins.render.codefence_syntax_highlighter = Some(&adapter); + + + let formatted = markdown_to_html_with_plugins(include_str!("../example.md"), &options, &plugins); + + println!("{}", formatted); +} + +fn tester<'a>(in: i32) { + println!("Hi {in}!"); +} + +impl MyExample { + fn fuck() -> T { + T + } +} + +struct MyMan { + man: i32 +} + +enum fuck { + RED: 1, + BLUE: 2, + GREEN: "Yep" +} +``` + +```js +var parseXML = function (data) { + var xml, tmp; + if (!data || typeof data !== "string") { + return null; + } + try { + if (window.DOMParser) { + // Standard + tmp = new DOMParser(); + xml = tmp.parseFromString(data, "text/xml"); + } else { + // IE + xml = new ActiveXObject("Microsoft.XMLDOM"); + xml.async = false; + xml.loadXML(data); + } + } catch (e) { + xml = undefined; + } + if ( + !xml || + !xml.documentElement || + xml.getElementsByTagName("parsererror").length + ) { + jQuery.error("Invalid XML: " + data); + } + return xml; +}; + +Sound.play = function() {} +Sound.prototype = { something; } +Sound.prototype.play = function() {} +Sound.prototype.play = myfunc +var parser = document.createElement('a'); +parser.href = "http://example.com:3000/pathname/?search=test#hash"; +parser.hostname; // => "example.com" +``` + +```python +import re + +class Example: + ... + +class Eee(Example): + ... + +print("Yest") + +def my_fn(): + ... + + my_fn(test, no) + +class SublimeTasksBase(sublime_plugin.TextCommand): + def run(self, edit): + self.open_tasks_bullet = self.view.settings().get('open_tasks_bullet') + self.done_tasks_bullet = self.view.settings().get('done_tasks_bullet') + self.date_format = self.view.settings().get('date_format') + if self.view.settings().get('done_tag'): + self.done_tag = "@done" + else: + self.done_tag = "" + self.runCommand(edit) + +class NewCommand(SublimeTasksBase): + thing = NewCommand() + def runCommand(self, edit): + for region in self.view.sel(): + line = self.view.line(region) + line_contents = self.view.substr(line).rstrip() + has_bullet = re.match('^(\s*)[' + re.escape(self.open_tasks_bullet) + re.escape(self.done_tasks_bullet) + ']', self.view.substr(line)) + current_scope = self.view.scope_name(self.view.sel()[0].b) + if has_bullet: + grps = has_bullet.groups() + line_contents = self.view.substr(line) + '\n' + grps[0] + self.open_tasks_bullet + ' ' + self.view.replace(edit, line, line_contents) +``` + +```php +edible = $edible; + $this->color = $color; + } + + function is_edible() + { + return $this->edible; + } + + function what_color() + { + return $this->color; + } + +} // end of class Vegetable + +// extends the base class +class Spinach extends Vegetable { + + var $cooked = false; + + function Spinach() + { + $this->Vegetable(true, "green"); + } + + function cook_it() + { + $this->cooked = true; + } + + function is_cooked() + { + return $this->cooked; + } + +} // end of class Spinach + +?> +``` + +```ocaml + + +open Lexer_flow +module Ast = Spider_monkey_ast +open Ast +module Error = Parse_error +module SSet = Set.Make(String) +module SMap = Map.Make(String) + +type lex_mode = + | NORMAL_LEX + | TYPE_LEX + | JSX_TAG + | JSX_CHILD + +let mode_to_string = function + | NORMAL_LEX -> "NORMAL" + | TYPE_LEX -> "TYPE" + | JSX_TAG -> "JSX TAG" + | JSX_CHILD -> "JSX CHILD" + +let lex lex_env = function + | NORMAL_LEX -> token lex_env + | TYPE_LEX -> type_token lex_env + | JSX_TAG -> lex_jsx_tag lex_env + | JSX_CHILD -> lex_jsx_child lex_env + +type env = { + errors : (Loc.t * Error.t) list ref; + comments : Comment.t list ref; + labels : SSet.t; + lb : Lexing.lexbuf; + lookahead : lex_result ref; + last : (lex_env * lex_result) option ref; + priority : int; + strict : bool; + in_export : bool; + in_loop : bool; + in_switch : bool; + in_function : bool; + no_in : bool; + no_call : bool; + no_let : bool; + allow_yield : bool; + (* Use this to indicate that the "()" as in "() => 123" is not allowed in + * this expression *) + error_callback : (env -> Error.t -> unit) option; + lex_mode_stack : lex_mode list ref; + lex_env : lex_env ref; +} +``` + +```css +body { + font-family: arial; +} + +h1, +p, +table { + background-color: #ccc; + border: 1px solid; + color: #39f; + text-align: center; + width: 100%; +} + +.addon-store .pagehead h1 { + display: inline-block; +} +.addon-store .addon-summary:after { + clear: both; +} + +#addon-store .pagehead .electrocat-small { + bottom: -7px; + position: absolute; + right: 0; +} + +.addon-store .addons-nav a.selected { + border-bottom-color: #d26911; + color: #333; + font-weight: bold; + padding: 0 0 14px; +} + +.addon-store .addon-icon { + background: #fff; + border: 1px solid #ddd; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); + float: left; + height: 80px; + margin-right: 14px; + width: 80px; +} + +.addon-store .developer-callout { + background-color: #f1f1f1; + background-image: -moz-linear-gradient(#fafafa, #f1f1f1); + background-image: -webkit-linear-gradient(#fafafa, #f1f1f1); + background-image: linear-gradient(#fafafa, #f1f1f1); + background-repeat: repeat-x; + border: 1px solid #ddd; + border-bottom: 1px solid #ccc; + border-radius: 3px; + box-shadow: + inset 0 1px 0 #fff, + 0 1px 5px #f1f1f1; + margin-top: 40px; + text-shadow: 0 1px 0 #fff; +} +``` + +``` +No language here! +``` + +```c +/* stringmerge.c -- Given two sorted files of strings, it creates + * a sorted file consisting of all their elements. + * The names of the files are passed as command + * line parameters. + */ + +#include +#define MAXBUFFER 128 + +int getline(FILE * fd, char buff[], int nmax){ + /* It reads a line from fd and stores up to nmax of + * its characters to buff. + */ + char c; + int n=0; + + while ((c=getc(fd))!='\n'){ + if(c==EOF)return EOF; + if(n Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa duis. Lorem ipsum dolor sit amet, officia excepteur ex fugiat reprehenderit enim labore culpa sint ad nisi Lorem pariatur mollit ex esse exercitation amet. Nisi anim cupidatat excepteur officia. Reprehenderit nostrud nostrud ipsum Lorem est aliquip amet voluptate voluptate dolor minim nulla est proident. Nostrud officia pariatur ut officia. Sit irure elit esse ea nulla sunt ex occaecat reprehenderit commodo officia dolor Lorem duis laboris cupidatat officia voluptate. Culpa proident adipisicing id nulla nisi laboris ex in Lorem sunt duis officia eiusmod. Aliqua reprehenderit commodo ex non excepteur duis sunt velit enim. Voluptate laboris sint cupidatat ullamco ut ea consectetur et est culpa et culpa duis. diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9cbefce --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,8 @@ +use tera::Tera; + +pub mod markdown; +pub mod page_gen; + +pub trait TemplateRenderer { + fn render_template(&self, tera: &Tera) -> anyhow::Result; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ed053e3 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,142 @@ +use anyhow::{Context, Ok}; +use clap::Parser; +use blog::{ + markdown::article::{Article, FrontMatter}, + page_gen::{ + articles::Articles, + tags::{TagArticles, Tags}, + }, + TemplateRenderer, +}; +use std::{collections::HashMap, path::PathBuf}; +use tera::Tera; + +#[derive(Parser, Debug)] +#[command(author = "Price Hiller ", version = "0.1", about = "Parses markdown documents to html with code syntax highlighting", long_about = None)] +struct Args { + /// Path to a directory containing markdown files to parse + #[arg()] + documents: PathBuf, + + /// Whether or not the parsed file should be written back as .html + #[arg(short, long, value_name = "write-html", default_value_t = false)] + write_html: bool, + + /// Path to a custom theme to use instead of default + #[arg(short, long)] + theme: Option, +} + +fn main() -> anyhow::Result<()> { + let comrak_settings = blog::markdown::MDComrakSettings::default().unwrap(); + let posts_dir = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/posts/")); + let posts_walkable = std::fs::read_dir(&posts_dir) + .context("Unable to read posts directory!")?; + let out_path = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/out")); + std::fs::create_dir_all(&out_path) + .context(format!("Unable to create out directory at '{out_path:?}'"))?; + + let mut tera = Tera::new(concat!( + env!("CARGO_MANIFEST_DIR"), + "/assets/templates/**/*.html" + )) + .context("Tera Template Import Error")?; + tera.autoescape_on(vec![]); + let mut detected_tags_article: HashMap> = HashMap::new(); + let mut article_links: Vec<(FrontMatter, String)> = Vec::new(); + println!("Rendering Articles"); + for dir_entry in posts_walkable { + let path = dir_entry?.path(); + if path.is_file() { + println!( + "Parsing Article: {}", + path.file_name().unwrap().to_str().unwrap() + ); + let parsed_article = Article::parse(&path, &comrak_settings).unwrap(); + println!( + "Rendering Article Template: {} - {}", + path.file_name().unwrap().to_str().unwrap(), + &parsed_article.frontmatter.name + ); + let rendered_article = parsed_article + .render_template(&tera) + .context("Article Template Rendering Error")?; + let new_file_name = String::from(path.file_stem().unwrap().to_str().unwrap()) + ".html"; + let write_path = &out_path.join(PathBuf::from(format!("articles/{}", &new_file_name))); + + write_file(&write_path, rendered_article.as_bytes())?; + println!("Finished Rendering Article Template"); + + for article_tag in &parsed_article.frontmatter.tags { + let tag = detected_tags_article + .entry(article_tag.clone()) + .or_default(); + tag.push((parsed_article.frontmatter.clone(), new_file_name.clone())); + } + article_links.push((parsed_article.frontmatter.clone(), new_file_name.clone())); + } + } + println!("Finished rendering Article templates"); + + println!("Rendering Tags Page"); + let tags_page = Tags::new(&detected_tags_article.keys().collect::>()) + .render_template(&tera) + .context("Main Tags Page Rendering Error")?; + + let tags_write_path = &out_path.join("tags.html"); + write_file(&tags_write_path, tags_page.as_bytes())?; + println!("Finished Rendering Tags Page"); + + println!("Rendering Articles Page"); + let articles_page = Articles::new(&article_links) + .render_template(&tera) + .context("Main Articles Page Rendering Error")?; + let articles_write_path = &out_path.join("articles.html"); + write_file(&articles_write_path, articles_page.as_bytes())?; + println!("Finished Rendering Articles Page"); + + println!("Rendering Individual Tag Pages"); + for (tag, article_link) in detected_tags_article.iter() { + println!("Rendering Tag Page: {}", &tag); + let tag_article = TagArticles::new(tag, article_link).render_template(&tera)?; + write_file( + &out_path.join(format!("tags/{tag}.html")), + tag_article.as_bytes(), + )?; + } + println!("Finished rendering Individual Tag Pages"); + + let base_asset_dir = PathBuf::from(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/")); + copy_recursive(&base_asset_dir.join("style/"), &out_path.join("style"))?; + copy_recursive(&posts_dir.join("assets/"), &out_path.join("articles/assets"))?; + + Ok(()) +} + +fn copy_recursive(src: &PathBuf, dest: &PathBuf) -> anyhow::Result<()> { + std::fs::create_dir_all(&dest)?; + for item in std::fs::read_dir(src)? { + let entry = item?; + let file_type = entry.file_type()?; + let dest = &dest.join(entry.file_name()); + if file_type.is_dir() { + copy_recursive(&entry.path(), &dest)?; + } else if file_type.is_symlink() { + let _ = std::fs::remove_file(&dest); + std::fs::copy(std::fs::read_link(entry.path())?, &dest)?; + } else { + let _ = std::fs::remove_file(&dest); + std::fs::copy(&entry.path(), &dest)?; + } + } + Ok(()) +} + +fn write_file(file_path: &PathBuf, contents: &[u8]) -> anyhow::Result<()> { + let mut dir = file_path.clone(); + if dir.pop() { + std::fs::create_dir_all(dir)?; + } + + std::fs::write(file_path, contents).context(format!("Failed to write to {file_path:?}")) +} diff --git a/src/markdown/article.rs b/src/markdown/article.rs new file mode 100644 index 0000000..1dae2d4 --- /dev/null +++ b/src/markdown/article.rs @@ -0,0 +1,100 @@ +use std::{ + fs::File, + io::Read, + path::{Path, PathBuf}, +}; + +use anyhow::Context; +use chrono::NaiveDate; +use comrak::{nodes::NodeValue, parse_document, Arena}; +use serde::{Deserialize, Serialize}; + +use crate::TemplateRenderer; + +use super::{iter_nodes, MDComrakSettings}; + +#[derive(Debug, Serialize)] +pub struct Article { + pub html_content: String, + pub frontmatter: FrontMatter +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct FrontMatter { + pub name: String, + pub summary: String, + pub published: NaiveDate, + pub updated: NaiveDate, + pub tags: Vec, +} + +impl Article { + pub fn parse( + article_md_path: &PathBuf, + comrak_settings: &MDComrakSettings, + ) -> anyhow::Result
{ + let article_content = Self::load_doc(article_md_path).with_context(|| { + format!("Could not read article markdown document at {article_md_path:?}") + })?; + let arena = Arena::new(); + let root = parse_document(&arena, &article_content, &comrak_settings.options); + + let mut front_matter_raw: String = String::from(""); + iter_nodes(root, &mut |node| match node.data.borrow().value { + // NOTE: This is kinda hacky, we just assume the frontmatter delimiter is ALWAYS "---"; + // furthermore, we assume there is even a frontmatter input period and this will have a + // nuclear incident if there doesn't happen to be a frontmatter delimiter. We should + // better handle this, but as of the time of this writing I don't fucken care enough. + // Will come back to later or this will be a temporary permanent fix. + NodeValue::FrontMatter(ref front_data) => { + front_matter_raw = front_data + .lines() + .filter(|line| match *line { + "---" => false, + _ => true, + }) + .map(|s| s.to_string() + "\n") + .collect::(); + } + _ => (), + }); + let frontmatter: FrontMatter = + serde_yaml::from_str(&front_matter_raw).with_context(|| { + format!("Failed to parse frontmatter for document: {article_md_path:?}") + })?; + + let mut html_out = vec![]; + comrak::format_html_with_plugins( + root, + &comrak_settings.options, + &mut html_out, + &comrak_settings.plugins, + )?; + let html = String::from_utf8(html_out)?; + + Ok(Article { + html_content: html, + frontmatter, + }) + } + + fn load_doc>(file_path: P) -> anyhow::Result { + let mut f = File::options().read(true).write(false).open(file_path)?; + let mut s = String::new(); + f.read_to_string(&mut s)?; + Ok(s) + } +} + +impl TemplateRenderer for Article { + fn render_template(&self, tera: &tera::Tera) -> anyhow::Result { + let mut tera_context = tera::Context::new(); + tera_context.insert("article_title", &self.frontmatter.name); + tera_context.insert("article_summary", &self.frontmatter.summary); + tera_context.insert("article_published", &self.frontmatter.published); + tera_context.insert("article_last_updated", &self.frontmatter.updated); + tera_context.insert("article_tags", &self.frontmatter.tags); + tera_context.insert("article_content", &self.html_content); + tera.render("article.html", &tera_context).context(format!("Failed to render Article: '{}'", &self.frontmatter.name)) + } +} diff --git a/src/markdown/mod.rs b/src/markdown/mod.rs new file mode 100644 index 0000000..2d0651d --- /dev/null +++ b/src/markdown/mod.rs @@ -0,0 +1,60 @@ +use std::io::Cursor; + +use comrak::{nodes::AstNode, ComrakOptions, ComrakPlugins, plugins::syntect::{SyntectAdapter, SyntectAdapterBuilder}}; +use lazy_static::lazy_static; +use syntect::highlighting::ThemeSet; + +pub mod article; + +lazy_static! { + pub static ref SYNTECT_ADAPTER: SyntectAdapter = + MDComrakSettings::load_theme("kanagawa", &mut Cursor::new(include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/assets/Kanagawa.tmTheme" + )))) + .expect("Unable to load custom syntax theme!"); +} + +pub fn iter_nodes<'a, F>(node: &'a AstNode<'a>, f: &mut F) +where + F: FnMut(&'a AstNode<'a>), +{ + f(node); + for c in node.children() { + iter_nodes(c, f); + } +} + +#[derive(Debug)] +pub struct MDComrakSettings<'a> { + pub options: ComrakOptions, + pub plugins: ComrakPlugins<'a>, +} + +impl MDComrakSettings<'_> { + pub fn default<'a>() -> anyhow::Result> { + let mut options = ComrakOptions::default(); + options.render.unsafe_ = true; + options.extension.front_matter_delimiter = Some("---".to_owned()); + + let mut plugins = ComrakPlugins::default(); + plugins.render.codefence_syntax_highlighter = Some(&*SYNTECT_ADAPTER); + + Ok(MDComrakSettings { options, plugins }) + } + + pub fn load_theme(theme_name: &str, theme_cursor: &mut R) -> anyhow::Result + where + R: std::io::BufRead + std::io::Seek, + { + let theme = ThemeSet::load_from_reader(theme_cursor)?; + let mut theme_set = ThemeSet::new(); + theme_set.themes.insert(String::from(theme_name), theme); + let adapter = SyntectAdapterBuilder::new() + .theme_set(theme_set) + .theme(theme_name) + .build(); + + Ok(adapter) + } +} diff --git a/src/page_gen/articles.rs b/src/page_gen/articles.rs new file mode 100644 index 0000000..7cdc11e --- /dev/null +++ b/src/page_gen/articles.rs @@ -0,0 +1,29 @@ +use super::tags::ArticleLink; +use crate::{markdown::article::FrontMatter, TemplateRenderer}; +use anyhow::Context; + +pub struct Articles<'a> { + articles: Vec>, +} + +impl Articles<'_> { + pub fn new<'a>(articles: &'a Vec<(FrontMatter, String)>) -> Articles<'a> { + let mut qual_article_links = Vec::new(); + for (frontmatter, link) in articles { + qual_article_links.push(ArticleLink { frontmatter, link }); + } + + Articles { + articles: qual_article_links, + } + } +} + +impl TemplateRenderer for Articles<'_> { + fn render_template(&self, tera: &tera::Tera) -> anyhow::Result { + let mut tera_context = tera::Context::new(); + tera_context.insert("articles", &self.articles); + tera.render("articles.html", &tera_context) + .context(format!("Failed to render primary articles page!")) + } +} diff --git a/src/page_gen/mod.rs b/src/page_gen/mod.rs new file mode 100644 index 0000000..cd4a95d --- /dev/null +++ b/src/page_gen/mod.rs @@ -0,0 +1,11 @@ +use crate::markdown::article::FrontMatter; +use serde::Serialize; + +pub mod articles; +pub mod tags; + +#[derive(Serialize)] +pub struct ArticleLink<'a> { + frontmatter: &'a FrontMatter, + link: &'a String, +} diff --git a/src/page_gen/tags.rs b/src/page_gen/tags.rs new file mode 100644 index 0000000..0c37ab7 --- /dev/null +++ b/src/page_gen/tags.rs @@ -0,0 +1,54 @@ +use anyhow::Context; +use serde::Serialize; +use crate::{TemplateRenderer, markdown::article::FrontMatter}; + +pub struct Tags<'a> { + tags: &'a Vec<&'a String>, +} + +impl Tags<'_> { + pub fn new<'a>(tags: &'a Vec<&'a String>) -> Tags<'a> { + Tags { tags } + } +} + +impl TemplateRenderer for Tags<'_> { + fn render_template(&self, tera: &tera::Tera) -> anyhow::Result { + let mut tera_context = tera::Context::new(); + tera_context.insert("tags", &self.tags); + tera.render("tags.html", &tera_context).context(format!( + "Failed to render tags page, had tags: {:#?}", + &self.tags + )) + } +} + +#[derive(Serialize)] +pub struct ArticleLink<'a> { + pub frontmatter: &'a FrontMatter, + pub link: &'a String +} + +pub struct TagArticles<'a> { + tag: &'a String, + article_links: Vec> +} + +impl TagArticles<'_> { + pub fn new<'a>(tag: &'a String, article_links: &'a Vec<(FrontMatter, String)>) -> TagArticles<'a> { + let mut qual_article_links = Vec::new(); + for (frontmatter, link) in article_links { + qual_article_links.push(ArticleLink { frontmatter, link }); + } + TagArticles { tag, article_links: qual_article_links } + } +} + +impl TemplateRenderer for TagArticles<'_> { + fn render_template(&self, tera: &tera::Tera) -> anyhow::Result { + let mut terra_context = tera::Context::new(); + terra_context.insert("tag", &self.tag); + terra_context.insert("article_links", &self.article_links); + tera.render("tag-articles.html", &terra_context).context(format!("Failed to render tag articles page for tag: {}", &self.tag)) + } +} diff --git a/src/tree_sitter_adapter.rs b/src/tree_sitter_adapter.rs new file mode 100644 index 0000000..4212e6b --- /dev/null +++ b/src/tree_sitter_adapter.rs @@ -0,0 +1,175 @@ +/// As a future note to myself. This shit is REALLY cool, but it seems there's some bugs on +/// treesitter's side when it comes to applying highlighting to javascript and that Neovim's +/// treesitter implementation is MUCH better than what you get out of the box from the treesitter +/// project. One on front, this is cool as fuck, on another front, this was a total pain in the +/// ass. Maybe try this later and next time don't go down the rabbit hole of binding rust to Neovim +/// to get their parsers and queries for our own use. Did it work? Yep. Was it fast? Fuck no. Could +/// it have been fast? Probably, but I'm not wasting the time to write the ffi to Neovim only for +/// some fucker over there to change an interface or nuke one; I'm not gonna put up the maintenance +/// effort. +/// +/// Full credit for a decent chunk of this to Andrew Biehl. His blog post +/// https://andrewtbiehl.com/blog/jekyll-tree-sitter is what sent me down this horrid path along +/// with some of his code in his kramdown syntax module. I did *significantly* speed this code up +/// though, as in several magnitudes for my purposes. + +use std::{ + collections::HashMap, + convert, + io::{self, Write}, + path::PathBuf, +}; + +use anyhow::Context; +use comrak::adapters::SyntaxHighlighterAdapter; +use tree_sitter::Language; +use tree_sitter_highlight::{HighlightConfiguration, HighlightEvent, Highlighter}; +use tree_sitter_loader::{Config, LanguageConfiguration, Loader}; + +pub struct TreesitterSyntaxAdapter { + parsers_directory: PathBuf, +} + +impl TreesitterSyntaxAdapter { + pub fn new(parsers_directory: PathBuf) -> anyhow::Result { + Ok(TreesitterSyntaxAdapter { parsers_directory }) + } + + pub fn get_loader(parsers_directory: &PathBuf) -> anyhow::Result { + Loader::new() + .and_then(|mut loader| { + let config = { + let parsers_directory = parsers_directory.clone(); + let parser_directories = vec![parsers_directory]; + Config { parser_directories } + }; + loader.find_all_languages(&config)?; + Ok(loader) + }) + .with_context(|| { + let parser_directory_str = parsers_directory.display(); + format!( + "Failed to load Treesitter parsers from directory: '{parser_directory_str}'" + ) + }) + } + + fn get_language_config<'a>( + loader: &'a Loader, + code_lang: &'a str, + ) -> anyhow::Result<(Language, &'a LanguageConfiguration<'a>)> { + loader + .language_configuration_for_scope(code_lang) + .transpose() + .context("Language configuration not found") + .and_then(convert::identity) + .with_context(|| format!("Failed to retrieve Treesitter language configuration for language: '{code_lang}'")) + } + + fn get_highlight_configuration<'a>( + language: Language, + config: &'a LanguageConfiguration<'a>, + scope: &'a str, + ) -> anyhow::Result<&'a HighlightConfiguration> { + config + .highlight_config(language) + .transpose() + .with_context(|| { + format!("Failed to retrieve Treesitter highlights for language: '{scope}'") + }) + .and_then(convert::identity) + } + + fn get_highlights<'a>( + &'a self, + loader: &'a Loader, + highlighter: &'a mut Highlighter, + code: &'a str, + code_lang: &'a str, + ) -> anyhow::Result< + impl Iterator> + 'a, + > { + let (language, lang_config) = Self::get_language_config(&loader, code_lang)?; + let highlight_config = Self::get_highlight_configuration(language, lang_config, code_lang)?; + let highlights = + highlighter.highlight(&highlight_config, code.as_bytes(), None, |lang| loader.highlight_config_for_injection_string(lang))?; + // loader.configure_highlights(&highlight_config.names().to_vec()); + + Ok(highlights) + } + + pub fn determine_ts_scope_name(code_lang: &str) -> String { + match code_lang { + _ => format!("source.{}", code_lang), + } + } +} + +impl SyntaxHighlighterAdapter for TreesitterSyntaxAdapter { + + fn write_highlighted( + &self, + output: &mut dyn Write, + lang: Option<&str>, + code: &str, + ) -> io::Result<()> { + let scope = if let Some(lang) = lang { + if lang.is_empty() { + return Ok(()); + } + TreesitterSyntaxAdapter::determine_ts_scope_name(lang) + } else { + return Ok(()); + }; + + let loader = TreesitterSyntaxAdapter::get_loader(&self.parsers_directory).unwrap(); + let mut highlighter = Highlighter::new(); + let highlights = self + .get_highlights(&loader, &mut highlighter, code, scope.as_str()) + .unwrap(); + + let highlight_names = loader.highlight_names(); + println!("AT LANGUAGE -> {}", scope); + println!("HIGHLIGHTS: {:#?}", highlight_names); + + for event in highlights { + match event.unwrap() { + HighlightEvent::Source { start, end } => { + write!(output, "{}", String::from(&code[start..end]))? + } + HighlightEvent::HighlightStart(s) => write!( + output, + "", + highlight_names[s.0].replace(".", "-") + )?, + HighlightEvent::HighlightEnd => write!(output, "")?, + } + } + + Ok(()) + } + + fn write_pre_tag( + &self, + output: &mut dyn Write, + attributes: HashMap, + ) -> io::Result<()> { + if attributes.contains_key("lang") { + write!(output, "
", attributes["lang"])
+        } else {
+            output.write_all(b"
")
+        }
+    }
+
+    fn write_code_tag(
+        &self,
+        output: &mut dyn Write,
+        attributes: HashMap,
+    ) -> io::Result<()> {
+        if attributes.contains_key("class") {
+            write!(output, "", attributes["class"])
+        } else {
+            output.write_all(b"")
+        }
+    }
+}