diff --git a/Cargo.lock b/Cargo.lock index d997b32..d20493f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,6 +120,24 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ar_archive_writer" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cd58deff2140a0a8eae87e417bd01db68a33e148aa93d1e8cd837e55e312b6" +dependencies = [ + "object", +] + [[package]] name = "arbitrary" version = "1.4.2" @@ -154,6 +172,18 @@ dependencies = [ "password-hash 0.6.1", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "asn1-rs" version = "0.7.2" @@ -431,6 +461,12 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + [[package]] name = "base16ct" version = "0.2.0" @@ -485,6 +521,44 @@ dependencies = [ "sha2 0.11.0", ] +[[package]] +name = "biblatex" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "591eba69b7c085632e22ca03606f0bbea68d53bbe26c8962e2d549af20c6a561" +dependencies = [ + "paste", + "roman-numerals-rs", + "strum", + "unic-langid", + "unicode-normalization", + "unscanny", +] + +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitfields" version = "1.0.3" @@ -630,12 +704,44 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.12.1" @@ -740,6 +846,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "chinese-number" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e964125508474a83c95eb935697abbeb446ff4e9d62c71ce880e3986d1c606b" +dependencies = [ + "chinese-variant", + "enum-ordinalize", + "num-bigint 0.4.8", + "num-traits", +] + +[[package]] +name = "chinese-variant" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d1275808335c5583ea45a4141d631dafcb36b79fa8a5e10b00e356b6af3e08a" + [[package]] name = "chrono" version = "0.4.45" @@ -760,7 +884,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ "chrono", - "phf", + "phf 0.12.1", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", ] [[package]] @@ -785,6 +936,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "citationberg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756ff1e3d43a9ecc8183932fb4d9fd3971236f3ce4acb62fe51d1cd43297547d" +dependencies = [ + "quick-xml 0.38.4", + "serde", + "serde_path_to_error", +] + [[package]] name = "cmac" version = "0.7.2" @@ -823,6 +985,39 @@ dependencies = [ "x509-cert", ] +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.20", +] + +[[package]] +name = "codex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0732ab1a27b4ea05e6f9f60a5122c9924dd5123defde0d8e907f58cf643d40e6" +dependencies = [ + "chinese-number", +] + +[[package]] +name = "color" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ec7c5eb7a16992b1904d76c517d170ab353b0e0b3d5a0c81a8a0cd1037893cf" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "combine" version = "4.6.8" @@ -833,6 +1028,30 @@ dependencies = [ "memchr", ] +[[package]] +name = "comemo" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c963350b2b08aa4b725d7802593245380ab53dacfedcaa971385fc33306c0d4" +dependencies = [ + "comemo-macros", + "parking_lot", + "rustc-hash", + "siphasher", + "slab", +] + +[[package]] +name = "comemo-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c400139ba1389ef9e20ad2d87cda68b437a66483aa0da616bdf2cea7413853" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "compression-codecs" version = "0.4.39" @@ -896,6 +1115,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + [[package]] name = "cpubits" version = "0.1.1" @@ -950,6 +1178,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-queue" version = "0.3.13" @@ -965,6 +1212,12 @@ version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -1026,6 +1279,27 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + [[package]] name = "ctr" version = "0.9.2" @@ -1170,6 +1444,12 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" +[[package]] +name = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + [[package]] name = "dbl" version = "0.3.2" @@ -1483,6 +1763,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1621,6 +1910,26 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + [[package]] name = "enum_dispatch" version = "0.3.13" @@ -1681,6 +1990,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + [[package]] name = "event-listener" version = "5.4.2" @@ -1701,12 +2019,44 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fancy-regex" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + [[package]] name = "fastrand" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fearless_simd" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97b65636e5b9ef369943878ac74335ba1c55c1cb6adbf1e2c293c624248d693" + +[[package]] +name = "fearless_simd" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3296eb97d869113eaf148a6bdf01884e90b3828ad7ae2340b0f93362fc158611" + [[package]] name = "ff" version = "0.13.1" @@ -1759,10 +2109,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.9.1", "zlib-rs", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + [[package]] name = "flume" version = "0.11.1" @@ -1792,6 +2148,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +[[package]] +name = "font-types" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b38ad915f6dadd993ced50848a8291a543bd41ca62bc10740d5e64e2ab4cfd7" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "log", + "slotmap", + "tinyvec", + "ttf-parser", +] + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -1994,6 +2371,39 @@ dependencies = [ "zeroize", ] +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "glidesort" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2e102e6eb644d3e0b186fc161e4460417880a0a0b87d235f2e5b8fb30f2e9e0" + +[[package]] +name = "glifo" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d99fc21d493812643aae86d53b7bbd02f376434a90317e8a790bc209fdd6605e" +dependencies = [ + "bytemuck", + "foldhash 0.2.0", + "hashbrown 0.17.1", + "log", + "peniko", + "png", + "skrifa", + "smallvec", + "vello_common 0.0.9", +] + [[package]] name = "gloo-timers" version = "0.4.0" @@ -2028,6 +2438,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "guillotiere" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" +dependencies = [ + "euclid", +] + [[package]] name = "h2" version = "0.4.19" @@ -2047,6 +2466,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -2082,6 +2512,138 @@ dependencies = [ "hashbrown 0.15.5", ] +[[package]] +name = "hayagriva" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b6c185c5c72546d50b25b70187f01ab9a1a2fa21c4db8691e2426fa5fce805c" +dependencies = [ + "biblatex", + "ciborium", + "citationberg", + "icu_collator", + "icu_locale", + "indexmap", + "paste", + "roman-numerals-rs", + "serde", + "serde_yaml", + "thiserror 2.0.20", + "unic-langid", + "unicode-segmentation", + "unscanny", + "url", +] + +[[package]] +name = "hayro" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4caa128ab87fd48ffb7490617cf93f77f606820dffbc9fd9ef6ab0ed077f56d" +dependencies = [ + "bytemuck", + "hayro-interpret", + "image", + "kurbo", + "pic-scale", + "vello_cpu", +] + +[[package]] +name = "hayro-ccitt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a" + +[[package]] +name = "hayro-ccitt" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2866f0d976e76497480b853d5e258dab6e4b89ecfe991124e08f15dfa8fd03ad" + +[[package]] +name = "hayro-cmap" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d285dc30731c8485de5fa732fbdf2b3affdf01e4da7c2135022ca6fa664bf6" +dependencies = [ + "hayro-postscript", +] + +[[package]] +name = "hayro-interpret" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2613d0406898995042d0794c4245b2f2fba1246490c8ac593769bba6551129d" +dependencies = [ + "bitflags", + "hayro-cmap", + "hayro-syntax", + "kurbo", + "moxcms", + "phf 0.13.1", + "rustc-hash", + "siphasher", + "skrifa", + "smallvec", + "yoke", +] + +[[package]] +name = "hayro-jbig2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000e025850f4592ddcaee85640db70704151f2bafd43b6f431aa5b6a2c6a35a9" +dependencies = [ + "fearless_simd 1.1.0", + "hayro-ccitt 0.4.0", +] + +[[package]] +name = "hayro-jpeg2000" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1" +dependencies = [ + "fearless_simd 0.4.1", +] + +[[package]] +name = "hayro-postscript" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "885c5ef0654933139a9b9546fc2c69e18d37f38aa2520f079092b1be18f1fcaa" + +[[package]] +name = "hayro-svg" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7434c89e920d84e077214a29e69b462a6518754610f732f1124af3948410cb8c" +dependencies = [ + "base64 0.22.1", + "hayro-interpret", + "image", + "kurbo", + "siphasher", + "xmlwriter", +] + +[[package]] +name = "hayro-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0edeafd70aa2db743de8ede8637d07ec87db05efe69cde371d03f1b185fcef27" +dependencies = [ + "flate2", + "hayro-ccitt 0.3.0", + "hayro-jbig2", + "hayro-jpeg2000", + "memchr", + "rustc-hash", + "smallvec", + "zune-jpeg", +] + [[package]] name = "heck" version = "0.5.0" @@ -2279,6 +2841,12 @@ dependencies = [ "tracing", ] +[[package]] +name = "hypher" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f2b4f6b5da34d400d4c112eadcc14512cc5d04307a8eee182586d9bebd7ce6" + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -2303,6 +2871,31 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collator" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08984ed58ac439ebf3e13d2cf26b0c46a60afcd21721c1d14087c0b240344dda" +dependencies = [ + "icu_collator_data", + "icu_collections", + "icu_locale_core", + "icu_locale_fallback", + "icu_normalizer", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_collator_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d7e54efdddeb1208c08dd5d32b53a879ac00d2d3d051b2255fd26821d16368" + [[package]] name = "icu_collections" version = "2.3.0" @@ -2311,12 +2904,28 @@ checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", + "serde", "utf8_iter", "yoke", "zerofrom", "zerovec", ] +[[package]] +name = "icu_locale" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "785f595c61ef57169a467eeed7b4b6936a66f6cacbb116a96ee86da983251bf4" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_locale_fallback", + "icu_provider", + "tinystr", + "zerovec", +] + [[package]] name = "icu_locale_core" version = "2.3.0" @@ -2325,11 +2934,38 @@ checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", + "serde", "tinystr", "writeable", "zerovec", ] +[[package]] +name = "icu_locale_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37d91460e362a5cf58907cd7ce871411775ee6294e49a5cc8e6cec16dfa75ea" + +[[package]] +name = "icu_locale_fallback" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251af8e57c9400e3eb58242fe5b8b1152b2a64fdf4cf632f923c38ccee6f2fa9" +dependencies = [ + "icu_locale_core", + "icu_locale_fallback_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_fallback_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf2a22ec8fa68f1a0c1129a3f8583f8f8bc24e8b9ccbe98ead99f62a4dc3a8" + [[package]] name = "icu_normalizer" version = "2.3.0" @@ -2341,6 +2977,9 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", + "utf16_iter", + "utf8_iter", + "write16", "zerovec", ] @@ -2361,6 +3000,7 @@ dependencies = [ "icu_locale_core", "icu_properties_data", "icu_provider", + "serde", "zerotrie", "zerovec", ] @@ -2379,6 +3019,9 @@ checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" dependencies = [ "displaydoc", "icu_locale_core", + "postcard", + "serde", + "stable_deref_trait", "writeable", "yoke", "zerofrom", @@ -2386,6 +3029,44 @@ dependencies = [ "zerovec", ] +[[package]] +name = "icu_provider_blob" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5916b44fac319d3f58e4d8d805a627df19e27937b582cd99fcde3bb6b7ce1b0e" +dependencies = [ + "icu_provider", + "postcard", + "serde", + "writeable", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d07aafccd67af15d02512a6adf5896fbc5ed00f2e99b471d2efa14016db3db" +dependencies = [ + "core_maths", + "icu_collections", + "icu_locale_fallback", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "serde", + "smallvec", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae293c039020f9ec10710af98d29ce6aa2051486638b49c9a6409f3b4a9e98ad" + [[package]] name = "idea" version = "0.5.1" @@ -2422,6 +3103,40 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imagesize" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c" + [[package]] name = "indexmap" version = "2.14.2" @@ -2430,6 +3145,9 @@ checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", "hashbrown 0.17.1", + "rayon", + "serde", + "serde_core", ] [[package]] @@ -2543,6 +3261,15 @@ dependencies = [ "signature 2.2.0", ] +[[package]] +name = "kamadak-exif" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1130d80c7374efad55a117d715a3af9368f0fa7a2c54573afc15a188cd984837" +dependencies = [ + "mutate_once", +] + [[package]] name = "keccak" version = "0.1.6" @@ -2584,6 +3311,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "kurbo" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b60dfc32f652b926df6192e55525b16d186c69d47876c3ead4da5cc9f8450e2" +dependencies = [ + "arrayvec", + "euclid", + "polycool", + "smallvec", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2671,17 +3410,42 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linebender_resource_handle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" + +[[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.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +[[package]] +name = "lipsum" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636860251af8963cc40f6b4baadee105f02e21b28131d76eba8e40ce84ab8064" +dependencies = [ + "rand 0.8.8", + "rand_chacha", +] + [[package]] name = "litemap" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" +dependencies = [ + "serde_core", +] [[package]] name = "lock_api" @@ -2781,6 +3545,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + [[package]] name = "miniz_oxide" version = "0.9.1" @@ -2827,6 +3601,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "multer" version = "3.1.0" @@ -2844,6 +3628,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "mutate_once" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" + [[package]] name = "narl-workspace" version = "0.1.0" @@ -2887,6 +3677,10 @@ dependencies = [ "tower-http", "tracing", "tracing-subscriber", + "typst", + "typst-assets", + "typst-layout", + "typst-svg", "uuid", "x509-parser", "zeroize", @@ -3075,6 +3869,15 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "object" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "memchr", +] + [[package]] name = "ocb3" version = "0.1.0" @@ -3252,6 +4055,39 @@ dependencies = [ "windows-strings", ] +[[package]] +name = "palette" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" +dependencies = [ + "approx", + "libm", + "palette_derive", + "palette_math", +] + +[[package]] +name = "palette_derive" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" +dependencies = [ + "libm", +] + [[package]] name = "parking" version = "2.2.1" @@ -3301,6 +4137,12 @@ dependencies = [ "phc", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pbkdf2" version = "0.13.0" @@ -3329,6 +4171,19 @@ dependencies = [ "base64ct", ] +[[package]] +name = "peniko" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c8299360d2e998bdb106dc0a6cd71dcc5f4df51df1b620361bf50e283cca6" +dependencies = [ + "bytemuck", + "color", + "kurbo", + "linebender_resource_handle", + "smallvec", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -3421,7 +4276,41 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" dependencies = [ - "phf_shared", + "phf_shared 0.12.1", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -3433,6 +4322,31 @@ dependencies = [ "siphasher", ] +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pic-scale" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb0ff645d35accaec252de081d55984a0d6c952cb1e5dc2b9afa7c78f07288" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project-lite" version = "0.2.17" @@ -3538,6 +4452,32 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "plist" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327a4cb2ad49dc48adfdc9da89e22c64d488b508c67a044d71ba729e4521a285" +dependencies = [ + "base64 0.23.1", + "indexmap", + "quick-xml 0.42.0", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.9", +] + [[package]] name = "polling" version = "3.11.0" @@ -3563,6 +4503,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "polycool" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" +dependencies = [ + "arrayvec", +] + [[package]] name = "polyval" version = "0.6.2" @@ -3587,12 +4536,30 @@ dependencies = [ "zeroize", ] +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ + "serde_core", + "writeable", "zerovec", ] @@ -3653,9 +4620,15 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit", + "toml_edit 0.25.13+spec-1.1.0", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.107" @@ -3726,6 +4699,47 @@ dependencies = [ "zeroize", ] +[[package]] +name = "psm" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd034599e63b970727f70d79e02d62390a4a84f7c6b827c27c46d5ac3fa622" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" +dependencies = [ + "memchr", +] + [[package]] name = "quinn" version = "0.11.11" @@ -3866,6 +4880,26 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "rc2" version = "0.9.0" @@ -3875,6 +4909,16 @@ dependencies = [ "cipher 0.5.2", ] +[[package]] +name = "read-fonts" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4ed38b89c2c77ff968c524145ad65fb010f38af5c7a224b53b81d47ac2daa81" +dependencies = [ + "bytemuck", + "font-types", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -4025,6 +5069,21 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "roman-numerals-rs" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85cd47a33a4510b1424fe796498e174c6a9cf94e606460ef022a19f3e4ff85e" + +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + [[package]] name = "rpassword" version = "7.5.4" @@ -4235,6 +5294,16 @@ dependencies = [ "walkdir", ] +[[package]] +name = "rust_decimal" +version = "1.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7653272e75dcac41dc199fbea6f5797633994fafd339943c06c9af16bf29cd3a" +dependencies = [ + "arrayvec", + "num-traits", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -4355,6 +5424,24 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "rustybuzz" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702" +dependencies = [ + "bitflags", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + [[package]] name = "ryu" version = "1.0.23" @@ -4559,6 +5646,15 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4571,6 +5667,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serdect" version = "0.2.0" @@ -4747,18 +5856,46 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" +[[package]] +name = "simplecss" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + [[package]] name = "siphasher" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" +[[package]] +name = "skrifa" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c34617370ae968efb7161bb2beb517d9084659aae19e24b89e3db25b46e4564" +dependencies = [ + "bytemuck", + "read-fonts", +] + [[package]] name = "slab" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.16.0" @@ -5084,12 +6221,34 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + [[package]] name = "stringprep" version = "0.1.5" @@ -5107,12 +6266,43 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "strum" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "svgtypes" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d" +dependencies = [ + "kurbo", + "siphasher", +] + [[package]] name = "syn" version = "2.0.119" @@ -5155,6 +6345,27 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "syntect" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" +dependencies = [ + "bincode", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror 2.0.20", + "walkdir", + "yaml-rust", +] + [[package]] name = "tap" version = "1.0.1" @@ -5174,6 +6385,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "thin-vec" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6a4b9ba8738cb4a4f399d37e266becfd475e75eb73425b87a05a2f2039ba63e" + [[package]] name = "thiserror" version = "1.0.69" @@ -5253,6 +6470,17 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-skia-path" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca365c3faccca67d06593c5980fa6c57687de727a03131735bb85f01fdeeb9" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + [[package]] name = "tinystr" version = "0.8.4" @@ -5260,6 +6488,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", + "serde_core", "zerovec", ] @@ -5341,6 +6570,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + [[package]] name = "toml_datetime" version = "1.1.1+spec-1.1.0" @@ -5350,6 +6600,20 @@ dependencies = [ "serde_core", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + [[package]] name = "toml_edit" version = "0.25.13+spec-1.1.0" @@ -5357,9 +6621,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap", - "toml_datetime", + "toml_datetime 1.1.1+spec-1.1.0", "toml_parser", - "winnow", + "winnow 1.0.4", ] [[package]] @@ -5368,9 +6632,15 @@ version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow", + "winnow 1.0.4", ] +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower" version = "0.5.3" @@ -5491,6 +6761,26 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +dependencies = [ + "core_maths", +] + +[[package]] +name = "two-face" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e51b6e60e545cfdae5a4639ff423818f52372211a8d9a3e892b4b0761f76b2" +dependencies = [ + "serde", + "serde_derive", + "syntect", +] + [[package]] name = "twofish" version = "0.7.1" @@ -5500,12 +6790,300 @@ dependencies = [ "cipher 0.4.4", ] +[[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.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "typst" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cb79435d128de5d5443a058a983f6dcc16738760fa55ed703762bc278b1fd3" +dependencies = [ + "arrayvec", + "comemo", + "ecow", + "rustc-hash", + "typst-eval", + "typst-html", + "typst-layout", + "typst-library", + "typst-macros", + "typst-realize", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-assets" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcee505dac6702dd1c5e65aa2e94a6179d19ee09e2e5637d7313db91765dc4e0" +dependencies = [ + "bitflags", +] + +[[package]] +name = "typst-eval" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8823e1822bd181d8bee47b05632d16bf3a0a8ab042e01d815826350d7ae16c3" +dependencies = [ + "comemo", + "ecow", + "indexmap", + "rustc-hash", + "stacker", + "toml", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-segmentation", +] + +[[package]] +name = "typst-html" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41bcfbe480b640c4447d8bf9bb59020da610f239aa032d53328651a03572c09" +dependencies = [ + "az", + "bumpalo", + "comemo", + "ecow", + "palette", + "rustc-hash", + "time", + "typst-assets", + "typst-library", + "typst-macros", + "typst-svg", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", +] + +[[package]] +name = "typst-layout" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1916c407baf8f8815e5d50030eed6d5ac6a0702d927b3c156e38db7a618499e2" +dependencies = [ + "az", + "bumpalo", + "codex", + "comemo", + "ecow", + "either", + "hypher", + "icu_properties", + "icu_provider", + "icu_provider_blob", + "icu_segmenter", + "kurbo", + "libm", + "memchr", + "rustc-hash", + "rustybuzz", + "smallvec", + "ttf-parser", + "typst-assets", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-bidi", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", +] + +[[package]] +name = "typst-library" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12becd02464849f1507f3c4ef3f401a4d28d5938cc74b6acc6f1d703458bf393" +dependencies = [ + "arrayvec", + "az", + "bitflags", + "bumpalo", + "ciborium", + "codex", + "comemo", + "csv", + "ecow", + "either", + "flate2", + "fontdb", + "glidesort", + "hayagriva", + "hayro-syntax", + "icu_properties", + "image", + "indexmap", + "kamadak-exif", + "kurbo", + "libm", + "lipsum", + "memchr", + "moxcms", + "palette", + "percent-encoding", + "phf 0.13.1", + "png", + "rayon", + "regex", + "regex-syntax", + "roxmltree", + "rust_decimal", + "rustc-hash", + "rustybuzz", + "serde", + "serde_json", + "serde_yaml", + "siphasher", + "smallvec", + "syntect", + "time", + "toml", + "ttf-parser", + "two-face", + "typed-arena", + "typst-assets", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", + "unicode-normalization", + "unicode-segmentation", + "unscanny", + "usvg", + "utf8_iter", + "wasmi", + "xmlwriter", +] + +[[package]] +name = "typst-macros" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033626e6fd43dc09170a9237c55a4dd308005fd751456a0c81b5864f822a97df" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "typst-realize" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f2eb73ab25add88cab03b26effabc657977fe850ff81556b28c6b137ff4bf1" +dependencies = [ + "arrayvec", + "bumpalo", + "comemo", + "ecow", + "regex", + "typst-html", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-svg" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5df6dc785695aae085678bd6657aa04a1d26058a76ed042e738658078bca681e" +dependencies = [ + "base64 0.22.1", + "comemo", + "ecow", + "flate2", + "hayro", + "hayro-svg", + "image", + "indexmap", + "itoa", + "rustc-hash", + "ryu", + "ttf-parser", + "typst-assets", + "typst-layout", + "typst-library", + "typst-macros", + "typst-timing", + "typst-utils", + "xmlwriter", +] + +[[package]] +name = "typst-syntax" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a20d79df5d10c7fb0b4f7c18e4b2671edfc21e5ed9ad9894e18cccefd1c70f" +dependencies = [ + "ecow", + "rustc-hash", + "serde", + "toml", + "typst-timing", + "typst-utils", + "unicode-ident", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", + "unscanny", +] + +[[package]] +name = "typst-timing" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6ee5110f671a23164c61caa85dbc476043d503103dedd36f16d93f970f3f59" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "typst-utils" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33ad1675497b45ae9d960a16e95207c35c2c46330d1a6249a9a977670c8c160" +dependencies = [ + "libm", + "once_cell", + "portable-atomic", + "rayon", + "rustc-hash", + "semver", + "siphasher", + "smallvec", + "thin-vec", + "unicode-math-class", +] + [[package]] name = "uds_windows" version = "1.2.1" @@ -5517,6 +7095,50 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "unic-langid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ba52c9b05311f4f6e62d5d9d46f094bd6e84cb8df7b3ef952748d752a7d05" +dependencies = [ + "unic-langid-impl", + "unic-langid-macros", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce1bf08044d4b7a94028c93786f8566047edc11110595914de93362559bc658" +dependencies = [ + "serde", + "tinystr", +] + +[[package]] +name = "unic-langid-macros" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5957eb82e346d7add14182a3315a7e298f04e1ba4baac36f7f0dbfedba5fc25" +dependencies = [ + "proc-macro-hack", + "tinystr", + "unic-langid-impl", + "unic-langid-macros-impl", +] + +[[package]] +name = "unic-langid-macros-impl" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" +dependencies = [ + "proc-macro-hack", + "quote", + "syn 2.0.119", + "unic-langid-impl", +] + [[package]] name = "unicase" version = "2.9.0" @@ -5529,12 +7151,30 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" +[[package]] +name = "unicode-bidi-mirroring" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfa6e8c60bb66d49db113e0125ee8711b7647b5579dc7f5f19c42357ed039fe" + +[[package]] +name = "unicode-ccc" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce61d488bcdc9bc8b5d1772c404828b17fc481c0a582b5581e95fb233aef503e" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-math-class" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d246cf599d5fae3c8d56e04b20eb519adb89a8af8d0b0fbcded369aa3647d65" + [[package]] name = "unicode-normalization" version = "0.1.25" @@ -5550,12 +7190,24 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" +[[package]] +name = "unicode-script" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" + [[package]] name = "unicode-segmentation" version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -5582,6 +7234,18 @@ dependencies = [ "ctutils", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + [[package]] name = "untrusted" version = "0.9.0" @@ -5598,8 +7262,43 @@ dependencies = [ "idna", "percent-encoding", "serde", + "serde_derive", ] +[[package]] +name = "usvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d46cf96c5f498d36b7a9693bc6a7075c0bb9303189d61b2249b0dc3d309c07de" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "ttf-parser", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -5629,6 +7328,53 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vello_common" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3361bff7f7d82c0c496b92048db83846691f0e844cc28dee92b1c824291b55ee" +dependencies = [ + "bytemuck", + "fearless_simd 0.4.1", + "guillotiere", + "hashbrown 0.17.1", + "log", + "peniko", + "png", + "smallvec", + "thiserror 2.0.20", +] + +[[package]] +name = "vello_common" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d672facaa2d697285a786cd9d44d614cd2ce54cdc022504bf339f8fff3b750" +dependencies = [ + "bytemuck", + "fearless_simd 0.4.1", + "guillotiere", + "hashbrown 0.17.1", + "log", + "peniko", + "png", + "smallvec", + "thiserror 2.0.20", +] + +[[package]] +name = "vello_cpu" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0" +dependencies = [ + "bytemuck", + "glifo", + "hashbrown 0.17.1", + "png", + "vello_common 0.0.8", +] + [[package]] name = "version_check" version = "0.9.5" @@ -5734,6 +7480,52 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2300d0f78cba12f14e29e8dd157ea64050c0a688179aefdb2050105805594a0c" +dependencies = [ + "spin", + "wasmi_collections", + "wasmi_core", + "wasmi_ir", + "wasmparser", +] + +[[package]] +name = "wasmi_collections" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a8c42a2a76148d43097b1d7cc2a5bf33d5c23bd4dd69015fc887e311767884" + +[[package]] +name = "wasmi_core" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9013136083d988725953390bf668b64b7a218fabf26f8b913bbc59546b97ee27" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmi_ir" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1fa003f79156f406d62ef0e1464dc03e11ace37170e9fa7524299a75ad8f68" +dependencies = [ + "wasmi_core", +] + +[[package]] +name = "wasmparser" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +dependencies = [ + "bitflags", +] + [[package]] name = "web-sys" version = "0.3.105" @@ -5772,6 +7564,12 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + [[package]] name = "whoami" version = "1.6.1" @@ -6124,6 +7922,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "1.0.4" @@ -6145,6 +7952,12 @@ dependencies = [ "primefield", ] +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + [[package]] name = "writeable" version = "0.6.4" @@ -6210,6 +8023,21 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yoke" version = "0.8.3" @@ -6358,8 +8186,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", + "litemap", + "serde_core", "yoke", "zerofrom", + "zerovec", ] [[package]] @@ -6368,6 +8199,7 @@ version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ + "serde", "yoke", "zerofrom", "zerovec-derive", @@ -6425,6 +8257,21 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] + [[package]] name = "zvariant" version = "4.2.0" diff --git a/Cargo.toml b/Cargo.toml index 4274c60..f8364c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,13 @@ pkcs8 = { version = "0.11", features = ["encryption", "3des", "std"] } sec1 = { version = "0.8", features = ["der"] } sha1 = "0.10" +# ```typst blocks in markdown, typeset on the server into SVG. The fonts come +# from typst-assets, inside the binary, so nothing is fetched to render. +typst = "0.15" +typst-svg = "0.15" +typst-layout = "0.15" +typst-assets = { version = "0.15", features = ["fonts"] } + [dev-dependencies] # A paused clock, so tests of timed loops do not wait in real time. tokio = { version = "1", features = ["test-util"] } diff --git a/README.md b/README.md index 314f358..f62f80c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ Everything is also in the [wiki](https://github.com/narrrl/narl-workspace/wiki). - **Write.** Markdown documents in spaces (`diary`, `work`, `uni`, …) with folders to any depth. Real vim keys on the desktop (CodeMirror 6), plain taps - on a phone. Math by KaTeX, `$x^2$` and `$$…$$`. `[[Title]]` links that are + on a phone. Math by KaTeX, `$x^2$` and `$$…$$`, and ` ```typst ` blocks + typeset by Typst on the server. `[[Title]]` links that are rewritten when what they point at is renamed or moved, and backlinks. - **Plan.** A kanban board per space, due dates said the way you say them (`fri`, `+3d`), cards that come back once done, and an agenda of what is late, @@ -883,6 +884,7 @@ sealed or not. | `POST` | `/api/backup/login/totp`, `/api/backup/login/captcha` | the two-factor code `{"code"}`, or the solved human check `{"token"}`, a waiting login asked for | | `GET`/`POST` | `/api/media` | list / upload (multipart) | | `GET`/`DELETE` | `/api/media/{id}` | serve (with `Range`) / delete a file nothing in the tree owns | +| `POST` | `/api/typst` | `{source}` of a ` ```typst ` block → `{svg}`, or `{error}` as typst words it | | `GET` | `/api/spaces/overview` | every space with what was last written in it | | `POST` | `/api/nodes/{id}/files` | upload files into this folder as file nodes (`?encrypt=true` seals them) | | `POST` | `/api/nodes/{id}/inspect` | what a certificate, key or keystore file holds (`{password}` opens a protected one) | @@ -893,6 +895,7 @@ sealed or not. | `DELETE` | `/api/ssh-keys/{id}` | remove a key, which ends its mounts | | `POST` | `/api/share/{token}` | public: read a shared document, body `{"key"}`; sets the share's media cookie | | `GET` | `/api/share/{token}/media/{id}` | public: media inside a shared document, with that cookie | +| `POST` | `/api/share/{token}/typst` | public: a typst block the shared document holds, with that cookie | ## Deploying diff --git a/docs/images/agenda.png b/docs/images/agenda.png index 04bd995..7a1eb12 100644 Binary files a/docs/images/agenda.png and b/docs/images/agenda.png differ diff --git a/docs/images/board.png b/docs/images/board.png index e5a2a74..7226ff0 100644 Binary files a/docs/images/board.png and b/docs/images/board.png differ diff --git a/docs/images/calendar.png b/docs/images/calendar.png index 37d03d3..1a50957 100644 Binary files a/docs/images/calendar.png and b/docs/images/calendar.png differ diff --git a/docs/images/document.png b/docs/images/document.png index bd96b9e..c655923 100644 Binary files a/docs/images/document.png and b/docs/images/document.png differ diff --git a/docs/images/editor.png b/docs/images/editor.png index f7d87b9..ddee446 100644 Binary files a/docs/images/editor.png and b/docs/images/editor.png differ diff --git a/docs/images/file-certificate.png b/docs/images/file-certificate.png index 17ab278..7a68163 100644 Binary files a/docs/images/file-certificate.png and b/docs/images/file-certificate.png differ diff --git a/docs/images/file-table.png b/docs/images/file-table.png index 54c12e7..3f9e868 100644 Binary files a/docs/images/file-table.png and b/docs/images/file-table.png differ diff --git a/docs/images/help.png b/docs/images/help.png index 13ad68a..b0d390c 100644 Binary files a/docs/images/help.png and b/docs/images/help.png differ diff --git a/docs/images/history.png b/docs/images/history.png index 8e3aa67..8695d31 100644 Binary files a/docs/images/history.png and b/docs/images/history.png differ diff --git a/docs/images/login.png b/docs/images/login.png index 28f4324..e577b02 100644 Binary files a/docs/images/login.png and b/docs/images/login.png differ diff --git a/docs/images/math.png b/docs/images/math.png index fe28e7b..2353d24 100644 Binary files a/docs/images/math.png and b/docs/images/math.png differ diff --git a/docs/images/mobile-document.png b/docs/images/mobile-document.png index a665ef0..f6950a9 100644 Binary files a/docs/images/mobile-document.png and b/docs/images/mobile-document.png differ diff --git a/docs/images/mobile-tree.png b/docs/images/mobile-tree.png index 41a230f..c821e0b 100644 Binary files a/docs/images/mobile-tree.png and b/docs/images/mobile-tree.png differ diff --git a/docs/images/overview.png b/docs/images/overview.png index 642c6a4..69e2411 100644 Binary files a/docs/images/overview.png and b/docs/images/overview.png differ diff --git a/docs/images/search.png b/docs/images/search.png index b9e625a..d3cfc56 100644 Binary files a/docs/images/search.png and b/docs/images/search.png differ diff --git a/docs/images/tiles.png b/docs/images/tiles.png index 3d73d9c..6f90f5b 100644 Binary files a/docs/images/tiles.png and b/docs/images/tiles.png differ diff --git a/docs/images/typst.png b/docs/images/typst.png new file mode 100644 index 0000000..da88cbd Binary files /dev/null and b/docs/images/typst.png differ diff --git a/docs/wiki/API.md b/docs/wiki/API.md index 91b4d78..7bd2e0b 100644 --- a/docs/wiki/API.md +++ b/docs/wiki/API.md @@ -47,6 +47,7 @@ sealed or not. | `POST` | `/api/backup/login/totp`, `/api/backup/login/captcha` | the two-factor code `{"code"}`, or the solved human check `{"token"}`, a waiting login asked for | | `GET`/`POST` | `/api/media` | list / upload (multipart) | | `GET`/`DELETE` | `/api/media/{id}` | serve (with `Range`) / delete a file nothing in the tree owns | +| `POST` | `/api/typst` | `{source}` of a ` ```typst ` block → `{svg}`, or `{error}` as typst words it | | `GET` | `/api/spaces/overview` | every space with what was last written in it | | `POST` | `/api/nodes/{id}/files` | upload files into this folder as file nodes (`?encrypt=true` seals them) | | `POST` | `/api/nodes/{id}/inspect` | what a certificate, key or keystore file holds (`{password}` opens a protected one) | @@ -57,3 +58,4 @@ sealed or not. | `DELETE` | `/api/ssh-keys/{id}` | remove a key, which ends its mounts | | `POST` | `/api/share/{token}` | public: read a shared document, body `{"key"}`; sets the share's media cookie | | `GET` | `/api/share/{token}/media/{id}` | public: media inside a shared document, with that cookie | +| `POST` | `/api/share/{token}/typst` | public: a typst block the shared document holds, with that cookie | diff --git a/docs/wiki/Writing.md b/docs/wiki/Writing.md index cc3e2a5..b34bba2 100644 --- a/docs/wiki/Writing.md +++ b/docs/wiki/Writing.md @@ -59,6 +59,23 @@ Math is set by KaTeX: ![Math in a document](../images/math.png) +### Typst + +A ` ```typst ` block (or ` ```typ `) is set by [Typst](https://typst.app) on +the server and shows as an image where it stands: math, tables, figures, +anything typst lays out. It shows its source while it is being set, and the +error typst gives, with the line of the block, when it cannot be. + +- The page fits what is on it and is transparent, and the text is the + theme's. `#set page(width: 15cm)` makes a block of prose wrap, and any other + `#set` changes what it says. +- A block is typeset with nothing but itself and the fonts built into the + binary: `#import "@preview/…"` and `#image("…")` are refused. +- On a share page the blocks are set too, for the reader holding the key, and + only blocks the shared document holds. + +![A typst block in a document](../images/typst.png) + ## Links A document links to another in two ways: diff --git a/scripts/screenshots.ts b/scripts/screenshots.ts index ea03368..04c575a 100644 --- a/scripts/screenshots.ts +++ b/scripts/screenshots.ts @@ -250,6 +250,28 @@ $$ The trace is the sum of the eigenvalues, $\\operatorname{tr} A = 4$, and the determinant their product, $\\det A = 3$. `, ) +await doc( + algebra.id, + 'Spectral theorem', + `A symmetric matrix is diagonalised by an orthonormal basis of eigenvectors. + +\`\`\`typst +#let A = $mat(2, 1; 1, 2)$ +$ A = Q Lambda Q^T, quad Q^T Q = I, quad Lambda = mat(3, 0; 0, 1) $ + +#table( + columns: 3, + stroke: 0.5pt + rgb("#545c52"), + inset: 6pt, + [*eigenvalue*], [*eigenvector*], [*multiplicity*], + $3$, $1/sqrt(2) vec(1, 1)$, $1$, + $1$, $1/sqrt(2) vec(1, -1)$, $1$, +) +\`\`\` + +The block above is typst; the rest of the page is markdown. +`, +) await doc(algebra.id, 'Exercise sheet 4', `- [x] 4.1 characteristic polynomial\n- [x] 4.2 diagonalise\n- [ ] 4.3 Jordan form\n`) const thesis = await folder(uni, 'thesis') await doc(thesis.id, 'Outline', `## Chapters\n\n1. Introduction\n2. Related work\n3. Method\n4. Evaluation\n`) @@ -388,6 +410,10 @@ await shot('editor') await open('/n/uni/linear-algebra/eigenvalues') await shot('math') +await open('/n/uni/linear-algebra/spectral-theorem') +await sleep(1500) +await shot('typst') + await open('/n/work') await keys('b') await sleep(800) diff --git a/src/main.rs b/src/main.rs index 402b3ec..3fbad8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ mod static_files; mod sweep; mod tasks; mod throttle; +mod typeset; mod vault; use std::sync::Arc; diff --git a/src/routes/mod.rs b/src/routes/mod.rs index aa1df17..7059ff2 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -18,6 +18,7 @@ pub mod share; pub mod ssh_keys; pub mod tokens; pub mod trash; +pub mod typeset; pub mod vault; use axum::{ @@ -108,6 +109,8 @@ pub fn api_router(max_upload: usize) -> Router { .route("/media/{id}", get(media::serve).delete(media::remove)) .route("/share/{token}", post(share::read)) .route("/share/{token}/media/{id}", get(share::serve_media)) + .route("/share/{token}/typst", post(share::typeset)) + .route("/typst", post(typeset::render)) .route("/trash", get(trash::list).delete(trash::empty)) .route("/trash/{id}", delete(trash::purge)) .route("/trash/{id}/restore", post(trash::restore)) @@ -139,6 +142,7 @@ pub(crate) mod tests { "/logout", "/share/{token}", "/share/{token}/media/{id}", + "/share/{token}/typst", ]; async fn state() -> AppState { diff --git a/src/routes/share.rs b/src/routes/share.rs index 36e666b..dc427d5 100644 --- a/src/routes/share.rs +++ b/src/routes/share.rs @@ -16,7 +16,7 @@ use crate::{ auth::{self, Session}, config::Config, error::{AppError, AppResult}, - routes::{media, trash}, + routes::{media, trash, typeset}, state::AppState, }; @@ -253,6 +253,34 @@ pub async fn serve_media( media::stream_media(&state, &id, false, headers.get(header::RANGE)).await } +/// `POST /api/share/{token}/typst` — public, as the media are: a ```typst +/// block of a shared document, typeset for a browser that read the document +/// with its key. Only a block the document holds is typeset, so the link is +/// not a typesetter for whoever has it. +pub async fn typeset( + State(state): State, + Path(token): Path, + headers: HeaderMap, + Json(body): Json, +) -> AppResult> { + let row = sqlx::query("SELECT id, body, share_key_hash FROM nodes WHERE share_token = ?1") + .bind(&token) + .fetch_optional(&state.db) + .await? + .ok_or(AppError::NotFound)?; + let stored: Option = row.get("share_key_hash"); + let allowed = + stored.is_some_and(|stored| holds_share_cookie(&state.config, &headers, &token, &stored)); + let document: String = row.get("body"); + if !allowed || body.source.trim().is_empty() || !document.contains(body.source.trim()) { + return Err(AppError::NotFound); + } + if trash::in_trash(&mut *state.db.acquire().await?, row.get("id")).await? { + return Err(AppError::NotFound); + } + typeset::answer(body.source).await.map(Json) +} + #[cfg(test)] mod tests { use axum::{ diff --git a/src/routes/typeset.rs b/src/routes/typeset.rs new file mode 100644 index 0000000..c7b509b --- /dev/null +++ b/src/routes/typeset.rs @@ -0,0 +1,68 @@ +//! `POST /api/typst`: a ```typst block of a document, typeset into SVG. + +use std::sync::LazyLock; + +use axum::{extract::State, Json}; +use serde::{Deserialize, Serialize}; +use tokio::sync::Semaphore; + +use crate::{ + auth::Session, + error::{AppError, AppResult}, + state::AppState, + typeset, +}; + +#[derive(Deserialize)] +pub struct TypesetRequest { + pub source: String, +} + +/// The block as SVG, or what typst said about it. A block that does not +/// compile is still an answer: the page shows the error where the block is. +#[derive(Serialize, Debug)] +pub struct Typeset { + #[serde(skip_serializing_if = "Option::is_none")] + pub svg: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, +} + +/// A page with many blocks asks for all of them at once; two are laid out at a +/// time, so they do not take every core from everyone else. +static AT_ONCE: LazyLock = LazyLock::new(|| Semaphore::new(2)); + +pub async fn render( + _: Session, + State(_): State, + Json(body): Json, +) -> AppResult> { + answer(body.source).await.map(Json) +} + +/// Typeset one block, off the async threads. +pub(crate) async fn answer(source: String) -> AppResult { + if source.len() > typeset::MAX_SOURCE { + return Err(AppError::BadRequest(format!( + "a typst block is at most {} KiB", + typeset::MAX_SOURCE / 1024 + ))); + } + let _turn = AT_ONCE + .acquire() + .await + .map_err(|e| AppError::Internal(e.into()))?; + let done = tokio::task::spawn_blocking(move || typeset::render(&source)) + .await + .map_err(|e| AppError::Internal(e.into()))?; + Ok(match done { + Ok(svg) => Typeset { + svg: Some(svg), + error: None, + }, + Err(error) => Typeset { + svg: None, + error: Some(error), + }, + }) +} diff --git a/src/typeset.rs b/src/typeset.rs new file mode 100644 index 0000000..1dbfc76 --- /dev/null +++ b/src/typeset.rs @@ -0,0 +1,206 @@ +//! ```typst blocks in markdown, typeset into SVG. +//! +//! Each block is a document of its own: its source is the only file there is, +//! and the fonts are the ones typst-assets builds into the binary. Nothing is +//! read from disk or fetched — an `#import "@preview/…"` or an `#image("…")` +//! is answered with an error in place of the block, as typst words it. +//! +//! The page fits what is on it and is transparent, and the text is the +//! theme's, so a block reads as part of the page it sits on. A block that +//! wants otherwise says so with its own `#set page(…)` or `#set text(…)`. + +use std::{ + collections::HashMap, + hash::{DefaultHasher, Hash, Hasher}, + sync::{LazyLock, Mutex}, +}; + +use chrono::{Datelike, TimeDelta, Utc}; +use typst::{ + diag::{FileError, FileResult, Severity, SourceDiagnostic}, + foundations::{Bytes, Datetime, Duration}, + layout::Abs, + syntax::{FileId, Source, VirtualRoot}, + text::{Font, FontBook}, + utils::LazyHash, + Library, LibraryExt, World, WorldExt, +}; +use typst_layout::PagedDocument; + +/// Set ahead of every block, on one line so an error's line number is the +/// block's own once one is taken off. `--fg` and the 14 px of the page's text. +const PREAMBLE: &str = "#set page(width: auto, height: auto, margin: 4pt, fill: none); \ + #set text(fill: rgb(\"#ccd2cb\"), size: 10.5pt)\n"; + +/// A block longer than this is not typeset: it is a document, not a block. +pub const MAX_SOURCE: usize = 64 * 1024; + +/// How many blocks are kept typeset. Rendering the same page again, or the +/// preview while the rest of the document is written, asks for the same ones. +const CACHE_SIZE: usize = 256; + +static LIBRARY: LazyLock> = LazyLock::new(|| LazyHash::new(Library::default())); + +static FONTS: LazyLock<(LazyHash, Vec)> = LazyLock::new(|| { + let fonts: Vec = typst_assets::fonts() + .flat_map(|data| Font::iter(Bytes::new(data))) + .collect(); + (LazyHash::new(FontBook::from_fonts(&fonts)), fonts) +}); + +static CACHE: LazyLock>> = LazyLock::new(Default::default); + +/// What a block became: its SVG, or what typst said about it. +pub type Typeset = Result; + +/// Typeset `source`, from the cache when it was typeset before. Blocking: the +/// layout runs on the calling thread, so call it from `spawn_blocking`. +pub fn render(source: &str) -> Typeset { + let key = { + let mut hasher = DefaultHasher::new(); + source.hash(&mut hasher); + hasher.finish() + }; + if let Some(done) = CACHE.lock().unwrap().get(&key) { + return done.clone(); + } + let done = typeset(source); + // comemo keeps what it memoised for every compile; let it go of what the + // last few did not use, or it grows with every block ever written. + typst::comemo::evict(10); + let mut cache = CACHE.lock().unwrap(); + if cache.len() >= CACHE_SIZE { + cache.clear(); + } + cache.insert(key, done.clone()); + done +} + +fn typeset(source: &str) -> Typeset { + let block = Block { + source: Source::detached(format!("{PREAMBLE}{source}")), + }; + let document = typst::compile::(&block) + .output + .map_err(|errors| block.explain(&errors))?; + Ok(typst_svg::svg_merged( + &document, + &Default::default(), + Abs::pt(8.0), + )) +} + +/// The world a block is typeset in: its own source, and nothing else. +struct Block { + source: Source, +} + +impl Block { + /// The errors as typst words them, each with the line of the block it is + /// on and the hints it gives. + fn explain(&self, errors: &[SourceDiagnostic]) -> String { + let lines = self.source.lines(); + errors + .iter() + .filter(|error| error.severity == Severity::Error) + .map(|error| { + let line = self + .range(error.span) + .and_then(|range| lines.byte_to_line(range.start)) + // The preamble is line 0, so the block's own count from 1. + .filter(|&line| line > 0); + let mut said = match line { + Some(line) => format!("line {line}: {}", error.message), + None => error.message.to_string(), + }; + for hint in &error.hints { + said.push_str(&format!("\n hint: {}", hint.v)); + } + said + }) + .collect::>() + .join("\n") + } + + fn only(&self, id: FileId) -> FileResult<()> { + if id == self.source.id() { + return Ok(()); + } + Err(FileError::Other(Some( + if matches!(id.root(), VirtualRoot::Package(_)) { + "packages are not available here: a block is typeset with nothing but itself" + } else { + "files are not available here: a block is typeset with nothing but itself" + } + .into(), + ))) + } +} + +impl World for Block { + fn library(&self) -> &LazyHash { + &LIBRARY + } + + fn book(&self) -> &LazyHash { + &FONTS.0 + } + + fn main(&self) -> FileId { + self.source.id() + } + + fn source(&self, id: FileId) -> FileResult { + self.only(id).map(|()| self.source.clone()) + } + + fn file(&self, id: FileId) -> FileResult { + self.only(id) + .map(|()| Bytes::from_string(self.source.text().to_owned())) + } + + fn font(&self, index: usize) -> Option { + FONTS.1.get(index).cloned() + } + + /// The day in UTC, moved by the hours asked for, or by none: the server's + /// zone is not the reader's, and `datetime.today()` is rarely what a block + /// is for. + fn today(&self, offset: Option) -> Option { + let shift = offset.map_or(0, |offset| offset.seconds() as i64); + let now = Utc::now() + TimeDelta::seconds(shift); + Datetime::from_ymd(now.year(), now.month() as u8, now.day() as u8) + } +} + +#[cfg(test)] +mod tests { + use super::render; + + #[test] + fn math_comes_out_as_svg() { + let svg = render("$ sum_(k=1)^n k = (n(n+1)) / 2 $").unwrap(); + assert!(svg.starts_with(" Option { /// Seal one 32-byte key under another. fn wrap(kek: &Key, key: &Key, aad: &[u8]) -> Result<([u8; WRAP_NONCE], Vec)> { let nonce = random::(); - let sealed = Aes256Gcm::new(kek.as_ref().into()) + let sealed = Aes256Gcm::new((&**kek).into()) .encrypt( Nonce::from_slice(&nonce), Payload { @@ -134,7 +134,7 @@ fn unwrap(kek: &Key, nonce: &[u8], sealed: &[u8], aad: &[u8]) -> Option { return None; } let plain = Zeroizing::new( - Aes256Gcm::new(kek.as_ref().into()) + Aes256Gcm::new((&**kek).into()) .decrypt(Nonce::from_slice(nonce), Payload { msg: sealed, aad }) .ok()?, ); @@ -157,7 +157,7 @@ impl Sealer { let wrap_nonce = random::(); let stream_nonce = random::(); - let sealed_key = Aes256Gcm::new(master.as_ref().into()) + let sealed_key = Aes256Gcm::new((&**master).into()) .encrypt( Nonce::from_slice(&wrap_nonce), Payload { @@ -174,7 +174,7 @@ impl Sealer { header.extend_from_slice(&stream_nonce); let stream = EncryptorBE32::from_aead( - Aes256Gcm::new(file_key.as_ref().into()), + Aes256Gcm::new((&*file_key).into()), stream_nonce.as_slice().into(), ); Ok(( @@ -1000,10 +1000,7 @@ mod tests { let kek = derive("correct horse", b"saltsaltsaltsalt", 256, 1, 1).expect("derive"); let master = key(5); let (nonce, sealed) = seal_master(&kek, &master).expect("seal"); - assert_eq!( - open_master(&kek, &nonce, &sealed).expect("opens").as_ref(), - master.as_ref() - ); + assert_eq!(*open_master(&kek, &nonce, &sealed).expect("opens"), *master); let wrong = derive("correct horse!", b"saltsaltsaltsalt", 256, 1, 1).expect("derive"); assert!(open_master(&wrong, &nonce, &sealed).is_none()); } diff --git a/web/src/app.css b/web/src/app.css index 65e415a..519c3c5 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -515,6 +515,14 @@ input::placeholder { color: var(--muted); } .md pre code { background: none; border: 0; padding: 0; font-size: inherit; } /* A long equation scrolls on its own rather than widening the page. */ .md .katex-display { overflow-x: auto; overflow-y: hidden; padding: 2px 0; } + +/* ```typst: the block as typst set it, at its own size, scrolling sideways + when wider than the column; its source while it is being set, and what + typst said under the source when it could not be. */ +.md figure.typst { margin: 1em 0; overflow-x: auto; overflow-y: hidden; } +.md figure.typst img { display: block; max-width: none; border: 0; border-radius: 0; background: none; padding: 0; } +.md pre.typst-source.pending { opacity: 0.55; } +.md pre.typst-error { margin-top: -0.6em; color: var(--alarm); border-color: color-mix(in oklab, var(--alarm) 40%, transparent); white-space: pre-wrap; } .md hr { border: 0; border-top: 1px solid var(--overlay); margin: 2.4em 0; } .md img, .md video { max-width: 100%; diff --git a/web/src/lib/Help.svelte b/web/src/lib/Help.svelte index 057f2d6..fc62a5d 100644 --- a/web/src/lib/Help.svelte +++ b/web/src/lib/Help.svelte @@ -158,6 +158,7 @@ ['vim', 'the full keymap — hjkl, w/b, dd, ciw, visual mode, macros; :w writes'], ['drop · paste', 'an image, video or audio file attaches it'], ['$x^2$ · $$…$$', 'set as math'], + ['```typst', 'a block typst sets, shown as an image — math, tables, figures; no packages or files'], [':12', 'jumps straight to entry 12'], ['y · d', 'copied to the system clipboard — :set noclipboard keeps them in the registers'], ['files', 'open in place — pdf, text and code, markdown, csv, certificates and keystores'], diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index ee65a86..7cd9473 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -631,6 +631,13 @@ export const api = { readShared: (token: string, key: string) => request(`/share/${encodeURIComponent(token)}`, { method: 'POST', body: body({ key }) }), + /** A ```typst block as SVG — or, on a share page, a block of the shared document. */ + typeset: (source: string, share?: string) => + request<{ svg?: string; error?: string }>(share ? `/share/${encodeURIComponent(share)}/typst` : '/typst', { + method: 'POST', + body: body({ source }), + }), + sessions: () => request('/sessions'), revokeSession: (id: string) => request<{ ok: true }>(`/sessions/${encodeURIComponent(id)}`, { method: 'DELETE' }), diff --git a/web/src/lib/markdown.ts b/web/src/lib/markdown.ts index c8ad098..d2fbc8d 100644 --- a/web/src/lib/markdown.ts +++ b/web/src/lib/markdown.ts @@ -1,6 +1,7 @@ import DOMPurify from 'dompurify' import { marked, type TokenizerAndRendererExtension } from 'marked' import { mathEngine } from './math.svelte' +import { typeset } from './typst.svelte' import { hardWrapped, titleHref } from './util' marked.setOptions({ gfm: true, breaks: true }) @@ -48,6 +49,8 @@ const WIKILINK = /^\[\[([^[\]|\n]+)(?:\|([^[\]\n]*))?\]\]/ /** What the page being rendered says about its `[[titles]]`, for the renderer. */ let wikiContext: { leads: Record; sharing: boolean } = { leads: {}, sharing: false } +/** The share the page is read under, whose server route typesets its typst. */ +let shareToken: string | undefined const wikilink: TokenizerAndRendererExtension = { name: 'wikilink', @@ -89,7 +92,9 @@ marked.use({ }, renderer: { code(token) { - return token.lang === 'math' ? tex(token.text, true) : false + if (token.lang === 'math') return tex(token.text, true) + if (token.lang === 'typst' || token.lang === 'typ') return typst(token.text) + return false }, }, }) @@ -105,6 +110,22 @@ function tex(source: string, display: boolean): string { return katex.renderToString(source, { displayMode: display, throwOnError: false }) } +/* + * A ```typst block as the SVG the server set it in, shown as an image: each + * SVG names its glyphs with the same ids, which inline on one page would + * draw each other's letters. Until it arrives, and when it does not compile, + * the source shows — with what typst said under it. + */ +function typst(source: string): string { + const answer = typeset(source, shareToken) + if (answer && 'svg' in answer) { + const data = encodeURIComponent(answer.svg) + return `
${escapeHtml(source)}
` + } + const error = answer ? `
${escapeHtml(answer.error)}
` : '' + return `
${escapeHtml(source)}
${error}` +} + /* * A link that opens another window leaves it no handle on this one. Only * `_blank` is kept as a target: a named one reuses whatever window has that @@ -144,6 +165,7 @@ export function renderMarkdown( : source wikiContext = { leads: wikilinks, sharing: !!share } + shareToken = share?.token const html = marked.parse(md, { async: false }) as string if (!share) return DOMPurify.sanitize(html, SANITIZE) diff --git a/web/src/lib/typst.svelte.ts b/web/src/lib/typst.svelte.ts new file mode 100644 index 0000000..4c21924 --- /dev/null +++ b/web/src/lib/typst.svelte.ts @@ -0,0 +1,33 @@ +/* + * ```typst blocks, typeset on the server. A block shows as its source until + * its SVG arrives, as math does until KaTeX has loaded; the answers are + * state, so markdown rendered without one renders again once it is here. + * Each block is asked for once per page load, however often the page is + * drawn — while writing, the preview asks only for a block that changed. + */ +import { api } from './api' + +type Answer = { svg: string } | { error: string } + +let answers = $state.raw(new Map()) +const asked = new Set() + +/** Forget a block once it is this far out of date: the preview of a long session asks for many. */ +const KEEP = 200 + +export function typeset(source: string, share?: string): Answer | null { + const key = `${share ?? ''}\n${source}` + const answer = answers.get(key) + if (answer || asked.has(key)) return answer ?? null + asked.add(key) + api + .typeset(source, share) + .then((done) => (done.svg !== undefined ? { svg: done.svg } : { error: done.error ?? 'typst said nothing' })) + .catch((e: Error) => ({ error: e.message })) + .then((done) => { + const next = new Map(answers) + if (next.size >= KEEP) next.delete(next.keys().next().value!) + answers = next.set(key, done) + }) + return null +}