From 5bcfc1795728cd566f0855015b4b841b023294b6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 13 Jan 2024 13:38:49 -0600 Subject: [PATCH] wip --- .idea/usage.iml | 2 + Cargo.lock | 333 +++++++++++++++---------------- Cargo.toml | 1 + cli/Cargo.toml | 5 +- cli/src/cli/generate/markdown.rs | 148 ++++++++------ cli/src/cli/generate/mod.rs | 6 +- examples/MISE_README.md | 189 ++++++++++++------ src/context.rs | 11 + src/lib.rs | 11 +- src/parse/spec.rs | 38 ++-- 10 files changed, 436 insertions(+), 308 deletions(-) create mode 100644 src/context.rs diff --git a/.idea/usage.iml b/.idea/usage.iml index 798678f..ebd7cd5 100644 --- a/.idea/usage.iml +++ b/.idea/usage.iml @@ -6,9 +6,11 @@ + + diff --git a/Cargo.lock b/Cargo.lock index 84a2450..05411c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +checksum = "4cd2405b3ac1faab2990b74d728624cd9fd115651fcecc7c2d8daf01376275ba" dependencies = [ "anstyle", "anstyle-parse", @@ -61,7 +61,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -71,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -98,6 +98,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.4.1" @@ -121,9 +127,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.11" +version = "4.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" +checksum = "58e54881c004cec7895b0068a0a954cd5d62da01aef83fa35b1e594497bf5445" dependencies = [ "clap_builder", "clap_derive", @@ -131,9 +137,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.11" +version = "4.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" +checksum = "59cb82d7f531603d2fd1f507441cdd35184fa81beff7bd489570de7f773460bb" dependencies = [ "anstream", "anstyle", @@ -150,7 +156,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -167,16 +173,33 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", - "windows-sys 0.45.0", + "windows-sys", ] +[[package]] +name = "contracts" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1d1429e3bd78171c65aa010eabcdf8f863ba3254728dbfb0ad4b1545beac15c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "either" version = "1.9.0" @@ -226,7 +249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -249,6 +272,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "gimli" version = "0.28.1" @@ -304,13 +333,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" dependencies = [ "hermit-abi", "rustix", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -347,9 +376,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" [[package]] name = "linked-hash-map" @@ -371,9 +400,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miette" @@ -404,7 +433,7 @@ checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -434,9 +463,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "memchr", ] @@ -453,6 +482,16 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro2" version = "1.0.76" @@ -471,6 +510,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "regex" version = "1.10.2" @@ -508,17 +556,23 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" -version = "0.38.28" +version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags", + "bitflags 2.4.1", "errno 0.3.8", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "shell-escape" version = "0.1.5" @@ -527,9 +581,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "similar" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aeaf503862c419d66959f5d7ca015337d864e9c49485d771b732e2a20453597" +checksum = "32fea41aca09ee824cc9724996433064c89f7777e60762749a4170a14abbfa21" [[package]] name = "smawk" @@ -543,6 +597,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + [[package]] name = "supports-color" version = "2.1.0" @@ -571,6 +647,17 @@ dependencies = [ "is-terminal", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.48" @@ -582,11 +669,24 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + [[package]] name = "termcolor" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -629,7 +729,7 @@ checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -655,6 +755,7 @@ name = "usage-cli" version = "0.1.0" dependencies = [ "clap", + "contracts", "env_logger", "exec", "itertools", @@ -663,8 +764,10 @@ dependencies = [ "miette", "once_cell", "regex", + "strum", "thiserror", "usage-lib", + "xx", ] [[package]] @@ -681,6 +784,7 @@ dependencies = [ "once_cell", "shell-escape", "thiserror", + "xx", ] [[package]] @@ -720,61 +824,13 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] @@ -783,141 +839,68 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "xx" +version = "0.2.0" +dependencies = [ + "miette", + "once_cell", + "pretty_assertions", + "tempfile", + "thiserror", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -926,3 +909,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index 2591bf9..a56c710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ shell-escape = "0.1" log = "0.4" itertools = "0.12.0" once_cell = "1.19.0" +xx = {path= "./xx"} [features] default = ["clap"] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index bcc3cc6..a04df38 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -15,6 +15,7 @@ path = "src/lib.rs" [dependencies] clap = { version = "4", features = ["derive", "string"] } +contracts = "0.6.3" env_logger = "0.10" exec = "0.3.1" itertools = "0.12.0" @@ -23,5 +24,7 @@ log = "0.4" miette = { version = "5", features = ["fancy"] } once_cell = "1" regex = "1" +strum = { version = "0.25.0", features = ["derive"] } +thiserror = "1" usage-lib = { path = "..", features=["clap"] } -thiserror = "1.0.56" +xx = {path= "../xx"} diff --git a/cli/src/cli/generate/markdown.rs b/cli/src/cli/generate/markdown.rs index 96e0863..492c043 100644 --- a/cli/src/cli/generate/markdown.rs +++ b/cli/src/cli/generate/markdown.rs @@ -1,17 +1,20 @@ +use std::fs; use std::fs::File; use std::io::Write; use std::iter::once; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::Mutex; -use std::{env, fs}; use clap::Args; +use contracts::requires; use kdl::{KdlDocument, KdlNode}; -use miette::{IntoDiagnostic, Result, SourceSpan}; +use miette::{IntoDiagnostic, SourceSpan}; +use strum::EnumIs; use thiserror::Error; use usage::{SchemaCmd, Spec}; +use xx::{context, file}; #[derive(Args)] #[clap(visible_alias = "md")] @@ -45,29 +48,27 @@ impl Markdown { Ok(()) } - fn inject_file(&self, inject: &Path) -> Result<()> { - let raw = fs::read_to_string(inject).into_diagnostic()?; - println!("{}", raw); - let root = inject.parent().unwrap().to_path_buf(); - let cwd = env::current_dir().into_diagnostic()?; - env::set_current_dir(&root).into_diagnostic()?; + fn inject_file(&self, inject: &Path) -> miette::Result<()> { + let raw = file::read_to_string(inject).into_diagnostic()?; + context::set_load_root(inject.parent().unwrap().to_path_buf()); let out = raw .lines() .map(|line| line.parse()) - .collect::>>()? + .collect::>>()? .into_iter() - .try_fold(UsageMdContext::new(root), |ctx, d| d.run(ctx))? + .try_fold(UsageMdContext::new(), |ctx, d| d.run(ctx))? .out .lock() .unwrap() - .join("\n"); - env::set_current_dir(cwd).into_diagnostic()?; - println!("{}", out); + .join("\n") + + "\n"; + print!("{}", out); fs::write(inject, out).into_diagnostic()?; Ok(()) } - fn _print(&self, spec: &Spec, dir: &Path, cmds: &[&SchemaCmd]) -> Result<()> { + //noinspection RsFormatMacroWithoutFormatArguments + fn _print(&self, spec: &Spec, dir: &Path, cmds: &[&SchemaCmd]) -> miette::Result<()> { let cmd = cmds.last().unwrap(); let mut out = vec![]; let cmd_path = cmds @@ -148,8 +149,10 @@ impl Markdown { } } +#[derive(Debug, EnumIs)] enum UsageMdDirective { Load { file: PathBuf }, + Title, UsageOverview, GlobalArgs, GlobalFlags, @@ -160,16 +163,14 @@ enum UsageMdDirective { } struct UsageMdContext { - _root: PathBuf, plain: bool, spec: Option, out: Mutex>, } impl UsageMdContext { - fn new(_root: PathBuf) -> Self { + fn new() -> Self { Self { - _root, plain: true, spec: None, out: Mutex::new(vec![]), @@ -182,27 +183,33 @@ impl UsageMdContext { } impl UsageMdDirective { + //noinspection RsFormatMacroWithoutFormatArguments + #[requires(self.requires_spec() -> ctx.spec.is_some())] + #[requires(self.is_load() -> ctx.spec.is_none())] fn run(&self, mut ctx: UsageMdContext) -> miette::Result { match self { UsageMdDirective::Load { file } => { - // let file = match file.is_relative() { - // true => ctx.root.join(file), - // false => file.clone(), - // }; - ctx.spec = Some(fs::read_to_string(file).into_diagnostic()?.parse()?); + let file = context::prepend_load_root(file); + ctx.spec = Some(fs::read_to_string(&file).into_diagnostic()?.parse()?); ctx.push(format!("", file.display())); } + UsageMdDirective::Title => { + ensure!(ctx.spec.is_some(), "spec must be loaded before title"); + ctx.plain = false; + let spec = ctx.spec.as_ref().unwrap(); + ctx.push(format!("")); + ctx.push(format!("# {name}", name = spec.name)); + ctx.push(format!("")); + } UsageMdDirective::UsageOverview => { ctx.plain = false; let spec = ctx.spec.as_ref().unwrap(); ctx.push("".to_string()); - ctx.push(format!("# {name}", name = spec.name)); - ctx.push("## Usage".to_string()); ctx.push("```".to_string()); ctx.push(format!("{bin} [flags] [args]", bin = spec.bin)); ctx.push("```".to_string()); - ctx.push("\n".to_string()); + ctx.push("".to_string()); } UsageMdDirective::GlobalArgs => { ctx.plain = false; @@ -211,7 +218,6 @@ impl UsageMdDirective { ctx.push("".to_string()); let args = spec.cmd.args.iter().filter(|a| !a.hide).collect::>(); if !args.is_empty() { - ctx.push(format!("## Args")); for arg in args { let name = &arg.usage(); if let Some(about) = &arg.long_help { @@ -224,7 +230,7 @@ impl UsageMdDirective { } } } - ctx.push(format!("\n")); + ctx.push(format!("")); } UsageMdDirective::GlobalFlags => { ctx.plain = false; @@ -238,7 +244,6 @@ impl UsageMdDirective { .filter(|f| !f.hide) .collect::>(); if !flags.is_empty() { - ctx.push(format!("## Flags")); for flag in flags { let name = flag.usage(); if let Some(about) = &flag.long_help { @@ -251,47 +256,21 @@ impl UsageMdDirective { } } } - ctx.push(format!("\n")); + ctx.push(format!("")); } UsageMdDirective::CommandIndex => { ctx.plain = false; let spec = ctx.spec.as_ref().unwrap(); ctx.push(format!("")); - - let subcommands = spec - .cmd - .subcommands - .values() - .filter(|c| !c.hide) - .collect::>(); - if !subcommands.is_empty() { - ctx.push(format!("## Commands")); - for cmd in subcommands { - let name = cmd.name.as_str(); - if let Some(about) = &cmd.help { - ctx.push(format!( - "- [`{name}`](./{name}): {about}", - name = name, - about = about - )); - } else { - ctx.push(format!("- [`{name}`](./{name})", name = name)); - } - } - } - - ctx.push(format!("\n")); + print_commands_index(&ctx, &[&spec.cmd])?; + ctx.push(format!("")); } UsageMdDirective::Commands => { ctx.plain = false; let spec = ctx.spec.as_ref().unwrap(); ctx.push(format!("")); - ctx.push(format!("# {name}", name = spec.name)); - ctx.push(format!("## Usage")); - ctx.push(format!("```")); - ctx.push(format!("{bin} [flags] [args]", bin = spec.bin)); - ctx.push(format!("```")); - ctx.push(format!("\n")); + print_commands(&ctx, &[&spec.cmd])?; + ctx.push(format!("")); } UsageMdDirective::EndToken => { ctx.plain = true; @@ -304,6 +283,56 @@ impl UsageMdDirective { }; Ok(ctx) } + + fn requires_spec(&self) -> bool { + !matches!( + self, + UsageMdDirective::Load { .. } | UsageMdDirective::Plain(_) + ) + } +} + +fn print_commands_index(ctx: &UsageMdContext, cmds: &[&SchemaCmd]) -> miette::Result<()> { + let subcommands = cmds[cmds.len() - 1] + .subcommands + .values() + .filter(|c| !c.hide) + .collect::>(); + for cmd in subcommands { + let cmds = cmds.iter().cloned().chain(once(cmd)).collect::>(); + let full_name = cmds + .iter() + .skip(1) + .map(|c| c.name.as_str()) + .collect::>() + .join(" "); + let slug = full_name.replace(" ", "-"); + ctx.push(format!("- [`{full_name}`](#{slug})",)); + print_commands_index(ctx, &cmds)?; + } + + Ok(()) +} + +fn print_commands(ctx: &UsageMdContext, cmds: &[&SchemaCmd]) -> miette::Result<()> { + let subcommands = cmds[cmds.len() - 1] + .subcommands + .values() + .filter(|c| !c.hide) + .collect::>(); + for cmd in subcommands { + let cmds = cmds.iter().cloned().chain(once(cmd)).collect::>(); + let full_name = cmds + .iter() + .skip(1) + .map(|c| c.name.as_str()) + .collect::>() + .join(" "); + ctx.push(format!("### `{full_name}`")); + print_commands(ctx, &cmds)?; + } + + Ok(()) } #[derive(Error, Diagnostic, Debug)] @@ -348,6 +377,7 @@ impl FromStr for UsageMdDirective { "load" => UsageMdDirective::Load { file: PathBuf::from(get_string(node, "file")?), }, + "title" => UsageMdDirective::Title, "usage_overview" => UsageMdDirective::UsageOverview, "global_args" => UsageMdDirective::GlobalArgs, "global_flags" => UsageMdDirective::GlobalFlags, diff --git a/cli/src/cli/generate/mod.rs b/cli/src/cli/generate/mod.rs index 69d1bc8..c7fd452 100644 --- a/cli/src/cli/generate/mod.rs +++ b/cli/src/cli/generate/mod.rs @@ -1,7 +1,5 @@ use std::path::PathBuf; -use miette::IntoDiagnostic; - use usage::Spec; mod completion; @@ -31,9 +29,9 @@ impl Generate { pub fn file_or_spec(file: &Option, spec: &Option) -> miette::Result { if let Some(file) = file { - let (spec, _) = Spec::parse_file(file).into_diagnostic()?; + let (spec, _) = Spec::parse_file(file)?; Ok(spec) } else { - spec.as_ref().unwrap().parse().into_diagnostic() + spec.as_ref().unwrap().parse() } } diff --git a/examples/MISE_README.md b/examples/MISE_README.md index 398cd81..1a40531 100644 --- a/examples/MISE_README.md +++ b/examples/MISE_README.md @@ -1,74 +1,151 @@ -# mise-en-place - - + + # mise + ## Usage + ``` [flags] [args] ``` - - +## Global Args - +## Global Flags -## Flags - `-C,--cd `: Change directory before running command - `-q,--quiet`: Suppress non-error messages - `-v,--verbose`: Show extra output (use -vv for even more) - `-y,--yes`: Answer yes to all confirmation prompts - +## Commands Index -## Commands -- [`activate`](./activate) -- [`alias`](./alias) -- [`bin-paths`](./bin-paths) -- [`cache`](./cache) -- [`completion`](./completion) -- [`config`](./config) -- [`current`](./current) -- [`deactivate`](./deactivate) -- [`direnv`](./direnv) -- [`doctor`](./doctor) -- [`env`](./env) -- [`exec`](./exec) -- [`implode`](./implode) -- [`install`](./install) -- [`latest`](./latest) -- [`link`](./link) -- [`ls`](./ls) -- [`ls-remote`](./ls-remote) -- [`outdated`](./outdated) -- [`plugins`](./plugins) -- [`prune`](./prune) -- [`reshim`](./reshim) -- [`run`](./run) -- [`self-update`](./self-update) -- [`set`](./set) -- [`settings`](./settings) -- [`shell`](./shell) -- [`sync`](./sync) -- [`task`](./task) -- [`trust`](./trust) -- [`uninstall`](./uninstall) -- [`unset`](./unset) -- [`upgrade`](./upgrade) -- [`usage`](./usage) -- [`use`](./use) -- [`version`](./version) -- [`watch`](./watch) -- [`where`](./where) -- [`which`](./which) - +- [`activate`](#activate) +- [`alias`](#alias) +- [`alias get`](#alias-get) +- [`alias ls`](#alias-ls) +- [`alias set`](#alias-set) +- [`alias unset`](#alias-unset) +- [`bin-paths`](#bin-paths) +- [`cache`](#cache) +- [`cache clear`](#cache-clear) +- [`completion`](#completion) +- [`config`](#config) +- [`config ls`](#config-ls) +- [`config generate`](#config-generate) +- [`current`](#current) +- [`deactivate`](#deactivate) +- [`direnv`](#direnv) +- [`direnv activate`](#direnv-activate) +- [`doctor`](#doctor) +- [`env`](#env) +- [`exec`](#exec) +- [`implode`](#implode) +- [`install`](#install) +- [`latest`](#latest) +- [`link`](#link) +- [`ls`](#ls) +- [`ls-remote`](#ls-remote) +- [`outdated`](#outdated) +- [`plugins`](#plugins) +- [`plugins install`](#plugins-install) +- [`plugins link`](#plugins-link) +- [`plugins ls`](#plugins-ls) +- [`plugins ls-remote`](#plugins-ls-remote) +- [`plugins uninstall`](#plugins-uninstall) +- [`plugins update`](#plugins-update) +- [`prune`](#prune) +- [`reshim`](#reshim) +- [`run`](#run) +- [`self-update`](#self-update) +- [`set`](#set) +- [`settings`](#settings) +- [`settings get`](#settings-get) +- [`settings ls`](#settings-ls) +- [`settings set`](#settings-set) +- [`settings unset`](#settings-unset) +- [`shell`](#shell) +- [`sync`](#sync) +- [`sync node`](#sync-node) +- [`sync python`](#sync-python) +- [`task`](#task) +- [`task edit`](#task-edit) +- [`task ls`](#task-ls) +- [`task run`](#task-run) +- [`trust`](#trust) +- [`uninstall`](#uninstall) +- [`unset`](#unset) +- [`upgrade`](#upgrade) +- [`usage`](#usage) +- [`use`](#use) +- [`version`](#version) +- [`watch`](#watch) +- [`where`](#where) +- [`which`](#which) +## Commands -# mise -## Usage -``` - [flags] [args] -``` - - \ No newline at end of file +### `activate` +### `alias` +### `alias get` +### `alias ls` +### `alias set` +### `alias unset` +### `bin-paths` +### `cache` +### `cache clear` +### `completion` +### `config` +### `config ls` +### `config generate` +### `current` +### `deactivate` +### `direnv` +### `direnv activate` +### `doctor` +### `env` +### `exec` +### `implode` +### `install` +### `latest` +### `link` +### `ls` +### `ls-remote` +### `outdated` +### `plugins` +### `plugins install` +### `plugins link` +### `plugins ls` +### `plugins ls-remote` +### `plugins uninstall` +### `plugins update` +### `prune` +### `reshim` +### `run` +### `self-update` +### `set` +### `settings` +### `settings get` +### `settings ls` +### `settings set` +### `settings unset` +### `shell` +### `sync` +### `sync node` +### `sync python` +### `task` +### `task edit` +### `task ls` +### `task run` +### `trust` +### `uninstall` +### `unset` +### `upgrade` +### `usage` +### `use` +### `version` +### `watch` +### `where` +### `which` + diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..ed5c4ff --- /dev/null +++ b/src/context.rs @@ -0,0 +1,11 @@ +use std::path::PathBuf; +use std::sync::Mutex; + +static LOAD_ROOT: Mutex> = Mutex::new(None); + +pub fn get_load_root() -> PathBuf { + LOAD_ROOT.lock().unwrap().clone().unwrap_or_default() +} +pub fn set_load_root(root: PathBuf) { + *LOAD_ROOT.lock().unwrap() = Some(root); +} diff --git a/src/lib.rs b/src/lib.rs index e2e9cb3..a23237c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,17 @@ #[macro_use] extern crate log; +#[macro_use] +extern crate miette; #[cfg(test)] #[macro_use] extern crate insta; pub mod complete; +pub mod context; pub(crate) mod env; pub mod error; pub mod parse; -pub use parse::arg::Arg; -pub use parse::cmd::SchemaCmd; -pub use parse::flag::Flag; -pub use parse::spec::Spec; +pub use crate::parse::arg::Arg; +pub use crate::parse::cmd::SchemaCmd; +pub use crate::parse::flag::Flag; +pub use crate::parse::spec::Spec; diff --git a/src/parse/spec.rs b/src/parse/spec.rs index f898af5..8e6be11 100644 --- a/src/parse/spec.rs +++ b/src/parse/spec.rs @@ -1,10 +1,11 @@ +use crate::context::get_load_root; use crate::error::UsageErr; use crate::parse::cmd::SchemaCmd; use kdl::{KdlDocument, KdlEntry, KdlNode}; use std::fmt::{Display, Formatter}; -use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str::FromStr; +use xx::file; #[derive(Debug, Default)] pub struct Spec { @@ -14,7 +15,7 @@ pub struct Spec { } impl Spec { - pub fn parse_file(file: &Path) -> Result<(Spec, String), UsageErr> { + pub fn parse_file(file: &Path) -> miette::Result<(Spec, String)> { let (spec, body) = split_script(file)?; let mut schema = Self::from_str(&spec)?; if schema.bin.is_empty() { @@ -45,8 +46,8 @@ impl Spec { } } -fn split_script(file: &Path) -> Result<(String, String), UsageErr> { - let full = fs::read_to_string(file)?; +fn split_script(file: &Path) -> miette::Result<(String, String)> { + let full = file::read_to_string(file)?; let schema = full.strip_prefix("#!/usr/bin/env usage\n").unwrap_or(&full); let (schema, body) = schema.split_once("\n#!").unwrap_or((&schema, "")); let schema = schema.trim().to_string(); @@ -54,9 +55,15 @@ fn split_script(file: &Path) -> Result<(String, String), UsageErr> { Ok((schema, body)) } +fn get_string_prop(node: &KdlNode, name: &str) -> Option { + node.get(name) + .and_then(|entry| entry.value().as_string()) + .map(|s| s.to_string()) +} + impl FromStr for Spec { - type Err = UsageErr; - fn from_str(input: &str) -> Result { + type Err = miette::Error; + fn from_str(input: &str) -> miette::Result { let kdl: KdlDocument = input .parse() .map_err(|err: kdl::KdlError| UsageErr::KdlError(err))?; @@ -74,11 +81,18 @@ impl FromStr for Spec { schema.cmd.subcommands.insert(node.name.to_string(), node); } "include" => { - let file = node.get("file").unwrap().value().as_string().unwrap(); - info!("include: {}", file); - let (spec, _) = split_script(Path::new(file))?; - let include = Self::from_str(&spec)?; - schema.merge(include); + let file = match get_string_prop(node, "file").map(PathBuf::from) { + Some(file) if file.is_relative() => get_load_root().join(file), + Some(file) => file.to_path_buf(), + None => Err(UsageErr::InvalidInput( + node.to_string(), + *node.span(), + input.to_string(), + ))?, + }; + info!("include: {}", file.display()); + let (spec, _) = split_script(&file)?; + schema.merge(spec.parse()?); } _ => Err(UsageErr::InvalidInput( node.to_string(),