diff --git a/.gitignore b/.gitignore index ea8c4bf..09b9279 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -/target +target +dist +oldicons diff --git a/Cargo.lock b/Cargo.lock index 6124af0..850a188 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,48 +2,12 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "allocator-api2" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" - [[package]] name = "anyhow" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - [[package]] name = "bumpalo" version = "3.16.0" @@ -51,193 +15,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] -name = "byteorder" -version = "1.5.0" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cached" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d73155ae6b28cf5de4cfc29aeb02b8a1c6dab883cb015d15cd514e42766846" -dependencies = [ - "ahash", - "cached_proc_macro", - "cached_proc_macro_types", - "directories", - "hashbrown", - "once_cell", - "rmp-serde", - "serde", - "sled", - "thiserror", - "web-time", -] - -[[package]] -name = "cached_proc_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f42a145ed2d10dce2191e1dcf30cfccfea9026660e143662ba5eec4017d5daa" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "cached_proc_macro_types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "directories" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] -name = "ident_case" -version = "1.0.1" +name = "indexmap" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ - "cfg-if", + "equivalent", + "hashbrown", ] [[package]] @@ -247,63 +43,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19fa1db3b285830176c8a940d4e3376679772bee9f58a83dd9285a4a54e30f6e" [[package]] -name = "js-sys" -version = "0.3.72" +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", -] - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "moonythm" version = "0.1.0" dependencies = [ "anyhow", - "cached", "jotdown", + "once_cell", "pulldown-latex", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", + "serde", + "toml", ] [[package]] @@ -312,48 +66,11 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "proc-macro2" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -376,68 +93,20 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "rmp" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", @@ -445,38 +114,19 @@ dependencies = [ ] [[package]] -name = "sled" -version = "0.34.7" +name = "serde_spanned" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ - "crc32fast", - "crossbeam-epoch", - "crossbeam-utils", - "fs2", - "fxhash", - "libc", - "log", - "parking_lot", + "serde", ] -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "syn" -version = "2.0.79" +version = "2.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" dependencies = [ "proc-macro2", "quote", @@ -484,23 +134,37 @@ dependencies = [ ] [[package]] -name = "thiserror" -version = "1.0.64" +name = "toml" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ - "thiserror-impl", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", ] [[package]] -name = "thiserror-impl" -version = "1.0.64" +name = "toml_datetime" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ - "proc-macro2", - "quote", - "syn", + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -510,186 +174,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] -name = "version_check" -version = "0.9.5" +name = "winnow" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[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.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[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-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -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.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 0c1188c..493c17a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,11 @@ edition = "2021" [dependencies] anyhow = "1.0.89" -cached = { version = "0.53.1", features = ["disk_store"] } jotdown = "0.6.0" pulldown-latex = "0.7.0" +serde = { version = "1.0.214", features = ["derive"] } +toml = "0.8.19" + +# Waiting for https://github.com/rust-lang/rust/issues/109737 +# before switching to the std version. +once_cell = "1.20.2" diff --git a/build.py b/build.py deleted file mode 100755 index ab6538a..0000000 --- a/build.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -p python3 -i python3 -import shutil -import subprocess - -shutil.rmtree("dist", ignore_errors=True) -shutil.copytree("public", "dist") - -with open("dist/index.html", "r") as file: - template = file.read() - -output = subprocess.check_output("cargo run", shell=True).decode("utf-8") -result = template.replace("$CONTENT", output) - -with open("dist/index.html", "w") as file: - file.write(result) diff --git a/content/index.dj b/content/index.dj new file mode 100644 index 0000000..0c70dcb --- /dev/null +++ b/content/index.dj @@ -0,0 +1,14 @@ +# Hiii + +Welcome to my ethereal realm (read: website). This place is still being conjured (read: under construction), so some things might be startlingly empty. Enjoy your stay on the moon! + +I'm known as `prescientmoon`, or sometimes `PGW`. I study mathematics, but I also really like coding and all computer-related sorcery. I love games of all kinds, although rhythm games have a special place in my heart. + +{ title="Contact me" character="canyou" } +::: aside +You can message me in the following places \^-\^ + +- via email at `hi@thisdomain` +- on discord as `@prescientmoon` +- on the ~ IRC network as `prescientmoon` +::: diff --git a/content/arcaea.dj b/content/posts/arcaea.dj similarity index 99% rename from content/arcaea.dj rename to content/posts/arcaea.dj index eabee96..22533ea 100644 --- a/content/arcaea.dj +++ b/content/posts/arcaea.dj @@ -1,5 +1,5 @@ ``` =toml -created-at: 2024-10-31 15:28 +created-at = "2024-10-31T15:28:OO" ``` # Why I love arcaea diff --git a/content/posts/games.dj b/content/posts/games.dj new file mode 100644 index 0000000..e909b6c --- /dev/null +++ b/content/posts/games.dj @@ -0,0 +1 @@ +# My game tier list diff --git a/content/posts/the-realm-s-secrets.dj b/content/posts/the-realm-s-secrets.dj new file mode 100644 index 0000000..7547412 --- /dev/null +++ b/content/posts/the-realm-s-secrets.dj @@ -0,0 +1,15 @@ +# The realm's secrets + +## Djot (why not markdown?) +- extensionability +- writing my own html generator +- templating +- metadata + +## Hosting +- hosted on my nixos server +- there's interesting stuff happening there too, but that deserves it's own post + +## LaTeX +- tried using `cached` with `latexmlmath`, but results were slow. +- ended up using the `pulldown-latex` crate. diff --git a/flake.nix b/flake.nix index 6c93e8d..b275b7b 100644 --- a/flake.nix +++ b/flake.nix @@ -16,8 +16,7 @@ pkgs.clippy pkgs.rust-analyzer pkgs.rustfmt - pkgs.ruff - pkgs.perl538Packages.LaTeXML + pkgs.imagemagick ]; buildInputs = with pkgs; [ ]; diff --git a/public/styles.css b/public/styles.css index 1280f81..4e85f9f 100644 --- a/public/styles.css +++ b/public/styles.css @@ -6,6 +6,7 @@ html { max-width: 70ch; margin-left: auto; margin-right: auto; + padding: 1em; } blockquote { @@ -28,19 +29,11 @@ ol { align-items: center; } -.aside-summary > .aside-title { - text-decoration: underline; -} - -.aside-summary > * { - padding: 0; - margin: 0; -} - img.aside-icon { + /* display: inline-block; */ height: 1.75rem; margin-right: 0.5rem; - transform: translateY(-2px); + /* transform: translateY(-100px); */ } .aside { @@ -53,6 +46,7 @@ img.aside-icon { .aside-summary { display: inline-flex; align-items: center; + box-sizing: border-box; } .aside-summary::marker { @@ -66,6 +60,15 @@ img.aside-icon { box-sizing: border-box; } +.aside-summary > .aside-title { + text-decoration: underline; +} + +.aside-summary > * { + padding: 0; + margin: 0; +} + .aside[open] .aside_summary:before { content: "▼"; } diff --git a/src/html.rs b/src/html.rs index 42df1b5..eb8a0bd 100644 --- a/src/html.rs +++ b/src/html.rs @@ -12,66 +12,26 @@ use jotdown::OrderedListNumbering::*; use jotdown::SpanLinkType; use crate::template; -use crate::template::Template; use crate::template::TemplateRenderer; // {{{ Renderer -/// Render events into a string. -pub fn render_to_string<'s, I>(events: I) -> anyhow::Result<String> -where - I: Iterator<Item = Event<'s>>, -{ - let mut s = String::new(); - Renderer::new()?.push(events, &mut s)?; - Ok(s) -} +/// Render djot content as HTML. +pub fn render_html<'s>( + mut events: impl Iterator<Item = Event<'s>>, + mut out: impl std::fmt::Write, +) -> anyhow::Result<()> { + let mut w = Writer::new(); + events.try_for_each(|e| w.render_event(&e, &mut out))?; + w.render_epilogue(&mut out)?; -/// [`Render`] implementor that writes HTML output. -#[derive(Clone, Debug)] -pub struct Renderer { - templates: BuiltinTempaltes, -} - -impl Renderer { - pub fn new() -> anyhow::Result<Self> { - Ok(Self { - templates: BuiltinTempaltes::new()?, - }) - } - - pub fn push<'s>( - &self, - mut events: impl Iterator<Item = Event<'s>>, - mut out: impl std::fmt::Write, - ) -> anyhow::Result<()> { - let mut w = Writer::new(self); - events.try_for_each(|e| w.render_event(&e, &mut out))?; - w.render_epilogue(&mut out)?; - - Ok(()) - } -} -// }}} -// {{{ Bring in templates -#[derive(Clone, Debug)] -struct BuiltinTempaltes { - aside_template: Template, -} - -impl BuiltinTempaltes { - fn new() -> anyhow::Result<Self> { - Ok(BuiltinTempaltes { - aside_template: template!("./templates/aside.html")?, - }) - } + Ok(()) } // }}} -struct Writer<'s> { +pub struct Writer<'s> { list_tightness: Vec<bool>, states: Vec<State<'s>>, footnotes: Footnotes<'s>, - renderer: &'s Renderer, } #[derive(Debug, Clone)] @@ -84,20 +44,20 @@ enum State<'s> { } impl<'s> Writer<'s> { - fn new(renderer: &'s Renderer) -> Self { + pub fn new() -> Self { Self { list_tightness: Vec::new(), states: Vec::new(), footnotes: Footnotes::default(), - renderer, } } #[allow(clippy::single_match)] - fn render_event<W>(&mut self, e: &Event<'s>, mut out: W) -> anyhow::Result<()> - where - W: std::fmt::Write, - { + pub fn render_event( + &mut self, + e: &Event<'s>, + mut out: impl std::fmt::Write, + ) -> anyhow::Result<()> { // {{{ Handle footnotes if let Event::Start(Container::Footnote { label }, ..) = e { self.footnotes.start(label, Vec::new()); @@ -157,7 +117,7 @@ impl<'s> Writer<'s> { } match &c { - Container::RawBlock { .. } => unreachable!(), + Container::RawBlock { .. } => {} Container::RawInline { .. } => unreachable!(), Container::Footnote { .. } => unreachable!(), // {{{ List @@ -226,7 +186,7 @@ impl<'s> Writer<'s> { })?; let mut renderer = - TemplateRenderer::new(&self.renderer.templates.aside_template); + TemplateRenderer::new(template!("templates/aside.html")?); while let Some(label) = renderer.current(&mut out)? { if label == "character" { @@ -378,7 +338,7 @@ impl<'s> Writer<'s> { } match c { - Container::RawBlock { .. } => unreachable!(), + Container::RawBlock { .. } => {} Container::RawInline { .. } => unreachable!(), Container::Footnote { .. } => unreachable!(), // {{{ List @@ -463,7 +423,6 @@ impl<'s> Writer<'s> { Some(State::TextOnly) => write_attr(s, &mut out)?, Some(State::Raw) => out.write_str(s)?, Some(State::Math(display)) => { - // let string: String = format!("{}{s}{}", delim, delim); let config = pulldown_latex::RenderConfig { display_mode: { use pulldown_latex::config::DisplayMode::*; diff --git a/src/main.rs b/src/main.rs index 486632f..595e76f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,15 @@ +use std::fs::{self}; use std::path::{Path, PathBuf}; use std::process::Command; use std::str::FromStr; -use anyhow::Context; -use html::Renderer; +use anyhow::{anyhow, Context}; +use html::render_html; use template::TemplateRenderer; mod html; +mod metadata; mod template; -mod tex; fn copy_recursively(from: &Path, to: &Path) -> anyhow::Result<()> { Command::new("cp").arg("-r").arg(from).arg(to).output()?; @@ -16,9 +17,68 @@ fn copy_recursively(from: &Path, to: &Path) -> anyhow::Result<()> { Ok(()) } +// {{{ Generate single page +fn generate_page(path: &Path) -> anyhow::Result<()> { + let content_path = PathBuf::from_str("content")?.join(path); + + let djot_input = std::fs::read_to_string(content_path).unwrap(); + let mut out = String::new(); + + let page_template = template!("templates/page.html")?; + let mut page_renderer = TemplateRenderer::new(page_template); + + // let events = jotdown::Parser::new(&djot_input); + // let meta = PageMetadata::new(events)?; + // println!("Metadata: {meta:?}"); + + while let Some(label) = page_renderer.next(&mut out)? { + if label == "content" { + let events = jotdown::Parser::new(&djot_input); + render_html(events, &mut out)?; + } else { + break; + } + } + + page_renderer.finish(&mut out)?; + + let mut out_path = PathBuf::from_str("dist")?.join(path); + out_path.set_file_name(format!( + "{}.html", + path.file_stem() + .ok_or_else(|| anyhow!("Empty filestem encountered"))? + .to_str() + .unwrap() + )); + std::fs::write(out_path, out).with_context(|| "Failed to write `arcaea.html` post")?; + + Ok(()) +} +// }}} +// {{{ Generate an entire directory +fn generate_dir(path: &Path) -> anyhow::Result<()> { + let content_path = PathBuf::from_str("content")?.join(path); + let out_path = PathBuf::from_str("dist")?.join(path); + fs::create_dir_all(out_path) + .with_context(|| format!("Could not generate directory {path:?}"))?; + + for file in fs::read_dir(content_path)? { + let file_path = file?.path(); + let path = path.join(file_path.file_name().unwrap()); + if file_path.is_dir() { + generate_dir(&path)?; + } else { + generate_page(&path)?; + } + } + + Ok(()) +} +// }}} + fn main() -> anyhow::Result<()> { - let dist_path = PathBuf::from_str("dist")?; let public_path = PathBuf::from_str("public")?; + let dist_path = PathBuf::from_str("dist")?; if dist_path.exists() { std::fs::remove_dir_all(&dist_path).with_context(|| "Cannot delete `dist` directory")?; @@ -31,30 +91,7 @@ fn main() -> anyhow::Result<()> { .with_context(|| "Cannot copy `public` -> `dist`")?; } - // {{{ Generate contents - let djot_input = std::fs::read_to_string("content/arcaea.dj").unwrap(); - let mut out = String::new(); - let page_template = template!("templates/page.html")?; - let mut page_renderer = TemplateRenderer::new(&page_template); - - while let Some(label) = page_renderer.next(&mut out)? { - if label == "content" { - let events = jotdown::Parser::new(&djot_input); - let html = Renderer::new()?; - html.push(events, &mut out)?; - } else { - break; - } - } - - page_renderer.finish(&mut out)?; - // }}} - - let posts_dir = dist_path.join("posts"); - std::fs::create_dir(&posts_dir).with_context(|| "Cannot create `dist/posts` directory")?; - - std::fs::write(posts_dir.join("arcaea.html"), out) - .with_context(|| "Failed to write `arcaea.html` post")?; + generate_dir(&PathBuf::new())?; Ok(()) } diff --git a/src/metadata.rs b/src/metadata.rs new file mode 100644 index 0000000..4515250 --- /dev/null +++ b/src/metadata.rs @@ -0,0 +1,138 @@ +#![allow(dead_code)] +use std::fmt::Write; + +use anyhow::{anyhow, bail, Context}; +use jotdown::{Container, Event}; +use serde::Deserialize; + +use crate::html; + +#[derive(Deserialize, Debug, Default)] +pub struct PageConfig { + created_at: Option<String>, +} + +impl PageConfig { + /// Merge another config into the current one. Might error out on duplicate values. + fn merge(&mut self, other: PageConfig) -> anyhow::Result<()> { + match &self.created_at { + None => self.created_at = other.created_at, + Some(first_created) => { + if let Some(second_created) = other.created_at { + if second_created != *first_created { + bail!("Conflicting values for `created_at` page attribute: {first_created} and {second_created}"); + } + } + } + }; + + Ok(()) + } +} + +#[derive(Debug)] +pub struct PageMetadata { + title: Heading, + config: PageConfig, + toc: Vec<Heading>, +} + +impl PageMetadata { + pub fn new<'s>(mut events: impl Iterator<Item = Event<'s>>) -> anyhow::Result<Self> { + let mut w = Writer::new(); + events.try_for_each(|e| w.render_event(&e))?; + + let title = w + .toc + .first() + .ok_or_else(|| anyhow!("No heading found to infer title from"))?; + + Ok(Self { + title: title.to_owned(), + config: w.config, + toc: w.toc, + }) + } +} + +#[derive(Debug, Clone)] +struct Heading { + pub level: u8, + pub id: String, + pub text: String, + pub html: String, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum State { + Toplevel, + Heading, + Toml, +} + +struct Writer<'s> { + html_renderer: html::Writer<'s>, + config: PageConfig, + toc: Vec<Heading>, + toml_text: String, + state: State, +} + +impl<'s> Writer<'s> { + fn new() -> Self { + Self { + html_renderer: html::Writer::new(), + config: PageConfig::default(), + toc: Vec::new(), + toml_text: String::new(), + state: State::Toplevel, + } + } + + fn render_event(&mut self, e: &jotdown::Event<'s>) -> anyhow::Result<()> { + match e { + Event::Start(Container::Heading { level, id, .. }, _) => { + assert_eq!(self.state, State::Toplevel); + self.state = State::Heading; + self.toc.push(Heading { + level: *level as u8, + id: id.to_string(), + text: String::new(), + html: String::new(), + }) + } + Event::End(Container::Heading { .. }) => { + assert_eq!(self.state, State::Heading); + self.state = State::Toplevel; + } + Event::Start(Container::RawBlock { format: "toml" }, _) => { + assert_eq!(self.state, State::Toplevel); + self.state = State::Toml + } + Event::End(Container::RawBlock { format: "toml" }) => { + assert_eq!(self.state, State::Toml); + self.state = State::Toplevel; + + let config: PageConfig = toml::from_str(&self.toml_text) + .with_context(|| "Failed to parse page config in TOML format")?; + self.config.merge(config)?; + + self.toml_text.clear(); + } + Event::Str(str) if self.state == State::Toml => { + self.toml_text.write_str(str)?; + } + other if self.state == State::Heading => { + let last_heading = self.toc.last_mut().unwrap(); + self.html_renderer.render_event(e, &mut last_heading.html)?; + + if let Event::Str(str) = other { + last_heading.text.write_str(str)?; + } + } + _ => {} + } + + Ok(()) + } +} diff --git a/src/template.rs b/src/template.rs index a206ad4..389bd35 100644 --- a/src/template.rs +++ b/src/template.rs @@ -1,25 +1,23 @@ -use std::fmt::Write; - use anyhow::bail; // {{{ Templates & stops #[derive(Clone, Debug)] -struct Stop { - label: String, +struct Stop<'s> { + label: &'s str, start: usize, length: usize, } #[derive(Clone, Debug)] -pub struct Template { - text: String, - stops: Vec<Stop>, +pub struct Template<'s> { + text: &'s str, + stops: Vec<Stop<'s>>, } -impl Template { +impl<'s> Template<'s> { // {{{ Parse template #[allow(clippy::iter_nth_zero)] - pub fn parse(text: String) -> anyhow::Result<Template> { + pub fn parse(text: &'s str) -> anyhow::Result<Template<'s>> { let mut stops = Vec::new(); let open_stop = "{{"; @@ -27,25 +25,23 @@ impl Template { let mut current_stop: Option<Stop> = None; let mut prev_ix = None; - for (ix, c) in text.char_indices() { + for (ix, _) in text.char_indices() { if let Some(prev) = prev_ix { // This char, together with the previous one let last_two = &text[prev..=ix]; if close_stop == last_two { if let Some(mut stop) = current_stop.take() { - stop.label.pop().unwrap(); - // I think this is safe, as } is ascii + // I think this is safe, as { and } are ascii + stop.label = &text[stop.start + 2..=ix - 2]; stop.length = ix + 1 - stop.start; stops.push(stop); } } else if open_stop == last_two && current_stop.is_none() { current_stop = Some(Stop { - label: String::new(), + label: "", start: prev, length: 0, }); - } else if let Some(stop) = current_stop.as_mut() { - stop.label.write_char(c)?; } } @@ -67,7 +63,7 @@ enum RendererState { #[derive(Clone, Debug)] pub struct TemplateRenderer<'a> { - template: &'a Template, + template: &'a Template<'a>, state: RendererState, } @@ -84,7 +80,7 @@ impl<'a> TemplateRenderer<'a> { pub fn current(&mut self, w: impl std::fmt::Write) -> anyhow::Result<Option<&'a str>> { let current_label = match self.state { RendererState::Started => self.next(w)?, - RendererState::InStop(ix) => Some(self.template.stops[ix].label.as_str()), + RendererState::InStop(ix) => Some(self.template.stops[ix].label), RendererState::Finished => None, }; @@ -125,7 +121,7 @@ impl<'a> TemplateRenderer<'a> { w.write_str(&self.template.text[current_pos..next_pos])?; let current_label = match self.state { - RendererState::InStop(ix) => Some(self.template.stops[ix].label.as_str()), + RendererState::InStop(ix) => Some(self.template.stops[ix].label), _ => None, }; @@ -150,8 +146,13 @@ impl<'a> TemplateRenderer<'a> { #[macro_export] macro_rules! template { ($path:literal) => {{ + use once_cell::sync::OnceCell; + use $crate::template::Template; + static TEMPLATE_TEXT: &str = include_str!($path); - $crate::template::Template::parse(TEMPLATE_TEXT.to_owned()) + static CELL: OnceCell<Template<'static>> = OnceCell::new(); + + CELL.get_or_try_init(|| Template::parse(TEMPLATE_TEXT)) }}; } // }}} diff --git a/src/tex.rs b/src/tex.rs deleted file mode 100644 index 84c5775..0000000 --- a/src/tex.rs +++ /dev/null @@ -1,32 +0,0 @@ -use anyhow::anyhow; -use cached::{proc_macro::io_cached, DiskCache}; - -fn make_cache() -> DiskCache<&'static str, String> { - DiskCache::new("tex-cache") - .set_disk_directory("/home/moon/.cache/moonythm") - .build() - .unwrap() -} - -#[io_cached( - disk = true, - map_error = r##"|err| anyhow::Error::from(err)"##, - create = r"{ make_cache() }" -)] -pub fn compile_tex(string: &str) -> Result<String, anyhow::Error> { - let res = std::process::Command::new("latexmlmath") - .arg("--preload=amsfonts") - .arg("--strict") - .arg("--quiet") - .arg(string) - .output() - .expect("failed to execute latexmathml process"); - - if res.status.success() { - let output = String::from_utf8_lossy(&res.stdout); - Ok(output.trim().to_owned()) - } else { - let output = String::from_utf8_lossy(&res.stderr); - Err(anyhow!("{}", output.trim())) - } -}