typst local package (tlp) manager

Initial commit

T0mstone d4744125

+1321
+1
.gitignore
··· 1 + /target
+929
Cargo.lock
··· 1 + # This file is automatically @generated by Cargo. 2 + # It is not intended for manual editing. 3 + version = 4 4 + 5 + [[package]] 6 + name = "anstream" 7 + version = "0.6.18" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" 10 + dependencies = [ 11 + "anstyle", 12 + "anstyle-parse", 13 + "anstyle-query", 14 + "anstyle-wincon", 15 + "colorchoice", 16 + "is_terminal_polyfill", 17 + "utf8parse", 18 + ] 19 + 20 + [[package]] 21 + name = "anstyle" 22 + version = "1.0.10" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 25 + 26 + [[package]] 27 + name = "anstyle-parse" 28 + version = "0.2.6" 29 + source = "registry+https://github.com/rust-lang/crates.io-index" 30 + checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" 31 + dependencies = [ 32 + "utf8parse", 33 + ] 34 + 35 + [[package]] 36 + name = "anstyle-query" 37 + version = "1.1.2" 38 + source = "registry+https://github.com/rust-lang/crates.io-index" 39 + checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" 40 + dependencies = [ 41 + "windows-sys", 42 + ] 43 + 44 + [[package]] 45 + name = "anstyle-wincon" 46 + version = "3.0.7" 47 + source = "registry+https://github.com/rust-lang/crates.io-index" 48 + checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" 49 + dependencies = [ 50 + "anstyle", 51 + "once_cell", 52 + "windows-sys", 53 + ] 54 + 55 + [[package]] 56 + name = "autocfg" 57 + version = "1.4.0" 58 + source = "registry+https://github.com/rust-lang/crates.io-index" 59 + checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 60 + 61 + [[package]] 62 + name = "bitflags" 63 + version = "2.9.0" 64 + source = "registry+https://github.com/rust-lang/crates.io-index" 65 + checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 66 + 67 + [[package]] 68 + name = "cc" 69 + version = "1.2.19" 70 + source = "registry+https://github.com/rust-lang/crates.io-index" 71 + checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" 72 + dependencies = [ 73 + "jobserver", 74 + "libc", 75 + "shlex", 76 + ] 77 + 78 + [[package]] 79 + name = "cfg-if" 80 + version = "1.0.0" 81 + source = "registry+https://github.com/rust-lang/crates.io-index" 82 + checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 83 + 84 + [[package]] 85 + name = "clap" 86 + version = "4.5.37" 87 + source = "registry+https://github.com/rust-lang/crates.io-index" 88 + checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" 89 + dependencies = [ 90 + "clap_builder", 91 + "clap_derive", 92 + ] 93 + 94 + [[package]] 95 + name = "clap_builder" 96 + version = "4.5.37" 97 + source = "registry+https://github.com/rust-lang/crates.io-index" 98 + checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" 99 + dependencies = [ 100 + "anstream", 101 + "anstyle", 102 + "clap_lex", 103 + "strsim", 104 + ] 105 + 106 + [[package]] 107 + name = "clap_derive" 108 + version = "4.5.32" 109 + source = "registry+https://github.com/rust-lang/crates.io-index" 110 + checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" 111 + dependencies = [ 112 + "heck", 113 + "proc-macro2", 114 + "quote", 115 + "syn", 116 + ] 117 + 118 + [[package]] 119 + name = "clap_lex" 120 + version = "0.7.4" 121 + source = "registry+https://github.com/rust-lang/crates.io-index" 122 + checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 123 + 124 + [[package]] 125 + name = "colorchoice" 126 + version = "1.0.3" 127 + source = "registry+https://github.com/rust-lang/crates.io-index" 128 + checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" 129 + 130 + [[package]] 131 + name = "dirs" 132 + version = "6.0.0" 133 + source = "registry+https://github.com/rust-lang/crates.io-index" 134 + checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" 135 + dependencies = [ 136 + "dirs-sys", 137 + ] 138 + 139 + [[package]] 140 + name = "dirs-sys" 141 + version = "0.5.0" 142 + source = "registry+https://github.com/rust-lang/crates.io-index" 143 + checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" 144 + dependencies = [ 145 + "libc", 146 + "option-ext", 147 + "redox_users", 148 + "windows-sys", 149 + ] 150 + 151 + [[package]] 152 + name = "displaydoc" 153 + version = "0.2.5" 154 + source = "registry+https://github.com/rust-lang/crates.io-index" 155 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 156 + dependencies = [ 157 + "proc-macro2", 158 + "quote", 159 + "syn", 160 + ] 161 + 162 + [[package]] 163 + name = "either" 164 + version = "1.15.0" 165 + source = "registry+https://github.com/rust-lang/crates.io-index" 166 + checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 167 + 168 + [[package]] 169 + name = "equivalent" 170 + version = "1.0.2" 171 + source = "registry+https://github.com/rust-lang/crates.io-index" 172 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 173 + 174 + [[package]] 175 + name = "form_urlencoded" 176 + version = "1.2.1" 177 + source = "registry+https://github.com/rust-lang/crates.io-index" 178 + checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 179 + dependencies = [ 180 + "percent-encoding", 181 + ] 182 + 183 + [[package]] 184 + name = "fs-err" 185 + version = "3.1.0" 186 + source = "registry+https://github.com/rust-lang/crates.io-index" 187 + checksum = "1f89bda4c2a21204059a977ed3bfe746677dfd137b83c339e702b0ac91d482aa" 188 + dependencies = [ 189 + "autocfg", 190 + ] 191 + 192 + [[package]] 193 + name = "getrandom" 194 + version = "0.2.16" 195 + source = "registry+https://github.com/rust-lang/crates.io-index" 196 + checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 197 + dependencies = [ 198 + "cfg-if", 199 + "libc", 200 + "wasi 0.11.0+wasi-snapshot-preview1", 201 + ] 202 + 203 + [[package]] 204 + name = "getrandom" 205 + version = "0.3.2" 206 + source = "registry+https://github.com/rust-lang/crates.io-index" 207 + checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" 208 + dependencies = [ 209 + "cfg-if", 210 + "libc", 211 + "r-efi", 212 + "wasi 0.14.2+wasi-0.2.4", 213 + ] 214 + 215 + [[package]] 216 + name = "git2" 217 + version = "0.20.1" 218 + source = "registry+https://github.com/rust-lang/crates.io-index" 219 + checksum = "5220b8ba44c68a9a7f7a7659e864dd73692e417ef0211bea133c7b74e031eeb9" 220 + dependencies = [ 221 + "bitflags", 222 + "libc", 223 + "libgit2-sys", 224 + "log", 225 + "url", 226 + ] 227 + 228 + [[package]] 229 + name = "hashbrown" 230 + version = "0.15.2" 231 + source = "registry+https://github.com/rust-lang/crates.io-index" 232 + checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 233 + 234 + [[package]] 235 + name = "heck" 236 + version = "0.5.0" 237 + source = "registry+https://github.com/rust-lang/crates.io-index" 238 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 239 + 240 + [[package]] 241 + name = "icu_collections" 242 + version = "1.5.0" 243 + source = "registry+https://github.com/rust-lang/crates.io-index" 244 + checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 245 + dependencies = [ 246 + "displaydoc", 247 + "yoke", 248 + "zerofrom", 249 + "zerovec", 250 + ] 251 + 252 + [[package]] 253 + name = "icu_locid" 254 + version = "1.5.0" 255 + source = "registry+https://github.com/rust-lang/crates.io-index" 256 + checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 257 + dependencies = [ 258 + "displaydoc", 259 + "litemap", 260 + "tinystr", 261 + "writeable", 262 + "zerovec", 263 + ] 264 + 265 + [[package]] 266 + name = "icu_locid_transform" 267 + version = "1.5.0" 268 + source = "registry+https://github.com/rust-lang/crates.io-index" 269 + checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 270 + dependencies = [ 271 + "displaydoc", 272 + "icu_locid", 273 + "icu_locid_transform_data", 274 + "icu_provider", 275 + "tinystr", 276 + "zerovec", 277 + ] 278 + 279 + [[package]] 280 + name = "icu_locid_transform_data" 281 + version = "1.5.1" 282 + source = "registry+https://github.com/rust-lang/crates.io-index" 283 + checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" 284 + 285 + [[package]] 286 + name = "icu_normalizer" 287 + version = "1.5.0" 288 + source = "registry+https://github.com/rust-lang/crates.io-index" 289 + checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 290 + dependencies = [ 291 + "displaydoc", 292 + "icu_collections", 293 + "icu_normalizer_data", 294 + "icu_properties", 295 + "icu_provider", 296 + "smallvec", 297 + "utf16_iter", 298 + "utf8_iter", 299 + "write16", 300 + "zerovec", 301 + ] 302 + 303 + [[package]] 304 + name = "icu_normalizer_data" 305 + version = "1.5.1" 306 + source = "registry+https://github.com/rust-lang/crates.io-index" 307 + checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" 308 + 309 + [[package]] 310 + name = "icu_properties" 311 + version = "1.5.1" 312 + source = "registry+https://github.com/rust-lang/crates.io-index" 313 + checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 314 + dependencies = [ 315 + "displaydoc", 316 + "icu_collections", 317 + "icu_locid_transform", 318 + "icu_properties_data", 319 + "icu_provider", 320 + "tinystr", 321 + "zerovec", 322 + ] 323 + 324 + [[package]] 325 + name = "icu_properties_data" 326 + version = "1.5.1" 327 + source = "registry+https://github.com/rust-lang/crates.io-index" 328 + checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" 329 + 330 + [[package]] 331 + name = "icu_provider" 332 + version = "1.5.0" 333 + source = "registry+https://github.com/rust-lang/crates.io-index" 334 + checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 335 + dependencies = [ 336 + "displaydoc", 337 + "icu_locid", 338 + "icu_provider_macros", 339 + "stable_deref_trait", 340 + "tinystr", 341 + "writeable", 342 + "yoke", 343 + "zerofrom", 344 + "zerovec", 345 + ] 346 + 347 + [[package]] 348 + name = "icu_provider_macros" 349 + version = "1.5.0" 350 + source = "registry+https://github.com/rust-lang/crates.io-index" 351 + checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 352 + dependencies = [ 353 + "proc-macro2", 354 + "quote", 355 + "syn", 356 + ] 357 + 358 + [[package]] 359 + name = "idna" 360 + version = "1.0.3" 361 + source = "registry+https://github.com/rust-lang/crates.io-index" 362 + checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 363 + dependencies = [ 364 + "idna_adapter", 365 + "smallvec", 366 + "utf8_iter", 367 + ] 368 + 369 + [[package]] 370 + name = "idna_adapter" 371 + version = "1.2.0" 372 + source = "registry+https://github.com/rust-lang/crates.io-index" 373 + checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 374 + dependencies = [ 375 + "icu_normalizer", 376 + "icu_properties", 377 + ] 378 + 379 + [[package]] 380 + name = "indexmap" 381 + version = "2.9.0" 382 + source = "registry+https://github.com/rust-lang/crates.io-index" 383 + checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 384 + dependencies = [ 385 + "equivalent", 386 + "hashbrown", 387 + ] 388 + 389 + [[package]] 390 + name = "is_terminal_polyfill" 391 + version = "1.70.1" 392 + source = "registry+https://github.com/rust-lang/crates.io-index" 393 + checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 394 + 395 + [[package]] 396 + name = "itertools" 397 + version = "0.14.0" 398 + source = "registry+https://github.com/rust-lang/crates.io-index" 399 + checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 400 + dependencies = [ 401 + "either", 402 + ] 403 + 404 + [[package]] 405 + name = "jobserver" 406 + version = "0.1.33" 407 + source = "registry+https://github.com/rust-lang/crates.io-index" 408 + checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" 409 + dependencies = [ 410 + "getrandom 0.3.2", 411 + "libc", 412 + ] 413 + 414 + [[package]] 415 + name = "libc" 416 + version = "0.2.172" 417 + source = "registry+https://github.com/rust-lang/crates.io-index" 418 + checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" 419 + 420 + [[package]] 421 + name = "libgit2-sys" 422 + version = "0.18.1+1.9.0" 423 + source = "registry+https://github.com/rust-lang/crates.io-index" 424 + checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" 425 + dependencies = [ 426 + "cc", 427 + "libc", 428 + "libz-sys", 429 + "pkg-config", 430 + ] 431 + 432 + [[package]] 433 + name = "libredox" 434 + version = "0.1.3" 435 + source = "registry+https://github.com/rust-lang/crates.io-index" 436 + checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" 437 + dependencies = [ 438 + "bitflags", 439 + "libc", 440 + ] 441 + 442 + [[package]] 443 + name = "libz-sys" 444 + version = "1.1.22" 445 + source = "registry+https://github.com/rust-lang/crates.io-index" 446 + checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" 447 + dependencies = [ 448 + "cc", 449 + "libc", 450 + "pkg-config", 451 + "vcpkg", 452 + ] 453 + 454 + [[package]] 455 + name = "litemap" 456 + version = "0.7.5" 457 + source = "registry+https://github.com/rust-lang/crates.io-index" 458 + checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" 459 + 460 + [[package]] 461 + name = "log" 462 + version = "0.4.27" 463 + source = "registry+https://github.com/rust-lang/crates.io-index" 464 + checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 465 + 466 + [[package]] 467 + name = "memchr" 468 + version = "2.7.4" 469 + source = "registry+https://github.com/rust-lang/crates.io-index" 470 + checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 471 + 472 + [[package]] 473 + name = "once_cell" 474 + version = "1.21.3" 475 + source = "registry+https://github.com/rust-lang/crates.io-index" 476 + checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 477 + 478 + [[package]] 479 + name = "option-ext" 480 + version = "0.2.0" 481 + source = "registry+https://github.com/rust-lang/crates.io-index" 482 + checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" 483 + 484 + [[package]] 485 + name = "percent-encoding" 486 + version = "2.3.1" 487 + source = "registry+https://github.com/rust-lang/crates.io-index" 488 + checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 489 + 490 + [[package]] 491 + name = "pkg-config" 492 + version = "0.3.32" 493 + source = "registry+https://github.com/rust-lang/crates.io-index" 494 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 495 + 496 + [[package]] 497 + name = "proc-macro2" 498 + version = "1.0.95" 499 + source = "registry+https://github.com/rust-lang/crates.io-index" 500 + checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 501 + dependencies = [ 502 + "unicode-ident", 503 + ] 504 + 505 + [[package]] 506 + name = "quote" 507 + version = "1.0.40" 508 + source = "registry+https://github.com/rust-lang/crates.io-index" 509 + checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 510 + dependencies = [ 511 + "proc-macro2", 512 + ] 513 + 514 + [[package]] 515 + name = "r-efi" 516 + version = "5.2.0" 517 + source = "registry+https://github.com/rust-lang/crates.io-index" 518 + checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 519 + 520 + [[package]] 521 + name = "redox_users" 522 + version = "0.5.0" 523 + source = "registry+https://github.com/rust-lang/crates.io-index" 524 + checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" 525 + dependencies = [ 526 + "getrandom 0.2.16", 527 + "libredox", 528 + "thiserror", 529 + ] 530 + 531 + [[package]] 532 + name = "serde" 533 + version = "1.0.219" 534 + source = "registry+https://github.com/rust-lang/crates.io-index" 535 + checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 536 + dependencies = [ 537 + "serde_derive", 538 + ] 539 + 540 + [[package]] 541 + name = "serde_derive" 542 + version = "1.0.219" 543 + source = "registry+https://github.com/rust-lang/crates.io-index" 544 + checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 545 + dependencies = [ 546 + "proc-macro2", 547 + "quote", 548 + "syn", 549 + ] 550 + 551 + [[package]] 552 + name = "serde_spanned" 553 + version = "0.6.8" 554 + source = "registry+https://github.com/rust-lang/crates.io-index" 555 + checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 556 + dependencies = [ 557 + "serde", 558 + ] 559 + 560 + [[package]] 561 + name = "shlex" 562 + version = "1.3.0" 563 + source = "registry+https://github.com/rust-lang/crates.io-index" 564 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 565 + 566 + [[package]] 567 + name = "smallvec" 568 + version = "1.15.0" 569 + source = "registry+https://github.com/rust-lang/crates.io-index" 570 + checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 571 + 572 + [[package]] 573 + name = "snafu" 574 + version = "0.8.5" 575 + source = "registry+https://github.com/rust-lang/crates.io-index" 576 + checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" 577 + dependencies = [ 578 + "snafu-derive", 579 + ] 580 + 581 + [[package]] 582 + name = "snafu-derive" 583 + version = "0.8.5" 584 + source = "registry+https://github.com/rust-lang/crates.io-index" 585 + checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" 586 + dependencies = [ 587 + "heck", 588 + "proc-macro2", 589 + "quote", 590 + "syn", 591 + ] 592 + 593 + [[package]] 594 + name = "stable_deref_trait" 595 + version = "1.2.0" 596 + source = "registry+https://github.com/rust-lang/crates.io-index" 597 + checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 598 + 599 + [[package]] 600 + name = "strsim" 601 + version = "0.11.1" 602 + source = "registry+https://github.com/rust-lang/crates.io-index" 603 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 604 + 605 + [[package]] 606 + name = "syn" 607 + version = "2.0.100" 608 + source = "registry+https://github.com/rust-lang/crates.io-index" 609 + checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 610 + dependencies = [ 611 + "proc-macro2", 612 + "quote", 613 + "unicode-ident", 614 + ] 615 + 616 + [[package]] 617 + name = "synstructure" 618 + version = "0.13.1" 619 + source = "registry+https://github.com/rust-lang/crates.io-index" 620 + checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 621 + dependencies = [ 622 + "proc-macro2", 623 + "quote", 624 + "syn", 625 + ] 626 + 627 + [[package]] 628 + name = "thiserror" 629 + version = "2.0.12" 630 + source = "registry+https://github.com/rust-lang/crates.io-index" 631 + checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 632 + dependencies = [ 633 + "thiserror-impl", 634 + ] 635 + 636 + [[package]] 637 + name = "thiserror-impl" 638 + version = "2.0.12" 639 + source = "registry+https://github.com/rust-lang/crates.io-index" 640 + checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 641 + dependencies = [ 642 + "proc-macro2", 643 + "quote", 644 + "syn", 645 + ] 646 + 647 + [[package]] 648 + name = "tinystr" 649 + version = "0.7.6" 650 + source = "registry+https://github.com/rust-lang/crates.io-index" 651 + checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 652 + dependencies = [ 653 + "displaydoc", 654 + "zerovec", 655 + ] 656 + 657 + [[package]] 658 + name = "toml" 659 + version = "0.8.20" 660 + source = "registry+https://github.com/rust-lang/crates.io-index" 661 + checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" 662 + dependencies = [ 663 + "serde", 664 + "serde_spanned", 665 + "toml_datetime", 666 + "toml_edit", 667 + ] 668 + 669 + [[package]] 670 + name = "toml_datetime" 671 + version = "0.6.8" 672 + source = "registry+https://github.com/rust-lang/crates.io-index" 673 + checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 674 + dependencies = [ 675 + "serde", 676 + ] 677 + 678 + [[package]] 679 + name = "toml_edit" 680 + version = "0.22.24" 681 + source = "registry+https://github.com/rust-lang/crates.io-index" 682 + checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" 683 + dependencies = [ 684 + "indexmap", 685 + "serde", 686 + "serde_spanned", 687 + "toml_datetime", 688 + "winnow", 689 + ] 690 + 691 + [[package]] 692 + name = "typst-localpkg" 693 + version = "0.1.0" 694 + dependencies = [ 695 + "clap", 696 + "dirs", 697 + "fs-err", 698 + "git2", 699 + "itertools", 700 + "snafu", 701 + "toml", 702 + "toml_edit", 703 + ] 704 + 705 + [[package]] 706 + name = "unicode-ident" 707 + version = "1.0.18" 708 + source = "registry+https://github.com/rust-lang/crates.io-index" 709 + checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 710 + 711 + [[package]] 712 + name = "url" 713 + version = "2.5.4" 714 + source = "registry+https://github.com/rust-lang/crates.io-index" 715 + checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 716 + dependencies = [ 717 + "form_urlencoded", 718 + "idna", 719 + "percent-encoding", 720 + ] 721 + 722 + [[package]] 723 + name = "utf16_iter" 724 + version = "1.0.5" 725 + source = "registry+https://github.com/rust-lang/crates.io-index" 726 + checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 727 + 728 + [[package]] 729 + name = "utf8_iter" 730 + version = "1.0.4" 731 + source = "registry+https://github.com/rust-lang/crates.io-index" 732 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 733 + 734 + [[package]] 735 + name = "utf8parse" 736 + version = "0.2.2" 737 + source = "registry+https://github.com/rust-lang/crates.io-index" 738 + checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 739 + 740 + [[package]] 741 + name = "vcpkg" 742 + version = "0.2.15" 743 + source = "registry+https://github.com/rust-lang/crates.io-index" 744 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 745 + 746 + [[package]] 747 + name = "wasi" 748 + version = "0.11.0+wasi-snapshot-preview1" 749 + source = "registry+https://github.com/rust-lang/crates.io-index" 750 + checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 751 + 752 + [[package]] 753 + name = "wasi" 754 + version = "0.14.2+wasi-0.2.4" 755 + source = "registry+https://github.com/rust-lang/crates.io-index" 756 + checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 757 + dependencies = [ 758 + "wit-bindgen-rt", 759 + ] 760 + 761 + [[package]] 762 + name = "windows-sys" 763 + version = "0.59.0" 764 + source = "registry+https://github.com/rust-lang/crates.io-index" 765 + checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 766 + dependencies = [ 767 + "windows-targets", 768 + ] 769 + 770 + [[package]] 771 + name = "windows-targets" 772 + version = "0.52.6" 773 + source = "registry+https://github.com/rust-lang/crates.io-index" 774 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 775 + dependencies = [ 776 + "windows_aarch64_gnullvm", 777 + "windows_aarch64_msvc", 778 + "windows_i686_gnu", 779 + "windows_i686_gnullvm", 780 + "windows_i686_msvc", 781 + "windows_x86_64_gnu", 782 + "windows_x86_64_gnullvm", 783 + "windows_x86_64_msvc", 784 + ] 785 + 786 + [[package]] 787 + name = "windows_aarch64_gnullvm" 788 + version = "0.52.6" 789 + source = "registry+https://github.com/rust-lang/crates.io-index" 790 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 791 + 792 + [[package]] 793 + name = "windows_aarch64_msvc" 794 + version = "0.52.6" 795 + source = "registry+https://github.com/rust-lang/crates.io-index" 796 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 797 + 798 + [[package]] 799 + name = "windows_i686_gnu" 800 + version = "0.52.6" 801 + source = "registry+https://github.com/rust-lang/crates.io-index" 802 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 803 + 804 + [[package]] 805 + name = "windows_i686_gnullvm" 806 + version = "0.52.6" 807 + source = "registry+https://github.com/rust-lang/crates.io-index" 808 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 809 + 810 + [[package]] 811 + name = "windows_i686_msvc" 812 + version = "0.52.6" 813 + source = "registry+https://github.com/rust-lang/crates.io-index" 814 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 815 + 816 + [[package]] 817 + name = "windows_x86_64_gnu" 818 + version = "0.52.6" 819 + source = "registry+https://github.com/rust-lang/crates.io-index" 820 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 821 + 822 + [[package]] 823 + name = "windows_x86_64_gnullvm" 824 + version = "0.52.6" 825 + source = "registry+https://github.com/rust-lang/crates.io-index" 826 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 827 + 828 + [[package]] 829 + name = "windows_x86_64_msvc" 830 + version = "0.52.6" 831 + source = "registry+https://github.com/rust-lang/crates.io-index" 832 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 833 + 834 + [[package]] 835 + name = "winnow" 836 + version = "0.7.7" 837 + source = "registry+https://github.com/rust-lang/crates.io-index" 838 + checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" 839 + dependencies = [ 840 + "memchr", 841 + ] 842 + 843 + [[package]] 844 + name = "wit-bindgen-rt" 845 + version = "0.39.0" 846 + source = "registry+https://github.com/rust-lang/crates.io-index" 847 + checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 848 + dependencies = [ 849 + "bitflags", 850 + ] 851 + 852 + [[package]] 853 + name = "write16" 854 + version = "1.0.0" 855 + source = "registry+https://github.com/rust-lang/crates.io-index" 856 + checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 857 + 858 + [[package]] 859 + name = "writeable" 860 + version = "0.5.5" 861 + source = "registry+https://github.com/rust-lang/crates.io-index" 862 + checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 863 + 864 + [[package]] 865 + name = "yoke" 866 + version = "0.7.5" 867 + source = "registry+https://github.com/rust-lang/crates.io-index" 868 + checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 869 + dependencies = [ 870 + "serde", 871 + "stable_deref_trait", 872 + "yoke-derive", 873 + "zerofrom", 874 + ] 875 + 876 + [[package]] 877 + name = "yoke-derive" 878 + version = "0.7.5" 879 + source = "registry+https://github.com/rust-lang/crates.io-index" 880 + checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 881 + dependencies = [ 882 + "proc-macro2", 883 + "quote", 884 + "syn", 885 + "synstructure", 886 + ] 887 + 888 + [[package]] 889 + name = "zerofrom" 890 + version = "0.1.6" 891 + source = "registry+https://github.com/rust-lang/crates.io-index" 892 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 893 + dependencies = [ 894 + "zerofrom-derive", 895 + ] 896 + 897 + [[package]] 898 + name = "zerofrom-derive" 899 + version = "0.1.6" 900 + source = "registry+https://github.com/rust-lang/crates.io-index" 901 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 902 + dependencies = [ 903 + "proc-macro2", 904 + "quote", 905 + "syn", 906 + "synstructure", 907 + ] 908 + 909 + [[package]] 910 + name = "zerovec" 911 + version = "0.10.4" 912 + source = "registry+https://github.com/rust-lang/crates.io-index" 913 + checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 914 + dependencies = [ 915 + "yoke", 916 + "zerofrom", 917 + "zerovec-derive", 918 + ] 919 + 920 + [[package]] 921 + name = "zerovec-derive" 922 + version = "0.10.3" 923 + source = "registry+https://github.com/rust-lang/crates.io-index" 924 + checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 925 + dependencies = [ 926 + "proc-macro2", 927 + "quote", 928 + "syn", 929 + ]
+17
Cargo.toml
··· 1 + [package] 2 + name = "typst-localpkg" 3 + version = "0.1.0" 4 + edition = "2024" 5 + 6 + [dependencies] 7 + clap = { version = "4.5", features = ["derive", "env"] } 8 + dirs = "6" # matches typst 9 + fs-err = "3.1" 10 + git2 = { version = "0.20.1", optional = true, default-features = false } 11 + itertools = "0.14.0" 12 + snafu = "0.8.5" 13 + toml = { version = "0.8.20", default-features = false, features = ["parse"] } 14 + toml_edit = "0.22.24" 15 + 16 + [features] 17 + git2 = ["dep:git2"]
+40
src/args.rs
··· 1 + use std::path::PathBuf; 2 + 3 + #[derive(Debug, clap::Parser)] 4 + pub struct Args { 5 + // clap attr matches typst 6 + #[clap(long, env = "TYPST_PACKAGE_PATH", value_name = "DIR")] 7 + pub package_path: Option<PathBuf>, 8 + #[clap(long)] 9 + #[cfg_attr(feature = "git2", clap(hide = true))] 10 + /// Path to the git binary 11 + pub git: Option<PathBuf>, 12 + #[clap(subcommand)] 13 + pub command: Subcommand, 14 + } 15 + 16 + #[derive(Debug, clap::Subcommand)] 17 + pub enum Subcommand { 18 + /// Create a new local package 19 + New { 20 + /// The name of the local package 21 + name: String, 22 + }, 23 + /// Print the path of a local package 24 + #[clap(name = "path")] 25 + PrintPath { 26 + /// The name of the local package 27 + name: String 28 + }, 29 + /// Increase the version of a local package by one 30 + Bump { 31 + /// The name of the local package 32 + name: String, 33 + /// Increase the major instead of the minor version 34 + #[clap(long, conflicts_with = "patch")] 35 + major: bool, 36 + /// Increase the patch instead of the minor version 37 + #[clap(long)] 38 + patch: bool, 39 + }, 40 + }
+124
src/git.rs
··· 1 + #[cfg(feature = "git2")] 2 + use std::error::Error; 3 + use std::path::Path; 4 + #[cfg(not(feature = "git2"))] 5 + use std::process::Command; 6 + 7 + #[allow(unused)] 8 + use snafu::{OptionExt as _, ResultExt as _, Whatever}; 9 + 10 + #[cfg(feature = "git2")] 11 + type GitError = Box<dyn Error>; 12 + #[cfg(not(feature = "git2"))] 13 + type GitError = Whatever; 14 + 15 + pub fn init(at: &Path, _git: &Path) -> Result<(), GitError> { 16 + #[cfg(feature = "git2")] 17 + git2::Repository::init_opts( 18 + at, 19 + git2::RepositoryInitOptions::new() 20 + .no_reinit(true) 21 + .mkdir(false) 22 + .mkpath(false) 23 + .external_template(false), 24 + )?; 25 + 26 + #[cfg(not(feature = "git2"))] 27 + run(at, _git, ["init", "-q"], []).whatever_context("failed to run `git init`")?; 28 + 29 + Ok(()) 30 + } 31 + 32 + pub fn commit(at: &Path, files: &str, msg: &str, _git: &Path, _root: bool) -> Result<(), Whatever> { 33 + #[cfg(feature = "git2")] 34 + { 35 + let repo = git2::Repository::open(at).whatever_context("failed to access repository")?; 36 + let mut ind = repo.index().whatever_context("failed to get index")?; 37 + ind.add_all([files].iter(), git2::IndexAddOption::DEFAULT, None) 38 + .whatever_context("failed to add files to index")?; 39 + ind.write().whatever_context("failed to write index")?; 40 + let oid = ind 41 + .write_tree() 42 + .whatever_context("failed to write index tree")?; 43 + let tree = repo.find_tree(oid).whatever_context("failed to get tree")?; 44 + let sig = repo 45 + .signature() 46 + .whatever_context("failed to obtain signature")?; 47 + let parent = (!_root) 48 + .then(|| { 49 + repo.head() 50 + .whatever_context("failed to get HEAD")? 51 + .peel_to_commit() 52 + .whatever_context("failed to get HEAD commit") 53 + }) 54 + .transpose()?; 55 + repo.commit( 56 + Some("HEAD"), 57 + &sig, 58 + &sig, 59 + msg, 60 + &tree, 61 + parent.as_ref().as_slice(), 62 + ) 63 + .whatever_context("failed to create commit")?; 64 + } 65 + 66 + #[cfg(not(feature = "git2"))] 67 + { 68 + run(at, _git, ["add", files], []).whatever_context("failed to run `git add *`")?; 69 + run(at, _git, ["commit", "-qm", msg], []).whatever_context("failed to run `git commit`")?; 70 + } 71 + 72 + Ok(()) 73 + } 74 + 75 + pub fn tag_and_worktree(at: &Path, tag: &str, _git: &Path) -> Result<(), Whatever> { 76 + #[cfg(feature = "git2")] 77 + { 78 + let repo = git2::Repository::open(at).whatever_context("failed to access repository")?; 79 + let head = repo 80 + .head() 81 + .whatever_context("failed to get HEAD")? 82 + .peel(git2::ObjectType::Any) 83 + .whatever_context("failed to get HEAD object")?; 84 + repo.tag_lightweight(&format!("v{tag}"), &head, false) 85 + .whatever_context("failed to create tag")?; 86 + 87 + repo.worktree(tag, &at.join(tag), None) 88 + .whatever_context("failed to create worktree")?; 89 + } 90 + 91 + #[cfg(not(feature = "git2"))] 92 + { 93 + run(at, _git, ["tag", &format!("v{tag}")], []) 94 + .whatever_context("failed to run `git tag`")?; 95 + run( 96 + at, 97 + _git, 98 + ["worktree", "add", "-q", tag, &format!("v{tag}")], 99 + [], 100 + ) 101 + .whatever_context("failed to run `git worktree add`")?; 102 + } 103 + 104 + Ok(()) 105 + } 106 + 107 + #[cfg(not(feature = "git2"))] 108 + fn run<const N: usize, const M: usize>( 109 + at: &Path, 110 + git: &Path, 111 + args: [&str; N], 112 + other_args: [&Path; M], 113 + ) -> Result<(), Whatever> { 114 + Command::new(git) 115 + .args(args) 116 + .args(other_args) 117 + .current_dir(at) 118 + .status() 119 + .whatever_context("couldn't execute command")? 120 + .success() 121 + .then_some(()) 122 + .whatever_context("command failed")?; 123 + Ok(()) 124 + }
+210
src/main.rs
··· 1 + use std::path::{Component, Path}; 2 + 3 + use args::Args; 4 + use args::Subcommand::*; 5 + use clap::Parser; 6 + use itertools::Itertools; 7 + use snafu::{OptionExt as _, ResultExt as _, Whatever, whatever}; 8 + 9 + mod args; 10 + mod git; 11 + 12 + fn typst_toml_template(name: &str) -> String { 13 + format!( 14 + "\ 15 + [package] 16 + name = {name:?} 17 + version = \"0.1.0\" 18 + entrypoint = \"lib.typ\" 19 + " 20 + ) 21 + } 22 + 23 + #[snafu::report] 24 + fn main() -> Result<(), Whatever> { 25 + let Args { 26 + package_path, 27 + git, 28 + command, 29 + } = Args::parse(); 30 + let packages_local = package_path 31 + .or_else(|| { 32 + // matches what typst-kit does 33 + dirs::data_dir().map(|d| d.join("typst/packages")) 34 + }) 35 + .whatever_context("failed to get `packages` directory")? 36 + .join("local"); 37 + #[cfg(feature = "git2")] 38 + if git.is_some() { 39 + eprintln!( 40 + "warning: this binary was compiled with the `git2` feature, \ 41 + so the `--git` option has no effect." 42 + ); 43 + } 44 + let git = git.unwrap_or_else(|| "git".into()); 45 + if !packages_local.exists() { 46 + fs_err::create_dir_all(&packages_local) 47 + .whatever_context("failed to create `packages/local` directory")?; 48 + } 49 + 50 + match command { 51 + New { name } => { 52 + verify_name(&name)?; 53 + let dir = packages_local.join(&name); 54 + if dir.exists() { 55 + whatever!("a local package called {name:?} already exists"); 56 + } 57 + fs_err::create_dir(&dir).whatever_context("failed to create package directory")?; 58 + git::init(&dir, &git).whatever_context("failed to create repository")?; 59 + fs_err::write(dir.join(".gitignore"), "/*.*.*\n") 60 + .whatever_context("failed to create .gitignore")?; 61 + fs_err::write(dir.join("typst.toml"), typst_toml_template(&name)) 62 + .whatever_context("failed to create typst.toml")?; 63 + fs_err::File::create(dir.join("lib.typ")) 64 + .whatever_context("failed to create lib.typ")?; 65 + symlink_dir(&dir, &dir.join("0.1.0")) 66 + .whatever_context("failed to create latest version symlink")?; 67 + git::commit(&dir, "*", "Initial commit", &git, true) 68 + .whatever_context("failed to create initial commit")?; 69 + eprintln!("created local package at {dir:?}"); 70 + eprintln!("you can import it with `#import \"@local/{name}:0.1.0\"`"); 71 + } 72 + PrintPath { name } => { 73 + verify_name(&name)?; 74 + let dir = packages_local.join(&name); 75 + if !dir.exists() { 76 + whatever!("no local package {name:?} found"); 77 + } 78 + println!("{}", dir.display()); 79 + } 80 + Bump { name, major, patch } => { 81 + verify_name(&name)?; 82 + let dir = packages_local.join(&name); 83 + if !dir.exists() { 84 + whatever!("no local package {name:?} found"); 85 + } 86 + let typst_toml = dir.join("typst.toml"); 87 + let mut ver = 88 + extract_version(&typst_toml).whatever_context("failed to get package version")?; 89 + 90 + let old_ver = format!("{}.{}.{}", ver[0], ver[1], ver[2]); 91 + let old_path = dir.join(&old_ver); 92 + 93 + // confirm that old_path is actually a symlink to dir 94 + if !old_path.exists() { 95 + whatever!("no version symlink for {old_ver:?}"); 96 + } 97 + let meta = fs_err::symlink_metadata(&old_path) 98 + .whatever_context("failed to get metadata for version symlink")?; 99 + if !meta.is_symlink() { 100 + whatever!("{old_path:?} is not a symlink"); 101 + } 102 + if fs_err::canonicalize( 103 + fs_err::read_link(&old_path).whatever_context("failed to read version symlink")?, 104 + ) 105 + .whatever_context("failed to canonicalize version symlink target")? 106 + != fs_err::canonicalize(&dir) 107 + .whatever_context("failed to canonicalize package dir")? 108 + { 109 + whatever!("{old_path:?} doesn't target {dir:?}"); 110 + } 111 + 112 + // increase version 113 + let i = if major { 114 + 0 115 + } else if patch { 116 + 2 117 + } else { 118 + 1 119 + }; 120 + ver[i] += 1; 121 + for x in &mut ver[i + 1..] { 122 + *x = 0; 123 + } 124 + 125 + let new_ver = format!("{}.{}.{}", ver[0], ver[1], ver[2]); 126 + fs_err::rename(dir.join(&old_ver), dir.join(&new_ver)) 127 + .whatever_context("failed to move version symlink")?; 128 + git::tag_and_worktree(&dir, &old_ver, &git)?; 129 + write_version(&typst_toml, &new_ver) 130 + .whatever_context("failed to write version to typst.toml")?; 131 + git::commit(&dir, "typst.toml", "Bump version", &git, false) 132 + .whatever_context("failed to commit typst.toml")?; 133 + eprintln!("bumped version of local package {name:?} from {old_ver} to {new_ver}."); 134 + } 135 + } 136 + 137 + Ok(()) 138 + } 139 + 140 + fn extract_version(typst_toml: &Path) -> Result<[u32; 3], Whatever> { 141 + let file = fs_err::read_to_string(typst_toml).whatever_context("failed to read file")?; 142 + let pkg = toml::from_str::<toml::Table>(&file).whatever_context("failed to parse file")?; 143 + let ver = pkg 144 + .get("package") 145 + .whatever_context("no `[package]` table")? 146 + .as_table() 147 + .whatever_context("`package` is not a table")? 148 + .get("version") 149 + .whatever_context("`[package]` table has no `version` key")? 150 + .as_str() 151 + .whatever_context("`package.version` is not a string")?; 152 + parse_version(ver).whatever_context("invalid `package.version`") 153 + } 154 + 155 + fn write_version(typst_toml: &Path, to: &str) -> Result<(), Whatever> { 156 + let file = fs_err::read_to_string(typst_toml).whatever_context("failed to read file")?; 157 + let mut pkg = file 158 + .parse::<toml_edit::DocumentMut>() 159 + .whatever_context("failed to parse file")?; 160 + let ver = pkg 161 + .get_mut("package") 162 + .whatever_context("no `[package]` table")? 163 + .as_table_like_mut() 164 + .whatever_context("`package` is not a table")? 165 + .get_mut("version") 166 + .whatever_context("`[package]` table has no `version` key")?; 167 + *ver = toml_edit::Item::Value(toml_edit::Value::String(toml_edit::Formatted::new( 168 + to.to_string(), 169 + ))); 170 + fs_err::write(typst_toml, pkg.to_string()).whatever_context("failed to write file") 171 + } 172 + 173 + fn parse_version(v: &str) -> Result<[u32; 3], Whatever> { 174 + let mut res = [0; 3]; 175 + let mut i = 0; 176 + for c in v.split('.') { 177 + if i == 3 { 178 + whatever!("more than 3 periods"); 179 + } 180 + res[i] = c 181 + .parse() 182 + .with_whatever_context(|_| format!("{c:?} is not a valid number"))?; 183 + i += 1; 184 + } 185 + if i < 3 { 186 + whatever!("fewer than 3 periods"); 187 + } 188 + Ok(res) 189 + } 190 + 191 + fn verify_name(name: &str) -> Result<(), Whatever> { 192 + if !Path::new(&name) 193 + .components() 194 + .exactly_one() 195 + .is_ok_and(|x| matches!(x, Component::Normal(_))) 196 + { 197 + whatever!("invalid file name: {name:?}"); 198 + } 199 + Ok(()) 200 + } 201 + 202 + fn symlink_dir(original: &Path, link: &Path) -> Result<(), std::io::Error> { 203 + #[cfg(unix)] 204 + fs_err::os::unix::fs::symlink(original, link)?; 205 + 206 + #[cfg(windows)] 207 + fs_err::os::windows::fs::symlink_dir(original, link)?; 208 + 209 + Ok(()) 210 + }