diff --git a/Cargo.lock b/Cargo.lock index 75107d5..e1af56a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,292 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" +dependencies = [ + "object", +] + +[[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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "az" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[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 = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bumpalo" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "cc" +version = "1.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[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", + "num-traits", +] + +[[package]] +name = "chinese-variant" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b52a9840ffff5d4d0058ae529fa066a75e794e3125546acfc61c23ad755e49" + +[[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]] +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 = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[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 = "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", +] + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + [[package]] name = "cph-check" version = "0.1.0" @@ -39,6 +325,158 @@ dependencies = [ [[package]] name = "cph-typst" version = "0.1.0" +dependencies = [ + "cph-diag", + "cph-model", + "tempfile", + "toml", + "typst", + "typst-kit", + "typst-layout", + "typst-library", + "typst-pdf", + "typst-syntax", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[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 = "data-url" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ecow" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78e4f79b296fbaab6ce2e22d52cb4c7f010fe0ebe7a32e34fa25885fd797bd02" +dependencies = [ + "serde", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "equivalent" @@ -46,11 +484,603 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "euclid" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a05365e3b1c6d1650318537c7460c6923f1abdd272ad6842baa2b509957a06" +dependencies = [ + "num-traits", +] + +[[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 = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[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 = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +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 = "fontconfig-parser" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646" +dependencies = [ + "roxmltree 0.20.0", +] + +[[package]] +name = "fontdb" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[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", + "hashbrown", + "log", + "peniko", + "png", + "skrifa", + "smallvec", + "vello_common 0.0.9", +] + +[[package]] +name = "guillotiere" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b17e70c989c36bad147b27a58d148c0741c51448aa5653436547323e524d0ab" +dependencies = [ + "euclid", +] + +[[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.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[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", + "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-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", + "rustc-hash", + "siphasher", + "skrifa", + "smallvec", + "yoke", +] + +[[package]] +name = "hayro-jbig2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69374b3668dd45aeb3d3145cda68f2c7b4f223aaa2511e67d076f1c7d741388d" +dependencies = [ + "fearless_simd", + "hayro-ccitt", +] + +[[package]] +name = "hayro-jpeg2000" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1" +dependencies = [ + "fearless_simd", +] + +[[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", + "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", + "hayro-jbig2", + "hayro-jpeg2000", + "memchr", + "rustc-hash", + "smallvec", + "zune-jpeg", +] + +[[package]] +name = "hayro-write" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b3db92c4917aad24ff30d61413a9a7509ae88b27aee1ae34eff881e1d2723a" +dependencies = [ + "flate2", + "hayro-syntax", + "pdf-writer", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hypher" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef68590049bab63a464eee1a1158ac04c6f6613a546d8d90f78636b8b94f171" + +[[package]] +name = "icu_collator" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b521b92a2666061ddda902769d8a4cf730b5c9529a845cc1b69770b12a6c9a71" +dependencies = [ + "icu_collator_data", + "icu_collections", + "icu_locale", + "icu_locale_core", + "icu_normalizer", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_collator_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038ed8e5817f2059c2f3efb0945ba78d060d3d25e8f1a1bea5139f821a21a2f0" + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "serde", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993" + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "serde", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "postcard", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_provider_blob" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99a43c4436b6c9a37c27a822ff05238bbad134bcdf6176732208acfae46a3f" +dependencies = [ + "icu_provider", + "postcard", + "serde", + "writeable", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_segmenter" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0794db0b1a86193ac9c48768d0e6c52c54448e0870ad87907d456ee0dac964" +dependencies = [ + "core_maths", + "icu_collections", + "icu_locale", + "icu_provider", + "icu_segmenter_data", + "potential_utf", + "serde", + "utf8_iter", + "zerovec", +] + +[[package]] +name = "icu_segmenter_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a2c462a4d927d512f5f882a033ddd62f33a05bb9f230d98f736ac3dc85938f" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "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" @@ -60,20 +1090,486 @@ checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", + "rayon", + "serde", + "serde_core", ] +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" + [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[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 = "krilla" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27da593198b20eeba65caeb73c2bbeec3e53ab08fa549898312ce81c4fce5e33" +dependencies = [ + "base64", + "bumpalo", + "comemo", + "flate2", + "float-cmp", + "gif", + "hayro-write", + "image-webp", + "imagesize", + "indexmap", + "pdf-writer", + "png", + "rayon", + "rustc-hash", + "rustybuzz", + "siphasher", + "skrifa", + "smallvec", + "subsetter", + "tiny-skia-path", + "xmp-writer", + "yoke", + "zune-jpeg", +] + +[[package]] +name = "krilla-svg" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1237d7c37b16ca9fbc2e72dde13a10d321f9a44aceee35c062bc0a43bfc7ce16" +dependencies = [ + "flate2", + "fontdb", + "krilla", + "resvg", + "skrifa", + "smallvec", + "tiny-skia", + "usvg", +] + +[[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 = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +dependencies = [ + "libc", +] + +[[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", + "rand_chacha", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +dependencies = [ + "serde_core", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + [[package]] name = "memchr" version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[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 = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "mutate_once" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d2233c9842d08cfe13f9eac96e207ca6a2ea10b80259ebe8ad0268be27d2af" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pdf-writer" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e456864a7a304047bff84977dc6fb162bd956475d40ba50b2dcecaada7f753" +dependencies = [ + "bitflags", + "itoa", + "memchr", + "ryu", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "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", +] + +[[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", + "proc-macro2", + "quote", + "syn", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b05a62c3762cb26cb62665b915fea652def8a9f609b0b289b7f782a7394307b" +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 = "plist" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092791278e026273c1b65bbdcfbba3a300f2994c896bd01ab01da613c29c46f1" +dependencies = [ + "base64", + "indexmap", + "quick-xml 0.39.4", + "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", +] + +[[package]] +name = "polycool" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50596ddc09eb5ad5f75cacd40209568e66df71baf86e1499a0e99c4cff12a5a6" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[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.106" @@ -83,6 +1579,47 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "psm" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645dbe486e346d9b5de3ef16ede18c26e6c70ad97418f4874b8b1889d6e761ea" +dependencies = [ + "ar_archive_writer", + "cc", +] + +[[package]] +name = "pxfm" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c5ccf5294c6ccd63a74f1565028353830a9c2f5eb0c682c355c471726a6e3f" + +[[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.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + [[package]] name = "quote" version = "1.0.45" @@ -92,6 +1629,237 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[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 = "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "resvg" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be183ad6a216aa96f33e4c8033b0988b8b3ea6fd2359d19af5bac4643fd8e81" +dependencies = [ + "gif", + "image-webp", + "log", + "pico-args", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" +dependencies = [ + "bytemuck", +] + +[[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.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "roxmltree" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1964b10c76125c36f8afe190065a4bf9a87bf324842c05701330bba9f1cacbb" +dependencies = [ + "memchr", +] + +[[package]] +name = "rust_decimal" +version = "1.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2a24f50780bc85f09cc6ac299bdf1424302742d77221106859c9d8b102126a" +dependencies = [ + "arrayvec", + "num-traits", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.228" @@ -135,6 +1903,17 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -144,6 +1923,154 @@ 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 = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[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.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stacker" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys", +] + +[[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 = "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", +] + +[[package]] +name = "subsetter" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38803281d1c23166c5ebcb455439a5d2afe711cc909cf88af72448c297756ad6" +dependencies = [ + "kurbo", + "rustc-hash", + "skrifa", + "write-fonts", +] + +[[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.118" @@ -155,6 +2082,159 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys", +] + +[[package]] +name = "thin-vec" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f7e269b48f0a7dd0146680fa24b50cc67fc0373f086a5b2f99bd084639b482" + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47ffee5eaaf5527f630fb0e356b90ebdec84d5d18d937c5e440350f88c5a91ea" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "toml" version = "0.8.23" @@ -196,12 +2276,682 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[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 = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typst" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8bf2a5a9d58cc542764a88dd43c8a679b683db4ae23e36267219339ab36b01" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9b236d339dce0ec443dc44afe4ba4c6d76b8917bd4b1ae80158d2111f6637b" +dependencies = [ + "bitflags", +] + +[[package]] +name = "typst-eval" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d064876305073ab75d5af039ae5e8dcb32c4cac4aa9f43d0f5aae347baef7c3" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d442f92bae44087735efc8b83508b259c573bbccf027e098ac68c8f4ca879f76" +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-kit" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a24650fc436d32deb55b49fd63f7bcad3a864c96f52587b9934c85e0092d6f" +dependencies = [ + "dirs", + "ecow", + "fontdb", + "once_cell", + "parking_lot", + "rustc-hash", + "serde", + "serde_json", + "typst-assets", + "typst-library", + "typst-syntax", + "typst-timing", + "typst-utils", + "url", +] + +[[package]] +name = "typst-layout" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae5af3949efc6d02e3d55e79430c9096415fcf68166414c3a0e5fed1c3325d5f" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9550a33d0f4e1965fd7d69abcf10135e965a4ad3a3aee24573b52dda9234e491" +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", + "png", + "rayon", + "regex", + "regex-syntax", + "roxmltree 0.21.1", + "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500e2873a544ca161f98183eea7ddb00030d16f4585b5ffa9e9c8e24f53148e1" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typst-pdf" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd7b33bcabc3357480768f6c78dda99a838d621c71b4738b25e09ac30ac063c9" +dependencies = [ + "az", + "bytemuck", + "codex", + "comemo", + "ecow", + "flate2", + "image", + "indexmap", + "infer", + "krilla", + "krilla-svg", + "rustc-hash", + "serde", + "smallvec", + "typst-assets", + "typst-layout", + "typst-library", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", +] + +[[package]] +name = "typst-realize" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917e09614771258b13409b9a8d4f3915b2a2f7f28ca987701695f82fc6a7c0b9" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878b6e1293c2bea77a8be50670d1cbca4e676af96480313a105cba539da51d1c" +dependencies = [ + "base64", + "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22bf7f87450e5841debd4986b0f912b0f7a2251e600c08aca406305ff52c67b4" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cc0c78ece2ade6ef73d00a13f9c474e02efc3bcfdb770e16d7c4d24e7492773" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "typst-utils" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40215eb2541102ecfb4cf3bef29da53033a82e22dbc2308c43bdb855701bf8d2" +dependencies = [ + "libm", + "once_cell", + "portable-atomic", + "rayon", + "rustc-hash", + "semver", + "siphasher", + "smallvec", + "thin-vec", + "unicode-math-class", +] + +[[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", + "unic-langid-impl", +] + +[[package]] +name = "unicode-bidi" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +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 = "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 = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "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", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree 0.21.1", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vello_common" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3361bff7f7d82c0c496b92048db83846691f0e844cc28dee92b1c824291b55ee" +dependencies = [ + "bytemuck", + "fearless_simd", + "guillotiere", + "hashbrown", + "log", + "peniko", + "png", + "smallvec", + "thiserror", +] + +[[package]] +name = "vello_common" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d672facaa2d697285a786cd9d44d614cd2ce54cdc022504bf339f8fff3b750" +dependencies = [ + "bytemuck", + "fearless_simd", + "guillotiere", + "hashbrown", + "log", + "peniko", + "png", + "smallvec", + "thiserror", +] + +[[package]] +name = "vello_cpu" +version = "0.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d8ded630e8316bb94a55881256506d1f3b9947b5f66db8a7d32ca7ba02decd0" +dependencies = [ + "bytemuck", + "glifo", + "hashbrown", + "png", + "vello_common 0.0.8", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[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 = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "winnow" version = "0.7.15" @@ -211,8 +2961,176 @@ dependencies = [ "memchr", ] +[[package]] +name = "write-fonts" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb731d4c4d93eacc69a1ad2f270f905788a98e4a3438267bcafbe08d3431c8d8" +dependencies = [ + "font-types", + "indexmap", + "kurbo", + "log", + "read-fonts", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "xmp-writer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9440ea3e5aeabb0ac63af70daf835274065238cdd0cec83418f417eae38bacee" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "litemap", + "serde_core", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zlib-rs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be3d40e40a133f9c916ee3f9f4fa2d9d63435b5fbe1bfc6d9dae0aa0ada1513" + [[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" + +[[package]] +name = "zune-jpeg" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/crates/cph-typst/Cargo.toml b/crates/cph-typst/Cargo.toml index 0b53ffa..cf7f3e7 100644 --- a/crates/cph-typst/Cargo.toml +++ b/crates/cph-typst/Cargo.toml @@ -5,3 +5,20 @@ edition.workspace = true license.workspace = true [dependencies] +cph-diag = { workspace = true } +cph-model = { workspace = true } +toml = { workspace = true } + +typst = "=0.15.0" +typst-layout = "=0.15.0" +typst-pdf = "=0.15.0" +typst-syntax = "=0.15.0" +typst-library = "=0.15.0" +typst-kit = { version = "=0.15.0", features = [ + "scan-fonts", + "embedded-fonts", +] } + +[dev-dependencies] +cph-model = { workspace = true } +tempfile = "3" diff --git a/crates/cph-typst/src/diag.rs b/crates/cph-typst/src/diag.rs new file mode 100644 index 0000000..f954227 --- /dev/null +++ b/crates/cph-typst/src/diag.rs @@ -0,0 +1,110 @@ +//! Map typst [`SourceDiagnostic`]s to [`cph_diag::Diagnostic`]s. +//! +//! ## Span mapping (typst 0.15 specifics) +//! +//! In 0.15 a diagnostic's `span` is a [`typst::syntax::DiagSpan`] (not the bare +//! `Span` of 0.14). To locate it we: +//! 1. `span.id() -> Option` for the owning file (`None` ⇒ detached, so +//! no span is emitted); +//! 2. `WorldExt::range(span) -> Option>` for the byte range — this +//! handles every `DiagSpanKind` variant internally (numbered source spans +//! *and* raw external byte ranges), so we never match the enum by hand; +//! 3. compute 1-based line/col from the file's [`typst::syntax::Source`] via +//! `lines().byte_to_line_column` (0-based ⇒ `+1`). +//! +//! A span whose `FileId` is the generated **driver** is re-pointed: its `file` +//! is set to the driver vpath and a hint flags it as driver-internal (a +//! driver-gen bug indicator) rather than dropped or mis-attributed to a user +//! file. Spans in the `cph-render` package are reported with an +//! `@local/cph-render:…` pseudo-path. + +use std::path::PathBuf; + +use cph_diag::{DiagCode, Diagnostic, Severity, SourceSpan}; +use typst::diag::{Severity as TypstSeverity, SourceDiagnostic}; +use typst::syntax::{FileId, VirtualRoot}; +use typst::{World, WorldExt}; + +use crate::world::LessonWorld; + +/// Convert one typst diagnostic into a `cph-diag` [`Diagnostic`], resolving its +/// span against `world`. +pub fn map_diagnostic(world: &LessonWorld, d: &SourceDiagnostic) -> Diagnostic { + let severity = match d.severity { + TypstSeverity::Error => Severity::Error, + TypstSeverity::Warning => Severity::Warning, + }; + + // Flatten the typst call trace into the message tail so call-site context + // isn't lost (the primary span points at the innermost node). + let mut message = d.message.to_string(); + for tp in &d.trace { + message.push_str(&format!("\n in {}", tp.v)); + } + + let mut diag = Diagnostic { + severity, + code: DiagCode::TypstCompile, + message, + span: None, + hint: None, + }; + + // typst's own hints are the product's core value — carry them through. + let mut hints: Vec = d.hints.iter().map(|h| h.v.to_string()).collect(); + + if let Some(id) = d.span.id() { + if let Some(file) = file_for(world, id) { + if id == world.main() { + hints.push( + "this span is inside the generated driver (.cph/driver-*.typ), \ + not a lesson source file — likely a driver-generation issue" + .to_string(), + ); + } + // Byte range via WorldExt::range (DiagSpan is Copy). + let byte_range = world.range(d.span).unwrap_or(0..0); + let (line, col) = line_col(world, id, byte_range.start); + diag.span = Some(SourceSpan { + file, + byte_range, + line, + col, + }); + } + } + + if !hints.is_empty() { + diag.hint = Some(hints.join("; ")); + } + diag +} + +/// 1-based (line, col) for a byte offset in file `id`, defaulting to `(1, 1)` +/// when the source can't be read or the offset is out of range. +fn line_col(world: &LessonWorld, id: FileId, byte: usize) -> (u32, u32) { + let Ok(source) = world.source(id) else { + return (1, 1); + }; + match source.lines().byte_to_line_column(byte) { + // byte_to_line_column is 0-based; editors are 1-based. + Some((line, col)) => (line as u32 + 1, col as u32 + 1), + None => (1, 1), + } +} + +/// File path for a `FileId`. Project files are relative to the lesson root (no +/// leading slash); package files use an `@namespace/name:version/path` form. +fn file_for(world: &LessonWorld, id: FileId) -> Option { + let _ = world; + match id.root() { + VirtualRoot::Project => Some(PathBuf::from(id.vpath().get_without_slash())), + VirtualRoot::Package(spec) => Some(PathBuf::from(format!( + "@{}/{}:{}{}", + spec.namespace, + spec.name, + spec.version, + id.vpath().get_with_slash() + ))), + } +} diff --git a/crates/cph-typst/src/driver.rs b/crates/cph-typst/src/driver.rs new file mode 100644 index 0000000..6757e00 --- /dev/null +++ b/crates/cph-typst/src/driver.rs @@ -0,0 +1,201 @@ +//! Driver generation: turn a [`Lesson`] + target into a typst entrypoint that +//! `include`s each part's content files and calls `cph-render`'s `display`. +//! +//! ## Decisions +//! +//! - **Include-path style: root-relative (`/segments/…`).** The lesson root is +//! mounted as the typst project root ([`crate::world::LessonWorld`] uses +//! `VirtualRoot::Project`), so a leading-`/` path resolves against the root +//! regardless of where the driver itself sits. This keeps include paths +//! identical to the part `path`s recorded in the manifest, independent of the +//! driver's `.cph/` location. +//! - **Content via `include`, not `import`** (ADR-0006): a `content` field's +//! value is the module *body*, which `include` yields (`import` would expose +//! only `#let` exports). +//! - **`@local/cph-render`** is referenced by the standard package import; the +//! World resolves it from the render directory (see `crate::world`). +//! - **Optional `proof`** (lemma) is emitted only when `/proof.typ` +//! exists on disk. +//! - **Scalars** (example `source`) come from `part.descriptor.scalars` and are +//! emitted as escaped typst string literals. + +use cph_model::{Lesson, Part}; + +/// In-memory directory the generated driver is mounted under (relative to the +/// lesson root). Not written to disk. +pub const DRIVER_DIR: &str = ".cph"; + +/// The package import line the driver opens with. +const RENDER_IMPORT: &str = "#import \"@local/cph-render:0.1.0\": display"; + +/// The content fields of each kind, in render-contract order. The `bool` is +/// whether the field is optional (only emitted if its `.typ` exists). +fn content_fields(kind: &str) -> &'static [(&'static str, bool)] { + match kind { + "segment" => &[("textbook", false)], + "example" => &[("problem", false), ("solution", false)], + "lemma" => &[("stmt", false), ("proof", true)], + "sop" => &[("sop", false)], + // Unknown kind: emit nothing for it; the render package surfaces the + // unknown kind visibly, and cph-model/cph-schema report it upstream. + _ => &[], + } +} + +/// The optional **scalar** string fields per kind (read from `element.toml`). +fn scalar_fields(kind: &str) -> &'static [&'static str] { + match kind { + "example" => &["source"], + _ => &[], + } +} + +/// Generate the driver source for `lesson` under `target`. +/// +/// The result is deterministic and order-preserving (parts emitted in +/// `lesson.parts` order, matching the render contract). It is pure text +/// generation — it touches the filesystem only to test for optional content +/// files (e.g. lemma `proof.typ`). +pub fn generate_driver(lesson: &Lesson, target: &str) -> String { + let mut s = String::new(); + s.push_str(RENDER_IMPORT); + s.push('\n'); + + // One `#let _pN_field = include "…"` per content file, then the parts array + // referencing those bindings. + let mut part_dicts: Vec = Vec::with_capacity(lesson.parts.len()); + + for (i, part) in lesson.parts.iter().enumerate() { + let mut entries: Vec = Vec::new(); + entries.push(format!("kind: {}", typst_str(&part.kind))); + + for &(field, optional) in content_fields(&part.kind) { + if optional && !content_file_exists(part, field) { + continue; + } + let binding = format!("_p{i}_{field}"); + let inc_path = include_path(part, field); + s.push_str(&format!( + "#let {binding} = include {}\n", + typst_str(&inc_path) + )); + entries.push(format!("{field}: {binding}")); + } + + for &field in scalar_fields(&part.kind) { + if let Some(value) = scalar_string(part, field) { + entries.push(format!("{field}: {}", typst_str(&value))); + } + } + + part_dicts.push(format!("({})", entries.join(", "))); + } + + s.push_str("#display(\n"); + s.push_str(&format!(" info: {},\n", info_dict(lesson))); + s.push_str(&format!(" target: {},\n", typst_str(target))); + s.push_str(" parts: (\n"); + for dict in &part_dicts { + s.push_str(&format!(" {dict},\n")); + } + // Trailing comma already present per element; ensure a 1-element array is + // still an array (typst needs the trailing comma, which we always emit). + s.push_str(" ),\n"); + s.push_str(")\n"); + s +} + +/// `(title: "…", author: "…")` — author key omitted when absent. +fn info_dict(lesson: &Lesson) -> String { + let mut parts = vec![format!("title: {}", typst_str(&lesson.info.title))]; + if let Some(author) = &lesson.info.author { + parts.push(format!("author: {}", typst_str(author))); + } + format!("({})", parts.join(", ")) +} + +/// Root-relative include path for `part`'s `field` content file, e.g. +/// `/segments/开场对照导言/textbook.typ`. Always forward-slashed and +/// leading-`/` so it resolves against the typst project root. +fn include_path(part: &Part, field: &str) -> String { + let mut p = String::from("/"); + // `part.path` is the manifest-relative folder; join the `.typ`. + p.push_str(&path_to_forward_slash(&part.path)); + if !p.ends_with('/') { + p.push('/'); + } + p.push_str(field); + p.push_str(".typ"); + p +} + +/// Does `/.typ` exist on disk? Used to gate optional content. +fn content_file_exists(part: &Part, field: &str) -> bool { + part.descriptor.dir.join(format!("{field}.typ")).is_file() +} + +/// Pull a scalar string field out of the element descriptor, if present and a +/// string (and non-empty). +fn scalar_string(part: &Part, field: &str) -> Option { + match part.descriptor.scalars.get(field) { + Some(toml::Value::String(s)) if !s.is_empty() => Some(s.clone()), + _ => None, + } +} + +/// Render a `PathBuf` (folder) as a forward-slash string, dropping any leading +/// `./` or `/`. Element folder names are UTF-8 (Chinese) and kept verbatim. +fn path_to_forward_slash(path: &std::path::Path) -> String { + use std::path::Component; + let mut out = String::new(); + for comp in path.components() { + // Only `Normal` segments contribute; RootDir / CurDir / Prefix / + // ParentDir are ignored. `..` is already rejected by cph-model's loader, + // and the part path is relative. + if let Component::Normal(s) = comp { + if !out.is_empty() { + out.push('/'); + } + out.push_str(&s.to_string_lossy()); + } + } + out +} + +/// Quote `value` as a typst string literal, escaping `\` and `"`. Unicode is +/// passed through as UTF-8 (typst sources are UTF-8). Control chars that would +/// break a single-line literal (newline, CR, tab) are escaped too. +fn typst_str(value: &str) -> String { + let mut out = String::with_capacity(value.len() + 2); + out.push('"'); + for c in value.chars() { + match c { + '\\' => out.push_str("\\\\"), + '"' => out.push_str("\\\""), + '\n' => out.push_str("\\n"), + '\r' => out.push_str("\\r"), + '\t' => out.push_str("\\t"), + _ => out.push(c), + } + } + out.push('"'); + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn escapes_quotes_and_backslashes() { + assert_eq!(typst_str(r#"a"b\c"#), r#""a\"b\\c""#); + // Unicode passes through. + assert_eq!(typst_str("自拟"), "\"自拟\""); + } + + #[test] + fn forward_slash_path_keeps_unicode() { + let p = std::path::Path::new("segments/开场对照导言"); + assert_eq!(path_to_forward_slash(p), "segments/开场对照导言"); + } +} diff --git a/crates/cph-typst/src/lib.rs b/crates/cph-typst/src/lib.rs index db52dcf..7197673 100644 --- a/crates/cph-typst/src/lib.rs +++ b/crates/cph-typst/src/lib.rs @@ -1,9 +1,141 @@ //! `cph-typst` — typst `World`, driver generation, compile, PDF, span mapping. //! -//! Owned by **WU-4**. Builds the typst compiler `World` over the engineering -//! file's virtual file system (ADR-0006/0007), generates the driver entrypoint -//! from the manifest, compiles to PDF, and maps typst spans back to source -//! locations for diagnostics. +//! Owned by **WU-4**. Embeds the typst 0.15 compiler as a library to: +//! - **compile-check** a [`cph_model::Lesson`] (collect typst errors+warnings as +//! [`cph_diag::Diagnostic`]s), and +//! - **export a PDF** for a render target. +//! +//! The lesson's engineering-file directory tree (ADR-0007) is mounted as the +//! typst project root; a generated *driver* entrypoint (one per target) lives +//! in-memory under `.cph/driver-.typ` and `include`s each part's +//! content files (ADR-0006: a `content` value denotes the module **body**, so +//! the driver uses `include`, never `import`). The driver hands an ordered +//! `parts` array to the `@local/cph-render` package's `display` entry. +//! +//! ## typst version +//! +//! Pinned to the `typst` family `=0.15.0`. The 0.15 path/file API differs from +//! 0.14: `FileId::new(RootedPath)` where `RootedPath::new(VirtualRoot, +//! VirtualPath)`, and a diagnostic span is a `DiagSpan` (not a bare `Span`). -// WU-4: implement the World + driver-gen + compile + span mapping. Empty for -// now so the workspace compiles. +mod diag; +mod driver; +mod world; + +use std::path::PathBuf; + +use cph_diag::Diagnostic; +use cph_model::Lesson; +use typst_kit::fonts::{self, FontStore}; +use typst_layout::PagedDocument; +use typst_pdf::PdfOptions; + +pub use driver::{generate_driver, DRIVER_DIR}; +pub use world::{render_package_spec, LessonWorld}; + +/// The compile/PDF engine: holds the shared font store and the on-disk location +/// of the `cph-render` package. +/// +/// Fonts are discovered once (system + embedded) and shared across every +/// compilation via an [`std::sync::Arc`] inside the per-compile [`LessonWorld`]. +pub struct Engine { + fonts: std::sync::Arc, + render_dir: PathBuf, +} + +impl Engine { + /// Construct an engine, discovering system + embedded fonts. The render + /// package directory is taken from the `CPH_RENDER_DIR` environment + /// variable when set, otherwise defaults to `/render` resolved + /// relative to this crate (`CARGO_MANIFEST_DIR/../../render`). + pub fn new() -> Self { + Self::with_render_dir(default_render_dir()) + } + + /// Construct an engine pointing at an explicit `cph-render` package + /// directory (the folder containing `lib.typ` / `typst.toml`). + pub fn with_render_dir(render_dir: PathBuf) -> Self { + let mut store = FontStore::new(); + // System fonts first (so the host's CJK fonts are preferred), then the + // embedded fallbacks. `scan-fonts` / `embedded-fonts` features gate + // these iterators. + store.extend(fonts::system()); + store.extend(fonts::embedded()); + Self { + fonts: std::sync::Arc::new(store), + render_dir, + } + } + + /// The directory this engine resolves `@local/cph-render` from. + pub fn render_dir(&self) -> &std::path::Path { + &self.render_dir + } + + /// Compile-check `lesson` for `target`, returning every typst diagnostic + /// (errors **and** warnings) mapped to [`Diagnostic`]s. An empty `Vec` means + /// a clean compile. Spans are resolved to files relative to `lesson.root`; + /// spans landing in the generated driver are re-pointed with a hint marking + /// them as driver-internal (a driver-gen bug indicator) rather than dropped. + pub fn compile_check(&self, lesson: &Lesson, target: &str) -> Vec { + let world = self.world_for(lesson, target); + let warned = typst::compile::(&world); + + let mut out = Vec::new(); + if let Err(errors) = &warned.output { + out.extend(map_all(&world, errors)); + } + out.extend(map_all(&world, &warned.warnings)); + out + } + + /// Build a PDF for `lesson` / `target`. On a clean compile returns the PDF + /// bytes; on fatal errors returns the mapped diagnostics. Compile warnings + /// are not surfaced here (use [`Engine::compile_check`] for those). + pub fn build_pdf(&self, lesson: &Lesson, target: &str) -> Result, Vec> { + let world = self.world_for(lesson, target); + let warned = typst::compile::(&world); + let doc = match warned.output { + Ok(doc) => doc, + Err(errors) => return Err(map_all(&world, &errors)), + }; + typst_pdf::pdf(&doc, &PdfOptions::default()).map_err(|errors| map_all(&world, &errors)) + } + + fn world_for(&self, lesson: &Lesson, target: &str) -> LessonWorld { + let driver_src = generate_driver(lesson, target); + LessonWorld::new( + lesson.root.clone(), + self.render_dir.clone(), + target, + driver_src, + self.fonts.clone(), + ) + } +} + +impl Default for Engine { + fn default() -> Self { + Self::new() + } +} + +/// Map a batch of typst diagnostics to `cph-diag` ones against `world`. +fn map_all(world: &LessonWorld, diags: &[typst::diag::SourceDiagnostic]) -> Vec { + diags + .iter() + .map(|d| diag::map_diagnostic(world, d)) + .collect() +} + +/// `/../../render` — the repo's render package, used when `CPH_RENDER_DIR` +/// is unset. +fn default_render_dir() -> PathBuf { + if let Ok(dir) = std::env::var("CPH_RENDER_DIR") { + return PathBuf::from(dir); + } + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") + .join("render") +} diff --git a/crates/cph-typst/src/world.rs b/crates/cph-typst/src/world.rs new file mode 100644 index 0000000..8a2e3a8 --- /dev/null +++ b/crates/cph-typst/src/world.rs @@ -0,0 +1,165 @@ +//! [`LessonWorld`] — a typst [`World`] over an engineering-file directory tree +//! plus an in-memory generated driver and a disk-mounted `cph-render` package. +//! +//! ## File resolution +//! +//! - **The driver** (`main()`): mounted in-memory at `VirtualRoot::Project` + +//! vpath `/.cph/driver-.typ`. `source()` returns it from the field; +//! it is never written to disk. Its root-relative `include "/segments/…"` +//! paths therefore anchor at the lesson root. +//! - **Project files**: any `FileId` with `VirtualRoot::Project` is read from +//! `root.join(vpath.realize)`. Used for content `.typ`, images, `toml()`, etc. +//! - **`@local/cph-render`**: a `FileId` whose root is the render package spec +//! is read from `render_dir.join(vpath.realize)`. This avoids installing the +//! package into the typst local-package directory (MVP: no environment +//! coupling). Any *other* `@package` id yields a `NotFound` error (the MVP +//! render package has no external `@preview` dependencies). +//! +//! Sources are cached in a `Mutex>` so repeated +//! accesses during one compilation are cheap, as the `World` contract expects. + +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +use typst::diag::{FileError, FileResult}; +use typst::foundations::{Bytes, Datetime, Duration}; +use typst::syntax::package::{PackageSpec, PackageVersion}; +use typst::syntax::{FileId, RootedPath, Source, VirtualPath, VirtualRoot}; +use typst::text::{Font, FontBook}; +use typst::utils::LazyHash; +use typst::{Library, LibraryExt, World}; +use typst_kit::fonts::FontStore; + +use crate::driver::DRIVER_DIR; + +/// The package spec the driver imports and the World mounts from `render_dir`. +pub fn render_package_spec() -> PackageSpec { + PackageSpec { + namespace: "local".into(), + name: "cph-render".into(), + version: PackageVersion { + major: 0, + minor: 1, + patch: 0, + }, + } +} + +/// A typst `World` for one lesson + target compilation. +pub struct LessonWorld { + /// Engineering-file root (the typst project root). + root: PathBuf, + /// On-disk location of the `cph-render` package. + render_dir: PathBuf, + /// The render package spec (`@local/cph-render:0.1.0`). + render_spec: PackageSpec, + /// FileId of the in-memory driver entrypoint. + main: FileId, + /// The driver source, parsed once. + driver_source: Source, + /// Standard library (default configuration). + library: LazyHash, + /// Shared font store (book + lazily-loaded fonts). + fonts: Arc, + /// Source cache for on-disk files. + sources: Mutex>, +} + +impl LessonWorld { + /// Build a world. `driver_src` is the generated entrypoint text; it is + /// mounted in-memory at `/.cph/driver-.typ` under the project root. + pub fn new( + root: PathBuf, + render_dir: PathBuf, + target: &str, + driver_src: String, + fonts: Arc, + ) -> Self { + let driver_vpath = VirtualPath::new(format!("/{DRIVER_DIR}/driver-{target}.typ")) + .expect("driver vpath is a valid virtual path"); + let main = FileId::new(RootedPath::new(VirtualRoot::Project, driver_vpath)); + let driver_source = Source::new(main, driver_src); + + Self { + root, + render_dir, + render_spec: render_package_spec(), + main, + driver_source, + library: LazyHash::new(Library::default()), + fonts, + sources: Mutex::new(HashMap::new()), + } + } + + /// Map a `FileId` to its on-disk path, honoring the project / render-package + /// roots. Returns a `FileError` for any other package root. + fn resolve(&self, id: FileId) -> FileResult { + let vpath = id.vpath(); + match id.root() { + VirtualRoot::Project => vpath.realize(&self.root).map_err(Into::into), + VirtualRoot::Package(spec) if *spec == self.render_spec => { + vpath.realize(&self.render_dir).map_err(Into::into) + } + VirtualRoot::Package(spec) => Err(FileError::Package( + typst::diag::PackageError::NotFound(spec.clone()), + )), + } + } + + /// Read raw bytes for `id` from disk (driver excluded — handled by callers). + fn read_bytes(&self, id: FileId) -> FileResult> { + let path = self.resolve(id)?; + std::fs::read(&path).map_err(|e| FileError::from_io(e, &path)) + } +} + +impl World for LessonWorld { + fn library(&self) -> &LazyHash { + &self.library + } + + fn book(&self) -> &LazyHash { + self.fonts.book() + } + + fn main(&self) -> FileId { + self.main + } + + fn source(&self, id: FileId) -> FileResult { + if id == self.main { + return Ok(self.driver_source.clone()); + } + // Cache hit? + if let Some(src) = self.sources.lock().expect("sources mutex").get(&id) { + return Ok(src.clone()); + } + let bytes = self.read_bytes(id)?; + let text = String::from_utf8(bytes).map_err(|_| FileError::InvalidUtf8)?; + let source = Source::new(id, text); + self.sources + .lock() + .expect("sources mutex") + .insert(id, source.clone()); + Ok(source) + } + + fn file(&self, id: FileId) -> FileResult { + if id == self.main { + return Ok(Bytes::from_string(self.driver_source.text().to_string())); + } + let bytes = self.read_bytes(id)?; + Ok(Bytes::new(bytes)) + } + + fn font(&self, index: usize) -> Option { + self.fonts.font(index) + } + + fn today(&self, _offset: Option) -> Option { + // No clock dependence needed; lessons are reproducible. + None + } +} diff --git a/crates/cph-typst/tests/compile.rs b/crates/cph-typst/tests/compile.rs new file mode 100644 index 0000000..6f645c4 --- /dev/null +++ b/crates/cph-typst/tests/compile.rs @@ -0,0 +1,189 @@ +//! Integration tests for `cph-typst`: driver generation, World, compile-check, +//! and PDF export over the `tests/fixtures/mini` lesson. +//! +//! Render-package dependency: most tests point the [`Engine`] at the bundled +//! **render-stub** (`tests/fixtures/render-stub`) so the World/compile/PDF path +//! is proven independently of WU-2. One `#[ignore]`d test points at the real +//! repo `render/` package for when it is ready / for manual runs. + +use std::path::PathBuf; + +use cph_diag::Severity; +use cph_typst::{generate_driver, Engine}; + +fn fixture_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/mini") +} + +fn stub_render_dir() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/render-stub") +} + +fn real_render_dir() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") + .join("render") +} + +fn load_mini() -> cph_model::Lesson { + let (lesson, diags) = cph_model::load(&fixture_root()); + let lesson = lesson.expect("mini fixture loads into a Lesson"); + let errors: Vec<_> = diags + .iter() + .filter(|d| d.severity == Severity::Error) + .collect(); + assert!(errors.is_empty(), "fixture has loader errors: {errors:?}"); + lesson +} + +/// PURE UNIT TEST (no fonts, no render package): the generated driver string +/// has the expected shape, order, includes, and scalar. +#[test] +fn driver_gen_shape_and_order() { + let lesson = load_mini(); + let src = generate_driver(&lesson, "student"); + + // Imports the render package and calls display. + assert!(src.contains("#import \"@local/cph-render:0.1.0\": display")); + assert!(src.contains("#display(")); + assert!(src.contains("target: \"student\"")); + assert!(src.contains("title: \"迷你示例课时\"")); + assert!(src.contains("author: \"测试作者\"")); + + // Root-relative includes with UTF-8 folder names, one per content field. + assert!(src.contains("include \"/segments/开场对照导言/textbook.typ\"")); + assert!(src.contains("include \"/lemmas/量纲分析估计/stmt.typ\"")); + assert!(src.contains("include \"/lemmas/量纲分析估计/proof.typ\"")); + assert!(src.contains("include \"/examples/自由落体/problem.typ\"")); + assert!(src.contains("include \"/examples/自由落体/solution.typ\"")); + + // Example scalar `source` is emitted from element.toml. + assert!(src.contains("source: \"自拟\"")); + + // Parts appear in manifest order: segment, then lemma, then example. + let seg = src.find("kind: \"segment\"").expect("segment present"); + let lem = src.find("kind: \"lemma\"").expect("lemma present"); + let exa = src.find("kind: \"example\"").expect("example present"); + assert!(seg < lem && lem < exa, "parts must keep manifest order"); +} + +/// Optional `proof.typ` is only included when it exists on disk. (It exists in +/// the mini fixture, so we assert presence; absence is covered by construction +/// — a kind without the file would simply omit the binding.) +#[test] +fn optional_proof_included_when_present() { + let lesson = load_mini(); + let src = generate_driver(&lesson, "teacher"); + assert!(src.contains("_p1_proof = include")); +} + +/// FONT-DEPENDENT: compile the mini lesson through the render-stub. Should +/// produce zero Error-severity diagnostics. If this fails purely because the +/// test host lacks fonts, the failure will be a typst font error — see the +/// note in the crate docs. +#[test] +fn compile_check_clean_with_stub() { + let lesson = load_mini(); + let engine = Engine::with_render_dir(stub_render_dir()); + let diags = engine.compile_check(&lesson, "student"); + let errors: Vec<_> = diags + .iter() + .filter(|d| d.severity == Severity::Error) + .collect(); + assert!(errors.is_empty(), "unexpected compile errors: {errors:#?}"); +} + +/// FONT-DEPENDENT: a real PDF is produced through the render-stub and is +/// non-trivial in size. +#[test] +fn build_pdf_with_stub() { + let lesson = load_mini(); + let engine = Engine::with_render_dir(stub_render_dir()); + let pdf = engine + .build_pdf(&lesson, "student") + .unwrap_or_else(|d| panic!("PDF build failed: {d:#?}")); + assert!(pdf.starts_with(b"%PDF"), "output is a PDF"); + assert!( + pdf.len() > 1024, + "PDF is non-trivial (got {} bytes)", + pdf.len() + ); + + let out = std::env::temp_dir().join("cph-typst-mini-student.pdf"); + std::fs::write(&out, &pdf).expect("write pdf"); + assert!(std::fs::metadata(&out).unwrap().len() > 1024); +} + +/// A diagnostic that lands inside the generated driver is re-pointed at the +/// driver path with a "generated driver" hint, not dropped. We force this by +/// compiling against a render dir whose `display` does not exist, so the +/// driver's `#display(...)` call is unknown — the error span is in the driver. +#[test] +fn driver_internal_span_is_repointed() { + let lesson = load_mini(); + // Point at a render dir with an EMPTY lib.typ (no `display`), so calling + // `#display(...)` errors inside the driver. + let empty = std::env::temp_dir().join("cph-typst-empty-render"); + std::fs::create_dir_all(&empty).unwrap(); + std::fs::write( + empty.join("typst.toml"), + "[package]\nname=\"cph-render\"\nversion=\"0.1.0\"\nentrypoint=\"lib.typ\"\n\ + authors=[\"t\"]\nlicense=\"MIT\"\ndescription=\"empty\"\n", + ) + .unwrap(); + std::fs::write(empty.join("lib.typ"), "// no display defined\n").unwrap(); + + let engine = Engine::with_render_dir(empty); + let diags = engine.compile_check(&lesson, "student"); + let errors: Vec<_> = diags + .iter() + .filter(|d| d.severity == Severity::Error) + .collect(); + assert!(!errors.is_empty(), "expected an unknown-`display` error"); + // At least one error should point at the driver and carry the driver hint. + let driver_err = errors.iter().find(|d| { + d.span + .as_ref() + .is_some_and(|s| s.file.to_string_lossy().contains(".cph/driver-")) + }); + assert!( + driver_err.is_some(), + "an error span should be re-pointed at the generated driver: {errors:#?}" + ); + assert!( + driver_err + .unwrap() + .hint + .as_deref() + .is_some_and(|h| h.contains("generated driver")), + "driver-internal error should carry the generated-driver hint" + ); +} + +/// Full end-to-end against the REAL repo `render/` package: load the mini +/// fixture, compile through `cph-render`'s `display`, export a PDF for both +/// targets. This proves the whole World → driver → render-package → PDF path, +/// not just the stub. Requires system CJK fonts (present on dev + CI via +/// fonts-noto-cjk). +#[test] +fn build_pdf_with_real_render() { + let lesson = load_mini(); + let render_dir = real_render_dir(); + assert!( + render_dir.join("lib.typ").is_file(), + "real render package missing at {}", + render_dir.display() + ); + let engine = Engine::with_render_dir(render_dir); + + for target in ["student", "teacher"] { + let pdf = engine + .build_pdf(&lesson, target) + .unwrap_or_else(|d| panic!("{target} PDF build failed: {d:#?}")); + assert!(pdf.starts_with(b"%PDF")); + assert!(pdf.len() > 1024, "{target} PDF too small"); + let out = std::env::temp_dir().join(format!("cph-typst-mini-real-{target}.pdf")); + std::fs::write(&out, &pdf).expect("write pdf"); + } +} diff --git a/crates/cph-typst/tests/fixtures/mini/examples/自由落体/element.toml b/crates/cph-typst/tests/fixtures/mini/examples/自由落体/element.toml new file mode 100644 index 0000000..b926a34 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/examples/自由落体/element.toml @@ -0,0 +1,2 @@ +kind = "example" +source = "自拟" diff --git a/crates/cph-typst/tests/fixtures/mini/examples/自由落体/problem.typ b/crates/cph-typst/tests/fixtures/mini/examples/自由落体/problem.typ new file mode 100644 index 0000000..bd1b529 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/examples/自由落体/problem.typ @@ -0,0 +1 @@ +一物体从静止自由下落,求下落时间 $t$ 后的速度 $v$ 与位移 $h$。 diff --git a/crates/cph-typst/tests/fixtures/mini/examples/自由落体/solution.typ b/crates/cph-typst/tests/fixtures/mini/examples/自由落体/solution.typ new file mode 100644 index 0000000..c232427 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/examples/自由落体/solution.typ @@ -0,0 +1 @@ +由匀加速运动公式,$v = g t$,$h = 1/2 g t^2$。代入 $g approx 9.8 "m/s"^2$ 即得数值结果。 diff --git a/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/element.toml b/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/element.toml new file mode 100644 index 0000000..e0a523e --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/element.toml @@ -0,0 +1 @@ +kind = "lemma" diff --git a/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/proof.typ b/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/proof.typ new file mode 100644 index 0000000..d1c6bb4 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/proof.typ @@ -0,0 +1,3 @@ +设 $T = l^a g^b$。量纲为 $[T] = "T"$,$[l] = "L"$,$[g] = "L T"^(-2)$。 +比较两端得 $a + b = 0$ 与 $-2 b = 1$,解得 $a = 1 slash 2$,$b = -1 slash 2$, +故 $T prop sqrt(l slash g)$。$qed$ diff --git a/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/stmt.typ b/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/stmt.typ new file mode 100644 index 0000000..a88a0fc --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/lemmas/量纲分析估计/stmt.typ @@ -0,0 +1,3 @@ +设单摆周期 $T$ 仅依赖摆长 $l$ 与重力加速度 $g$,则由量纲分析必有 +$ T = k sqrt(l / g) $ +其中 $k$ 为无量纲常数。 diff --git a/crates/cph-typst/tests/fixtures/mini/manifest.toml b/crates/cph-typst/tests/fixtures/mini/manifest.toml new file mode 100644 index 0000000..9215ca8 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/manifest.toml @@ -0,0 +1,23 @@ +[project] +id = "mini" +name = "迷你课时" + +[info] +title = "迷你示例课时" +author = "测试作者" + +[[parts]] +kind = "segment" +path = "segments/开场对照导言" + +[[parts]] +kind = "lemma" +path = "lemmas/量纲分析估计" + +[[parts]] +kind = "example" +path = "examples/自由落体" + +[targets.student] + +[targets.teacher] diff --git a/crates/cph-typst/tests/fixtures/mini/segments/开场对照导言/element.toml b/crates/cph-typst/tests/fixtures/mini/segments/开场对照导言/element.toml new file mode 100644 index 0000000..d67ae12 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/segments/开场对照导言/element.toml @@ -0,0 +1 @@ +kind = "segment" diff --git a/crates/cph-typst/tests/fixtures/mini/segments/开场对照导言/textbook.typ b/crates/cph-typst/tests/fixtures/mini/segments/开场对照导言/textbook.typ new file mode 100644 index 0000000..c38b680 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/mini/segments/开场对照导言/textbook.typ @@ -0,0 +1,2 @@ +本节通过对照两种估计方法,引入量纲分析这一工具。我们先回顾自由落体, +其中能量与质量的关系可写作 $E = m c^2$(此处仅作记号示例)。 diff --git a/crates/cph-typst/tests/fixtures/render-stub/lib.typ b/crates/cph-typst/tests/fixtures/render-stub/lib.typ new file mode 100644 index 0000000..1b9184b --- /dev/null +++ b/crates/cph-typst/tests/fixtures/render-stub/lib.typ @@ -0,0 +1,29 @@ +// Minimal stand-in for the real `cph-render` package, used so cph-typst's +// World / compile / PDF path can be proven independently of WU-2. +// +// It exercises the same call shape as the real entry: it reads `info`, walks +// `parts` IN ORDER, and renders each part's content fields by `kind`. Content +// values are already-evaluated content (the driver produced them via include). +#let display(info: (:), target: "student", parts: ()) = { + set document(title: info.at("title", default: "")) + [= #info.at("title", default: "")] + [target: #target] + for p in parts { + let kind = p.at("kind", default: none) + [== #kind] + if kind == "segment" { + p.textbook + } else if kind == "lemma" { + p.stmt + let proof = p.at("proof", default: none) + if proof != none { proof } + } else if kind == "example" { + p.problem + p.solution + let src = p.at("source", default: none) + if src != none [来源:#src] + } else if kind == "sop" { + p.sop + } + } +} diff --git a/crates/cph-typst/tests/fixtures/render-stub/typst.toml b/crates/cph-typst/tests/fixtures/render-stub/typst.toml new file mode 100644 index 0000000..9199835 --- /dev/null +++ b/crates/cph-typst/tests/fixtures/render-stub/typst.toml @@ -0,0 +1,7 @@ +[package] +name = "cph-render" +version = "0.1.0" +entrypoint = "lib.typ" +authors = ["cph-typst tests"] +license = "MIT" +description = "Minimal stand-in for cph-render used by cph-typst tests." diff --git a/render/typst.toml b/render/typst.toml index c389bf2..058fabc 100644 --- a/render/typst.toml +++ b/render/typst.toml @@ -2,7 +2,7 @@ name = "cph-render" version = "0.1.0" entrypoint = "lib.typ" -compiler = ">=0.15.0" +compiler = "0.15.0" authors = ["curriculum-project-hub"] license = "MIT" description = "Curriculum lesson render package: single `display` entry over an ordered list of typed parts (segment/example/lemma/sop), targeting student/teacher handouts."