diff options
42 files changed, 1451 insertions, 135 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0cec42b..4dc56c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,6 +94,9 @@ jobs: - name: Run cov-test run: cargo run --manifest-path .run/Cargo.toml --bin cov-test + - name: Package mling templates + run: cargo run --manifest-path .run/Cargo.toml --bin package-mling-tmpls + - name: Delete .temp directory before deployment run: rm -rf .temp @@ -9,6 +9,9 @@ docs/api-docs/ # Temp file for .run/src/bin/cov-test.rs docs/cov-test/ +# Mling Template Exports +/templates/ + # Drafts __*.md __*/ diff --git a/.run/Cargo.lock b/.run/Cargo.lock index 3117d0b..70021b9 100644 --- a/.run/Cargo.lock +++ b/.run/Cargo.lock @@ -9,6 +9,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] name = "arg-picker" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -26,7 +46,7 @@ checksum = "04fddbb5c1f26450cfc6aded0559b759b292d400dba1ff4e45128f3e0e1ffe6b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -36,18 +56,74 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" [[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] name = "bumpalo" version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bzip2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" +dependencies = [ + "bzip2-sys", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] name = "colored" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -69,6 +145,36 @@ dependencies = [ ] [[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] name = "crc32fast" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -78,6 +184,67 @@ dependencies = [ ] [[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deflate64" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6b926516df9c60bfa16e107b21086399f8285a44ca9711344b9e553c5146e2" + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] name = "encode_unicode" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -110,6 +277,12 @@ dependencies = [ ] [[package]] +name = "find-msvc-tools" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" + +[[package]] name = "flate2" version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -144,12 +317,56 @@ dependencies = [ ] [[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[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 6.0.0", +] + +[[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] name = "indexmap" version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -173,12 +390,31 @@ dependencies = [ ] [[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] name = "js-sys" version = "0.3.102" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -223,6 +459,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "lzma-rs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" +dependencies = [ + "byteorder", + "crc", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] name = "memchr" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -239,24 +502,52 @@ dependencies = [ ] [[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] name = "pin-project-lite" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] name = "portable-atomic" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] name = "proc-macro2" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -275,6 +566,18 @@ dependencies = [ ] [[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] name = "rustix" version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -320,7 +623,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -346,6 +649,34 @@ dependencies = [ ] [[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[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.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -358,6 +689,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] name = "syn" version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -369,6 +706,17 @@ dependencies = [ ] [[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] name = "tar" version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -380,6 +728,45 @@ dependencies = [ ] [[package]] +name = "thiserror" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] name = "tokio" version = "1.52.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -397,7 +784,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.119", ] [[package]] @@ -453,12 +840,20 @@ dependencies = [ "just_template", "serde", "serde_json", + "sha2", "tar", "tokio", "toml", + "zip", ] [[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -477,6 +872,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" [[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] name = "wasm-bindgen" version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -508,7 +918,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn", + "syn 2.0.119", "wasm-bindgen-shared", ] @@ -556,6 +966,12 @@ dependencies = [ ] [[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] name = "xattr" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -566,7 +982,106 @@ dependencies = [ ] [[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zip" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +dependencies = [ + "aes", + "arbitrary", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "deflate64", + "displaydoc", + "flate2", + "getrandom 0.3.4", + "hmac", + "indexmap", + "lzma-rs", + "memchr", + "pbkdf2", + "sha1", + "thiserror", + "time", + "xz2", + "zeroize", + "zopfli", + "zstd", +] + +[[package]] name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/.run/Cargo.toml b/.run/Cargo.toml index 4935f2d..9f5e0a4 100644 --- a/.run/Cargo.toml +++ b/.run/Cargo.toml @@ -21,6 +21,8 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros"] } indicatif = "0.18.4" flate2 = "1" tar = "0.4" +sha2 = "0.10" +zip = "2" arg-picker = "0.1.0" [workspace] diff --git a/.run/src/bin/install-mling.ps1 b/.run/src/bin/install-mling.ps1 index bc3bdc3..2bc28ee 100644 --- a/.run/src/bin/install-mling.ps1 +++ b/.run/src/bin/install-mling.ps1 @@ -5,5 +5,6 @@ cargo build --release --manifest-path mingling_cli/Cargo.toml New-Item -ItemType Directory -Force -Path .temp/mling/bin, .temp/mling/scripts | Out-Null Copy-Item .temp/target/release/mling.exe .temp/mling/bin/ +Copy-Item .temp/target/release/mingling-cli.exe .temp/mling/bin/ Copy-Item .temp/target/release/mling_comp.ps1 .temp/mling/scripts/mling_comp.ps1 Copy-Item mingling_cli/scripts/load_mling.ps1 .temp/mling/ diff --git a/.run/src/bin/install-mling.sh b/.run/src/bin/install-mling.sh index f80bc2e..139e221 100755 --- a/.run/src/bin/install-mling.sh +++ b/.run/src/bin/install-mling.sh @@ -7,6 +7,7 @@ cargo build --release --manifest-path mingling_cli/Cargo.toml mkdir -p .temp/mling/bin .temp/mling/scripts cp .temp/target/release/mling .temp/mling/bin/ +cp .temp/target/release/mingling-cli .temp/mling/bin/ for comp in zsh sh fish; do cp ".temp/target/release/mling_comp.$comp" ".temp/mling/scripts/mling_comp.$comp" diff --git a/.run/src/bin/package-mling-tmpls.rs b/.run/src/bin/package-mling-tmpls.rs new file mode 100644 index 0000000..84bcc16 --- /dev/null +++ b/.run/src/bin/package-mling-tmpls.rs @@ -0,0 +1,177 @@ +//! Package the versioned mingling project templates under +//! `mingling_cli/tmpls/mingling_tmpl/` into per-version ZIP archives +//! (e.g. `mingling-tmpl-0.4.zip`) plus SHA-256 checksum files +//! (e.g. `mingling_tmpl-0.4.sha256`), written into `templates/`. + +use std::fs::File; +use std::io::Read; +use std::path::{Path, PathBuf}; + +use sha2::{Digest, Sha256}; +use tools::{dependency_order::find_workspace_root, eprintln_cargo_style, println_cargo_style}; +use zip::write::SimpleFileOptions; +use zip::CompressionMethod; + +fn main() { + // 1. Determine the workspace root + let cwd = std::env::current_dir().expect("failed to get current working directory"); + let workspace_root = find_workspace_root(&cwd).expect("not inside a Cargo workspace"); + println_cargo_style!("Workspace: {}", workspace_root.display()); + + // 2. Locate the versioned template directories + let tmpls_root = workspace_root.join("mingling_cli/tmpls/mingling_tmpl"); + if !tmpls_root.is_dir() { + eprintln_cargo_style!(format!( + "template root not found: {}", + tmpls_root.display() + )); + std::process::exit(1); + } + + let mut versions: Vec<String> = Vec::new(); + for entry in std::fs::read_dir(&tmpls_root).expect("failed to read template root") { + let entry = entry.expect("failed to read template root entry"); + let name = entry.file_name().to_string_lossy().to_string(); + if entry.path().is_dir() && is_version(&name) { + versions.push(name); + } + } + + if versions.is_empty() { + eprintln_cargo_style!("no versioned template directories found"); + std::process::exit(1); + } + + versions.sort_by(|a, b| cmp_versions(a, b)); + for v in &versions { + println_cargo_style!("Template: {} ({})", v, tmpls_root.join(v).display()); + } + + // 3. Prepare the output directory + let out_dir = workspace_root.join("templates"); + println_cargo_style!("Clean: templates/"); + let _ = std::fs::remove_dir_all(&out_dir); + std::fs::create_dir_all(&out_dir).expect("failed to create templates/"); + + // 4. Package each version: ZIP + SHA-256 + let mut failed = false; + for version in &versions { + let src_dir = tmpls_root.join(version); + let zip_name = format!("mingling-tmpl-{version}.zip"); + let sha_name = format!("mingling_tmpl-{version}.sha256"); + let zip_path = out_dir.join(&zip_name); + let sha_path = out_dir.join(&sha_name); + + println_cargo_style!("Package: {}", zip_name); + if let Err(e) = package_template(&src_dir, &zip_path) { + eprintln_cargo_style!(format!("failed to package {}: {e}", zip_name)); + failed = true; + continue; + } + + let digest = sha256_of_file(&zip_path).unwrap_or_else(|e| { + eprintln_cargo_style!(format!("failed to hash {}: {e}", zip_path.display())); + std::process::exit(1); + }); + + // sha256sum-compatible line: "<hex> <zip file name>" + let checksum_line = format!("{digest} {zip_name}\n"); + std::fs::write(&sha_path, checksum_line) + .unwrap_or_else(|e| panic!("failed to write {}: {e}", sha_path.display())); + println_cargo_style!("Checksum: {} {}", digest, sha_name); + } + + if failed { + eprintln_cargo_style!("one or more templates failed to package"); + std::process::exit(1); + } + + println_cargo_style!("Done: templates/ is ready"); +} + +/// Version directory names look like `0.4`, `0.3`, `1.2.3`, ... +fn is_version(name: &str) -> bool { + !name.is_empty() + && name + .split('.') + .all(|part| !part.is_empty() && part.chars().all(|c| c.is_ascii_digit())) +} + +/// Compare two version strings numerically, component by component. +fn cmp_versions(a: &str, b: &str) -> std::cmp::Ordering { + let a_parts: Vec<u64> = a.split('.').filter_map(|p| p.parse().ok()).collect(); + let b_parts: Vec<u64> = b.split('.').filter_map(|p| p.parse().ok()).collect(); + for (x, y) in a_parts.iter().zip(b_parts.iter()) { + match x.cmp(y) { + std::cmp::Ordering::Equal => continue, + ord => return ord, + } + } + a_parts.len().cmp(&b_parts.len()) +} + +/// Recursively ZIP the *contents* of `src_dir` (files at the archive root) +/// into `dest_zip`, preserving the relative directory structure. +fn package_template(src_dir: &Path, dest_zip: &Path) -> Result<(), zip::result::ZipError> { + let file = File::create(dest_zip).map_err(zip::result::ZipError::Io)?; + let mut writer = zip::ZipWriter::new(file); + let options = SimpleFileOptions::default().compression_method(CompressionMethod::Deflated); + + // Collect entries first so the archive is written in a deterministic order. + let mut entries: Vec<PathBuf> = Vec::new(); + collect_entries(src_dir, src_dir, &mut entries).map_err(zip::result::ZipError::Io)?; + entries.sort(); + + for rel_path in &entries { + let full_path = src_dir.join(rel_path); + // ZIP archives always use `/` as the path separator. + let name = rel_path.to_string_lossy().replace('\\', "/"); + if full_path.is_dir() { + writer.add_directory(name, options)?; + } else { + writer.start_file(name, options)?; + let mut file = File::open(&full_path).map_err(zip::result::ZipError::Io)?; + std::io::copy(&mut file, &mut writer).map_err(zip::result::ZipError::Io)?; + } + } + + writer.finish().map(|_| ()) +} + +/// Recursively collect all relative paths (files and directories) under `dir`. +fn collect_entries(root: &Path, dir: &Path, out: &mut Vec<PathBuf>) -> std::io::Result<()> { + let mut children: Vec<PathBuf> = std::fs::read_dir(dir)? + .map(|e| e.map(|e| e.path())) + .collect::<std::io::Result<Vec<_>>>()?; + children.sort(); + + for child in children { + let rel = child + .strip_prefix(root) + .expect("collected entry is inside root") + .to_path_buf(); + if child.is_dir() { + out.push(rel); + collect_entries(root, &child, out)?; + } else { + out.push(rel); + } + } + Ok(()) +} + +/// Compute the lowercase hex SHA-256 digest of a file. +fn sha256_of_file(path: &Path) -> std::io::Result<String> { + let mut file = File::open(path)?; + let mut hasher = Sha256::new(); + let mut buf = [0u8; 64 * 1024]; + loop { + let n = file.read(&mut buf)?; + if n == 0 { + break; + } + hasher.update(&buf[..n]); + } + let digest = hasher.finalize(); + Ok(digest.iter().map(|b| format!("{b:02x}")).collect()) +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 93b64a6..75b53f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,6 +106,15 @@ None Structs that are analyzed by other patterns (e.g., `GroupedDerivePattern`, `ChainPattern`, etc.) continue to work exactly as before — only the standalone "bare struct with no macro association" detection has been removed. +9. **[`comps:pwsh`]** Fixed and refactored the PowerShell completion script template in `mingling_core/tmpls/comps/pwsh.ps1`: + + - **Option value passing** — Changed from the compact `"-f", ($line -replace '-', '^')` array-literal style to conditionally appended `$args += "-f"` / `$args += ($line -replace '-', '^')` pairs for each of `-f`, `-w`, `-p`, and `-c`. This ensures empty values are not passed to the completion engine, preventing spurious argument parsing. + - **Word index fix** — `$wordIndex` is now `$i + 1` (when the current word is found in the element list) and `$elements.Count + 1` (when not found), correcting off-by-one indexing. Since the elements array starts at index 0, the actual 1-based word index that the completion engine expects is the array index plus one. + - **Empty element filtering** — The `-a` argument loop now skips empty elements (`if ($element)`) so blank entries in the element list are not passed as standalone `-a` arguments with empty values. + - **Non-flag optional arguments** — The `-C` (cursor position) and `-i` (word index) parameters remain unconditionally passed, while `-f`, `-w`, `-p`, `-c`, and `-a` are only emitted when their corresponding values are non-empty. + + These changes fix incorrect word-index computation and avoid sending empty option values to the underlying completion engine from PowerShell completions. + #### Optimizations: 1. **[`pathf`]** Added `is_module` field to `AnalyzeItem` and a new constructor `AnalyzeItem::local_module(module, item_name)` which sets `is_module: true`. The `type_mapping_builder` now tracks whether an item is a module: when generating `type_using.rs`, module items produce `use path::to::module::*;` (glob import) instead of the standard `use path::to::TypeName;` direct import. Non-module items continue to use direct imports as before. The internal data structure changed from `Vec<(String, String)>` to `Vec<(String, String, bool)>` to carry the `is_module` flag through the pipeline. @@ -270,7 +270,7 @@ dependencies = [ [[package]] name = "mingling" -version = "0.3.0" +version = "0.4.0" dependencies = [ "arg-picker", "mingling", @@ -283,11 +283,11 @@ dependencies = [ [[package]] name = "mingling-workspace" -version = "0.3.0" +version = "0.4.0" [[package]] name = "mingling_core" -version = "0.3.0" +version = "0.4.0" dependencies = [ "env_logger", "just_fmt 0.2.0", @@ -304,7 +304,7 @@ dependencies = [ [[package]] name = "mingling_macros" -version = "0.3.0" +version = "0.4.0" dependencies = [ "just_fmt 0.2.0", "proc-macro2", @@ -314,7 +314,7 @@ dependencies = [ [[package]] name = "mingling_pathf" -version = "0.3.0" +version = "0.4.0" dependencies = [ "just_fmt 0.2.0", "proc-macro2", @@ -12,9 +12,6 @@ members = [ # Picker2 "arg_picker", "arg_picker_macros", - - # Scaffolding tool - # "mling" (deprecated) ] exclude = [ @@ -64,7 +61,7 @@ log = "0.4.33" env_logger = "0.11.11" [workspace.package] -version = "0.3.0" +version = "0.4.0" edition = "2024" license = "MIT OR Apache-2.0" repository = "https://github.com/mingling-rs/mingling" @@ -27,7 +27,7 @@ 💡 Its name comes from the Chinese pinyin **"Mìng Lìng"**, which means **"command"**. -## WARNING +## ⚠WARNING Mingling is currently usable at a basic level, but it is still under active development, so many APIs are not yet mature. Any changes to the public API will be documented in detail in the [Changelog](https://github.com/mingling-rs/mingling/blob/main/CHANGELOG.md). @@ -99,7 +99,7 @@ Add Mingling to your `Cargo.toml`: ```toml [dependencies.mingling] -version = "0.3.0" +version = "0.4.0" features = [] ``` diff --git a/docs/_zh_CN/pages/1-getting-started.md b/docs/_zh_CN/pages/1-getting-started.md index 2fca931..6aa6229 100644 --- a/docs/_zh_CN/pages/1-getting-started.md +++ b/docs/_zh_CN/pages/1-getting-started.md @@ -13,7 +13,7 @@ cd my-cli ```toml [dependencies.mingling] -version = "0.3.0" +version = "0.4.0" features = [] ``` @@ -25,7 +25,7 @@ features = [] ```toml [dependencies.mingling] -version = "0.3.0" +version = "0.4.0" features = [ "parser", "comp", diff --git a/docs/pages/1-getting-started.md b/docs/pages/1-getting-started.md index 8c81100..443ed74 100644 --- a/docs/pages/1-getting-started.md +++ b/docs/pages/1-getting-started.md @@ -13,7 +13,7 @@ Add the following to `Cargo.toml`: ```toml [dependencies.mingling] -version = "0.3.0" +version = "0.4.0" features = [] ``` @@ -25,7 +25,7 @@ Some features **directly affect the entire lifecycle behavior**, so you need to ```toml [dependencies.mingling] -version = "0.3.0" +version = "0.4.0" features = [ "parser", "comp", diff --git a/docs/res/guide.txt b/docs/res/guide.txt index 657c7ca..74f9c69 100644 --- a/docs/res/guide.txt +++ b/docs/res/guide.txt @@ -5,5 +5,5 @@ │ > cargo add mingling │ │ │ │ Or add this to your Cargo.toml │ - │ > mingling = "0.3.0" │ + │ > mingling = "0.4.0" │ └────────────────────────────────────┘ diff --git a/mingling_cli/Cargo.lock b/mingling_cli/Cargo.lock index dff20e5..ddfe01c 100644 --- a/mingling_cli/Cargo.lock +++ b/mingling_cli/Cargo.lock @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "mingling" -version = "0.3.0" +version = "0.4.0" dependencies = [ "arg-picker", "mingling_core", @@ -331,7 +331,7 @@ dependencies = [ [[package]] name = "mingling-cli" -version = "0.3.0" +version = "0.4.0" dependencies = [ "annotate-snippets", "cargo_metadata", @@ -351,7 +351,7 @@ dependencies = [ [[package]] name = "mingling_core" -version = "0.3.0" +version = "0.4.0" dependencies = [ "just_fmt 0.2.0", "just_template", @@ -361,7 +361,7 @@ dependencies = [ [[package]] name = "mingling_macros" -version = "0.3.0" +version = "0.4.0" dependencies = [ "just_fmt 0.2.0", "proc-macro2", @@ -371,7 +371,7 @@ dependencies = [ [[package]] name = "mingling_pathf" -version = "0.3.0" +version = "0.4.0" dependencies = [ "just_fmt 0.2.0", "proc-macro2", diff --git a/mingling_cli/Cargo.toml b/mingling_cli/Cargo.toml index fec4fc1..2bb3fd3 100644 --- a/mingling_cli/Cargo.toml +++ b/mingling_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mingling-cli" -version = "0.3.0" +version = "0.4.0" edition = "2024" license = "MIT OR Apache-2.0" repository = "https://github.com/mingling-rs/mingling/tree/main/mingling_cli" diff --git a/mingling_cli/src/errors.rs b/mingling_cli/src/errors.rs index 5cdc43f..754dcc6 100644 --- a/mingling_cli/src/errors.rs +++ b/mingling_cli/src/errors.rs @@ -1,3 +1,2 @@ pub mod io_error; pub mod serde_json; - diff --git a/mingling_cli/src/linter/cmd_explain.rs b/mingling_cli/src/linter/cmd_explain.rs index d1758e1..5346255 100644 --- a/mingling_cli/src/linter/cmd_explain.rs +++ b/mingling_cli/src/linter/cmd_explain.rs @@ -1,6 +1,6 @@ -use crate::{Next, linter::registry::ResLintRegistry}; +use crate::{Next, eprintln_cargo, linter::registry::ResLintRegistry}; use mingling::{ - Grouped, LazyRes, Routable, ShellContext, Suggest, SuggestItem, + Grouped, LazyRes, RenderResult, Routable, ShellContext, Suggest, SuggestItem, macros::{ arg, buffer, chain, completion, dispatcher, metadata, pack, pack_err, r_println, renderer, routeify, @@ -71,22 +71,29 @@ pub fn render_explain_lint(r: ResultExplainLint) { r_println!("{}", r.summary); } -#[renderer(buffer)] -pub fn render_error_no_explain_lint_provided(_: ErrorNoExplainLintProvided) { - r_println!("No lint name provided"); - r_println!(""); - r_println!("Usage: mling explain <LINT>"); +#[renderer] +pub fn render_error_no_explain_lint_provided(_: ErrorNoExplainLintProvided) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "No lint name provided"); + r_println!(r, ""); + r_println!(r, "Usage: mling explain <LINT>"); + r } -#[renderer(buffer)] -pub fn render_error_no_such_lint(err: ErrorNoSuchLint, registry: &mut LazyRes<ResLintRegistry>) { +#[renderer] +pub fn render_error_no_such_lint( + err: ErrorNoSuchLint, + registry: &mut LazyRes<ResLintRegistry>, +) -> RenderResult { + let mut r = RenderResult::new(); let registry = registry.get_ref(); - r_println!("No such lint: \"{}\"", err.info); - r_println!(""); - r_println!("Available lints:"); + eprintln_cargo!(r, "No such lint: \"{}\"", err.info); + r_println!(r, ""); + r_println!(r, "Available lints:"); for entry in registry.lints.iter() { - r_println!(" {}", entry.name); + r_println!(r, " {}", entry.name); } + r } #[completion(EntryExplain)] diff --git a/mingling_cli/src/pkg_mgr.rs b/mingling_cli/src/pkg_mgr.rs index f244fa7..080c50f 100644 --- a/mingling_cli/src/pkg_mgr.rs +++ b/mingling_cli/src/pkg_mgr.rs @@ -8,11 +8,11 @@ pub mod cmd_uninstall; use std::path::PathBuf; use mingling::{ - Program, - macros::{buffer, pack_err, program_setup, r_println, renderer}, + Program, RenderResult, + macros::{pack_err, program_setup, r_println, renderer}, }; -use crate::ThisProgram; +use crate::{ThisProgram, eprintln_cargo, hprintln_cargo}; pack_err!(ErrorRootPackageNotFound); pack_err!(ErrorNoDataDirectory); @@ -33,24 +33,35 @@ pub fn package_manager_setup(program: &mut Program<ThisProgram>) { program.with_resource(ResPackagesDir { path }); } -#[renderer(buffer)] -pub fn render_error_root_package_not_found(_: ErrorRootPackageNotFound) { - r_println!("error: failed to determine the root package"); - r_println!(""); - r_println!("Run `mling install` / `mling uninstall` inside a Cargo workspace"); +#[renderer] +pub fn render_error_root_package_not_found(_: ErrorRootPackageNotFound) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "failed to determine the root package"); + r_println!(r, ""); + hprintln_cargo!( + r, + "Run `mling install` / `mling uninstall` inside a Cargo workspace" + ); + r } -#[renderer(buffer)] -pub fn render_error_no_data_directory(_: ErrorNoDataDirectory) { - r_println!("error: failed to determine the data directory"); +#[renderer] +pub fn render_error_no_data_directory(_: ErrorNoDataDirectory) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "failed to determine the data directory"); + r } -#[renderer(buffer)] -pub fn render_error_package_spec_invalid(err: ErrorPackageSpecInvalid) { - r_println!("error: invalid package spec: {}", err.info); +#[renderer] +pub fn render_error_package_spec_invalid(err: ErrorPackageSpecInvalid) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "invalid package spec: {}", err.info); + r } -#[renderer(buffer)] -pub fn render_error_package_name_required(_: ErrorPackageNameRequired) { - r_println!("error: a package name is required"); +#[renderer] +pub fn render_error_package_name_required(_: ErrorPackageNameRequired) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "a package name is required"); + r } diff --git a/mingling_cli/src/pkg_mgr/cmd_install.rs b/mingling_cli/src/pkg_mgr/cmd_install.rs index a399e83..2b4082a 100644 --- a/mingling_cli/src/pkg_mgr/cmd_install.rs +++ b/mingling_cli/src/pkg_mgr/cmd_install.rs @@ -2,15 +2,16 @@ use std::{env, fs, io, path::PathBuf, process::Command}; use cargo_metadata::TargetKind; use mingling::{ - Grouped, LazyRes, Routable, - macros::{buffer, chain, command, metadata, pack_err, r_println, renderer, routeify}, + Grouped, LazyRes, RenderResult, Routable, + macros::{chain, command, metadata, pack_err, renderer, routeify}, metadata::Description, }; use crate::{ - Next, + Next, eprintln_cargo, metadata::setup::ResMetadata, pkg_mgr::{ErrorNoDataDirectory, ErrorRootPackageNotFound, ResPackagesDir}, + println_cargo, }; pack_err!(ErrorBuildFailed = String); @@ -159,20 +160,26 @@ pub fn handle_state_install_copy( .to_chain() } -#[renderer(buffer)] -pub fn render_result_install(r: ResultInstall) { - r_println!("Installed to {}", r.install_dir.display()); - for file in r.installed { - r_println!(" {}", file.display()); +#[renderer] +pub fn render_result_install(result: ResultInstall) -> RenderResult { + let mut r = RenderResult::new(); + println_cargo!(r, "Installed: {}", result.install_dir.display()); + for file in result.installed { + println_cargo!(r, "Copy: {}", file.display()); } + r } -#[renderer(buffer)] -pub fn render_error_build_failed(err: ErrorBuildFailed) { - r_println!("error: {}", err.info); +#[renderer] +pub fn render_error_build_failed(err: ErrorBuildFailed) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "{}", err.info); + r } -#[renderer(buffer)] -pub fn render_error_binary_not_found(err: ErrorBinaryNotFound) { - r_println!("error: binary not found: {}", err.info); +#[renderer] +pub fn render_error_binary_not_found(err: ErrorBinaryNotFound) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "binary not found: {}", err.info); + r } diff --git a/mingling_cli/src/pkg_mgr/cmd_pkg_disable.rs b/mingling_cli/src/pkg_mgr/cmd_pkg_disable.rs index 679421c..041bb09 100644 --- a/mingling_cli/src/pkg_mgr/cmd_pkg_disable.rs +++ b/mingling_cli/src/pkg_mgr/cmd_pkg_disable.rs @@ -1,20 +1,18 @@ use std::{fs, io}; use mingling::{ - Grouped, Routable, ShellContext, Suggest, SuggestItem, - macros::{ - arg, buffer, chain, command, completion, metadata, pack, pack_err, r_println, renderer, - routeify, - }, + Grouped, RenderResult, Routable, ShellContext, Suggest, SuggestItem, + macros::{arg, chain, command, completion, metadata, pack, pack_err, renderer, routeify}, metadata::Description, picker::{EntryPicker, PickerArg}, }; use crate::{ - Next, + Next, eprintln_cargo, pkg_mgr::{ ErrorNoDataDirectory, ErrorPackageNameRequired, ErrorPackageSpecInvalid, ResPackagesDir, }, + println_cargo, }; /// Positional argument: package name @@ -78,14 +76,18 @@ pub fn handle_state_pkg_disable(p: StatePkgDisable, packages_dir: &ResPackagesDi .to_chain() } -#[renderer(buffer)] -pub fn render_result_pkg_disable(r: ResultPkgDisable) { - r_println!("Disabled {}", r.name); +#[renderer] +pub fn render_result_pkg_disable(result: ResultPkgDisable) -> RenderResult { + let mut r = RenderResult::new(); + println_cargo!(r, "Disabled: {}", result.name); + r } -#[renderer(buffer)] -pub fn render_error_package_not_enabled(err: ErrorPackageNotEnabled) { - r_println!("error: package is not enabled: {}", err.info); +#[renderer] +pub fn render_error_package_not_enabled(err: ErrorPackageNotEnabled) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "package is not enabled: {}", err.info); + r } #[completion(EntryPkgDisable)] diff --git a/mingling_cli/src/pkg_mgr/cmd_pkg_enable.rs b/mingling_cli/src/pkg_mgr/cmd_pkg_enable.rs index b545a4d..8f6a234 100644 --- a/mingling_cli/src/pkg_mgr/cmd_pkg_enable.rs +++ b/mingling_cli/src/pkg_mgr/cmd_pkg_enable.rs @@ -1,20 +1,18 @@ use std::{fs, io}; use mingling::{ - Grouped, Routable, ShellContext, Suggest, SuggestItem, - macros::{ - arg, buffer, chain, command, completion, metadata, pack, pack_err, r_println, renderer, - routeify, - }, + Grouped, RenderResult, Routable, ShellContext, Suggest, SuggestItem, + macros::{arg, chain, command, completion, metadata, pack, pack_err, renderer, routeify}, metadata::Description, picker::{EntryPicker, PickerArg}, }; use crate::{ - Next, + Next, eprintln_cargo, pkg_mgr::{ ErrorNoDataDirectory, ErrorPackageNameRequired, ErrorPackageSpecInvalid, ResPackagesDir, }, + println_cargo, }; /// Positional argument: package spec (`foo`, `foo@0`, `foo@0.1`, `foo@0.1.2`) @@ -102,9 +100,18 @@ pub fn handle_state_pkg_enable(p: StatePkgEnable, packages_dir: &ResPackagesDir) ResultPkgEnable { name, version }.to_chain() } -#[renderer(buffer)] -pub fn render_result_pkg_enable(r: ResultPkgEnable) { - r_println!("Enabled {}@{}", r.name, r.version); +#[renderer] +pub fn render_result_pkg_enable(result: ResultPkgEnable) -> RenderResult { + let mut r = RenderResult::new(); + println_cargo!(r, "Enabled: {}@{}", result.name, result.version); + r +} + +#[renderer] +pub fn render_error_no_matching_version(err: ErrorNoMatchingVersion) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "no matching version for: {}", err.info); + r } #[completion(EntryPkgEnable)] diff --git a/mingling_cli/src/pkg_mgr/cmd_pkg_show.rs b/mingling_cli/src/pkg_mgr/cmd_pkg_show.rs index 68aef2b..88c79ef 100644 --- a/mingling_cli/src/pkg_mgr/cmd_pkg_show.rs +++ b/mingling_cli/src/pkg_mgr/cmd_pkg_show.rs @@ -2,13 +2,13 @@ use std::{collections::BTreeMap, fs, io}; use colored::Colorize; use mingling::{ - Grouped, Routable, - macros::{buffer, command, metadata, r_println, renderer, routeify}, + Grouped, RenderResult, Routable, + macros::{buffer, command, metadata, pack_err, r_println, renderer, routeify}, metadata::Description, }; use crate::{ - Next, + Next, eprintln_cargo, pkg_mgr::{ErrorNoDataDirectory, ResPackagesDir}, }; @@ -31,6 +31,8 @@ pub fn desc_pkg_show() -> Description { "Show locally installed packages".into() } +pack_err!(ErrorNoPackagesInstalled); + #[command(node = "pkg-show", routeify)] pub fn package_show(packages_dir: &ResPackagesDir) -> Next { let packages_dir = &packages_dir.path; @@ -79,17 +81,17 @@ pub fn package_show(packages_dir: &ResPackagesDir) -> Next { pkg.versions.sort_by(|a, b| compare_versions(b, a)); } - ResultPkgShow { - packages: entries.into_values().collect(), + let packages: Vec<PkgShowEntry> = entries.into_values().collect(); + + if packages.is_empty() { + return ErrorNoPackagesInstalled::default().into(); } - .to_chain() + + ResultPkgShow { packages }.to_chain() } #[renderer(buffer)] pub fn render_result_pkg_show(r: ResultPkgShow) { - if r.packages.is_empty() { - r_println!("No packages installed"); - } for pkg in r.packages { if let Some(enabled) = &pkg.enabled { r_println!("{}", format!("{} ({})", pkg.name, enabled).bright_cyan()); @@ -102,6 +104,13 @@ pub fn render_result_pkg_show(r: ResultPkgShow) { } } +#[renderer] +pub fn render_error_no_packages_installed(_: ErrorNoPackagesInstalled) -> RenderResult { + let mut r = RenderResult::new(); + eprintln_cargo!(r, "No packages installed"); + r +} + /// Newest first; unparsable versions sort last, compared lexicographically. fn compare_versions(a: &str, b: &str) -> std::cmp::Ordering { match (semver::Version::parse(a), semver::Version::parse(b)) { diff --git a/mingling_cli/src/pkg_mgr/cmd_uninstall.rs b/mingling_cli/src/pkg_mgr/cmd_uninstall.rs index 69c5aa5..988437c 100644 --- a/mingling_cli/src/pkg_mgr/cmd_uninstall.rs +++ b/mingling_cli/src/pkg_mgr/cmd_uninstall.rs @@ -1,32 +1,35 @@ use std::{fs, io, path::PathBuf}; use mingling::{ - Grouped, LazyRes, Routable, ShellContext, Suggest, SuggestItem, - macros::{ - arg, buffer, chain, command, completion, metadata, pack, r_println, renderer, routeify, - }, + LazyRes, RenderResult, Routable, ShellContext, Suggest, SuggestItem, + macros::{arg, chain, command, completion, metadata, pack, pack_err, renderer, routeify}, metadata::Description, picker::{EntryPicker, PickerArg}, }; use crate::{ - Next, + Next, eprintln_cargo, metadata::setup::ResMetadata, pkg_mgr::{ ErrorNoDataDirectory, ErrorPackageSpecInvalid, ErrorRootPackageNotFound, ResPackagesDir, }, + println_cargo, }; /// Optional positional argument: package spec (`name` or `name@version`) pub static ARG_PACKAGE: PickerArg<Option<String>> = arg![Option<String>]; +// Directory names to remove, e.g. `["omg@0.1.0", "omg@0.1.1"]` pack!(StateUninstallPackages = Vec<String>); -#[derive(Debug, Default, Grouped)] -pub struct ResultUninstall { - pub removed: Vec<PathBuf>, - pub not_installed: Vec<PathBuf>, -} +// Directories that were successfully removed. +pack!(ResultPackageUninstalled = Vec<PathBuf>); + +// Directories that were not installed. +pack_err!(ErrorPackageNotInstall = Vec<PathBuf>); + +// No installed package matched the given spec. +pack_err!(ErrorNoMatchingPackages); /// `{data_dir}/.mingling` #[metadata(EntryUninstall)] @@ -96,6 +99,7 @@ pub fn handle_state_uninstall_packages( if packages_dir.as_os_str().is_empty() { return ErrorNoDataDirectory::default().to_chain(); } + let mut removed = Vec::new(); let mut not_installed = Vec::new(); @@ -111,25 +115,38 @@ pub fn handle_state_uninstall_packages( removed.push(dir); } - ResultUninstall { - removed, - not_installed, + if removed.is_empty() && not_installed.is_empty() { + return ErrorNoMatchingPackages::default().to_chain(); + } + if !removed.is_empty() { + return ResultPackageUninstalled::new(removed).to_chain(); } - .to_chain() + ErrorPackageNotInstall::new(not_installed).to_chain() } -#[renderer(buffer)] -pub fn render_result_uninstall(r: ResultUninstall) { - if r.removed.is_empty() && r.not_installed.is_empty() { - r_println!("No matching packages installed"); - } else { - for dir in r.removed { - r_println!("Uninstalled: {}", dir.display()); - } - for dir in r.not_installed { - r_println!("Not installed: {}", dir.display()); - } +#[renderer] +pub fn render_result_package_uninstalled(r: ResultPackageUninstalled) -> RenderResult { + let mut result = RenderResult::new(); + for dir in r.inner { + println_cargo!(result, "Uninstalled: {}", dir.display()); + } + result +} + +#[renderer] +pub fn render_error_package_not_install(err: ErrorPackageNotInstall) -> RenderResult { + let mut result = RenderResult::new(); + for dir in err.info { + eprintln_cargo!(result, "not installed: {}", dir.display()); } + result +} + +#[renderer] +pub fn render_error_no_matching_packages(_: ErrorNoMatchingPackages) -> RenderResult { + let mut result = RenderResult::new(); + eprintln_cargo!(result, "no matching packages installed"); + result } #[completion(EntryUninstall)] diff --git a/mingling_cli/src/proj_mgr.rs b/mingling_cli/src/proj_mgr.rs index e69de29..8b13789 100644 --- a/mingling_cli/src/proj_mgr.rs +++ b/mingling_cli/src/proj_mgr.rs @@ -0,0 +1 @@ + diff --git a/mingling_cli/src/utils.rs b/mingling_cli/src/utils.rs index 8754563..6acf1c6 100644 --- a/mingling_cli/src/utils.rs +++ b/mingling_cli/src/utils.rs @@ -1 +1,2 @@ +pub mod cargo_style; pub mod display; diff --git a/mingling_cli/src/utils/cargo_style.rs b/mingling_cli/src/utils/cargo_style.rs new file mode 100644 index 0000000..8c19c07 --- /dev/null +++ b/mingling_cli/src/utils/cargo_style.rs @@ -0,0 +1,218 @@ +use colored::Colorize; + +/// Formats a message in cargo-style format with a bold green prefix. +/// +/// The message should be in the format `prefix: content`. The prefix will be +/// bold green and right-padded to 12 characters. If there is no colon in the +/// string, the entire string is printed as content with an empty prefix. +/// +/// # Macros +/// +/// - `format_cargo!("prefix: {}", arg)` — format-style invocation +/// - `format_cargo!(expr)` — direct expression invocation +/// +/// # Panics +/// +/// Panics if the prefix (text before the first `:`) exceeds 12 characters. +/// +/// # Examples +/// +/// ```ignore +/// format_cargo!("Compiling: hello.rs"); +/// // Output: " Compiling hello.rs" (green bold "Compiling" padded to 12) +/// ``` +#[macro_export] +macro_rules! format_cargo { + ($fmt:literal, $($arg:tt)*) => { + $crate::utils::cargo_style::get_cargo_info_format(format!($fmt, $($arg)*)) + }; + ($cmd:expr) => { + $crate::utils::cargo_style::get_cargo_info_format($cmd) + }; +} + +/// Formats an error message in cargo-style format with a bold red "error" prefix. +/// +/// # Macros +/// +/// - `eformat_cargo!("prefix: {}", arg)` — format-style invocation +/// - `eformat_cargo!(expr)` — direct expression invocation +/// +/// # Examples +/// +/// ```ignore +/// eformat_cargo!("failed to parse input"); +/// // Output: "error: failed to parse input" (red bold "error") +/// ``` +#[macro_export] +macro_rules! eformat_cargo { + ($fmt:literal, $($arg:tt)*) => { + $crate::utils::cargo_style::get_cargo_error_format(format!($fmt, $($arg)*)) + }; + ($cmd:expr) => { + $crate::utils::cargo_style::get_cargo_error_format($cmd) + }; +} + +/// Formats a help message in cargo-style format with a bright white "help" prefix. +/// +/// # Macros +/// +/// - `hformat_cargo!("prefix: {}", arg)` — format-style invocation +/// - `hformat_cargo!(expr)` — direct expression invocation +/// +/// # Examples +/// +/// ```ignore +/// hformat_cargo!("use --verbose for more info"); +/// // Output: "help: use --verbose for more info" (bright white "help") +/// ``` +#[macro_export] +macro_rules! hformat_cargo { + ($fmt:literal, $($arg:tt)*) => { + $crate::utils::cargo_style::get_cargo_help_format(format!($fmt, $($arg)*)) + }; + ($cmd:expr) => { + $crate::utils::cargo_style::get_cargo_help_format($cmd) + }; +} + +/// Print a message in cargo-style format into a `RenderResult` buffer. +/// +/// The first argument must be the renderer's buffer variable (e.g. +/// `__render_result_buffer` inside a `#[renderer(buffer)]` function). +/// +/// # Examples +/// +/// ```ignore +/// #[renderer(buffer)] +/// fn render_ok(_: ResOk) { +/// println_cargo!(__render_result_buffer, "Compiling: {}", name); +/// } +/// ``` +#[macro_export] +macro_rules! println_cargo { + ($buf:ident, $fmt:literal, $($arg:tt)*) => { + ::mingling::macros::r_println!($buf, "{}", $crate::utils::cargo_style::get_cargo_info_format(format!($fmt, $($arg)*))) + }; + ($buf:ident, $cmd:expr) => { + ::mingling::macros::r_println!($buf, "{}", $crate::utils::cargo_style::get_cargo_info_format($cmd)) + }; +} + +/// Print an error message in cargo-style format into a `RenderResult` buffer. +/// +/// # Examples +/// +/// ```ignore +/// #[renderer(buffer)] +/// fn render_err(_: ResErr) { +/// eprintln_cargo!(__render_result_buffer, "failed to parse input"); +/// } +/// ``` +#[macro_export] +macro_rules! eprintln_cargo { + ($buf:ident, $fmt:literal, $($arg:tt)*) => { + ::mingling::macros::r_println!($buf, "{}", $crate::utils::cargo_style::get_cargo_error_format(format!($fmt, $($arg)*))) + }; + ($buf:ident, $cmd:expr) => { + ::mingling::macros::r_println!($buf, "{}", $crate::utils::cargo_style::get_cargo_error_format($cmd)) + }; +} + +/// Print a help message in cargo-style format into a `RenderResult` buffer. +/// +/// # Examples +/// +/// ```ignore +/// #[renderer(buffer)] +/// fn render_help(_: ResHelp) { +/// hprintln_cargo!(__render_result_buffer, "use --verbose for more info"); +/// } +/// ``` +#[macro_export] +macro_rules! hprintln_cargo { + ($buf:ident, $fmt:literal, $($arg:tt)*) => { + ::mingling::macros::r_println!($buf, "{}", $crate::utils::cargo_style::get_cargo_help_format(format!($fmt, $($arg)*))) + }; + ($buf:ident, $cmd:expr) => { + ::mingling::macros::r_println!($buf, "{}", $crate::utils::cargo_style::get_cargo_help_format($cmd)) + }; +} + +/// Format a message in cargo style format, with bold green prefix. +/// +/// The input string is split at the first `:`. The part before the colon becomes +/// the prefix (bold green, right-padded to 12 characters), and the part after +/// becomes the content. +/// +/// If no colon is found, the entire string is treated as content and no prefix +/// is shown. +/// +/// # Panics +/// +/// Panics if the prefix (text before the first `:`) exceeds 12 characters. +/// +/// # Examples +/// +/// ```ignore +/// get_cargo_info_format("Compiling: my_program.rs"); +/// // returns " Compiling my_program.rs" +/// ``` +pub fn get_cargo_info_format(str: impl Into<String>) -> String { + let s = str.into(); + let (prefix, content) = if let Some(pos) = s.find(':') { + ( + s[..pos].trim().to_string(), + s[pos + 1..].trim_start().to_string(), + ) + } else { + (String::new(), s.trim().to_string()) + }; + + assert!( + prefix.len() <= 12, + "prefix length exceeds 12: '{}' has length {}", + prefix, + prefix.len() + ); + + let padding = " ".repeat(12 - prefix.len()); + + format!( + "{}{} {}", + padding, + prefix.bold().bright_green(), + content.trim() + ) +} + +/// Format an error message in cargo style format, with bold red "error" prefix. +/// +/// The input string is printed as the error content, prefixed by a bold red +/// `error:` label. +/// +/// # Examples +/// +/// ```ignore +/// get_cargo_error_format("something went wrong"); +/// // returns "error: something went wrong" +/// ``` +pub fn get_cargo_error_format(str: impl Into<String>) -> String { + format!("{}: {}", "error".bold().bright_red(), str.into()) +} + +/// Format a help message in cargo style format, with bright white "help" prefix. +/// +/// The input string is printed as the help content, prefixed by a bright white +/// `help:` label (not bold). +/// +/// # Examples +/// +/// ```ignore +/// get_cargo_help_format("use --verbose for more info"); +/// // returns "help: use --verbose for more info" +/// ``` +pub fn get_cargo_help_format(str: impl Into<String>) -> String { + format!("{}: {}", "help".bright_white(), str.into()) +} diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/checklist.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/checklist.toml new file mode 100644 index 0000000..0a5d4a2 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/checklist.toml @@ -0,0 +1,63 @@ +# --------------------------------------------------------------------------- # +# +# Mingling 0.4 Template +# +# > Welcome to Mingling. +# > Before starting your project, please fill out this `checklist` file, +# > as it will determine the structure of your project. +# +# --------------------------------------------------------------------------- # + +### 1. Please enter your program name: + +program_name = "my-cli" + +### 2. Please select the parser used in the project, + +# Clap Derive, the most mainstream option. +# When enabled, +# Mingling will use the struct implementing clap::Parser as the Entry Type +# ------------------ +# parser = "clap" +# ------------------ + +# Builtin, Mingling's built-in argument parser, lightweight, order-sensitive, suitable for simple parsing +# ------------------ +# parser = "builtin" +# ------------------ + +# Picker, based on `arg-picker`, a lightweight and type-safe argument parser that aligns better with Mingling's paradigm +# ------------------ +parser = "picker" +# ------------------ + +### 3. If you have async requirements, please select an async runtime +# Hint: You can only enable one of them +# ------------------ +# tokio = true +# async_std = true +# ------------------ + +### 4. If you need flexible management of your program's exit codes, enable this +# ------------------ +exit_code = true +# ------------------ + +### 5. If your project has completion needs, enable this +# ------------------ +completion = true +# ------------------ + +### 6. If you expect the number of commands to be > 20, +# enable the compile-time dispatch tree for faster matching +# ------------------ +# dispatch_tree = true +# ------------------ + +### 7. If you want the program to be able to output structured data controlled by flags such as `--json`, enable this +# ------------------ +# structural_renderer = true +# ------------------ + +### Final. All set. +# Please run `mling proj-init` in this directory to continue creating the project. diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/rule.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/rule.toml new file mode 100644 index 0000000..0ff6ffb --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/rule.toml @@ -0,0 +1,95 @@ +[[user.input]] +name = "program_name" + +[[user.toggle]] +name = "exit_code" + +[[user.toggle]] +name = "tokio" + +[[user.toggle]] +name = "async_std" + +[[user.toggle-mutex]] +mutex = [ "tokio", "async_std" ] +reason = "You can only select one async runtime" + +[[user.toggle]] +name = "completion" + +[[user.toggle]] +name = "pathf" +default = true + +[[user.toggle]] +name = "structural_renderer" + +[[user.toggle]] +name = "dispatch_tree" + +[[user.toggle]] +name = "use_parser" + +[[user.selection]] +name = "parser" +option = [ "clap", "builtin", "picker" ] + +[[user.toggle-mutex]] +mutex = [ "clap", "builtin", "picker" ] +reason = "You can only select one argument parser" + +[[display]] +name = "ASYNC_STD" +rule = "async_std" + +[[display]] +name = "TOKIO" +rule = "tokio" + +[[display]] +name = "ASYNC" +rule = "tokio || async_std" + +[[display]] +name = "BUILD_TIME" +rule = "completion || pathf" + +[[hide-file]] +file = "./build.rs" +rule = "!completion && !pathf" + +[[display]] +name = "PARSER_CLAP" +rule = "use_parser && parser == clap" + +[[display]] +name = "PARSER_BUILTIN" +rule = "use_parser && parser == builtin" + +[[display]] +name = "PARSER_PICKER" +rule = "use_parser && parser == picker" + +[[display]] +name = "COMPLETION" +rule = "completion" + +[[display]] +name = "STRUCTURAL_RENDERER" +rule = "structural_renderer" + +[[display]] +name = "EXIT_CODE" +rule = "exit_code" + +[[display]] +name = "DISPATCH_TREE" +rule = "dispatch_tree" + +[[display]] +name = "NOT_DISPATCH_TREE" +rule = "!dispatch_tree" + +[[display]] +name = "PATHF" +rule = "pathf" diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.gitignore b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.gitignore @@ -0,0 +1 @@ +/target diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_command/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_command/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_command/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_completion/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_completion/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_completion/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_help/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_help/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_help/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_outside_type/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_outside_type/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_outside_type/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_resource/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_resource/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_resource/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_setup/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_setup/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_setup/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_setup_hook/class.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_setup_hook/class.toml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_.mling/tmpl_setup_hook/class.toml diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_Cargo.toml b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_Cargo.toml new file mode 100644 index 0000000..2345911 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_Cargo.toml @@ -0,0 +1,79 @@ +[package] +name = "<<<program_name>>>" +version = "0.1.0" +edition = "2024" + +[[bin]] +name = "<<<program_name>>>" +path = "src/main.rs" + +[profile.dev] +opt-level = 0 +debug = true +panic = "unwind" +lto = false + +[profile.release] +opt-level = 3 +# If you need to use exec_panic hook, enable `unwind` +# panic = "unwind" +panic = "abort" +lto = true + +[dependencies.mingling] +version = "0.4" +features = [ + "extras", +??? >>> ASYNC + "async", +??? <<< +??? >>> PARSER_PICKER + "picker", +??? <<< +??? >>> PARSER_CLAP + "clap", +??? <<< +??? >>> PARSER_BUILTIN + "parser", +??? <<< +??? >>> DISPATCH_TREE + "dispatch_tree", +??? <<< +??? >>> PATHF + "pathf", +??? <<< +??? >>> COMPLETION + "comp", +??? <<< +??? >>> STRUCTURAL_RENDERER + "structural_renderer", +??? <<< +] + +??? >>> BUILD_TIME +[build-dependencies.mingling] +version = "0.4" +features = [ + "build", +??? >>> DISPATCH_TREE + "dispatch_tree", +??? <<< +??? >>> PATHF + "pathf", +??? <<< +??? >>> COMPLETION + "comp", +??? <<< +] +??? <<< + +[dependencies] +??? >>> PARSER_CLAP +clap = { version = "4", features = [ "derive" ] } +??? <<< +??? >>> TOKIO +tokio = { version = "1", features = [ "full" ] } +??? <<< +??? >>> ASYNC_STD +async-std = "1" +??? <<< diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_build.rs b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_build.rs new file mode 100644 index 0000000..e90070c --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_build.rs @@ -0,0 +1,31 @@ +fn main() { +??? >>> COMPLETION + build_scripts(); +??? <<< +??? >>> PATHF + build_pathf_mapping(); +??? <<< +} +??? >>> COMPLETION + +/// Generate completion scripts +fn build_scripts() { + // `env!("CARGO_PKG_NAME")` equals the crate name, which matches the binary name. + // If your binary name differs from the crate name, specify it explicitly. + mingling::build::build_comp_scripts( + // Your binary name: + env!("CARGO_PKG_NAME"), + ) + .unwrap(); +} +??? <<< +??? >>> PATHF + +/// Use `pathf` to analyze the workspace's mingling macro calls +/// and generate type path mappings for them +fn build_pathf_mapping() { + // Build pathf type mapping to ensure that the enabled `pathf` feature + // can correctly scan macros in the project + mingling::build::analyze_and_build_type_mapping().unwrap(); +} +??? <<< diff --git a/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_src/tmpl_main.rs b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_src/tmpl_main.rs new file mode 100644 index 0000000..02f3cc9 --- /dev/null +++ b/mingling_cli/tmpls/mingling_tmpl/0.4/tmpl_src/tmpl_main.rs @@ -0,0 +1,45 @@ +pub(crate) mod commands; +pub(crate) mod helps; +pub(crate) mod renderers; + +use mingling::macros::buffer; +use mingling::prelude::*; +??? >>> EXIT_CODE +use mingling::setup::ExitCodeSetup; +??? <<< +use mingling::setup::picker::BasicProgramSetup; + +fn main() { + let mut program = ThisProgram::new(); + + // Plugins + program.with_setup(BasicProgramSetup); +??? >>> EXIT_CODE + program.with_setup(ExitCodeSetup::default()); +??? <<< +??? >>> COMPLETION + + // Completion Dispatcher + program.with_dispatcher(CMDCompletion); +??? <<< +??? >>> NOT_DISPATCH_TREE + + // Dispatchers + program.with_dispatcher(commands::greet::CMDGreet); +??? <<< + + program.exec_and_exit(); +} + +#[renderer(buffer)] +fn handle_error_dispatcher_not_found(prev: ErrorDispatcherNotFound) { + r_println!("Error: cannot match \"{}\" to any command", prev.join(" ")); +} + +#[renderer(buffer)] +fn handle_error_renderer_not_found(prev: ErrorRendererNotFound) { + let type_name = prev.inner; + r_println!("Error: renderer not found for \"{}\"", type_name); +} + +gen_program!(); diff --git a/mingling_core/tmpls/comps/pwsh.ps1 b/mingling_core/tmpls/comps/pwsh.ps1 index eccb776..d72a027 100644 --- a/mingling_core/tmpls/comps/pwsh.ps1 +++ b/mingling_core/tmpls/comps/pwsh.ps1 @@ -18,7 +18,7 @@ Register-ArgumentCompleter -Native -CommandName '<<<bin_name>>>' -ScriptBlock { $found = $false for ($i = 0; $i -lt $elements.Count; $i++) { if ($elements[$i] -eq $currentWord) { - $wordIndex = $i + $wordIndex = $i + 1 if ($i -gt 0) { $previousWord = $elements[$i - 1] } @@ -28,25 +28,40 @@ Register-ArgumentCompleter -Native -CommandName '<<<bin_name>>>' -ScriptBlock { } if (-not $found) { - $wordIndex = $elements.Count + $wordIndex = $elements.Count + 1 if ($elements.Count -gt 0) { $previousWord = $elements[-1] } } $args = @( - "-f", ($line -replace '-', '^') "-C", $cursorPosition.ToString() - "-w", ($currentWord -replace '-', '^') - "-p", ($previousWord -replace '-', '^') - "-c", ($commandName -replace '-', '^') "-i", $wordIndex.ToString() "-F", "Powershell" ) + if ($line) { + $args += "-f" + $args += ($line -replace '-', '^') + } + if ($currentWord) { + $args += "-w" + $args += ($currentWord -replace '-', '^') + } + if ($previousWord) { + $args += "-p" + $args += ($previousWord -replace '-', '^') + } + if ($commandName) { + $args += "-c" + $args += ($commandName -replace '-', '^') + } + foreach ($element in $elements) { - $args += "-a" - $args += ($element -replace '-', '^') + if ($element) { + $args += "-a" + $args += ($element -replace '-', '^') + } } $originalEncoding = [Console]::OutputEncoding diff --git a/mingling_pathf/test/Cargo.lock b/mingling_pathf/test/Cargo.lock index 1260662..e7de689 100644 --- a/mingling_pathf/test/Cargo.lock +++ b/mingling_pathf/test/Cargo.lock @@ -16,7 +16,7 @@ checksum = "6170dccbc3ea15dfb7f2da964097f814aba1dd8f746d4ffc56f33245c38e6d96" [[package]] name = "mingling_pathf" -version = "0.3.0" +version = "0.4.0" dependencies = [ "just_fmt 0.2.0", "proc-macro2", |
