diff --git a/tools/Cargo.lock b/tools/Cargo.lock index 04908babb4..7795e97293 100644 --- a/tools/Cargo.lock +++ b/tools/Cargo.lock @@ -11,6 +11,91 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-hermes" +version = "0.1.0" +dependencies = [ + "anyhow", + "cargo_metadata", + "clap", + "regex", + "walkdir", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + [[package]] name = "cargo-zerocopy" version = "0.0.0" @@ -18,6 +103,66 @@ dependencies = [ "toml", ] +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "clap" +version = "4.5.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + [[package]] name = "equivalent" version = "1.0.2" @@ -37,6 +182,12 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "indexmap" version = "2.13.0" @@ -47,12 +198,30 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "proc-macro2" version = "1.0.105" @@ -100,6 +269,25 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + [[package]] name = "serde" version = "1.0.228" @@ -107,6 +295,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -129,6 +318,19 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + [[package]] name = "serde_spanned" version = "0.6.9" @@ -138,6 +340,12 @@ dependencies = [ "serde", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.114" @@ -149,6 +357,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml" version = "0.8.23" @@ -196,6 +424,46 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "winnow" version = "0.7.14" @@ -204,3 +472,9 @@ checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] + +[[package]] +name = "zmij" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" diff --git a/tools/Cargo.toml b/tools/Cargo.toml index d4acb52cb2..db582a301d 100644 --- a/tools/Cargo.toml +++ b/tools/Cargo.toml @@ -1,25 +1,26 @@ -# Copyright 2018 The Fuchsia Authors -# -# Licensed under a BSD-style license , Apache License, Version 2.0 -# , or the MIT -# license , at your option. -# This file may not be copied, modified, or distributed except according to -# those terms. - -[workspace] -members = [ - "cargo-zerocopy", - "generate-readme", -] -resolver = "2" - -[workspace.package] -edition = "2021" -version = "0.0.0" -authors = ["Joshua Liebow-Feeser "] -license = "BSD-2-Clause OR Apache-2.0 OR MIT" -publish = false - -[workspace.dependencies] -regex = "1" -toml = "0.8" +# Copyright 2018 The Fuchsia Authors +# +# Licensed under a BSD-style license , Apache License, Version 2.0 +# , or the MIT +# license , at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +[workspace] +members = [ + "hermes", + "cargo-zerocopy", + "generate-readme", +] +resolver = "2" + +[workspace.package] +edition = "2021" +version = "0.0.0" +authors = ["Joshua Liebow-Feeser "] +license = "BSD-2-Clause OR Apache-2.0 OR MIT" +publish = false + +[workspace.dependencies] +regex = "1" +toml = "0.8" diff --git a/tools/hermes/Cargo.lock b/tools/hermes/Cargo.lock new file mode 100644 index 0000000000..f7d14f3ea4 --- /dev/null +++ b/tools/hermes/Cargo.lock @@ -0,0 +1,267 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "cargo-hermes" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "regex", + "walkdir", +] + +[[package]] +name = "clap" +version = "4.5.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/tools/hermes/Cargo.toml b/tools/hermes/Cargo.toml new file mode 100644 index 0000000000..e97b6e74c7 --- /dev/null +++ b/tools/hermes/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cargo-hermes" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = "1.0.100" +clap = { version = "4.5.56", features = ["derive"] } +regex = "1.12.2" +walkdir = "2.5.0" +cargo_metadata = "0.18" diff --git a/tools/hermes/src/lib.rs b/tools/hermes/src/lib.rs new file mode 100644 index 0000000000..7cd4c70a3d --- /dev/null +++ b/tools/hermes/src/lib.rs @@ -0,0 +1,18 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +//! Hermes: A verification orchestrator for Rust. +//! +//! This library provides the core logic for the `cargo-hermes` CLI tool, including: +//! - Parsing Rust code for verification annotations. +//! - Orchestrating the execution of Charon and Aeneas. +//! - Stitching generated Lean code with user-provided proofs. + +pub mod orchestration; +pub mod parser; +pub mod pipeline; diff --git a/tools/hermes/src/main.rs b/tools/hermes/src/main.rs new file mode 100644 index 0000000000..c25cdc98cd --- /dev/null +++ b/tools/hermes/src/main.rs @@ -0,0 +1,56 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use std::path::PathBuf; + +use anyhow::Result; +use cargo_hermes::pipeline::run_pipeline; +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(name = "cargo-hermes")] +#[command(bin_name = "cargo")] +pub enum CargoCli { + Hermes(HermesArgs), +} + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct HermesArgs { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + /// Verify the current crate + /// Verify a crate or script + Verify { + /// Optional crate name + #[arg(long)] + crate_name: Option, + /// Path to generated files directory + #[arg(long, default_value = "verification")] + dest: PathBuf, + /// Path to local Aeneas repository (specifically backends/lean) + #[arg(long)] + aeneas_path: Option, + /// Path to Cargo.toml or Cargo script + #[arg(long)] + manifest_path: Option, + }, +} + +fn main() -> Result<()> { + let CargoCli::Hermes(args) = CargoCli::parse(); + let Commands::Verify { crate_name, dest, aeneas_path, manifest_path } = args.command; + + let crate_root = std::env::current_dir()?; + let dest = dest.canonicalize()?; + run_pipeline(crate_name, &crate_root, &dest, aeneas_path, manifest_path) +} diff --git a/tools/hermes/src/orchestration.rs b/tools/hermes/src/orchestration.rs new file mode 100644 index 0000000000..912967b09f --- /dev/null +++ b/tools/hermes/src/orchestration.rs @@ -0,0 +1,87 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use std::{path::Path, process::Command}; + +use anyhow::{Context, Result, anyhow}; + +/// Runs the Charon tool to extract LLBC (Low-Level Borrow Calculus) from the crate. +/// +/// # Arguments +/// * `crate_root` - Path to the root of the crate to analyze. +/// * `dest_file` - Destination path for the LLBC file (e.g. `.../crate.llbc`). +/// * `manifest_path` - Optional path to a specific Cargo.toml or script file. +pub fn run_charon(crate_root: &Path, dest_file: &Path, manifest_path: Option<&Path>) -> Result<()> { + let crate_root = crate_root.to_str().unwrap(); + let dest_file = dest_file.to_str().unwrap(); + + println!("Running charon in {:?}", crate_root); + let mut cmd = Command::new("charon"); + cmd.current_dir(crate_root); + cmd.arg("cargo"); + + // Charon args first + args(&mut cmd, &["--dest-file", dest_file, "--preset", "aeneas"]); + + if let Some(path) = manifest_path { + cmd.arg("--"); + if path.extension().map_or(false, |e| e == "rs") { + cmd.arg("-Zscript"); + } + cmd.arg("--manifest-path"); + cmd.arg(path); + } + + let status = cmd.status().context("Failed to execute charon. Ensure it is in your PATH.")?; + if !status.success() { + return Err(anyhow!("charon failed with exit code: {}", status)); + } + Ok(()) +} + +/// Runs the Aeneas tool to translate LLBC files into Lean code. +/// +/// # Arguments +/// * `llbc_path` - Path to the input LLBC file. +/// * `dest` - Destination directory for the generated Lean files. +pub fn run_aeneas(llbc_path: &Path, dest: &Path) -> Result<()> { + let llbc_path = llbc_path.to_str().unwrap(); + let dest = dest.to_str().unwrap(); + + let mut cmd = Command::new("aeneas"); + args(&mut cmd, &["-backend", "lean", llbc_path, "-dest", dest]); + let status = cmd.status().context("Failed to execute aeneas. Ensure it is in your PATH.")?; + + if !status.success() { + return Err(anyhow!("aeneas failed with exit code: {}", status)); + } + Ok(()) +} + +/// Runs `lake build` to compile and verify the generated Lean code. +/// +/// # Arguments +/// * `dir` - Directory containing the `lakefile.lean`. +pub fn run_lake_build(dir: &Path) -> Result<()> { + let status = Command::new("lake") + .current_dir(dir) + .arg("build") + .status() + .context("Failed to execute lake. Ensure Lean 4 is installed.")?; + + if !status.success() { + return Err(anyhow!("lake build failed with exit code: {}", status)); + } + Ok(()) +} + +fn args(cmd: &mut Command, args: &[&str]) { + for arg in args { + cmd.arg(arg); + } +} diff --git a/tools/hermes/src/parser.rs b/tools/hermes/src/parser.rs new file mode 100644 index 0000000000..8251e672d5 --- /dev/null +++ b/tools/hermes/src/parser.rs @@ -0,0 +1,75 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use std::sync::LazyLock; + +use anyhow::Result; +use regex::Regex; + +/// Represents a specification block extracted from the source code. +/// +/// Contains the function name it applies to and the raw body of the specification. +#[derive(Debug, Clone)] +pub struct SpecBlock { + pub function_name: String, + pub body: String, +} + +/// Represents a proof block extracted from the source code. +/// +/// Contains the raw body of the proof. +#[derive(Debug, Clone)] +pub struct ProofBlock { + pub body: String, +} + +#[derive(Debug, Clone)] +pub struct ExtractedBlocks { + pub specs: Vec, + pub proofs: Vec, +} + +/// Extracts both specification and proof blocks from the provided source content. +/// +/// This function uses regular expressions to find blocks formatted as: +/// - `/*@ lean spec function_name ... @*/` +/// - `/*@ proof ... @*/` +pub fn extract_blocks(content: &str) -> Result { + // Regex matches: + // - Start with `/*@` + // - `lean spec` followed by function name + // - Capture function name in `fn_name` + // - Capture content in `body` (non-greedy) + // - End with `@*/` + static SPEC_RE: LazyLock = LazyLock::new(|| { + Regex::new(r"(?ms)/\*\@\s*lean\s+spec\s+(?P\w+)\s+(?P.*?)\s*@\*/").unwrap() + }); + + // Regex matches: + // - Start with `/*@` + // - `proof` + // - Capture content in `body` (non-greedy) + // - End with `@*/` + static PROOF_RE: LazyLock = + LazyLock::new(|| Regex::new(r"(?ms)/\*\@\s*proof\s+(?P.*?)\s*@\*/").unwrap()); + + let mut specs = Vec::new(); + for cap in SPEC_RE.captures_iter(content) { + specs.push(SpecBlock { + function_name: cap["fn_name"].to_string(), + body: cap["body"].trim().to_string(), + }); + } + + let mut proofs = Vec::new(); + for cap in PROOF_RE.captures_iter(content) { + proofs.push(ProofBlock { body: cap["body"].trim().to_string() }); + } + + Ok(ExtractedBlocks { specs, proofs }) +} diff --git a/tools/hermes/src/pipeline.rs b/tools/hermes/src/pipeline.rs new file mode 100644 index 0000000000..b077dc0981 --- /dev/null +++ b/tools/hermes/src/pipeline.rs @@ -0,0 +1,278 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use anyhow::{Context, Result, anyhow}; +use walkdir::WalkDir; + +use crate::{ + orchestration::{run_aeneas, run_charon, run_lake_build}, + parser::{ProofBlock, SpecBlock, extract_blocks}, +}; + +fn get_crate_name( + manifest_path: Option<&Path>, + crate_name: Option, + crate_root: &Path, +) -> Result { + if let Some(name) = crate_name { + return Ok(name); + } + + let mut cmd = cargo_metadata::MetadataCommand::new(); + if let Some(path) = manifest_path { + // If it's a script, we just use the filename. + if path.extension().map_or(false, |e| e == "rs") { + return Ok(path.file_stem().unwrap().to_string_lossy().to_string()); + } + + cmd.manifest_path(path); + } else { + cmd.manifest_path(crate_root.join("Cargo.toml")); + } + + // We don't need dependencies, just the root package info. + cmd.no_deps(); + + let metadata = cmd.exec().context("Failed to load cargo metadata")?; + + // If we have a specific manifest path, look for the package with that path + if let Some(path) = manifest_path { + let canonical_manifest = fs::canonicalize(path).unwrap_or(path.to_path_buf()); + if let Some(pkg) = metadata.packages.iter().find(|p| { + // Try to canonicalize package manifest path for comparison + p.manifest_path + .as_std_path() + .canonicalize() + .map_or(p.manifest_path.as_std_path() == canonical_manifest, |p| { + p == canonical_manifest + }) + }) { + return Ok(pkg.name.clone()); + } + } + + // If no manifest path provided or not found, try root_package (works for non-virtual) + if let Some(root) = metadata.root_package() { + return Ok(root.name.clone()); + } + + // Try finding a package whose manifest is in crate_root/Cargo.toml + let default_manifest = crate_root.join("Cargo.toml"); + let canonical_default = fs::canonicalize(&default_manifest).unwrap_or(default_manifest); + if let Some(pkg) = metadata.packages.iter().find(|p| { + p.manifest_path + .as_std_path() + .canonicalize() + .map_or(p.manifest_path.as_std_path() == canonical_default, |p| p == canonical_default) + }) { + return Ok(pkg.name.clone()); + } + + Err(anyhow!("Could not determine crate name from Cargo.toml")) +} + +pub fn run_pipeline( + crate_name: Option, + crate_root: &Path, + dest: &Path, + aeneas_path: Option, + manifest_path: Option, +) -> Result<()> { + let crate_name = get_crate_name(manifest_path.as_deref(), crate_name, crate_root)?; + + fs::create_dir_all(dest).context("Failed to create destination directory")?; + + let crate_name_snake = crate_name.replace('-', "_"); + let llbc_path = dest.join(format!("{}.llbc", crate_name_snake)); + + // Clean up stale artifacts before running Charon. While it's not strictly + // necessary under ideal conditions, it hedges against Charon failing to + // produce a new file (or producing one with a different name), which would + // result in us verifying a stale artifact. + if llbc_path.exists() { + fs::remove_file(&llbc_path)?; + } + + run_charon(crate_root, &llbc_path, manifest_path.as_deref())?; + + if !llbc_path.exists() { + return Err(anyhow!("Charon did not produce expected LLBC file: {:?}", llbc_path)); + } + + // 4. Run Aeneas + println!("Step 2: Running Aeneas..."); + run_aeneas(&llbc_path, dest)?; + + // 4. Stitching + println!("Step 3: Stitching..."); + + // Aeneas enforces PascalCase (CamelCase) for generated files. + let camel_name: String = crate_name_snake + .split('_') + .map(|s| { + let mut c = s.chars(); + match c.next() { + None => String::new(), + Some(f) => f.to_uppercase().to_string() + c.as_str(), + } + }) + .collect(); + + let generated_camel = dest.join(format!("{}.lean", camel_name)); + if !generated_camel.exists() { + return Err(anyhow!("Aeneas did not produce expected output file: {:?}", generated_camel)); + } + + stitch_user_proofs( + &crate_root, + &crate_name_snake, + &camel_name, + dest, + manifest_path.as_deref(), + )?; + + // 5. Verify + println!("Step 4: Verifying..."); + // ensure lakefile exists + // Note: lakefile still uses snake_case for package name and roots, but `CamelCase` structure for imports + write_lakefile(dest, &crate_name_snake, &camel_name, aeneas_path)?; + run_lake_build(dest)?; + + println!("Verification Successful!"); + Ok(()) +} + +fn stitch_user_proofs( + crate_root: &Path, + crate_name_snake: &str, + crate_name_camel: &str, + dest: &Path, + source_file: Option<&Path>, +) -> Result<()> { + let mut all_specs = Vec::new(); + let mut all_proofs = Vec::new(); + + if let Some(path) = source_file { + // If a specific source file is provided (e.g. script), uses that. + // We only scan this single file. + if path.exists() { + let content = fs::read_to_string(path)?; + let extracted = extract_blocks(&content)?; + all_specs.extend(extracted.specs); + all_proofs.extend(extracted.proofs); + } + } else { + // Otherwise scan src dir + let src_dir = crate_root.join("src"); + if src_dir.exists() { + for entry in WalkDir::new(src_dir) { + let entry = entry?; + if entry.path().extension().map_or(false, |ext| ext == "rs") { + let content = fs::read_to_string(entry.path())?; + let extracted = extract_blocks(&content)?; + all_specs.extend(extracted.specs); + all_proofs.extend(extracted.proofs); + } + } + } + } + + generate_lean_file(dest, crate_name_snake, crate_name_camel, &all_specs, &all_proofs) +} + +fn generate_lean_file( + dest: &Path, + namespace_name: &str, + import_name: &str, + specs: &[SpecBlock], + proofs: &[ProofBlock], +) -> Result<()> { + let mut content = String::new(); + content.push_str(&format!("import {}\n", import_name)); + content.push_str("import Aeneas\n"); + content.push_str("open Aeneas Aeneas.Std Result Error\n\n"); + content.push_str(&format!("open {}\n\n", namespace_name)); + + // For the initial version, we assume a strict one-to-one mapping between + // spec blocks and proof blocks. + // Future improvements should support matching by name or more complex interleaving. + // + // The current implementation expects: + // /*@ lean spec ... @*/ + // /*@ proof ... @*/ + // appearing in pairs. + + if specs.len() != proofs.len() { + eprintln!( + "Warning: Number of specs ({}) does not match number of proofs ({})", + specs.len(), + proofs.len() + ); + } + + for (i, spec) in specs.iter().enumerate() { + let proof = proofs.get(i).map(|p| p.body.as_str()).unwrap_or("sorry"); + + // Transform the spec body into a valid Lean theorem type. + // If the body contains "ensures", we format it as a return type check. + // + // Example Input: "ensures |ret| ..." + // Example Output: ": ensures |ret| ..." + let body = if spec.body.contains("ensures") && !spec.body.contains(": ensures") { + spec.body.replacen("ensures", ": ensures", 1) + } else { + spec.body.clone() + }; + + content.push_str(&format!("theorem {}_spec {}\n", spec.function_name, body)); + content.push_str(" :=\n"); + content.push_str(" by\n"); + content.push_str(proof); + content.push_str("\n\n"); + } + + fs::write(dest.join("UserProofs.lean"), content).map_err(Into::into) +} + +fn write_lakefile( + dest: &Path, + crate_name_snake: &str, + crate_name_camel: &str, + aeneas_path: Option, +) -> Result<()> { + let lakefile_path = dest.join("lakefile.lean"); + // Only create if missing. If the user wants to force regen, they should delete it or we add a flag. + let require_line = if let Some(path) = aeneas_path { + format!("require aeneas from \"{}\"", path.display()) + } else { + r#"require aeneas from git "https://github.com/AeneasVerif/aeneas" @ "main""#.to_string() + }; + + let content = format!( + r#" +import Lake +open Lake DSL + +package {} + +{} + +@[default_target] +lean_lib {} {{ + roots := #[`{}, `UserProofs] +}} +"#, + crate_name_snake, require_line, crate_name_snake, crate_name_camel + ); + fs::write(lakefile_path, content).map_err(Into::into) +} diff --git a/tools/hermes/tests/cases/failure/incorrect_proof.rs b/tools/hermes/tests/cases/failure/incorrect_proof.rs new file mode 100644 index 0000000000..e376e8c6c3 --- /dev/null +++ b/tools/hermes/tests/cases/failure/incorrect_proof.rs @@ -0,0 +1,23 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "incorrect_proof" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +spec incorrect (x : U32) +: ∃ ret, incorrect x = ok ret ∧ ret.val = x.val + 1 +@*/ +/*@ proof + simp [incorrect] + -- Error: x != x + 1, so this goal remains unsolved +@*/ +pub fn incorrect(x: u32) -> u32 { + x +} + +fn main() {} diff --git a/tools/hermes/tests/cases/failure/syntax_error_in_spec.rs b/tools/hermes/tests/cases/failure/syntax_error_in_spec.rs new file mode 100644 index 0000000000..c6fbf1605a --- /dev/null +++ b/tools/hermes/tests/cases/failure/syntax_error_in_spec.rs @@ -0,0 +1,19 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "syntax_error_in_spec" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +spec syntax_error (x : U32) +: ∃ ret, syntax_error x = ok ret ∧ (((( +@*/ +pub fn syntax_error(x: u32) -> u32 { + x +} + +fn main() {} diff --git a/tools/hermes/tests/cases/failure/undefined_variable.rs b/tools/hermes/tests/cases/failure/undefined_variable.rs new file mode 100644 index 0000000000..9fc68802ad --- /dev/null +++ b/tools/hermes/tests/cases/failure/undefined_variable.rs @@ -0,0 +1,19 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "undefined_variable" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +spec undefined_var (x : u32) +ensures |ret| ret.val = y.val -- y is undefined +@*/ +pub fn undefined_var(x: u32) -> u32 { + x +} + +fn main() {} diff --git a/tools/hermes/tests/cases/success/add.rs b/tools/hermes/tests/cases/success/add.rs new file mode 100644 index 0000000000..6b13bb6e09 --- /dev/null +++ b/tools/hermes/tests/cases/success/add.rs @@ -0,0 +1,24 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "test_case" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +spec add (a b : U32) +: ∃ ret, add a b = ok ret ∧ ret.val = (a.val + b.val) % 4294967296 +@*/ +/*@ proof + sorry +@*/ +pub fn add(a: u32, b: u32) -> u32 { + a.wrapping_add(b) +} + +fn main() { + let _ = add(1, 2); +} diff --git a/tools/hermes/tests/cases/success/checked_add.rs b/tools/hermes/tests/cases/success/checked_add.rs new file mode 100644 index 0000000000..775f4fd337 --- /dev/null +++ b/tools/hermes/tests/cases/success/checked_add.rs @@ -0,0 +1,22 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +spec checked_add (a b : U32) +: ∃ ret, checked_add a b = ok ret ∧ + (match ret with + | none => a.val + b.val > 4294967295 + | some r => r.val = a.val + b.val) +@*/ +/*@ proof + sorry +@*/ +pub fn checked_add(a: u32, b: u32) -> Option { + a.checked_add(b) +} +fn main() {} diff --git a/tools/hermes/tests/cases/success/generic_id.rs b/tools/hermes/tests/cases/success/generic_id.rs new file mode 100644 index 0000000000..0cb18b4e9b --- /dev/null +++ b/tools/hermes/tests/cases/success/generic_id.rs @@ -0,0 +1,29 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "generic_id" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +<<<<<<< Updated upstream +spec id (T : Type) (x : T) +: id T x = ok x +@*/ +/*@ proof +======= +spec id {T : Type} (x : T) +ensures |ret| ret = x +@*/ +/*@ proof +:= by +>>>>>>> Stashed changes + simp [id] +@*/ +pub fn id(x: T) -> T { + x +} +fn main() {} diff --git a/tools/hermes/tests/cases/success/struct_method.rs b/tools/hermes/tests/cases/success/struct_method.rs new file mode 100644 index 0000000000..93dadae3d4 --- /dev/null +++ b/tools/hermes/tests/cases/success/struct_method.rs @@ -0,0 +1,43 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "struct_method" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +pub struct Point { + pub x: u32, + pub y: u32, +} + +/*@ lean +<<<<<<< Updated upstream +spec move_pt (self : Point) (dx dy : U32) +: ∃ self_final, move_pt self dx dy = ok ((), self_final) ∧ + self_final.x.val = self.x.val + dx.val ∧ + self_final.y.val = self.y.val + dy.val +@*/ +/*@ proof + sorry +======= +spec move_pt (self : Point) (dx dy : u32) +ensures |ret, self_final| + ret = () /\ self_final.x.val = self.x.val + dx.val /\ self_final.y.val = self.y.val + dy.val +@*/ +/*@ proof +:= by + simp [move_pt] + simp [nop_div_pt] -- Aeneas might generate different names? + linarith +>>>>>>> Stashed changes +@*/ +impl Point { + pub fn move_pt(&mut self, dx: u32, dy: u32) { + self.x += dx; + self.y += dy; + } +} +fn main() {} diff --git a/tools/hermes/tests/cases/success/unchecked_wrapper.rs b/tools/hermes/tests/cases/success/unchecked_wrapper.rs new file mode 100644 index 0000000000..96daf460b9 --- /dev/null +++ b/tools/hermes/tests/cases/success/unchecked_wrapper.rs @@ -0,0 +1,57 @@ +#!/usr/bin/env cargo +//! ```cargo +//! [package] +//! name = "unchecked_wrapper" +//! version = "0.1.0" +//! edition = "2021" +//! +//! [dependencies] +//! ``` + +/*@ lean +<<<<<<< Updated upstream +spec raw_inc (x : U32) +: ∃ ret, raw_inc x = ok ret ∧ ret.val = x.val + 1 +======= +model raw_inc (x : u32) +requires h_safe : x.val < 4294967295 +ensures |ret| ret.val = x.val + 1 +>>>>>>> Stashed changes +@*/ +#[allow(unused_unsafe)] +unsafe fn raw_inc(x: u32) -> u32 { + unsafe { x + 1 } +} + +/*@ lean +<<<<<<< Updated upstream +spec safe_inc (x : U32) +: ∃ ret, safe_inc x = ok ret ∧ + (if x.val < 4294967295 then ret.val = x.val + 1 else ret.val = 0) +@*/ +/*@ proof + sorry +======= +spec safe_inc (x : u32) + ensures |ret| + if x.val < 4294967295 then ret.val = x.val + 1 else ret.val = 0 +@*/ +/*@ proof +:= by + simp [safe_inc] + split + case inl h => + simp [raw_inc] + simp [h] + case inr h => + simp +>>>>>>> Stashed changes +@*/ +pub fn safe_inc(x: u32) -> u32 { + if x < u32::MAX { + unsafe { raw_inc(x) } + } else { + 0 + } +} +fn main() {} diff --git a/tools/hermes/tests/integration.rs b/tools/hermes/tests/integration.rs new file mode 100644 index 0000000000..d08961916c --- /dev/null +++ b/tools/hermes/tests/integration.rs @@ -0,0 +1,137 @@ +// Copyright 2026 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use std::{ + env, fs, + io::Write as _, + path::{Path, PathBuf}, +}; + +use cargo_hermes::pipeline::run_pipeline; + +struct TestTempDir { + path: PathBuf, +} + +impl TestTempDir { + fn new() -> Self { + // Use a persistent directory in target/ to allow caching across runs + let target_dir = env::var("CARGO_TARGET_DIR").map(PathBuf::from).unwrap_or_else(|_| { + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + manifest_dir.join("../../target") + }); + let cache_dir = target_dir.join("hermes_integration_cache"); + fs::create_dir_all(&cache_dir).expect("Failed to create cache dir"); + + Self { path: cache_dir } + } + + fn path(&self) -> &Path { + &self.path + } +} + +impl Drop for TestTempDir { + fn drop(&mut self) { + // Do NOT delete the directory to preserve cache (Mathlib takes forever to download/build) + // clean up specific files if needed, but not the whole thing. + } +} + +fn setup_env() -> (PathBuf, PathBuf) { + println!("DEBUG: Starting setup_env"); + std::io::stdout().flush().unwrap(); + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let cases_dir = manifest_dir.join("tests/cases"); + + let aeneas_path = + PathBuf::from("/usr/local/google/home/joshlf/workspace/zerocopy/hermes2/aeneas"); + let aeneas_lean_path = aeneas_path.join("backends/lean"); + + let charon_bin = aeneas_path.join("charon/bin"); + let aeneas_bin = aeneas_path.join("bin"); + if charon_bin.exists() { + println!("DEBUG: Found charon bin at {:?}", charon_bin); + std::io::stdout().flush().unwrap(); + let home_dir = env::var("HOME").map(PathBuf::from).unwrap_or_else(|_| PathBuf::from(".")); + let elan_bin = home_dir.join(".elan/bin"); + let current_path = env::var("PATH").unwrap_or_default(); + let new_path = format!( + "{}:{}:{}:{}", + charon_bin.display(), + aeneas_bin.display(), + elan_bin.display(), + current_path + ); + unsafe { + env::set_var("PATH", new_path); + } + } + println!("DEBUG: setup_env complete"); + std::io::stdout().flush().unwrap(); + (cases_dir, aeneas_lean_path) +} + +fn run_suite(suite_name: &str, expect_success: bool) { + println!("DEBUG: Starting run_{}_cases", suite_name); + std::io::stdout().flush().unwrap(); + let (cases_dir, aeneas_lean_path) = setup_env(); + let suite_dir = cases_dir.join(suite_name); + if suite_dir.exists() { + for entry in fs::read_dir(suite_dir) + .unwrap_or_else(|_| panic!("Failed to read {} cases dir", suite_name)) + { + let entry = entry.expect("Failed to read entry"); + let path = entry.path(); + if path.extension().map_or(false, |e| e == "rs") { + let file_name = path.file_stem().unwrap().to_string_lossy().to_string(); + println!("Running {} test case: {:?}", suite_name, path.file_name().unwrap()); + run_case(&path, &aeneas_lean_path, Some(file_name), expect_success); + } + } + } +} + +#[test] +fn test_integration_suite() { + run_suite("success", true); + run_suite("failure", false); +} + +fn run_case( + source_path: &Path, + aeneas_path: &Path, + crate_name: Option, + expect_success: bool, +) { + let temp_dir = TestTempDir::new(); + let crate_root = temp_dir.path(); + + // Run pipeline directly on the script source path + let dest = crate_root.join("verification"); + let result = run_pipeline( + crate_name.clone(), + crate_root, + &dest, + Some(aeneas_path.to_path_buf()), + Some(source_path.to_path_buf()), + ); + + if expect_success { + result.expect("Pipeline failed for success case"); + // Assert Output + assert!(dest.join("UserProofs.lean").exists(), "UserProofs.lean not generated"); + assert!(dest.join("lakefile.lean").exists(), "lakefile.lean not generated"); + } else { + assert!( + result.is_err(), + "Pipeline succeeded for failure case {:?}, expected error", + source_path.file_name() + ); + } +} diff --git a/tools/vendor/anstream/.cargo-checksum.json b/tools/vendor/anstream/.cargo-checksum.json new file mode 100644 index 0000000000..567fee3b8d --- /dev/null +++ b/tools/vendor/anstream/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"76102cb3e05fd6f8c974bbdf9ae0636616d4daf389e68d58c7e1659da2ffc69f","Cargo.lock":"b1e73368b13ab4a6d1f076e8b6b1dbb202387e4c6987cab455174f72907c0243","Cargo.toml":"a562ec0a5c9404f4e1938e4b0bbfe396f9cc751b133e3f1aceb519d6d725201a","Cargo.toml.orig":"59786f3efab1c982a40dac0b8ff9cd7567eb7e158611f7f715b5b12464c43116","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"7e90b134ad15dc4368d2a27efeb8db9d155dcd0886b72a032ffb367616255807","examples/dump-stream.rs":"6dbd8fca846ac8addd43ae941fa1220a7c31862896ac2ae4971afe792480523d","examples/query-stream.rs":"3796dec1ffe79cc49d088086eb27214764e8e0cff0370d60150aeecdadd47d30","src/_macros.rs":"04590ef86f86bb67fb11580ab101caffde4d36da84652537da20424b72c8729a","src/adapter/mod.rs":"baf4237ea0b18df63609e49d93572ca27c2202a4cbec0220adb5a7e815c7d8ed","src/adapter/strip.rs":"642375f9dc5836eb5aa6eba7be849a84786d22764d470672bf1f646061254c1c","src/adapter/wincon.rs":"88607742fb7bbfb85e122a8dcc3188ef7c15ef332063af3a8939701dad05b90a","src/auto.rs":"73b39540ac20e609ecbd32aff057a0cb1ec806374360b87e611ff83579b5582c","src/buffer.rs":"597cc2a109a49f0a48888c7d882058d0ec4b771da34348d4da384ba056c6ea1c","src/fmt.rs":"cc11b005c4559843bd908a57958a13c8d0922fae6aff5261f3583c90e60da73c","src/lib.rs":"abe525407298c0767ba1e5678863e89cdc3024258107a9ea829b5abd48c9a56e","src/stream.rs":"82565c3aa4c493e75a90a64bb6022ab9b5a5212806ac9a0548c7d2d34d5dace3","src/strip.rs":"0268bdc9155fc91bd7e92337c5e3ba96999780b46fab311b00922c7a3047233c","src/wincon.rs":"16afb01d151c3992bb3ee50871723f1e1f1f6b34d3f161d4a8dc6fd27db4cb1c"},"package":"43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"} \ No newline at end of file diff --git a/tools/vendor/anstream/.cargo_vcs_info.json b/tools/vendor/anstream/.cargo_vcs_info.json new file mode 100644 index 0000000000..6082274833 --- /dev/null +++ b/tools/vendor/anstream/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "f7aff1c56febbd5ec054da313c730cd7c1a44b5c" + }, + "path_in_vcs": "crates/anstream" +} \ No newline at end of file diff --git a/tools/vendor/anstream/Cargo.lock b/tools/vendor/anstream/Cargo.lock new file mode 100644 index 0000000000..5c3155e5ca --- /dev/null +++ b/tools/vendor/anstream/Cargo.lock @@ -0,0 +1,782 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.21" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "divan", + "is_terminal_polyfill", + "lexopt", + "owo-colors", + "proptest", + "strip-ansi-escapes", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "clap" +version = "4.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" +dependencies = [ + "anstyle", + "clap_lex", + "terminal_size", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "condtype" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" + +[[package]] +name = "divan" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc40f214f0d9e897cfc72e2edfa5c225d3252f758c537f11ac0a80371c073a6" +dependencies = [ + "cfg-if", + "clap", + "condtype", + "divan-macros", + "libc", + "regex-lite", +] + +[[package]] +name = "divan-macros" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bdb5411188f7f878a17964798c1264b6b0a9f915bd39b20bf99193c923e1b4e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi 0.5.2", + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2736dd548daf35f50d261bbad35a83890bb9b461797f15de528485fbf206ab15" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lexopt" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ecf5dec444661aad892044dfcc6ea9b2d1be3db6c78916b91bbf9d903fc3006" +dependencies = [ + "once_cell", +] + +[[package]] +name = "owo-colors" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.9.4", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "regex-lite" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + +[[package]] +name = "rustix" +version = "0.37.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.59.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix 1.1.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.28", + "windows-sys 0.48.0", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.14.4+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[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.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + +[[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", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "wit-bindgen" +version = "0.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/tools/vendor/anstream/Cargo.toml b/tools/vendor/anstream/Cargo.toml new file mode 100644 index 0000000000..7c4249d4ef --- /dev/null +++ b/tools/vendor/anstream/Cargo.toml @@ -0,0 +1,220 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.66.0" +name = "anstream" +version = "0.6.21" +build = false +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "Cargo.lock", + "LICENSE*", + "README.md", + "examples/**/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "IO stream adapters for writing colored text that will gracefully degrade according to your terminal's capabilities." +readme = "README.md" +keywords = [ + "ansi", + "terminal", + "color", + "strip", + "wincon", +] +categories = ["command-line-interface"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-cli/anstyle.git" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", + "--generate-link-to-definition", +] + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "Unreleased" +replace = "{{version}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = '\.\.\.HEAD' +replace = "...{{tag_name}}" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "ReleaseDate" +replace = "{{date}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +## [Unreleased] - ReleaseDate +""" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD""" +exactly = 1 + +[features] +auto = ["dep:anstyle-query"] +default = [ + "auto", + "wincon", +] +test = [] +wincon = ["dep:anstyle-wincon"] + +[lib] +name = "anstream" +path = "src/lib.rs" + +[[example]] +name = "dump-stream" +path = "examples/dump-stream.rs" +required-features = ["auto"] + +[[example]] +name = "query-stream" +path = "examples/query-stream.rs" +required-features = ["auto"] + +[dependencies.anstyle] +version = "1.0.0" + +[dependencies.anstyle-parse] +version = "0.2.0" + +[dependencies.anstyle-query] +version = "1.0.0" +optional = true + +[dependencies.colorchoice] +version = "1.0.0" + +[dependencies.is_terminal_polyfill] +version = "1.48" + +[dependencies.utf8parse] +version = "0.2.2" + +[dev-dependencies.divan] +version = "0.1.16" + +[dev-dependencies.lexopt] +version = "0.3.1" + +[dev-dependencies.owo-colors] +version = "4.0.0" + +[dev-dependencies.proptest] +version = "1.7.0" + +[dev-dependencies.strip-ansi-escapes] +version = "0.2.1" + +[target."cfg(windows)".dependencies.anstyle-wincon] +version = "3.0.5" +optional = true + +[lints.clippy] +bool_assert_comparison = "allow" +branches_sharing_code = "allow" +checked_conversions = "warn" +collapsible_else_if = "allow" +create_dir = "warn" +dbg_macro = "warn" +debug_assert_with_mut_call = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +fallible_impl_from = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp_const = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +imprecise_flops = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +invalid_upcast_comparisons = "warn" +large_digit_groups = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +let_and_return = "allow" +linkedlist = "warn" +lossy_float_literal = "warn" +macro_use_imports = "warn" +mem_forget = "warn" +mutex_integer = "warn" +needless_continue = "allow" +needless_for_each = "warn" +negative_feature_names = "warn" +path_buf_push_overwrite = "warn" +ptr_as_ptr = "warn" +rc_mutex = "warn" +redundant_feature_names = "warn" +ref_option_ref = "warn" +rest_pat_in_fully_bound_structs = "warn" +result_large_err = "allow" +same_functions_in_if_condition = "warn" +self_named_module_files = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" +string_add = "warn" +string_add_assign = "warn" +string_lit_as_bytes = "warn" +string_to_string = "warn" +todo = "warn" +trait_duplication_in_bounds = "warn" +uninlined_format_args = "warn" +verbose_file_reads = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" + +[lints.rust] +unnameable_types = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[lints.rust.rust_2018_idioms] +level = "warn" +priority = -1 diff --git a/tools/vendor/anstream/Cargo.toml.orig b/tools/vendor/anstream/Cargo.toml.orig new file mode 100644 index 0000000000..942ac10f08 --- /dev/null +++ b/tools/vendor/anstream/Cargo.toml.orig @@ -0,0 +1,72 @@ +[package] +name = "anstream" +version = "0.6.21" +description = "IO stream adapters for writing colored text that will gracefully degrade according to your terminal's capabilities." +categories = ["command-line-interface"] +keywords = ["ansi", "terminal", "color", "strip", "wincon"] +repository.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[features] +default = ["auto", "wincon"] +auto = ["dep:anstyle-query"] +wincon = ["dep:anstyle-wincon"] +# Enable in `dev-dependencies` to make sure output is captured for tests +test = [] + +[dependencies] +anstyle = { version = "1.0.0", path = "../anstyle" } +anstyle-parse = { version = "0.2.0", path = "../anstyle-parse" } +colorchoice = { version = "1.0.0", path = "../colorchoice" } +anstyle-query = { version = "1.0.0", path = "../anstyle-query", optional = true } +utf8parse = "0.2.2" +is_terminal_polyfill = "1.48" + +[target.'cfg(windows)'.dependencies] +anstyle-wincon = { version = "3.0.5", path = "../anstyle-wincon", optional = true } + +[dev-dependencies] +divan = "0.1.16" +lexopt = "0.3.1" +owo-colors = "4.0.0" +proptest = "1.7.0" +strip-ansi-escapes = "0.2.1" + +[[example]] +name = "dump-stream" +required-features = ["auto"] + +[[example]] +name = "query-stream" +required-features = ["auto"] + +[[bench]] +name = "strip" +harness = false + +[[bench]] +name = "wincon" +harness = false + +[[bench]] +name = "stream" +harness = false + +[lints] +workspace = true diff --git a/tools/vendor/anstream/LICENSE-APACHE b/tools/vendor/anstream/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/tools/vendor/anstream/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/tools/vendor/anstream/LICENSE-MIT b/tools/vendor/anstream/LICENSE-MIT new file mode 100644 index 0000000000..a2d01088b6 --- /dev/null +++ b/tools/vendor/anstream/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/vendor/anstream/README.md b/tools/vendor/anstream/README.md new file mode 100644 index 0000000000..508dc72ba5 --- /dev/null +++ b/tools/vendor/anstream/README.md @@ -0,0 +1,34 @@ +# anstream + +> A simple cross platform library for writing colored text to a terminal. + +*A portmanteau of "ansi stream"* + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/anstream.svg) +[![Crates Status](https://img.shields.io/crates/v/anstream.svg)](https://crates.io/crates/anstream) + +Specialized `stdout` and `stderr` that accept ANSI escape codes and adapt them +based on the terminal's capabilities. + +`anstream::adapter::strip_str` may also be of interest on its own for low +overhead stripping of ANSI escape codes. + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## [Contribute](../../CONTRIBUTING.md) + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual-licensed as above, without any additional terms or +conditions. + +[Crates.io]: https://crates.io/crates/anstream +[Documentation]: https://docs.rs/anstream diff --git a/tools/vendor/anstream/examples/dump-stream.rs b/tools/vendor/anstream/examples/dump-stream.rs new file mode 100644 index 0000000000..18bd2eb22f --- /dev/null +++ b/tools/vendor/anstream/examples/dump-stream.rs @@ -0,0 +1,130 @@ +//! Write colored text, adapting to the terminals capabilities + +use std::io::Write; + +fn main() -> Result<(), lexopt::Error> { + let args = Args::parse()?; + let stdout = anstream::stdout(); + let mut stdout = stdout.lock(); + + for fixed in 0..16 { + let color = anstyle::Ansi256Color(fixed) + .into_ansi() + .expect("within 4-bit color range"); + let style = style(color, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + if fixed == 7 || fixed == 15 { + let _ = writeln!(&mut stdout); + } + } + + for fixed in 16..232 { + let col = (fixed - 16) % 36; + if col == 0 { + let _ = writeln!(stdout); + } + let color = anstyle::Ansi256Color(fixed); + let style = style(color, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + let _ = writeln!(stdout); + let _ = writeln!(stdout); + for fixed in 232..=255 { + let color = anstyle::Ansi256Color(fixed); + let style = style(color, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + let _ = writeln!(stdout); + + Ok(()) +} + +fn style( + color: impl Into, + layer: Layer, + effects: anstyle::Effects, +) -> anstyle::Style { + let color = color.into(); + (match layer { + Layer::Fg => anstyle::Style::new().fg_color(Some(color)), + Layer::Bg => anstyle::Style::new().bg_color(Some(color)), + Layer::Underline => anstyle::Style::new().underline_color(Some(color)), + }) | effects +} + +fn print_number(stdout: &mut impl Write, fixed: u8, style: anstyle::Style) -> std::io::Result<()> { + write!(stdout, "{style}{fixed:>3X}{style:#}",) +} + +#[derive(Default)] +struct Args { + effects: anstyle::Effects, + layer: Layer, +} + +#[derive(Copy, Clone, Default)] +enum Layer { + #[default] + Fg, + Bg, + Underline, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("layer") => { + res.layer = args.value()?.parse_with(|s| match s { + "fg" => Ok(Layer::Fg), + "bg" => Ok(Layer::Bg), + "underline" => Ok(Layer::Underline), + _ => Err("expected values fg, bg, underline"), + })?; + } + Long("effect") => { + const EFFECTS: [(&str, anstyle::Effects); 12] = [ + ("bold", anstyle::Effects::BOLD), + ("dimmed", anstyle::Effects::DIMMED), + ("italic", anstyle::Effects::ITALIC), + ("underline", anstyle::Effects::UNDERLINE), + ("double_underline", anstyle::Effects::DOUBLE_UNDERLINE), + ("curly_underline", anstyle::Effects::CURLY_UNDERLINE), + ("dotted_underline", anstyle::Effects::DOTTED_UNDERLINE), + ("dashed_underline", anstyle::Effects::DASHED_UNDERLINE), + ("blink", anstyle::Effects::BLINK), + ("invert", anstyle::Effects::INVERT), + ("hidden", anstyle::Effects::HIDDEN), + ("strikethrough", anstyle::Effects::STRIKETHROUGH), + ]; + let effect = args.value()?.parse_with(|s| { + EFFECTS + .into_iter() + .find(|(name, _)| *name == s) + .map(|(_, effect)| effect) + .ok_or_else(|| { + format!( + "expected one of {}", + EFFECTS + .into_iter() + .map(|(n, _)| n) + .collect::>() + .join(", ") + ) + }) + })?; + res.effects = res.effects.insert(effect); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/tools/vendor/anstream/examples/query-stream.rs b/tools/vendor/anstream/examples/query-stream.rs new file mode 100644 index 0000000000..1c8670ecb1 --- /dev/null +++ b/tools/vendor/anstream/examples/query-stream.rs @@ -0,0 +1,22 @@ +//! Report a terminal's capabilities + +fn main() { + println!("stdout:"); + println!( + " choice: {:?}", + anstream::AutoStream::choice(&std::io::stdout()) + ); + println!( + " choice: {:?}", + anstream::AutoStream::auto(std::io::stdout()).current_choice() + ); + println!("stderr:"); + println!( + " choice: {:?}", + anstream::AutoStream::choice(&std::io::stderr()) + ); + println!( + " choice: {:?}", + anstream::AutoStream::auto(std::io::stderr()).current_choice() + ); +} diff --git a/tools/vendor/anstream/src/_macros.rs b/tools/vendor/anstream/src/_macros.rs new file mode 100644 index 0000000000..a1fa97d3b6 --- /dev/null +++ b/tools/vendor/anstream/src/_macros.rs @@ -0,0 +1,364 @@ +/// Prints to [`stdout`][crate::stdout]. +/// +/// Equivalent to the [`println!`] macro except that a newline is not printed at +/// the end of the message. +/// +/// Note that stdout is frequently line-buffered by default so it may be +/// necessary to use [`std::io::Write::flush()`] to ensure the output is emitted +/// immediately. +/// +/// **NOTE:** The `print!` macro will lock the standard output on each call. If you call +/// `print!` within a hot loop, this behavior may be the bottleneck of the loop. +/// To avoid this, lock stdout with [`AutoStream::lock`][crate::AutoStream::lock]: +/// ``` +/// # #[cfg(feature = "auto")] { +/// use std::io::Write as _; +/// +/// let mut lock = anstream::stdout().lock(); +/// write!(lock, "hello world").unwrap(); +/// # } +/// ``` +/// +/// Use `print!` only for the primary output of your program. Use +/// [`eprint!`] instead to print error and progress messages. +/// +/// **NOTE:** Not all `print!` calls will be captured in tests like [`std::print!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// +/// # Panics +/// +/// Panics if writing to `stdout` fails for any reason **except** broken pipe. +/// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "auto")] { +/// use std::io::Write as _; +/// use anstream::print; +/// use anstream::stdout; +/// +/// print!("this "); +/// print!("will "); +/// print!("be "); +/// print!("on "); +/// print!("the "); +/// print!("same "); +/// print!("line "); +/// +/// stdout().flush().unwrap(); +/// +/// print!("this string has a newline, why not choose println! instead?\n"); +/// +/// stdout().flush().unwrap(); +/// # } +/// ``` +#[cfg(feature = "auto")] +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => {{ + if cfg!(test) || $crate::_macros::FEATURE_TEST_ACTIVATED { + let target_stream = std::io::stdout(); + let buffer = $crate::_macros::to_adapted_string(&format_args!($($arg)*), &target_stream); + ::std::print!("{}", buffer) + } else { + use std::io::Write as _; + + let mut stream = $crate::stdout(); + match ::std::write!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stdout: {e}"); + } + Err(_) | Ok(_) => {} + } + } + }}; +} + +/// Prints to [`stdout`][crate::stdout], with a newline. +/// +/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone +/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)). +/// +/// This macro uses the same syntax as [`format!`], but writes to the standard output instead. +/// See [`std::fmt`] for more information. +/// +/// **NOTE:** The `println!` macro will lock the standard output on each call. If you call +/// `println!` within a hot loop, this behavior may be the bottleneck of the loop. +/// To avoid this, lock stdout with [`AutoStream::lock`][crate::AutoStream::lock]: +/// ``` +/// # #[cfg(feature = "auto")] { +/// use std::io::Write as _; +/// +/// let mut lock = anstream::stdout().lock(); +/// writeln!(lock, "hello world").unwrap(); +/// # } +/// ``` +/// +/// Use `println!` only for the primary output of your program. Use +/// [`eprintln!`] instead to print error and progress messages. +/// +/// **NOTE:** Not all `println!` calls will be captured in tests like [`std::println!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// +/// # Panics +/// +/// Panics if writing to `stdout` fails for any reason **except** broken pipe. +/// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "auto")] { +/// use anstream::println; +/// +/// println!(); // prints just a newline +/// println!("hello there!"); +/// println!("format {} arguments", "some"); +/// let local_variable = "some"; +/// println!("format {local_variable} arguments"); +/// # } +/// ``` +#[cfg(feature = "auto")] +#[macro_export] +macro_rules! println { + () => { + $crate::print!("\n") + }; + ($($arg:tt)*) => {{ + if cfg!(test) || $crate::_macros::FEATURE_TEST_ACTIVATED { + let target_stream = std::io::stdout(); + let buffer = $crate::_macros::to_adapted_string(&format_args!($($arg)*), &target_stream); + ::std::println!("{}", buffer) + } else { + use std::io::Write as _; + + let mut stream = $crate::stdout(); + match ::std::writeln!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stdout: {e}"); + } + Err(_) | Ok(_) => {} + } + } + }}; +} + +/// Prints to [`stderr`][crate::stderr]. +/// +/// Equivalent to the [`print!`] macro, except that output goes to +/// `stderr` instead of `stdout`. See [`print!`] for +/// example usage. +/// +/// Use `eprint!` only for error and progress messages. Use `print!` +/// instead for the primary output of your program. +/// +/// **NOTE:** Not all `eprint!` calls will be captured in tests like [`std::eprint!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// +/// # Panics +/// +/// Panics if writing to `stderr` fails for any reason **except** broken pipe. +/// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "auto")] { +/// use anstream::eprint; +/// +/// eprint!("Error: Could not complete task"); +/// # } +/// ``` +#[cfg(feature = "auto")] +#[macro_export] +macro_rules! eprint { + ($($arg:tt)*) => {{ + if cfg!(test) || $crate::_macros::FEATURE_TEST_ACTIVATED { + let target_stream = std::io::stderr(); + let buffer = $crate::_macros::to_adapted_string(&format_args!($($arg)*), &target_stream); + ::std::eprint!("{}", buffer) + } else { + use std::io::Write as _; + + let mut stream = $crate::stderr(); + match ::std::write!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stderr: {e}"); + } + Err(_) | Ok(_) => {} + } + } + }}; +} + +/// Prints to [`stderr`][crate::stderr], with a newline. +/// +/// Equivalent to the [`println!`] macro, except that output goes to +/// `stderr` instead of `stdout`. See [`println!`] for +/// example usage. +/// +/// Use `eprintln!` only for error and progress messages. Use `println!` +/// instead for the primary output of your program. +/// +/// **NOTE:** Not all `eprintln!` calls will be captured in tests like [`std::eprintln!`] +/// - Capturing will automatically be activated in test binaries +/// - Otherwise, only when the `test` feature is enabled +/// +/// # Panics +/// +/// Panics if writing to `stderr` fails for any reason **except** broken pipe. +/// +/// Writing to non-blocking stdout can cause an error, which will lead +/// this macro to panic. +/// +/// # Examples +/// +/// ``` +/// # #[cfg(feature = "auto")] { +/// use anstream::eprintln; +/// +/// eprintln!("Error: Could not complete task"); +/// # } +/// ``` +#[cfg(feature = "auto")] +#[macro_export] +macro_rules! eprintln { + () => { + $crate::eprint!("\n") + }; + ($($arg:tt)*) => {{ + if cfg!(test) || $crate::_macros::FEATURE_TEST_ACTIVATED { + let target_stream = std::io::stderr(); + let buffer = $crate::_macros::to_adapted_string(&format_args!($($arg)*), &target_stream); + ::std::eprintln!("{}", buffer) + } else { + use std::io::Write as _; + + let mut stream = $crate::stderr(); + match ::std::writeln!(&mut stream, $($arg)*) { + Err(e) if e.kind() != ::std::io::ErrorKind::BrokenPipe => { + ::std::panic!("failed printing to stderr: {e}"); + } + Err(_) | Ok(_) => {} + } + } + }}; +} + +/// Panics the current thread. +/// +/// This allows a program to terminate immediately and provide feedback +/// to the caller of the program. +/// +/// This macro is the perfect way to assert conditions in example code and in +/// tests. `panic!` is closely tied with the `unwrap` method of both +/// [`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call +/// `panic!` when they are set to [`None`] or [`Err`] variants. +/// +/// When using `panic!()` you can specify a string payload, that is built using +/// the [`format!`] syntax. That payload is used when injecting the panic into +/// the calling Rust thread, causing the thread to panic entirely. +/// +/// The behavior of the default `std` hook, i.e. the code that runs directly +/// after the panic is invoked, is to print the message payload to +/// `stderr` along with the file/line/column information of the `panic!()` +/// call. You can override the panic hook using [`std::panic::set_hook()`]. +/// Inside the hook a panic can be accessed as a `&dyn Any + Send`, +/// which contains either a `&str` or `String` for regular `panic!()` invocations. +/// To panic with a value of another other type, [`panic_any`] can be used. +/// +/// See also the macro [`compile_error!`], for raising errors during compilation. +/// +/// # When to use `panic!` vs `Result` +/// +/// The Rust language provides two complementary systems for constructing / +/// representing, reporting, propagating, reacting to, and discarding errors. These +/// responsibilities are collectively known as "error handling." `panic!` and +/// `Result` are similar in that they are each the primary interface of their +/// respective error handling systems; however, the meaning these interfaces attach +/// to their errors and the responsibilities they fulfill within their respective +/// error handling systems differ. +/// +/// The `panic!` macro is used to construct errors that represent a bug that has +/// been detected in your program. With `panic!` you provide a message that +/// describes the bug and the language then constructs an error with that message, +/// reports it, and propagates it for you. +/// +/// `Result` on the other hand is used to wrap other types that represent either +/// the successful result of some computation, `Ok(T)`, or error types that +/// represent an anticipated runtime failure mode of that computation, `Err(E)`. +/// `Result` is used alongside user defined types which represent the various +/// anticipated runtime failure modes that the associated computation could +/// encounter. `Result` must be propagated manually, often with the help of the +/// `?` operator and `Try` trait, and they must be reported manually, often with +/// the help of the `Error` trait. +/// +/// For more detailed information about error handling check out the [book] or the +/// [`std::result`] module docs. +/// +/// [ounwrap]: Option::unwrap +/// [runwrap]: Result::unwrap +/// [`std::panic::set_hook()`]: ../std/panic/fn.set_hook.html +/// [`panic_any`]: ../std/panic/fn.panic_any.html +/// [`Box`]: ../std/boxed/struct.Box.html +/// [`format!`]: ../std/macro.format.html +/// [book]: ../book/ch09-00-error-handling.html +/// [`std::result`]: ../std/result/index.html +/// +/// # Current implementation +/// +/// If the main thread panics it will terminate all your threads and end your +/// program with code `101`. +/// +/// # Examples +/// +/// ```should_panic +/// # #![allow(unreachable_code)] +/// use anstream::panic; +/// panic!(); +/// panic!("this is a terrible mistake!"); +/// panic!("this is a {} {message}", "fancy", message = "message"); +/// ``` +#[cfg(feature = "auto")] +#[macro_export] +macro_rules! panic { + () => { + ::std::panic!() + }; + ($($arg:tt)*) => {{ + let target_stream = std::io::stderr(); + let buffer = $crate::_macros::to_adapted_string(&format_args!($($arg)*), &target_stream); + ::std::panic!("{}", buffer) + }}; +} + +#[cfg(feature = "auto")] +pub const FEATURE_TEST_ACTIVATED: bool = cfg!(feature = "test"); + +#[cfg(feature = "auto")] +pub fn to_adapted_string( + display: &dyn std::fmt::Display, + stream: &impl crate::stream::RawStream, +) -> String { + use std::io::Write as _; + + let choice = crate::AutoStream::choice(stream); + let buffer = Vec::new(); + let mut stream = crate::AutoStream::new(buffer, choice); + // Ignore errors rather than panic + let _ = ::std::write!(&mut stream, "{display}"); + let buffer = stream.into_inner(); + // Should be UTF-8 but not wanting to panic + let buffer = String::from_utf8_lossy(&buffer).into_owned(); + buffer +} diff --git a/tools/vendor/anstream/src/adapter/mod.rs b/tools/vendor/anstream/src/adapter/mod.rs new file mode 100644 index 0000000000..f266b68055 --- /dev/null +++ b/tools/vendor/anstream/src/adapter/mod.rs @@ -0,0 +1,15 @@ +//! Gracefully degrade styled output + +mod strip; +mod wincon; + +pub use strip::strip_bytes; +pub use strip::strip_str; +pub use strip::StripBytes; +pub use strip::StripBytesIter; +pub use strip::StripStr; +pub use strip::StripStrIter; +pub use strip::StrippedBytes; +pub use strip::StrippedStr; +pub use wincon::WinconBytes; +pub use wincon::WinconBytesIter; diff --git a/tools/vendor/anstream/src/adapter/strip.rs b/tools/vendor/anstream/src/adapter/strip.rs new file mode 100644 index 0000000000..dca414bbc4 --- /dev/null +++ b/tools/vendor/anstream/src/adapter/strip.rs @@ -0,0 +1,511 @@ +use anstyle_parse::state::state_change; +use anstyle_parse::state::Action; +use anstyle_parse::state::State; + +/// Strip ANSI escapes from a `&str`, returning the printable content +/// +/// This can be used to take output from a program that includes escape sequences and write it +/// somewhere that does not easily support them, such as a log file. +/// +/// For non-contiguous data, see [`StripStr`]. +/// +/// # Example +/// +/// ```rust +/// use std::io::Write as _; +/// +/// let styled_text = "\x1b[32mfoo\x1b[m bar"; +/// let plain_str = anstream::adapter::strip_str(&styled_text).to_string(); +/// assert_eq!(plain_str, "foo bar"); +/// ``` +#[inline] +pub fn strip_str(data: &str) -> StrippedStr<'_> { + StrippedStr::new(data) +} + +/// See [`strip_str`] +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct StrippedStr<'s> { + bytes: &'s [u8], + state: State, +} + +impl<'s> StrippedStr<'s> { + #[inline] + fn new(data: &'s str) -> Self { + Self { + bytes: data.as_bytes(), + state: State::Ground, + } + } + + /// Create a [`String`] of the printable content + #[inline] + #[allow(clippy::inherent_to_string_shadow_display)] // Single-allocation implementation + pub fn to_string(&self) -> String { + use std::fmt::Write as _; + let mut stripped = String::with_capacity(self.bytes.len()); + let _ = write!(&mut stripped, "{self}"); + stripped + } +} + +impl std::fmt::Display for StrippedStr<'_> { + /// **Note:** this does *not* exhaust the [`Iterator`] + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let iter = Self { + bytes: self.bytes, + state: self.state, + }; + for printable in iter { + printable.fmt(f)?; + } + Ok(()) + } +} + +impl<'s> Iterator for StrippedStr<'s> { + type Item = &'s str; + + #[inline] + fn next(&mut self) -> Option { + next_str(&mut self.bytes, &mut self.state) + } +} + +/// Incrementally strip non-contiguous data +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct StripStr { + state: State, +} + +impl StripStr { + /// Initial state + pub fn new() -> Self { + Default::default() + } + + /// Strip the next segment of data + pub fn strip_next<'s>(&'s mut self, data: &'s str) -> StripStrIter<'s> { + StripStrIter { + bytes: data.as_bytes(), + state: &mut self.state, + } + } +} + +/// See [`StripStr`] +#[derive(Debug, PartialEq, Eq)] +pub struct StripStrIter<'s> { + bytes: &'s [u8], + state: &'s mut State, +} + +impl<'s> Iterator for StripStrIter<'s> { + type Item = &'s str; + + #[inline] + fn next(&mut self) -> Option { + next_str(&mut self.bytes, self.state) + } +} + +#[inline] +fn next_str<'s>(bytes: &mut &'s [u8], state: &mut State) -> Option<&'s str> { + let offset = bytes.iter().copied().position(|b| { + let (next_state, action) = state_change(*state, b); + if next_state != State::Anywhere { + *state = next_state; + } + is_printable_bytes(action, b) + }); + let (_, next) = bytes.split_at(offset.unwrap_or(bytes.len())); + *bytes = next; + *state = State::Ground; + + let offset = bytes.iter().copied().position(|b| { + let (_next_state, action) = state_change(State::Ground, b); + !(is_printable_bytes(action, b) || is_utf8_continuation(b)) + }); + let (printable, next) = bytes.split_at(offset.unwrap_or(bytes.len())); + *bytes = next; + if printable.is_empty() { + None + } else { + let printable = unsafe { + from_utf8_unchecked( + printable, + "`bytes` was validated as UTF-8, the parser preserves UTF-8 continuations", + ) + }; + Some(printable) + } +} + +#[inline] +unsafe fn from_utf8_unchecked<'b>(bytes: &'b [u8], safety_justification: &'static str) -> &'b str { + unsafe { + if cfg!(debug_assertions) { + // Catch problems more quickly when testing + std::str::from_utf8(bytes).expect(safety_justification) + } else { + std::str::from_utf8_unchecked(bytes) + } + } +} + +#[inline] +fn is_utf8_continuation(b: u8) -> bool { + matches!(b, 0x80..=0xbf) +} + +/// Strip ANSI escapes from bytes, returning the printable content +/// +/// This can be used to take output from a program that includes escape sequences and write it +/// somewhere that does not easily support them, such as a log file. +/// +/// # Example +/// +/// ```rust +/// use std::io::Write as _; +/// +/// let styled_text = "\x1b[32mfoo\x1b[m bar"; +/// let plain_str = anstream::adapter::strip_bytes(styled_text.as_bytes()).into_vec(); +/// assert_eq!(plain_str.as_slice(), &b"foo bar"[..]); +/// ``` +#[inline] +pub fn strip_bytes(data: &[u8]) -> StrippedBytes<'_> { + StrippedBytes::new(data) +} + +/// See [`strip_bytes`] +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct StrippedBytes<'s> { + bytes: &'s [u8], + state: State, + utf8parser: Utf8Parser, +} + +impl<'s> StrippedBytes<'s> { + /// See [`strip_bytes`] + #[inline] + pub fn new(bytes: &'s [u8]) -> Self { + Self { + bytes, + state: State::Ground, + utf8parser: Default::default(), + } + } + + /// Strip the next slice of bytes + /// + /// Used when the content is in several non-contiguous slices + /// + /// # Panic + /// + /// May panic if it is not exhausted / empty + #[inline] + pub fn extend(&mut self, bytes: &'s [u8]) { + debug_assert!( + self.is_empty(), + "current bytes must be processed to ensure we end at the right state" + ); + self.bytes = bytes; + } + + /// Report the bytes has been exhausted + #[inline] + pub fn is_empty(&self) -> bool { + self.bytes.is_empty() + } + + /// Create a [`Vec`] of the printable content + #[inline] + pub fn into_vec(self) -> Vec { + let mut stripped = Vec::with_capacity(self.bytes.len()); + for printable in self { + stripped.extend(printable); + } + stripped + } +} + +impl<'s> Iterator for StrippedBytes<'s> { + type Item = &'s [u8]; + + #[inline] + fn next(&mut self) -> Option { + next_bytes(&mut self.bytes, &mut self.state, &mut self.utf8parser) + } +} + +/// Incrementally strip non-contiguous data +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct StripBytes { + state: State, + utf8parser: Utf8Parser, +} + +impl StripBytes { + /// Initial state + pub fn new() -> Self { + Default::default() + } + + /// Strip the next segment of data + pub fn strip_next<'s>(&'s mut self, bytes: &'s [u8]) -> StripBytesIter<'s> { + StripBytesIter { + bytes, + state: &mut self.state, + utf8parser: &mut self.utf8parser, + } + } +} + +/// See [`StripBytes`] +#[derive(Debug, PartialEq, Eq)] +pub struct StripBytesIter<'s> { + bytes: &'s [u8], + state: &'s mut State, + utf8parser: &'s mut Utf8Parser, +} + +impl<'s> Iterator for StripBytesIter<'s> { + type Item = &'s [u8]; + + #[inline] + fn next(&mut self) -> Option { + next_bytes(&mut self.bytes, self.state, self.utf8parser) + } +} + +#[inline] +fn next_bytes<'s>( + bytes: &mut &'s [u8], + state: &mut State, + utf8parser: &mut Utf8Parser, +) -> Option<&'s [u8]> { + let offset = bytes.iter().copied().position(|b| { + if *state == State::Utf8 { + true + } else { + let (next_state, action) = state_change(*state, b); + if next_state != State::Anywhere { + *state = next_state; + } + is_printable_bytes(action, b) + } + }); + let (_, next) = bytes.split_at(offset.unwrap_or(bytes.len())); + *bytes = next; + + let offset = bytes.iter().copied().position(|b| { + if *state == State::Utf8 { + if utf8parser.add(b) { + *state = State::Ground; + } + false + } else { + let (next_state, action) = state_change(State::Ground, b); + if next_state != State::Anywhere { + *state = next_state; + } + if *state == State::Utf8 { + utf8parser.add(b); + false + } else { + !is_printable_bytes(action, b) + } + } + }); + let (printable, next) = bytes.split_at(offset.unwrap_or(bytes.len())); + *bytes = next; + if printable.is_empty() { + None + } else { + Some(printable) + } +} + +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub(crate) struct Utf8Parser { + utf8_parser: utf8parse::Parser, +} + +impl Utf8Parser { + fn add(&mut self, byte: u8) -> bool { + let mut b = false; + let mut receiver = VtUtf8Receiver(&mut b); + self.utf8_parser.advance(&mut receiver, byte); + b + } +} + +struct VtUtf8Receiver<'a>(&'a mut bool); + +impl utf8parse::Receiver for VtUtf8Receiver<'_> { + fn codepoint(&mut self, _: char) { + *self.0 = true; + } + + fn invalid_sequence(&mut self) { + *self.0 = true; + } +} + +#[inline] +fn is_printable_bytes(action: Action, byte: u8) -> bool { + // VT320 considered 0x7f to be `Print`able but we expect to be working in UTF-8 systems and not + // ISO Latin-1, making it DEL and non-printable + const DEL: u8 = 0x7f; + + // Continuations aren't included as they may also be control codes, requiring more context + (action == Action::Print && byte != DEL) + || action == Action::BeginUtf8 + || (action == Action::Execute && byte.is_ascii_whitespace()) +} + +#[cfg(test)] +mod test { + use super::*; + use proptest::prelude::*; + + /// Model based off full parser + fn parser_strip(bytes: &[u8]) -> String { + #[derive(Default)] + struct Strip(String); + impl Strip { + fn with_capacity(capacity: usize) -> Self { + Self(String::with_capacity(capacity)) + } + } + impl anstyle_parse::Perform for Strip { + fn print(&mut self, c: char) { + self.0.push(c); + } + + fn execute(&mut self, byte: u8) { + if byte.is_ascii_whitespace() { + self.0.push(byte as char); + } + } + } + + let mut stripped = Strip::with_capacity(bytes.len()); + let mut parser = anstyle_parse::Parser::::new(); + for byte in bytes { + parser.advance(&mut stripped, *byte); + } + stripped.0 + } + + /// Model verifying incremental parsing + fn strip_char(mut s: &str) -> String { + let mut result = String::new(); + let mut state = StripStr::new(); + while !s.is_empty() { + let mut indices = s.char_indices(); + indices.next(); // current + let offset = indices.next().map(|(i, _)| i).unwrap_or_else(|| s.len()); + let (current, remainder) = s.split_at(offset); + for printable in state.strip_next(current) { + result.push_str(printable); + } + s = remainder; + } + result + } + + /// Model verifying incremental parsing + fn strip_byte(s: &[u8]) -> Vec { + let mut result = Vec::new(); + let mut state = StripBytes::default(); + for start in 0..s.len() { + let current = &s[start..=start]; + for printable in state.strip_next(current) { + result.extend(printable); + } + } + result + } + + #[test] + fn test_strip_bytes_multibyte() { + let bytes = [240, 145, 141, 139]; + let expected = parser_strip(&bytes); + let actual = String::from_utf8(strip_bytes(&bytes).into_vec()).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + fn test_strip_byte_multibyte() { + let bytes = [240, 145, 141, 139]; + let expected = parser_strip(&bytes); + let actual = String::from_utf8(strip_byte(&bytes).clone()).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + fn test_strip_str_del() { + let input = std::str::from_utf8(&[0x7f]).unwrap(); + let expected = ""; + let actual = strip_str(input).to_string(); + assert_eq!(expected, actual); + } + + #[test] + fn test_strip_byte_del() { + let bytes = [0x7f]; + let expected = ""; + let actual = String::from_utf8(strip_byte(&bytes).clone()).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + fn test_strip_str_handles_broken_sequence() { + // valid utf8: \xc3\xb6 then \x1b then \xf0\x9f\x98\x80 + let s = "ö\x1b😀hello😀goodbye"; + let mut it = strip_str(s); + assert_eq!("ö", it.next().unwrap()); + assert_eq!("ello😀goodbye", it.next().unwrap()); + } + + proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn strip_str_no_escapes(s in "\\PC*") { + let expected = parser_strip(s.as_bytes()); + let actual = strip_str(&s).to_string(); + assert_eq!(expected, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn strip_char_no_escapes(s in "\\PC*") { + let expected = parser_strip(s.as_bytes()); + let actual = strip_char(&s); + assert_eq!(expected, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn strip_bytes_no_escapes(s in "\\PC*") { + dbg!(&s); + dbg!(s.as_bytes()); + let expected = parser_strip(s.as_bytes()); + let actual = String::from_utf8(strip_bytes(s.as_bytes()).into_vec()).unwrap(); + assert_eq!(expected, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn strip_byte_no_escapes(s in "\\PC*") { + dbg!(&s); + dbg!(s.as_bytes()); + let expected = parser_strip(s.as_bytes()); + let actual = String::from_utf8(strip_byte(s.as_bytes()).clone()).unwrap(); + assert_eq!(expected, actual); + } + } +} diff --git a/tools/vendor/anstream/src/adapter/wincon.rs b/tools/vendor/anstream/src/adapter/wincon.rs new file mode 100644 index 0000000000..c211491983 --- /dev/null +++ b/tools/vendor/anstream/src/adapter/wincon.rs @@ -0,0 +1,378 @@ +/// Incrementally convert to wincon calls for non-contiguous data +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct WinconBytes { + parser: anstyle_parse::Parser, + capture: WinconCapture, +} + +impl WinconBytes { + /// Initial state + pub fn new() -> Self { + Default::default() + } + + /// Strip the next segment of data + pub fn extract_next<'s>(&'s mut self, bytes: &'s [u8]) -> WinconBytesIter<'s> { + self.capture.reset(); + self.capture.printable.reserve(bytes.len()); + WinconBytesIter { + bytes, + parser: &mut self.parser, + capture: &mut self.capture, + } + } +} + +/// See [`WinconBytes`] +#[derive(Debug, PartialEq, Eq)] +pub struct WinconBytesIter<'s> { + bytes: &'s [u8], + parser: &'s mut anstyle_parse::Parser, + capture: &'s mut WinconCapture, +} + +impl Iterator for WinconBytesIter<'_> { + type Item = (anstyle::Style, String); + + #[inline] + fn next(&mut self) -> Option { + next_bytes(&mut self.bytes, self.parser, self.capture) + } +} + +#[inline] +fn next_bytes( + bytes: &mut &[u8], + parser: &mut anstyle_parse::Parser, + capture: &mut WinconCapture, +) -> Option<(anstyle::Style, String)> { + capture.reset(); + while capture.ready.is_none() { + let byte = if let Some((byte, remainder)) = (*bytes).split_first() { + *bytes = remainder; + *byte + } else { + break; + }; + parser.advance(capture, byte); + } + if capture.printable.is_empty() { + return None; + } + + let style = capture.ready.unwrap_or(capture.style); + Some((style, std::mem::take(&mut capture.printable))) +} + +#[derive(Default, Clone, Debug, PartialEq, Eq)] +struct WinconCapture { + style: anstyle::Style, + printable: String, + ready: Option, +} + +impl WinconCapture { + fn reset(&mut self) { + self.ready = None; + } +} + +impl anstyle_parse::Perform for WinconCapture { + /// Draw a character to the screen and update states. + fn print(&mut self, c: char) { + self.printable.push(c); + } + + /// Execute a C0 or C1 control function. + fn execute(&mut self, byte: u8) { + if byte.is_ascii_whitespace() { + self.printable.push(byte as char); + } + } + + fn csi_dispatch( + &mut self, + params: &anstyle_parse::Params, + _intermediates: &[u8], + ignore: bool, + action: u8, + ) { + if ignore { + return; + } + if action != b'm' { + return; + } + + let mut style = self.style; + // param/value differences are dependent on the escape code + let mut state = CsiState::Normal; + let mut r = None; + let mut g = None; + let mut color_target = ColorTarget::Fg; + for param in params { + for value in param { + match (state, *value) { + (CsiState::Normal, 0) => { + style = anstyle::Style::default(); + break; + } + (CsiState::Normal, 1) => { + style = style.bold(); + break; + } + (CsiState::Normal, 2) => { + style = style.dimmed(); + break; + } + (CsiState::Normal, 3) => { + style = style.italic(); + break; + } + (CsiState::Normal, 4) => { + style = style.underline(); + state = CsiState::Underline; + } + (CsiState::Normal, 21) => { + style |= anstyle::Effects::DOUBLE_UNDERLINE; + break; + } + (CsiState::Normal, 7) => { + style = style.invert(); + break; + } + (CsiState::Normal, 8) => { + style = style.hidden(); + break; + } + (CsiState::Normal, 9) => { + style = style.strikethrough(); + break; + } + (CsiState::Normal, 30..=37) => { + let color = to_ansi_color(value - 30).expect("within 4-bit range"); + style = style.fg_color(Some(color.into())); + break; + } + (CsiState::Normal, 38) => { + color_target = ColorTarget::Fg; + state = CsiState::PrepareCustomColor; + } + (CsiState::Normal, 39) => { + style = style.fg_color(None); + break; + } + (CsiState::Normal, 40..=47) => { + let color = to_ansi_color(value - 40).expect("within 4-bit range"); + style = style.bg_color(Some(color.into())); + break; + } + (CsiState::Normal, 48) => { + color_target = ColorTarget::Bg; + state = CsiState::PrepareCustomColor; + } + (CsiState::Normal, 49) => { + style = style.bg_color(None); + break; + } + (CsiState::Normal, 58) => { + color_target = ColorTarget::Underline; + state = CsiState::PrepareCustomColor; + } + (CsiState::Normal, 90..=97) => { + let color = to_ansi_color(value - 90) + .expect("within 4-bit range") + .bright(true); + style = style.fg_color(Some(color.into())); + break; + } + (CsiState::Normal, 100..=107) => { + let color = to_ansi_color(value - 100) + .expect("within 4-bit range") + .bright(true); + style = style.bg_color(Some(color.into())); + break; + } + (CsiState::PrepareCustomColor, 5) => { + state = CsiState::Ansi256; + } + (CsiState::PrepareCustomColor, 2) => { + state = CsiState::Rgb; + r = None; + g = None; + } + (CsiState::Ansi256, n) => { + let color = anstyle::Ansi256Color(n as u8); + style = match color_target { + ColorTarget::Fg => style.fg_color(Some(color.into())), + ColorTarget::Bg => style.bg_color(Some(color.into())), + ColorTarget::Underline => style.underline_color(Some(color.into())), + }; + break; + } + (CsiState::Rgb, b) => match (r, g) { + (None, _) => { + r = Some(b); + } + (Some(_), None) => { + g = Some(b); + } + (Some(r), Some(g)) => { + let color = anstyle::RgbColor(r as u8, g as u8, b as u8); + style = match color_target { + ColorTarget::Fg => style.fg_color(Some(color.into())), + ColorTarget::Bg => style.bg_color(Some(color.into())), + ColorTarget::Underline => style.underline_color(Some(color.into())), + }; + break; + } + }, + (CsiState::Underline, 0) => { + style = + style.effects(style.get_effects().remove(anstyle::Effects::UNDERLINE)); + } + (CsiState::Underline, 1) => { + // underline already set + } + (CsiState::Underline, 2) => { + style = style + .effects(style.get_effects().remove(anstyle::Effects::UNDERLINE)) + | anstyle::Effects::DOUBLE_UNDERLINE; + } + (CsiState::Underline, 3) => { + style = style + .effects(style.get_effects().remove(anstyle::Effects::UNDERLINE)) + | anstyle::Effects::CURLY_UNDERLINE; + } + (CsiState::Underline, 4) => { + style = style + .effects(style.get_effects().remove(anstyle::Effects::UNDERLINE)) + | anstyle::Effects::DOTTED_UNDERLINE; + } + (CsiState::Underline, 5) => { + style = style + .effects(style.get_effects().remove(anstyle::Effects::UNDERLINE)) + | anstyle::Effects::DASHED_UNDERLINE; + } + _ => { + break; + } + } + } + } + + if style != self.style && !self.printable.is_empty() { + self.ready = Some(self.style); + } + self.style = style; + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum CsiState { + Normal, + PrepareCustomColor, + Ansi256, + Rgb, + Underline, +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum ColorTarget { + Fg, + Bg, + Underline, +} + +fn to_ansi_color(digit: u16) -> Option { + match digit { + 0 => Some(anstyle::AnsiColor::Black), + 1 => Some(anstyle::AnsiColor::Red), + 2 => Some(anstyle::AnsiColor::Green), + 3 => Some(anstyle::AnsiColor::Yellow), + 4 => Some(anstyle::AnsiColor::Blue), + 5 => Some(anstyle::AnsiColor::Magenta), + 6 => Some(anstyle::AnsiColor::Cyan), + 7 => Some(anstyle::AnsiColor::White), + _ => None, + } +} + +#[cfg(test)] +mod test { + use super::*; + use proptest::prelude::*; + + #[track_caller] + fn verify(input: &str, expected: Vec<(anstyle::Style, &str)>) { + let expected = expected + .into_iter() + .map(|(style, value)| (style, value.to_owned())) + .collect::>(); + let mut state = WinconBytes::new(); + let actual = state.extract_next(input.as_bytes()).collect::>(); + assert_eq!(expected, actual, "{input:?}"); + } + + #[test] + fn start() { + let green_on_red = anstyle::AnsiColor::Green.on(anstyle::AnsiColor::Red); + let input = format!("{green_on_red}Hello{green_on_red:#} world!"); + let expected = vec![ + (green_on_red, "Hello"), + (anstyle::Style::default(), " world!"), + ]; + verify(&input, expected); + } + + #[test] + fn middle() { + let green_on_red = anstyle::AnsiColor::Green.on(anstyle::AnsiColor::Red); + let input = format!("Hello {green_on_red}world{green_on_red:#}!"); + let expected = vec![ + (anstyle::Style::default(), "Hello "), + (green_on_red, "world"), + (anstyle::Style::default(), "!"), + ]; + verify(&input, expected); + } + + #[test] + fn end() { + let green_on_red = anstyle::AnsiColor::Green.on(anstyle::AnsiColor::Red); + let input = format!("Hello {green_on_red}world!{green_on_red:#}"); + let expected = vec![ + (anstyle::Style::default(), "Hello "), + (green_on_red, "world!"), + ]; + verify(&input, expected); + } + + #[test] + fn ansi256_colors() { + let ansi_11 = anstyle::Ansi256Color(11).on_default(); + // termcolor only supports "brights" via these + let input = format!("Hello {ansi_11}world{ansi_11:#}!"); + let expected = vec![ + (anstyle::Style::default(), "Hello "), + (ansi_11, "world"), + (anstyle::Style::default(), "!"), + ]; + verify(&input, expected); + } + + proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn wincon_no_escapes(s in "\\PC*") { + let expected = if s.is_empty() { + vec![] + } else { + vec![(anstyle::Style::default(), s.clone())] + }; + let mut state = WinconBytes::new(); + let actual = state.extract_next(s.as_bytes()).collect::>(); + assert_eq!(expected, actual); + } + } +} diff --git a/tools/vendor/anstream/src/auto.rs b/tools/vendor/anstream/src/auto.rs new file mode 100644 index 0000000000..16c995d0a5 --- /dev/null +++ b/tools/vendor/anstream/src/auto.rs @@ -0,0 +1,313 @@ +use crate::stream::AsLockedWrite; +use crate::stream::RawStream; +use crate::ColorChoice; +use crate::StripStream; +#[cfg(all(windows, feature = "wincon"))] +use crate::WinconStream; + +/// [`std::io::Write`] that adapts ANSI escape codes to the underlying `Write`s capabilities +/// +/// This includes +/// - Stripping colors for non-terminals +/// - Respecting env variables like [NO_COLOR](https://no-color.org/) or [CLICOLOR](https://bixense.com/clicolors/) +/// - *(windows)* Falling back to the wincon API where [ENABLE_VIRTUAL_TERMINAL_PROCESSING](https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#output-sequences) is unsupported +/// +/// You can customize auto-detection by calling into +/// [anstyle_query](https://docs.rs/anstyle-query/latest/anstyle_query/) +/// to get a [`ColorChoice`] and then calling [`AutoStream::new(stream, choice)`]. +#[derive(Debug)] +pub struct AutoStream { + inner: StreamInner, +} + +#[derive(Debug)] +enum StreamInner { + PassThrough(S), + Strip(StripStream), + #[cfg(all(windows, feature = "wincon"))] + Wincon(WinconStream), +} + +impl AutoStream +where + S: RawStream, +{ + /// Runtime control over styling behavior + /// + /// # Example + /// + /// ```rust + /// # #[cfg(feature = "auto")] { + /// # use std::io::IsTerminal as _; + /// // Like `AutoStream::choice` but without `NO_COLOR`, `CLICOLOR_FORCE`, `CI` + /// fn choice(raw: &dyn anstream::stream::RawStream) -> anstream::ColorChoice { + /// let choice = anstream::ColorChoice::global(); + /// if choice == anstream::ColorChoice::Auto { + /// if raw.is_terminal() && anstyle_query::term_supports_color() { + /// anstream::ColorChoice::Always + /// } else { + /// anstream::ColorChoice::Never + /// } + /// } else { + /// choice + /// } + /// } + /// + /// let stream = std::io::stdout(); + /// let choice = choice(&stream); + /// let auto = anstream::AutoStream::new(stream, choice); + /// # } + /// ``` + #[inline] + pub fn new(raw: S, choice: ColorChoice) -> Self { + match choice { + #[cfg(feature = "auto")] + ColorChoice::Auto => Self::auto(raw), + #[cfg(not(feature = "auto"))] + ColorChoice::Auto => Self::never(raw), + ColorChoice::AlwaysAnsi => Self::always_ansi(raw), + ColorChoice::Always => Self::always(raw), + ColorChoice::Never => Self::never(raw), + } + } + + /// Auto-adapt for the stream's capabilities + #[cfg(feature = "auto")] + #[inline] + pub fn auto(raw: S) -> Self { + let choice = Self::choice(&raw); + debug_assert_ne!(choice, ColorChoice::Auto); + Self::new(raw, choice) + } + + /// Report the desired choice for the given stream + #[cfg(feature = "auto")] + pub fn choice(raw: &S) -> ColorChoice { + choice(raw) + } + + /// Force ANSI escape codes to be passed through as-is, no matter what the inner `Write` + /// supports. + #[inline] + pub fn always_ansi(raw: S) -> Self { + #[cfg(feature = "auto")] + { + if raw.is_terminal() { + let _ = anstyle_query::windows::enable_ansi_colors(); + } + } + Self::always_ansi_(raw) + } + + #[inline] + fn always_ansi_(raw: S) -> Self { + let inner = StreamInner::PassThrough(raw); + AutoStream { inner } + } + + /// Force color, no matter what the inner `Write` supports. + #[inline] + pub fn always(raw: S) -> Self { + if cfg!(windows) { + #[cfg(feature = "auto")] + let use_wincon = raw.is_terminal() + && !anstyle_query::windows::enable_ansi_colors().unwrap_or(true) + && !anstyle_query::term_supports_ansi_color(); + #[cfg(not(feature = "auto"))] + let use_wincon = true; + if use_wincon { + Self::wincon(raw).unwrap_or_else(|raw| Self::always_ansi_(raw)) + } else { + Self::always_ansi_(raw) + } + } else { + Self::always_ansi(raw) + } + } + + /// Only pass printable data to the inner `Write`. + #[inline] + pub fn never(raw: S) -> Self { + let inner = StreamInner::Strip(StripStream::new(raw)); + AutoStream { inner } + } + + #[inline] + fn wincon(raw: S) -> Result { + #[cfg(all(windows, feature = "wincon"))] + { + Ok(Self { + inner: StreamInner::Wincon(WinconStream::new(raw)), + }) + } + #[cfg(not(all(windows, feature = "wincon")))] + { + Err(raw) + } + } + + /// Get the wrapped [`RawStream`] + #[inline] + pub fn into_inner(self) -> S { + match self.inner { + StreamInner::PassThrough(w) => w, + StreamInner::Strip(w) => w.into_inner(), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.into_inner(), + } + } + + /// Get the wrapped [`RawStream`] + #[inline] + pub fn as_inner(&self) -> &S { + match &self.inner { + StreamInner::PassThrough(w) => w, + StreamInner::Strip(w) => w.as_inner(), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.as_inner(), + } + } + + /// Returns `true` if the descriptor/handle refers to a terminal/tty. + #[inline] + pub fn is_terminal(&self) -> bool { + match &self.inner { + StreamInner::PassThrough(w) => w.is_terminal(), + StreamInner::Strip(w) => w.is_terminal(), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(_) => true, // its only ever a terminal + } + } + + /// Prefer [`AutoStream::choice`] + /// + /// This doesn't report what is requested but what is currently active. + #[inline] + #[cfg(feature = "auto")] + pub fn current_choice(&self) -> ColorChoice { + match &self.inner { + StreamInner::PassThrough(_) => ColorChoice::AlwaysAnsi, + StreamInner::Strip(_) => ColorChoice::Never, + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(_) => ColorChoice::Always, + } + } +} + +#[cfg(feature = "auto")] +fn choice(raw: &dyn RawStream) -> ColorChoice { + let choice = ColorChoice::global(); + match choice { + ColorChoice::Auto => { + let clicolor = anstyle_query::clicolor(); + let clicolor_enabled = clicolor.unwrap_or(false); + let clicolor_disabled = !clicolor.unwrap_or(true); + if anstyle_query::no_color() { + ColorChoice::Never + } else if anstyle_query::clicolor_force() { + ColorChoice::Always + } else if clicolor_disabled { + ColorChoice::Never + } else if raw.is_terminal() + && (anstyle_query::term_supports_color() + || clicolor_enabled + || anstyle_query::is_ci()) + { + ColorChoice::Always + } else { + ColorChoice::Never + } + } + ColorChoice::AlwaysAnsi | ColorChoice::Always | ColorChoice::Never => choice, + } +} + +impl AutoStream { + /// Get exclusive access to the `AutoStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> AutoStream> { + let inner = match self.inner { + StreamInner::PassThrough(w) => StreamInner::PassThrough(w.lock()), + StreamInner::Strip(w) => StreamInner::Strip(w.lock()), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => StreamInner::Wincon(w.lock()), + }; + AutoStream { inner } + } +} + +impl AutoStream { + /// Get exclusive access to the `AutoStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> AutoStream> { + let inner = match self.inner { + StreamInner::PassThrough(w) => StreamInner::PassThrough(w.lock()), + StreamInner::Strip(w) => StreamInner::Strip(w.lock()), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => StreamInner::Wincon(w.lock()), + }; + AutoStream { inner } + } +} + +impl std::io::Write for AutoStream +where + S: RawStream + AsLockedWrite, +{ + // Must forward all calls to ensure locking happens appropriately + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().write(buf), + StreamInner::Strip(w) => w.write(buf), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.write(buf), + } + } + #[inline] + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().write_vectored(bufs), + StreamInner::Strip(w) => w.write_vectored(bufs), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.write_vectored(bufs), + } + } + // is_write_vectored: nightly only + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().flush(), + StreamInner::Strip(w) => w.flush(), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.flush(), + } + } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().write_all(buf), + StreamInner::Strip(w) => w.write_all(buf), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.write_all(buf), + } + } + // write_all_vectored: nightly only + #[inline] + fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> { + match &mut self.inner { + StreamInner::PassThrough(w) => w.as_locked_write().write_fmt(args), + StreamInner::Strip(w) => w.write_fmt(args), + #[cfg(all(windows, feature = "wincon"))] + StreamInner::Wincon(w) => w.write_fmt(args), + } + } +} diff --git a/tools/vendor/anstream/src/buffer.rs b/tools/vendor/anstream/src/buffer.rs new file mode 100644 index 0000000000..92e5aafe88 --- /dev/null +++ b/tools/vendor/anstream/src/buffer.rs @@ -0,0 +1,56 @@ +#![allow(deprecated)] + +/// In-memory [`RawStream`][crate::stream::RawStream] +#[derive(Clone, Default, Debug, PartialEq, Eq)] +#[deprecated(since = "0.6.2", note = "Use Vec")] +#[doc(hidden)] +pub struct Buffer(Vec); + +impl Buffer { + #[inline] + pub fn new() -> Self { + Default::default() + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Self(Vec::with_capacity(capacity)) + } + + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } +} + +impl AsRef<[u8]> for Buffer { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl std::io::Write for Buffer { + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.0.extend(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} + +#[cfg(all(windows, feature = "wincon"))] +impl anstyle_wincon::WinconStream for Buffer { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + self.0.write_colored(fg, bg, data) + } +} diff --git a/tools/vendor/anstream/src/fmt.rs b/tools/vendor/anstream/src/fmt.rs new file mode 100644 index 0000000000..e673c26dd5 --- /dev/null +++ b/tools/vendor/anstream/src/fmt.rs @@ -0,0 +1,54 @@ +/// A shim which allows a [`std::io::Write`] to be implemented in terms of a [`std::fmt::Write`] +/// +/// This saves off I/O errors. instead of discarding them +pub(crate) struct Adapter +where + W: FnMut(&[u8]) -> std::io::Result<()>, +{ + writer: W, + error: std::io::Result<()>, +} + +impl Adapter +where + W: FnMut(&[u8]) -> std::io::Result<()>, +{ + pub(crate) fn new(writer: W) -> Self { + Adapter { + writer, + error: Ok(()), + } + } + + pub(crate) fn write_fmt(mut self, fmt: std::fmt::Arguments<'_>) -> std::io::Result<()> { + match std::fmt::write(&mut self, fmt) { + Ok(()) => Ok(()), + Err(..) => { + // check if the error came from the underlying `Write` or not + if self.error.is_err() { + self.error + } else { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + "formatter error", + )) + } + } + } + } +} + +impl std::fmt::Write for Adapter +where + W: FnMut(&[u8]) -> std::io::Result<()>, +{ + fn write_str(&mut self, s: &str) -> std::fmt::Result { + match (self.writer)(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(std::fmt::Error) + } + } + } +} diff --git a/tools/vendor/anstream/src/lib.rs b/tools/vendor/anstream/src/lib.rs new file mode 100644 index 0000000000..5ada312eac --- /dev/null +++ b/tools/vendor/anstream/src/lib.rs @@ -0,0 +1,90 @@ +//! **Auto-adapting [`stdout`] / [`stderr`] streams** +//! +//! *A portmanteau of "ansi stream"* +//! +//! [`AutoStream`] always accepts [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code), +//! [adapting to the user's terminal's capabilities][AutoStream]. +//! +//! Benefits +//! - Allows the caller to not be concerned with the terminal's capabilities +//! - Semver safe way of passing styled text between crates as ANSI escape codes offer more +//! compatibility than most crate APIs. +//! +//! Available styling crates: +//! - [anstyle](https://docs.rs/anstyle) for minimal runtime styling, designed to go in public APIs +//! - [owo-colors](https://docs.rs/owo-colors) for feature-rich runtime styling +//! - [color-print](https://docs.rs/color-print) for feature-rich compile-time styling +//! +//! # Example +//! +//! ``` +//! # #[cfg(feature = "auto")] { +//! use anstream::println; +//! use owo_colors::OwoColorize as _; +//! +//! // Foreground colors +//! println!("My number is {:#x}!", 10.green()); +//! // Background colors +//! println!("My number is not {}!", 4.on_red()); +//! # } +//! ``` +//! +//! And this will correctly handle piping to a file, etc + +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs)] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] + +pub mod adapter; +pub mod stream; +#[doc(hidden)] +#[macro_use] +pub mod _macros; + +mod auto; +mod buffer; +mod fmt; +mod strip; +#[cfg(all(windows, feature = "wincon"))] +mod wincon; + +pub use auto::AutoStream; +pub use strip::StripStream; +#[cfg(all(windows, feature = "wincon"))] +pub use wincon::WinconStream; + +#[allow(deprecated)] +pub use buffer::Buffer; + +/// An adaptive wrapper around the global standard output stream of the current process +pub type Stdout = AutoStream; +/// An adaptive wrapper around the global standard error stream of the current process +pub type Stderr = AutoStream; + +/// Create an ANSI escape code compatible stdout +/// +/// **Note:** Call [`AutoStream::lock`] in loops to avoid the performance hit of acquiring/releasing +/// from the implicit locking in each [`std::io::Write`] call +#[cfg(feature = "auto")] +pub fn stdout() -> Stdout { + let stdout = std::io::stdout(); + AutoStream::auto(stdout) +} + +/// Create an ANSI escape code compatible stderr +/// +/// **Note:** Call [`AutoStream::lock`] in loops to avoid the performance hit of acquiring/releasing +/// from the implicit locking in each [`std::io::Write`] call +#[cfg(feature = "auto")] +pub fn stderr() -> Stderr { + let stderr = std::io::stderr(); + AutoStream::auto(stderr) +} + +/// Selection for overriding color output +pub use colorchoice::ColorChoice; + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/tools/vendor/anstream/src/stream.rs b/tools/vendor/anstream/src/stream.rs new file mode 100644 index 0000000000..49103221a7 --- /dev/null +++ b/tools/vendor/anstream/src/stream.rs @@ -0,0 +1,316 @@ +//! Higher-level traits to describe writeable streams + +/// Required functionality for underlying [`std::io::Write`] for adaptation +#[cfg(not(all(windows, feature = "wincon")))] +pub trait RawStream: std::io::Write + IsTerminal + private::Sealed {} + +/// Required functionality for underlying [`std::io::Write`] for adaptation +#[cfg(all(windows, feature = "wincon"))] +pub trait RawStream: + std::io::Write + IsTerminal + anstyle_wincon::WinconStream + private::Sealed +{ +} + +impl RawStream for &mut T {} +impl RawStream for Box {} + +impl RawStream for std::io::Stdout {} + +impl RawStream for std::io::StdoutLock<'_> {} + +impl RawStream for std::io::Stderr {} + +impl RawStream for std::io::StderrLock<'_> {} + +impl RawStream for dyn std::io::Write {} +impl RawStream for dyn std::io::Write + Send {} +impl RawStream for dyn std::io::Write + Send + Sync {} + +impl RawStream for Vec {} + +impl RawStream for std::fs::File {} + +#[allow(deprecated)] +impl RawStream for crate::Buffer {} + +/// Trait to determine if a descriptor/handle refers to a terminal/tty. +pub trait IsTerminal: private::Sealed { + /// Returns `true` if the descriptor/handle refers to a terminal/tty. + fn is_terminal(&self) -> bool; +} + +impl IsTerminal for &T { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +impl IsTerminal for &mut T { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +impl IsTerminal for Box { + #[inline] + fn is_terminal(&self) -> bool { + (**self).is_terminal() + } +} + +impl IsTerminal for std::io::Stdout { + #[inline] + fn is_terminal(&self) -> bool { + is_terminal_polyfill::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for std::io::StdoutLock<'_> { + #[inline] + fn is_terminal(&self) -> bool { + is_terminal_polyfill::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for std::io::Stderr { + #[inline] + fn is_terminal(&self) -> bool { + is_terminal_polyfill::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for std::io::StderrLock<'_> { + #[inline] + fn is_terminal(&self) -> bool { + is_terminal_polyfill::IsTerminal::is_terminal(self) + } +} + +impl IsTerminal for dyn std::io::Write { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for dyn std::io::Write + Send { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for dyn std::io::Write + Send + Sync { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for Vec { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +impl IsTerminal for std::fs::File { + #[inline] + fn is_terminal(&self) -> bool { + is_terminal_polyfill::IsTerminal::is_terminal(self) + } +} + +#[allow(deprecated)] +impl IsTerminal for crate::Buffer { + #[inline] + fn is_terminal(&self) -> bool { + false + } +} + +/// Lock a stream +pub trait AsLockedWrite: private::Sealed { + /// Locked writer type + type Write<'w>: RawStream + 'w + where + Self: 'w; + + /// Lock a stream + fn as_locked_write(&mut self) -> Self::Write<'_>; +} + +impl AsLockedWrite for &mut T { + type Write<'w> + = T::Write<'w> + where + Self: 'w; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + (**self).as_locked_write() + } +} + +impl AsLockedWrite for Box { + type Write<'w> + = T::Write<'w> + where + Self: 'w; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + (**self).as_locked_write() + } +} + +impl AsLockedWrite for std::io::Stdout { + type Write<'w> = std::io::StdoutLock<'w>; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self.lock() + } +} + +impl AsLockedWrite for std::io::StdoutLock<'static> { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for std::io::Stderr { + type Write<'w> = std::io::StderrLock<'w>; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self.lock() + } +} + +impl AsLockedWrite for std::io::StderrLock<'static> { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for dyn std::io::Write { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for dyn std::io::Write + Send { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for dyn std::io::Write + Send + Sync { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for Vec { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +impl AsLockedWrite for std::fs::File { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +#[allow(deprecated)] +impl AsLockedWrite for crate::Buffer { + type Write<'w> = &'w mut Self; + + #[inline] + fn as_locked_write(&mut self) -> Self::Write<'_> { + self + } +} + +mod private { + #[allow(unnameable_types)] + pub trait Sealed {} + + impl Sealed for &T {} + impl Sealed for &mut T {} + impl Sealed for Box {} + + impl Sealed for std::io::Stdout {} + + impl Sealed for std::io::StdoutLock<'_> {} + + impl Sealed for std::io::Stderr {} + + impl Sealed for std::io::StderrLock<'_> {} + + impl Sealed for dyn std::io::Write {} + impl Sealed for dyn std::io::Write + Send {} + impl Sealed for dyn std::io::Write + Send + Sync {} + + impl Sealed for Vec {} + + impl Sealed for std::fs::File {} + + #[allow(deprecated)] + impl Sealed for crate::Buffer {} +} + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_raw_stream() + where + crate::AutoStream: std::io::Write, + { + } + + #[test] + fn test() { + assert_raw_stream::>(); + assert_raw_stream::>(); + assert_raw_stream::>(); + assert_raw_stream::>(); + + assert_raw_stream::<&mut dyn std::io::Write>(); + assert_raw_stream::<&mut (dyn std::io::Write + 'static)>(); + assert_raw_stream::<&mut (dyn std::io::Write + Send)>(); + assert_raw_stream::<&mut (dyn std::io::Write + Send + Sync)>(); + + assert_raw_stream::>(); + assert_raw_stream::<&mut Vec>(); + + assert_raw_stream::(); + assert_raw_stream::<&mut std::fs::File>(); + } +} diff --git a/tools/vendor/anstream/src/strip.rs b/tools/vendor/anstream/src/strip.rs new file mode 100644 index 0000000000..47a0db0ddf --- /dev/null +++ b/tools/vendor/anstream/src/strip.rs @@ -0,0 +1,233 @@ +use crate::adapter::StripBytes; +use crate::stream::AsLockedWrite; +use crate::stream::IsTerminal; + +/// Only pass printable data to the inner `Write` +#[derive(Debug)] +pub struct StripStream +where + S: std::io::Write, +{ + raw: S, + state: StripBytes, +} + +impl StripStream +where + S: std::io::Write, +{ + /// Only pass printable data to the inner `Write` + #[inline] + pub fn new(raw: S) -> Self { + Self { + raw, + state: Default::default(), + } + } + + /// Get the wrapped [`std::io::Write`] + #[inline] + pub fn into_inner(self) -> S { + self.raw + } + + /// Get the wrapped [`std::io::Write`] + #[inline] + pub fn as_inner(&self) -> &S { + &self.raw + } +} + +impl StripStream +where + S: std::io::Write, + S: IsTerminal, +{ + /// Returns `true` if the descriptor/handle refers to a terminal/tty. + #[inline] + pub fn is_terminal(&self) -> bool { + self.raw.is_terminal() + } +} + +impl StripStream { + /// Get exclusive access to the `StripStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> StripStream> { + StripStream { + raw: self.raw.lock(), + state: self.state, + } + } +} + +impl StripStream { + /// Get exclusive access to the `StripStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> StripStream> { + StripStream { + raw: self.raw.lock(), + state: self.state, + } + } +} + +impl std::io::Write for StripStream +where + S: std::io::Write, + S: AsLockedWrite, +{ + // Must forward all calls to ensure locking happens appropriately + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + write(&mut self.raw.as_locked_write(), &mut self.state, buf) + } + #[inline] + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + let buf = bufs + .iter() + .find(|b| !b.is_empty()) + .map(|b| &**b) + .unwrap_or(&[][..]); + self.write(buf) + } + // is_write_vectored: nightly only + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.raw.as_locked_write().flush() + } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + write_all(&mut self.raw.as_locked_write(), &mut self.state, buf) + } + // write_all_vectored: nightly only + #[inline] + fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> { + write_fmt(&mut self.raw.as_locked_write(), &mut self.state, args) + } +} + +fn write( + raw: &mut dyn std::io::Write, + state: &mut StripBytes, + buf: &[u8], +) -> std::io::Result { + let initial_state = state.clone(); + + for printable in state.strip_next(buf) { + let possible = printable.len(); + let written = raw.write(printable)?; + if possible != written { + let divergence = &printable[written..]; + let offset = offset_to(buf, divergence); + let consumed = &buf[offset..]; + *state = initial_state; + state.strip_next(consumed).last(); + return Ok(offset); + } + } + Ok(buf.len()) +} + +fn write_all( + raw: &mut dyn std::io::Write, + state: &mut StripBytes, + buf: &[u8], +) -> std::io::Result<()> { + for printable in state.strip_next(buf) { + raw.write_all(printable)?; + } + Ok(()) +} + +fn write_fmt( + raw: &mut dyn std::io::Write, + state: &mut StripBytes, + args: std::fmt::Arguments<'_>, +) -> std::io::Result<()> { + let write_all = |buf: &[u8]| write_all(raw, state, buf); + crate::fmt::Adapter::new(write_all).write_fmt(args) +} + +#[inline] +fn offset_to(total: &[u8], subslice: &[u8]) -> usize { + let total = total.as_ptr(); + let subslice = subslice.as_ptr(); + + debug_assert!( + total <= subslice, + "`Offset::offset_to` only accepts slices of `self`" + ); + subslice as usize - total as usize +} + +#[cfg(test)] +mod test { + use super::*; + use proptest::prelude::*; + use std::io::Write as _; + + proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_all_no_escapes(s in "\\PC*") { + let buffer = Vec::new(); + let mut stream = StripStream::new(buffer); + stream.write_all(s.as_bytes()).unwrap(); + let buffer = stream.into_inner(); + let actual = std::str::from_utf8(buffer.as_ref()).unwrap(); + assert_eq!(s, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_byte_no_escapes(s in "\\PC*") { + let buffer = Vec::new(); + let mut stream = StripStream::new(buffer); + for byte in s.as_bytes() { + stream.write_all(&[*byte]).unwrap(); + } + let buffer = stream.into_inner(); + let actual = std::str::from_utf8(buffer.as_ref()).unwrap(); + assert_eq!(s, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_all_random(s in any::>()) { + let buffer = Vec::new(); + let mut stream = StripStream::new(buffer); + stream.write_all(s.as_slice()).unwrap(); + let buffer = stream.into_inner(); + if let Ok(actual) = std::str::from_utf8(buffer.as_ref()) { + for char in actual.chars() { + assert!(!char.is_ascii() || !char.is_control() || char.is_ascii_whitespace(), "{:?} -> {:?}: {:?}", String::from_utf8_lossy(&s), actual, char); + } + } + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_byte_random(s in any::>()) { + let buffer = Vec::new(); + let mut stream = StripStream::new(buffer); + for byte in s.as_slice() { + stream.write_all(&[*byte]).unwrap(); + } + let buffer = stream.into_inner(); + if let Ok(actual) = std::str::from_utf8(buffer.as_ref()) { + for char in actual.chars() { + assert!(!char.is_ascii() || !char.is_control() || char.is_ascii_whitespace(), "{:?} -> {:?}: {:?}", String::from_utf8_lossy(&s), actual, char); + } + } + } + } +} diff --git a/tools/vendor/anstream/src/wincon.rs b/tools/vendor/anstream/src/wincon.rs new file mode 100644 index 0000000000..bb3fbdb8f7 --- /dev/null +++ b/tools/vendor/anstream/src/wincon.rs @@ -0,0 +1,232 @@ +use crate::adapter::WinconBytes; +use crate::stream::AsLockedWrite; +use crate::stream::IsTerminal; + +/// Only pass printable data to the inner `Write` +#[cfg(feature = "wincon")] // here mostly for documentation purposes +#[derive(Debug)] +pub struct WinconStream +where + S: anstyle_wincon::WinconStream, +{ + raw: S, + // `WinconBytes` is especially large compared to other variants of `AutoStream`, so boxing it + // here so `AutoStream` doesn't have to discard one allocation and create another one when + // calling `AutoStream::lock` + state: Box, +} + +impl WinconStream +where + S: anstyle_wincon::WinconStream, +{ + /// Only pass printable data to the inner `Write` + #[inline] + pub fn new(raw: S) -> Self { + Self { + raw, + state: Default::default(), + } + } + + /// Get the wrapped [`anstyle_wincon::WinconStream`] + #[inline] + pub fn into_inner(self) -> S { + self.raw + } + + /// Get the wrapped [`std::io::Write`] + #[inline] + pub fn as_inner(&self) -> &S { + &self.raw + } +} + +impl WinconStream +where + S: anstyle_wincon::WinconStream, + S: IsTerminal, +{ + /// Returns `true` if the descriptor/handle refers to a terminal/tty. + #[inline] + pub fn is_terminal(&self) -> bool { + self.raw.is_terminal() + } +} + +impl WinconStream { + /// Get exclusive access to the `WinconStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> WinconStream> { + WinconStream { + raw: self.raw.lock(), + state: self.state, + } + } +} + +impl WinconStream { + /// Get exclusive access to the `WinconStream` + /// + /// Why? + /// - Faster performance when writing in a loop + /// - Avoid other threads interleaving output with the current thread + #[inline] + pub fn lock(self) -> WinconStream> { + WinconStream { + raw: self.raw.lock(), + state: self.state, + } + } +} + +impl std::io::Write for WinconStream +where + S: anstyle_wincon::WinconStream, + S: AsLockedWrite, +{ + // Must forward all calls to ensure locking happens appropriately + #[inline] + fn write(&mut self, buf: &[u8]) -> std::io::Result { + write(&mut self.raw.as_locked_write(), &mut self.state, buf) + } + #[inline] + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + let buf = bufs + .iter() + .find(|b| !b.is_empty()) + .map(|b| &**b) + .unwrap_or(&[][..]); + self.write(buf) + } + // is_write_vectored: nightly only + #[inline] + fn flush(&mut self) -> std::io::Result<()> { + self.raw.as_locked_write().flush() + } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { + write_all(&mut self.raw.as_locked_write(), &mut self.state, buf) + } + // write_all_vectored: nightly only + #[inline] + fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> { + write_fmt(&mut self.raw.as_locked_write(), &mut self.state, args) + } +} + +fn write( + raw: &mut dyn anstyle_wincon::WinconStream, + state: &mut WinconBytes, + buf: &[u8], +) -> std::io::Result { + for (style, printable) in state.extract_next(buf) { + let fg = style.get_fg_color().and_then(cap_wincon_color); + let bg = style.get_bg_color().and_then(cap_wincon_color); + let written = raw.write_colored(fg, bg, printable.as_bytes())?; + let possible = printable.len(); + if possible != written { + // HACK: Unsupported atm + break; + } + } + Ok(buf.len()) +} + +fn write_all( + raw: &mut dyn anstyle_wincon::WinconStream, + state: &mut WinconBytes, + buf: &[u8], +) -> std::io::Result<()> { + for (style, printable) in state.extract_next(buf) { + let mut buf = printable.as_bytes(); + let fg = style.get_fg_color().and_then(cap_wincon_color); + let bg = style.get_bg_color().and_then(cap_wincon_color); + while !buf.is_empty() { + match raw.write_colored(fg, bg, buf) { + Ok(0) => { + return Err(std::io::Error::new( + std::io::ErrorKind::WriteZero, + "failed to write whole buffer", + )); + } + Ok(n) => buf = &buf[n..], + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + } + Ok(()) +} + +fn write_fmt( + raw: &mut dyn anstyle_wincon::WinconStream, + state: &mut WinconBytes, + args: std::fmt::Arguments<'_>, +) -> std::io::Result<()> { + let write_all = |buf: &[u8]| write_all(raw, state, buf); + crate::fmt::Adapter::new(write_all).write_fmt(args) +} + +fn cap_wincon_color(color: anstyle::Color) -> Option { + match color { + anstyle::Color::Ansi(c) => Some(c), + anstyle::Color::Ansi256(c) => c.into_ansi(), + anstyle::Color::Rgb(_) => None, + } +} + +#[cfg(test)] +mod test { + use super::*; + use proptest::prelude::*; + use std::io::Write as _; + + proptest! { + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_all_no_escapes(s in "\\PC*") { + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); + stream.write_all(s.as_bytes()).unwrap(); + let buffer = stream.into_inner(); + let actual = std::str::from_utf8(buffer.as_ref()).unwrap(); + assert_eq!(s, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_byte_no_escapes(s in "\\PC*") { + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); + for byte in s.as_bytes() { + stream.write_all(&[*byte]).unwrap(); + } + let buffer = stream.into_inner(); + let actual = std::str::from_utf8(buffer.as_ref()).unwrap(); + assert_eq!(s, actual); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_all_random(s in any::>()) { + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); + stream.write_all(s.as_slice()).unwrap(); + } + + #[test] + #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 + fn write_byte_random(s in any::>()) { + let buffer = Vec::new(); + let mut stream = WinconStream::new(buffer); + for byte in s.as_slice() { + stream.write_all(&[*byte]).unwrap(); + } + } + } +} diff --git a/tools/vendor/anstyle-parse/.cargo-checksum.json b/tools/vendor/anstyle-parse/.cargo-checksum.json new file mode 100644 index 0000000000..d9c421d2ba --- /dev/null +++ b/tools/vendor/anstyle-parse/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"fe7a6da9f06f68bfdb3ba960ba4ed96f9e2487acb759fe62fa25a0096c9c244e","Cargo.lock":"10930fdde31ba98c5a454ca3a9b974e217a5422938770b97d73292be0c080c43","Cargo.toml":"7979e45c36e6da58160e4653d9aa5d7865f1c5d9cb9330aad3b113f755bcee83","Cargo.toml.orig":"268291d9f66d6e3c9855c80cb9791c3420b42808ac10d6c6e2ed511c20d866fc","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"d66bf61a027a03eb7cc34a7eaf9f8e91657445e978b6545169d629e0188d89ea","examples/parselog.rs":"83bb99aec7704e6aa5524dd6090f1f4837c37935e53d6ff5d17b723b0c55d029","src/lib.rs":"67f8827a91300cdb431b751ad0a7ef451c453e477a4f97749f850bdfe678def6","src/params.rs":"8cfef4e2ab1961ca2d9f210da553fc6ac64bb6dbd03321f0ee7d6089ab45389c","src/state/codegen.rs":"0820bb4e54d9b3f1e0e80c1935ca57466cfe60e98f556c31f19e5e1b6ed31787","src/state/definitions.rs":"8a819bd7238edeb02aff3697e07fadfb8978a00f9f255812838326b904010e82","src/state/mod.rs":"5c07420f7245b823bc1bcff797ae70c21cfdfaee8f326d37a6e95d529b08f38d","src/state/table.rs":"673b7e9242c5248efc076086cc6923578ec2f059c0c26da21363528e20e4285c"},"package":"4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"} \ No newline at end of file diff --git a/tools/vendor/anstyle-parse/.cargo_vcs_info.json b/tools/vendor/anstyle-parse/.cargo_vcs_info.json new file mode 100644 index 0000000000..cc991cccb4 --- /dev/null +++ b/tools/vendor/anstyle-parse/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "886539c95318db5de9db49b6d66d19413bd308cc" + }, + "path_in_vcs": "crates/anstyle-parse" +} \ No newline at end of file diff --git a/tools/vendor/anstyle-parse/Cargo.lock b/tools/vendor/anstyle-parse/Cargo.lock new file mode 100644 index 0000000000..2aadc1bad7 --- /dev/null +++ b/tools/vendor/anstyle-parse/Cargo.lock @@ -0,0 +1,740 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle", + "anstyle-parse 0.2.6", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +dependencies = [ + "arrayvec", + "codegenrs", + "divan", + "proptest", + "snapbox", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" +dependencies = [ + "anstyle", + "clap_lex", + "terminal_size", +] + +[[package]] +name = "clap_lex" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "codegenrs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a564a9c6e001f881ff5074dc1fb10aae609c82c92b7ddb47e40987be820771" +dependencies = [ + "difference", + "normalize-line-endings", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "condtype" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "divan" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e05d17bd4ff1c1e7998ed4623d2efd91f72f1e24141ac33aac9377974270e1f" +dependencies = [ + "cfg-if", + "clap", + "condtype", + "divan-macros", + "libc", + "regex-lite", +] + +[[package]] +name = "divan-macros" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b4464d46ce68bfc7cb76389248c7c254def7baca8bece0693b02b83842c4c88" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "errno" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2736dd548daf35f50d261bbad35a83890bb9b461797f15de528485fbf206ab15" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.9.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + +[[package]] +name = "snapbox" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881f1849454828a68363dd288b7a0a071e55e2a4356d2c38b567db18a9be0d9f" +dependencies = [ + "anstream", + "anstyle", + "normalize-line-endings", + "similar", + "snapbox-macros", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" +dependencies = [ + "anstream", +] + +[[package]] +name = "syn" +version = "2.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix 0.38.38", + "windows-sys 0.59.0", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.27", + "windows-sys 0.48.0", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[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", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/tools/vendor/anstyle-parse/Cargo.toml b/tools/vendor/anstyle-parse/Cargo.toml new file mode 100644 index 0000000000..a55012c6c1 --- /dev/null +++ b/tools/vendor/anstyle-parse/Cargo.toml @@ -0,0 +1,196 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.66.0" +name = "anstyle-parse" +version = "0.2.7" +build = false +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "Cargo.lock", + "LICENSE*", + "README.md", + "examples/**/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Parse ANSI Style Escapes" +readme = "README.md" +keywords = [ + "ansi", + "terminal", + "color", + "vte", +] +categories = ["command-line-interface"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-cli/anstyle.git" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", + "--generate-link-to-definition", +] + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +min = 1 +replace = "{{version}}" +search = "Unreleased" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = "...{{tag_name}}" +search = '\.\.\.HEAD' + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +min = 1 +replace = "{{date}}" +search = "ReleaseDate" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = """ + +## [Unreleased] - ReleaseDate +""" +search = "" + +[[package.metadata.release.pre-release-replacements]] +exactly = 1 +file = "CHANGELOG.md" +replace = """ + +[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD""" +search = "" + +[features] +core = ["dep:arrayvec"] +default = ["utf8"] +utf8 = ["dep:utf8parse"] + +[lib] +name = "anstyle_parse" +path = "src/lib.rs" + +[[example]] +name = "parselog" +path = "examples/parselog.rs" + +[dependencies.arrayvec] +version = "0.7.2" +optional = true +default-features = false + +[dependencies.utf8parse] +version = "0.2.1" +optional = true + +[dev-dependencies.codegenrs] +version = "3.0.1" +default-features = false + +[dev-dependencies.divan] +version = "0.1.14" + +[dev-dependencies.proptest] +version = "1.4.0" + +[dev-dependencies.snapbox] +version = "0.6.5" + +[dev-dependencies.vte_generate_state_changes] +version = "0.1.1" + +[lints.clippy] +bool_assert_comparison = "allow" +branches_sharing_code = "allow" +checked_conversions = "warn" +collapsible_else_if = "allow" +create_dir = "warn" +dbg_macro = "warn" +debug_assert_with_mut_call = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +fallible_impl_from = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp_const = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +imprecise_flops = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +invalid_upcast_comparisons = "warn" +large_digit_groups = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +let_and_return = "allow" +linkedlist = "warn" +lossy_float_literal = "warn" +macro_use_imports = "warn" +mem_forget = "warn" +mutex_integer = "warn" +needless_continue = "allow" +needless_for_each = "warn" +negative_feature_names = "warn" +path_buf_push_overwrite = "warn" +ptr_as_ptr = "warn" +rc_mutex = "warn" +redundant_feature_names = "warn" +ref_option_ref = "warn" +rest_pat_in_fully_bound_structs = "warn" +result_large_err = "allow" +same_functions_in_if_condition = "warn" +self_named_module_files = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" +string_add = "warn" +string_add_assign = "warn" +string_lit_as_bytes = "warn" +string_to_string = "warn" +todo = "warn" +trait_duplication_in_bounds = "warn" +uninlined_format_args = "warn" +verbose_file_reads = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" + +[lints.rust] +unnameable_types = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[lints.rust.rust_2018_idioms] +level = "warn" +priority = -1 diff --git a/tools/vendor/anstyle-parse/Cargo.toml.orig b/tools/vendor/anstyle-parse/Cargo.toml.orig new file mode 100644 index 0000000000..4ccea6c86a --- /dev/null +++ b/tools/vendor/anstyle-parse/Cargo.toml.orig @@ -0,0 +1,48 @@ +[package] +name = "anstyle-parse" +version = "0.2.7" +description = "Parse ANSI Style Escapes" +categories = ["command-line-interface"] +keywords = ["ansi", "terminal", "color", "vte"] +repository.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[dependencies] +arrayvec = { version = "0.7.2", default-features = false, optional = true } +utf8parse = { version = "0.2.1", optional = true } + +[features] +default = ["utf8"] +core = ["dep:arrayvec"] +utf8 = ["dep:utf8parse"] + +[dev-dependencies] +codegenrs = { version = "3.0.1", default-features = false } +divan = "0.1.14" +proptest = "1.4.0" +snapbox = "0.6.5" +vte_generate_state_changes = { version = "0.1.1" } + +[[bench]] +name = "parse" +harness = false +required-features = ["utf8"] + +[lints] +workspace = true diff --git a/tools/vendor/anstyle-parse/LICENSE-APACHE b/tools/vendor/anstyle-parse/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/tools/vendor/anstyle-parse/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/tools/vendor/anstyle-parse/LICENSE-MIT b/tools/vendor/anstyle-parse/LICENSE-MIT new file mode 100644 index 0000000000..a2d01088b6 --- /dev/null +++ b/tools/vendor/anstyle-parse/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/vendor/anstyle-parse/README.md b/tools/vendor/anstyle-parse/README.md new file mode 100644 index 0000000000..705b3e0c92 --- /dev/null +++ b/tools/vendor/anstyle-parse/README.md @@ -0,0 +1,33 @@ +# anstyle-parse + +> Parse [Parse ANSI Style Escapes](https://vt100.net/emu/dec_ansi_parser) + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/anstyle-parse.svg) +[![Crates Status](https://img.shields.io/crates/v/anstyle-parse.svg)](https://crates.io/crates/anstyle-parse) + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## [Contribute](../../CONTRIBUTING.md) + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual-licensed as above, without any additional terms or +conditions. + +### Special Thanks + +[chrisduerr](https://github.com/alacritty/vte/commits?author=chrisduerr) and the +[alacritty project](https://github.com/alacritty/alacritty) for +[vte](https://crates.io/crates/vte) which +[this was forked from](https://github.com/alacritty/vte/issues/82) + +[Crates.io]: https://crates.io/crates/anstyle-parse +[Documentation]: https://docs.rs/anstyle-parse diff --git a/tools/vendor/anstyle-parse/examples/parselog.rs b/tools/vendor/anstyle-parse/examples/parselog.rs new file mode 100644 index 0000000000..22b1711bf8 --- /dev/null +++ b/tools/vendor/anstyle-parse/examples/parselog.rs @@ -0,0 +1,72 @@ +//! Parse input from stdin and log actions on stdout +use std::io::{self, Read}; + +use anstyle_parse::{DefaultCharAccumulator, Params, Parser, Perform}; + +/// A type implementing Perform that just logs actions +struct Log; + +impl Perform for Log { + fn print(&mut self, c: char) { + println!("[print] {c:?}"); + } + + fn execute(&mut self, byte: u8) { + println!("[execute] {byte:02x}"); + } + + fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: u8) { + println!( + "[hook] params={params:?}, intermediates={intermediates:?}, ignore={ignore:?}, char={c:?}" + ); + } + + fn put(&mut self, byte: u8) { + println!("[put] {byte:02x}"); + } + + fn unhook(&mut self) { + println!("[unhook]"); + } + + fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { + println!("[osc_dispatch] params={params:?} bell_terminated={bell_terminated}"); + } + + fn csi_dispatch(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: u8) { + println!( + "[csi_dispatch] params={params:#?}, intermediates={intermediates:?}, ignore={ignore:?}, char={c:?}" + ); + } + + fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { + println!( + "[esc_dispatch] intermediates={intermediates:?}, ignore={ignore:?}, byte={byte:02x}" + ); + } +} + +fn main() { + let input = io::stdin(); + let mut handle = input.lock(); + + let mut statemachine = Parser::::new(); + let mut performer = Log; + + let mut buf = [0; 2048]; + + loop { + match handle.read(&mut buf) { + Ok(0) => break, + Ok(n) => { + for byte in &buf[..n] { + statemachine.advance(&mut performer, *byte); + } + } + Err(err) => { + println!("err: {err}"); + break; + } + } + } +} diff --git a/tools/vendor/anstyle-parse/src/lib.rs b/tools/vendor/anstyle-parse/src/lib.rs new file mode 100644 index 0000000000..28f50e42c2 --- /dev/null +++ b/tools/vendor/anstyle-parse/src/lib.rs @@ -0,0 +1,442 @@ +//! Parser for implementing virtual terminal emulators +//! +//! [`Parser`] is implemented according to [Paul Williams' ANSI parser +//! state machine]. The state machine doesn't assign meaning to the parsed data +//! and is thus not itself sufficient for writing a terminal emulator. Instead, +//! it is expected that an implementation of [`Perform`] is provided which does +//! something useful with the parsed data. The [`Parser`] handles the book +//! keeping, and the [`Perform`] gets to simply handle actions. +//! +//! # Examples +//! +//! For an example of using the [`Parser`] please see the examples folder. The example included +//! there simply logs all the actions [`Perform`] does. One quick thing to see it in action is to +//! pipe `vim` into it +//! +//! ```sh +//! cargo build --release --example parselog +//! vim | target/release/examples/parselog +//! ``` +//! +//! Just type `:q` to exit. +//! +//! # Differences from original state machine description +//! +//! * UTF-8 Support for Input +//! * OSC Strings can be terminated by 0x07 +//! * Only supports 7-bit codes. Some 8-bit codes are still supported, but they no longer work in +//! all states. +//! +//! [Paul Williams' ANSI parser state machine]: https://vt100.net/emu/dec_ansi_parser +#![cfg_attr(not(test), no_std)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![allow(missing_docs)] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] + +#[cfg(not(feature = "core"))] +extern crate alloc; + +use core::mem::MaybeUninit; + +#[cfg(feature = "core")] +use arrayvec::ArrayVec; +#[cfg(feature = "utf8")] +use utf8parse as utf8; + +mod params; +pub mod state; + +pub use params::{Params, ParamsIter}; + +use state::{state_change, Action, State}; + +const MAX_INTERMEDIATES: usize = 2; +const MAX_OSC_PARAMS: usize = 16; +#[cfg(feature = "core")] +const MAX_OSC_RAW: usize = 1024; + +/// Parser for raw _VTE_ protocol which delegates actions to a [`Perform`] +#[allow(unused_qualifications)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct Parser { + state: State, + intermediates: [u8; MAX_INTERMEDIATES], + intermediate_idx: usize, + params: Params, + param: u16, + #[cfg(feature = "core")] + osc_raw: ArrayVec, + #[cfg(not(feature = "core"))] + osc_raw: alloc::vec::Vec, + osc_params: [(usize, usize); MAX_OSC_PARAMS], + osc_num_params: usize, + ignoring: bool, + utf8_parser: C, +} + +impl Parser +where + C: CharAccumulator, +{ + /// Create a new Parser + pub fn new() -> Parser { + Parser::default() + } + + #[inline] + fn params(&self) -> &Params { + &self.params + } + + #[inline] + fn intermediates(&self) -> &[u8] { + &self.intermediates[..self.intermediate_idx] + } + + /// Advance the parser state + /// + /// Requires a [`Perform`] in case `byte` triggers an action + #[inline] + pub fn advance(&mut self, performer: &mut P, byte: u8) { + // Utf8 characters are handled out-of-band. + if let State::Utf8 = self.state { + self.process_utf8(performer, byte); + return; + } + + let (state, action) = state_change(self.state, byte); + self.perform_state_change(performer, state, action, byte); + } + + #[inline] + fn process_utf8

(&mut self, performer: &mut P, byte: u8) + where + P: Perform, + { + if let Some(c) = self.utf8_parser.add(byte) { + performer.print(c); + self.state = State::Ground; + } + } + + #[inline] + fn perform_state_change

(&mut self, performer: &mut P, state: State, action: Action, byte: u8) + where + P: Perform, + { + match state { + State::Anywhere => { + // Just run the action + self.perform_action(performer, action, byte); + } + state => { + match self.state { + State::DcsPassthrough => { + self.perform_action(performer, Action::Unhook, byte); + } + State::OscString => { + self.perform_action(performer, Action::OscEnd, byte); + } + _ => (), + } + + match action { + Action::Nop => (), + action => { + self.perform_action(performer, action, byte); + } + } + + match state { + State::CsiEntry | State::DcsEntry | State::Escape => { + self.perform_action(performer, Action::Clear, byte); + } + State::DcsPassthrough => { + self.perform_action(performer, Action::Hook, byte); + } + State::OscString => { + self.perform_action(performer, Action::OscStart, byte); + } + _ => (), + } + + // Assume the new state + self.state = state; + } + } + } + + /// Separate method for `osc_dispatch` that borrows self as read-only + /// + /// The aliasing is needed here for multiple slices into `self.osc_raw` + #[inline] + fn osc_dispatch(&self, performer: &mut P, byte: u8) { + let mut slices: [MaybeUninit<&[u8]>; MAX_OSC_PARAMS] = + unsafe { MaybeUninit::uninit().assume_init() }; + + for (i, slice) in slices.iter_mut().enumerate().take(self.osc_num_params) { + let indices = self.osc_params[i]; + *slice = MaybeUninit::new(&self.osc_raw[indices.0..indices.1]); + } + + unsafe { + let num_params = self.osc_num_params; + let params = &slices[..num_params] as *const [MaybeUninit<&[u8]>] as *const [&[u8]]; + performer.osc_dispatch(&*params, byte == 0x07); + } + } + + #[inline] + fn perform_action(&mut self, performer: &mut P, action: Action, byte: u8) { + match action { + Action::Print => performer.print(byte as char), + Action::Execute => performer.execute(byte), + Action::Hook => { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + } + + performer.hook(self.params(), self.intermediates(), self.ignoring, byte); + } + Action::Put => performer.put(byte), + Action::OscStart => { + self.osc_raw.clear(); + self.osc_num_params = 0; + } + Action::OscPut => { + #[cfg(feature = "core")] + { + if self.osc_raw.is_full() { + return; + } + } + + let idx = self.osc_raw.len(); + + // Param separator + if byte == b';' { + let param_idx = self.osc_num_params; + match param_idx { + // Only process up to MAX_OSC_PARAMS + MAX_OSC_PARAMS => return, + + // First param is special - 0 to current byte index + 0 => { + self.osc_params[param_idx] = (0, idx); + } + + // All other params depend on previous indexing + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); + } + } + + self.osc_num_params += 1; + } else { + self.osc_raw.push(byte); + } + } + Action::OscEnd => { + let param_idx = self.osc_num_params; + let idx = self.osc_raw.len(); + + match param_idx { + // Finish last parameter if not already maxed + MAX_OSC_PARAMS => (), + + // First param is special - 0 to current byte index + 0 => { + self.osc_params[param_idx] = (0, idx); + self.osc_num_params += 1; + } + + // All other params depend on previous indexing + _ => { + let prev = self.osc_params[param_idx - 1]; + let begin = prev.1; + self.osc_params[param_idx] = (begin, idx); + self.osc_num_params += 1; + } + } + self.osc_dispatch(performer, byte); + } + Action::Unhook => performer.unhook(), + Action::CsiDispatch => { + if self.params.is_full() { + self.ignoring = true; + } else { + self.params.push(self.param); + } + + performer.csi_dispatch(self.params(), self.intermediates(), self.ignoring, byte); + } + Action::EscDispatch => { + performer.esc_dispatch(self.intermediates(), self.ignoring, byte); + } + Action::Collect => { + if self.intermediate_idx == MAX_INTERMEDIATES { + self.ignoring = true; + } else { + self.intermediates[self.intermediate_idx] = byte; + self.intermediate_idx += 1; + } + } + Action::Param => { + if self.params.is_full() { + self.ignoring = true; + return; + } + + if byte == b';' { + self.params.push(self.param); + self.param = 0; + } else if byte == b':' { + self.params.extend(self.param); + self.param = 0; + } else { + // Continue collecting bytes into param + self.param = self.param.saturating_mul(10); + self.param = self.param.saturating_add((byte - b'0') as u16); + } + } + Action::Clear => { + // Reset everything on ESC/CSI/DCS entry + self.intermediate_idx = 0; + self.ignoring = false; + self.param = 0; + + self.params.clear(); + } + Action::BeginUtf8 => self.process_utf8(performer, byte), + Action::Ignore => (), + Action::Nop => (), + } + } +} + +/// Build a `char` out of bytes +pub trait CharAccumulator: Default { + /// Build a `char` out of bytes + /// + /// Return `None` when more data is needed + fn add(&mut self, byte: u8) -> Option; +} + +/// Most flexible [`CharAccumulator`] for [`Parser`] based on active features +#[cfg(feature = "utf8")] +pub type DefaultCharAccumulator = Utf8Parser; +#[cfg(not(feature = "utf8"))] +pub type DefaultCharAccumulator = AsciiParser; + +/// Only allow parsing 7-bit ASCII +#[allow(clippy::exhaustive_structs)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct AsciiParser; + +impl CharAccumulator for AsciiParser { + fn add(&mut self, _byte: u8) -> Option { + unreachable!("multi-byte UTF8 characters are unsupported") + } +} + +/// Allow parsing UTF-8 +#[cfg(feature = "utf8")] +#[derive(Default, Clone, Debug, PartialEq, Eq)] +pub struct Utf8Parser { + utf8_parser: utf8::Parser, +} + +#[cfg(feature = "utf8")] +impl CharAccumulator for Utf8Parser { + fn add(&mut self, byte: u8) -> Option { + let mut c = None; + let mut receiver = VtUtf8Receiver(&mut c); + self.utf8_parser.advance(&mut receiver, byte); + c + } +} + +#[cfg(feature = "utf8")] +struct VtUtf8Receiver<'a>(&'a mut Option); + +#[cfg(feature = "utf8")] +impl utf8::Receiver for VtUtf8Receiver<'_> { + fn codepoint(&mut self, c: char) { + *self.0 = Some(c); + } + + fn invalid_sequence(&mut self) { + *self.0 = Some('�'); + } +} + +/// Performs actions requested by the [`Parser`] +/// +/// Actions in this case mean, for example, handling a CSI escape sequence describing cursor +/// movement, or simply printing characters to the screen. +/// +/// The methods on this type correspond to actions described in +/// . I've done my best to describe them in +/// a useful way in my own words for completeness, but the site should be +/// referenced if something isn't clear. If the site disappears at some point in +/// the future, consider checking archive.org. +pub trait Perform { + /// Draw a character to the screen and update states. + fn print(&mut self, _c: char) {} + + /// Execute a C0 or C1 control function. + fn execute(&mut self, _byte: u8) {} + + /// Invoked when a final character arrives in first part of device control string. + /// + /// The control function should be determined from the private marker, final character, and + /// execute with a parameter list. A handler should be selected for remaining characters in the + /// string; the handler function should subsequently be called by `put` for every character in + /// the control string. + /// + /// The `ignore` flag indicates that more than two intermediates arrived and + /// subsequent characters were ignored. + fn hook(&mut self, _params: &Params, _intermediates: &[u8], _ignore: bool, _action: u8) {} + + /// Pass bytes as part of a device control string to the handle chosen in `hook`. C0 controls + /// will also be passed to the handler. + fn put(&mut self, _byte: u8) {} + + /// Called when a device control string is terminated. + /// + /// The previously selected handler should be notified that the DCS has + /// terminated. + fn unhook(&mut self) {} + + /// Dispatch an operating system command. + fn osc_dispatch(&mut self, _params: &[&[u8]], _bell_terminated: bool) {} + + /// A final character has arrived for a CSI sequence + /// + /// The `ignore` flag indicates that either more than two intermediates arrived + /// or the number of parameters exceeded the maximum supported length, + /// and subsequent characters were ignored. + fn csi_dispatch( + &mut self, + _params: &Params, + _intermediates: &[u8], + _ignore: bool, + _action: u8, + ) { + } + + /// The final character of an escape sequence has arrived. + /// + /// The `ignore` flag indicates that more than two intermediates arrived and + /// subsequent characters were ignored. + fn esc_dispatch(&mut self, _intermediates: &[u8], _ignore: bool, _byte: u8) {} +} + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/tools/vendor/anstyle-parse/src/params.rs b/tools/vendor/anstyle-parse/src/params.rs new file mode 100644 index 0000000000..7cc146fcdf --- /dev/null +++ b/tools/vendor/anstyle-parse/src/params.rs @@ -0,0 +1,143 @@ +//! Fixed size parameters list with optional subparameters. + +use core::fmt::{self, Debug, Formatter}; + +pub(crate) const MAX_PARAMS: usize = 32; + +#[derive(Default, Clone, PartialEq, Eq)] +pub struct Params { + /// Number of subparameters for each parameter. + /// + /// For each entry in the `params` slice, this stores the length of the param as number of + /// subparams at the same index as the param in the `params` slice. + /// + /// At the subparam positions the length will always be `0`. + subparams: [u8; MAX_PARAMS], + + /// All parameters and subparameters. + params: [u16; MAX_PARAMS], + + /// Number of suparameters in the current parameter. + current_subparams: u8, + + /// Total number of parameters and subparameters. + len: usize, +} + +impl Params { + /// Returns the number of parameters. + #[inline] + pub fn len(&self) -> usize { + self.len + } + + /// Returns `true` if there are no parameters present. + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + /// Returns an iterator over all parameters and subparameters. + #[inline] + pub fn iter(&self) -> ParamsIter<'_> { + ParamsIter::new(self) + } + + /// Returns `true` if there is no more space for additional parameters. + #[inline] + pub(crate) fn is_full(&self) -> bool { + self.len == MAX_PARAMS + } + + /// Clear all parameters. + #[inline] + pub(crate) fn clear(&mut self) { + self.current_subparams = 0; + self.len = 0; + } + + /// Add an additional parameter. + #[inline] + pub(crate) fn push(&mut self, item: u16) { + self.subparams[self.len - self.current_subparams as usize] = self.current_subparams + 1; + self.params[self.len] = item; + self.current_subparams = 0; + self.len += 1; + } + + /// Add an additional subparameter to the current parameter. + #[inline] + pub(crate) fn extend(&mut self, item: u16) { + self.subparams[self.len - self.current_subparams as usize] = self.current_subparams + 1; + self.params[self.len] = item; + self.current_subparams += 1; + self.len += 1; + } +} + +impl<'a> IntoIterator for &'a Params { + type IntoIter = ParamsIter<'a>; + type Item = &'a [u16]; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// Immutable subparameter iterator. +pub struct ParamsIter<'a> { + params: &'a Params, + index: usize, +} + +impl<'a> ParamsIter<'a> { + fn new(params: &'a Params) -> Self { + Self { params, index: 0 } + } +} + +impl<'a> Iterator for ParamsIter<'a> { + type Item = &'a [u16]; + + fn next(&mut self) -> Option { + if self.index >= self.params.len() { + return None; + } + + // Get all subparameters for the current parameter. + let num_subparams = self.params.subparams[self.index]; + let param = &self.params.params[self.index..self.index + num_subparams as usize]; + + // Jump to the next parameter. + self.index += num_subparams as usize; + + Some(param) + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = self.params.len() - self.index; + (remaining, Some(remaining)) + } +} + +impl Debug for Params { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "[")?; + + for (i, param) in self.iter().enumerate() { + if i != 0 { + write!(f, ";")?; + } + + for (i, subparam) in param.iter().enumerate() { + if i != 0 { + write!(f, ":")?; + } + + subparam.fmt(f)?; + } + } + + write!(f, "]") + } +} diff --git a/tools/vendor/anstyle-parse/src/state/codegen.rs b/tools/vendor/anstyle-parse/src/state/codegen.rs new file mode 100644 index 0000000000..60aae35dda --- /dev/null +++ b/tools/vendor/anstyle-parse/src/state/codegen.rs @@ -0,0 +1,218 @@ +use super::{pack, unpack, Action, State}; + +use snapbox::file; +use vte_generate_state_changes::generate_state_changes; + +#[test] +fn table() { + let mut content = vec![]; + generate_table(&mut content).unwrap(); + + let content = String::from_utf8(content).unwrap(); + let content = codegenrs::rustfmt(&content, None).unwrap(); + snapbox::assert_data_eq!(content, file!["table.rs"].raw()); +} + +#[allow(clippy::write_literal)] +fn generate_table(file: &mut impl std::io::Write) -> std::io::Result<()> { + writeln!( + file, + "// This file is @generated by {}", + std::file!().replace('\\', "/") + )?; + writeln!(file)?; + writeln!( + file, + "{}", + r#"#[rustfmt::skip] +pub(crate) const STATE_CHANGES: [[u8; 256]; 16] = ["# + )?; + + for (state, entries) in STATE_CHANGES.iter().enumerate() { + writeln!(file, " // {:?}", State::try_from(state as u8).unwrap())?; + write!(file, " [")?; + let mut last_entry = None; + for packed in entries { + let (next_state, action) = unpack(*packed); + if last_entry != Some(packed) { + writeln!(file)?; + writeln!(file, " // {next_state:?} {action:?}")?; + write!(file, " ")?; + } + write!(file, "0x{packed:0>2x}, ")?; + last_entry = Some(packed); + } + writeln!(file)?; + writeln!(file, " ],")?; + } + + writeln!(file, "{}", r#"];"#)?; + Ok(()) +} + +/// This is the state change table. It's indexed first by current state and then by the next +/// character in the pty stream. +pub(crate) static STATE_CHANGES: [[u8; 256]; 16] = state_changes(); +generate_state_changes!(state_changes, { + Anywhere { + 0x18 => (Ground, Execute), + 0x1a => (Ground, Execute), + 0x1b => (Escape, Nop), + }, + + Ground { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x7f => (Anywhere, Print), + 0x80..=0x8f => (Anywhere, Execute), + 0x91..=0x9a => (Anywhere, Execute), + 0x9c => (Anywhere, Execute), + // Beginning of UTF-8 2 byte sequence + 0xc2..=0xdf => (Utf8, BeginUtf8), + // Beginning of UTF-8 3 byte sequence + 0xe0..=0xef => (Utf8, BeginUtf8), + // Beginning of UTF-8 4 byte sequence + 0xf0..=0xf4 => (Utf8, BeginUtf8), + }, + + Escape { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x7f => (Anywhere, Ignore), + 0x20..=0x2f => (EscapeIntermediate, Collect), + 0x30..=0x4f => (Ground, EscDispatch), + 0x51..=0x57 => (Ground, EscDispatch), + 0x59 => (Ground, EscDispatch), + 0x5a => (Ground, EscDispatch), + 0x5c => (Ground, EscDispatch), + 0x60..=0x7e => (Ground, EscDispatch), + 0x5b => (CsiEntry, Nop), + 0x5d => (OscString, Nop), + 0x50 => (DcsEntry, Nop), + 0x58 => (SosPmApcString, Nop), + 0x5e => (SosPmApcString, Nop), + 0x5f => (SosPmApcString, Nop), + }, + + EscapeIntermediate { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x2f => (Anywhere, Collect), + 0x7f => (Anywhere, Ignore), + 0x30..=0x7e => (Ground, EscDispatch), + }, + + CsiEntry { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x7f => (Anywhere, Ignore), + 0x20..=0x2f => (CsiIntermediate, Collect), + 0x30..=0x39 => (CsiParam, Param), + 0x3a..=0x3b => (CsiParam, Param), + 0x3c..=0x3f => (CsiParam, Collect), + 0x40..=0x7e => (Ground, CsiDispatch), + }, + + CsiIgnore { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x3f => (Anywhere, Ignore), + 0x7f => (Anywhere, Ignore), + 0x40..=0x7e => (Ground, Nop), + }, + + CsiParam { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x30..=0x39 => (Anywhere, Param), + 0x3a..=0x3b => (Anywhere, Param), + 0x7f => (Anywhere, Ignore), + 0x3c..=0x3f => (CsiIgnore, Nop), + 0x20..=0x2f => (CsiIntermediate, Collect), + 0x40..=0x7e => (Ground, CsiDispatch), + }, + + CsiIntermediate { + 0x00..=0x17 => (Anywhere, Execute), + 0x19 => (Anywhere, Execute), + 0x1c..=0x1f => (Anywhere, Execute), + 0x20..=0x2f => (Anywhere, Collect), + 0x7f => (Anywhere, Ignore), + 0x30..=0x3f => (CsiIgnore, Nop), + 0x40..=0x7e => (Ground, CsiDispatch), + }, + + DcsEntry { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x7f => (Anywhere, Ignore), + 0x20..=0x2f => (DcsIntermediate, Collect), + 0x30..=0x39 => (DcsParam, Param), + 0x3a..=0x3b => (DcsParam, Param), + 0x3c..=0x3f => (DcsParam, Collect), + 0x40..=0x7e => (DcsPassthrough, Nop), + }, + + DcsIntermediate { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0x2f => (Anywhere, Collect), + 0x7f => (Anywhere, Ignore), + 0x30..=0x3f => (DcsIgnore, Nop), + 0x40..=0x7e => (DcsPassthrough, Nop), + }, + + DcsIgnore { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0x7f => (Anywhere, Ignore), + 0x9c => (Ground, Nop), + }, + + DcsParam { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x30..=0x39 => (Anywhere, Param), + 0x3a..=0x3b => (Anywhere, Param), + 0x7f => (Anywhere, Ignore), + 0x3c..=0x3f => (DcsIgnore, Nop), + 0x20..=0x2f => (DcsIntermediate, Collect), + 0x40..=0x7e => (DcsPassthrough, Nop), + }, + + DcsPassthrough { + 0x00..=0x17 => (Anywhere, Put), + 0x19 => (Anywhere, Put), + 0x1c..=0x1f => (Anywhere, Put), + 0x20..=0x7e => (Anywhere, Put), + 0x7f => (Anywhere, Ignore), + 0x9c => (Ground, Nop), + }, + + SosPmApcString { + 0x00..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0x7f => (Anywhere, Ignore), + 0x9c => (Ground, Nop), + }, + + OscString { + 0x00..=0x06 => (Anywhere, Ignore), + 0x07 => (Ground, Nop), + 0x08..=0x17 => (Anywhere, Ignore), + 0x19 => (Anywhere, Ignore), + 0x1c..=0x1f => (Anywhere, Ignore), + 0x20..=0xff => (Anywhere, OscPut), + } +}); diff --git a/tools/vendor/anstyle-parse/src/state/definitions.rs b/tools/vendor/anstyle-parse/src/state/definitions.rs new file mode 100644 index 0000000000..0b9f99a0fd --- /dev/null +++ b/tools/vendor/anstyle-parse/src/state/definitions.rs @@ -0,0 +1,171 @@ +#![allow(clippy::exhaustive_enums)] + +use core::mem; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u8)] +#[derive(Default)] +pub enum State { + Anywhere = 0, + CsiEntry = 1, + CsiIgnore = 2, + CsiIntermediate = 3, + CsiParam = 4, + DcsEntry = 5, + DcsIgnore = 6, + DcsIntermediate = 7, + DcsParam = 8, + DcsPassthrough = 9, + Escape = 10, + EscapeIntermediate = 11, + #[default] + Ground = 12, + OscString = 13, + SosPmApcString = 14, + Utf8 = 15, +} + +impl TryFrom for State { + type Error = u8; + + #[inline(always)] + fn try_from(raw: u8) -> Result { + STATES.get(raw as usize).ok_or(raw).copied() + } +} + +const STATES: [State; 16] = [ + State::Anywhere, + State::CsiEntry, + State::CsiIgnore, + State::CsiIntermediate, + State::CsiParam, + State::DcsEntry, + State::DcsIgnore, + State::DcsIntermediate, + State::DcsParam, + State::DcsPassthrough, + State::Escape, + State::EscapeIntermediate, + State::Ground, + State::OscString, + State::SosPmApcString, + State::Utf8, +]; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u8)] +#[derive(Default)] +pub enum Action { + #[default] + Nop = 0, + Clear = 1, + Collect = 2, + CsiDispatch = 3, + EscDispatch = 4, + Execute = 5, + Hook = 6, + Ignore = 7, + OscEnd = 8, + OscPut = 9, + OscStart = 10, + Param = 11, + Print = 12, + Put = 13, + Unhook = 14, + BeginUtf8 = 15, +} + +impl TryFrom for Action { + type Error = u8; + + #[inline(always)] + fn try_from(raw: u8) -> Result { + ACTIONS.get(raw as usize).ok_or(raw).copied() + } +} + +const ACTIONS: [Action; 16] = [ + Action::Nop, + Action::Clear, + Action::Collect, + Action::CsiDispatch, + Action::EscDispatch, + Action::Execute, + Action::Hook, + Action::Ignore, + Action::OscEnd, + Action::OscPut, + Action::OscStart, + Action::Param, + Action::Print, + Action::Put, + Action::Unhook, + Action::BeginUtf8, +]; + +/// Unpack a u8 into a State and Action +/// +/// The implementation of this assumes that there are *precisely* 16 variants for both Action and +/// State. Furthermore, it assumes that the enums are tag-only; that is, there is no data in any +/// variant. +/// +/// Bad things will happen if those invariants are violated. +#[inline(always)] +pub(crate) const fn unpack(delta: u8) -> (State, Action) { + unsafe { + ( + // State is stored in bottom 4 bits + mem::transmute::(delta & 0x0f), + // Action is stored in top 4 bits + mem::transmute::(delta >> 4), + ) + } +} + +#[inline(always)] +#[cfg(test)] +pub(crate) const fn pack(state: State, action: Action) -> u8 { + ((action as u8) << 4) | state as u8 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn unpack_state_action() { + match unpack(0xee) { + (State::SosPmApcString, Action::Unhook) => (), + _ => panic!("unpack failed"), + } + + match unpack(0x0f) { + (State::Utf8, Action::Nop) => (), + _ => panic!("unpack failed"), + } + + match unpack(0xff) { + (State::Utf8, Action::BeginUtf8) => (), + _ => panic!("unpack failed"), + } + } + + #[test] + fn pack_state_action() { + match unpack(0xee) { + (State::SosPmApcString, Action::Unhook) => (), + _ => panic!("unpack failed"), + } + + match unpack(0x0f) { + (State::Utf8, Action::Nop) => (), + _ => panic!("unpack failed"), + } + + match unpack(0xff) { + (State::Utf8, Action::BeginUtf8) => (), + _ => panic!("unpack failed"), + } + } +} diff --git a/tools/vendor/anstyle-parse/src/state/mod.rs b/tools/vendor/anstyle-parse/src/state/mod.rs new file mode 100644 index 0000000000..a1d869187a --- /dev/null +++ b/tools/vendor/anstyle-parse/src/state/mod.rs @@ -0,0 +1,43 @@ +//! ANSI escape code parsing state machine + +#[cfg(test)] +mod codegen; +mod definitions; +mod table; + +#[cfg(test)] +pub(crate) use definitions::pack; +pub(crate) use definitions::unpack; +pub use definitions::Action; +pub use definitions::State; + +/// Transition to next [`State`] +/// +/// Note: This does not directly support UTF-8. +/// - If the data is validated as UTF-8 (e.g. `str`) or single-byte C1 control codes are +/// unsupported, then treat [`Action::BeginUtf8`] and [`Action::Execute`] for UTF-8 continuations +/// as [`Action::Print`]. +/// - If the data is not validated, then a UTF-8 state machine will need to be implemented on top, +/// starting with [`Action::BeginUtf8`]. +/// +/// Note: When [`State::Anywhere`] is returned, revert back to the prior state. +#[inline] +pub const fn state_change(state: State, byte: u8) -> (State, Action) { + // Handle state changes in the anywhere state before evaluating changes + // for current state. + let mut change = state_change_(State::Anywhere, byte); + if change == 0 { + change = state_change_(state, byte); + } + + // Unpack into a state and action + unpack(change) +} + +#[inline] +const fn state_change_(state: State, byte: u8) -> u8 { + let state_idx = state as usize; + let byte_idx = byte as usize; + + table::STATE_CHANGES[state_idx][byte_idx] +} diff --git a/tools/vendor/anstyle-parse/src/state/table.rs b/tools/vendor/anstyle-parse/src/state/table.rs new file mode 100644 index 0000000000..f6f10703cb --- /dev/null +++ b/tools/vendor/anstyle-parse/src/state/table.rs @@ -0,0 +1,361 @@ +// This file is @generated by crates/anstyle-parse/src/state/codegen.rs + +#[rustfmt::skip] +pub(crate) const STATE_CHANGES: [[u8; 256]; 16] = [ + // Anywhere + [ + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Ground Execute + 0x5c, + // Anywhere Nop + 0x00, + // Ground Execute + 0x5c, + // Escape Nop + 0x0a, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // CsiEntry + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // CsiIntermediate Collect + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + // CsiParam Param + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + // CsiParam Collect + 0x24, 0x24, 0x24, 0x24, + // Ground CsiDispatch + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // CsiIgnore + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Ground Nop + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // CsiIntermediate + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // Anywhere Collect + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + // CsiIgnore Nop + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + // Ground CsiDispatch + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // CsiParam + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // CsiIntermediate Collect + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + // Anywhere Param + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + // CsiIgnore Nop + 0x02, 0x02, 0x02, 0x02, + // Ground CsiDispatch + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // DcsEntry + [ + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, + // DcsIntermediate Collect + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + // DcsParam Param + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + // DcsParam Collect + 0x28, 0x28, 0x28, 0x28, + // DcsPassthrough Nop + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // DcsIgnore + [ + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Ground Nop + 0x0c, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // DcsIntermediate + [ + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, + // Anywhere Collect + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + // DcsIgnore Nop + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + // DcsPassthrough Nop + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // DcsParam + [ + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, + // DcsIntermediate Collect + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + // Anywhere Param + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + // DcsIgnore Nop + 0x06, 0x06, 0x06, 0x06, + // DcsPassthrough Nop + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // DcsPassthrough + [ + // Anywhere Put + 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + // Anywhere Nop + 0x00, + // Anywhere Put + 0xd0, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Put + 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Ground Nop + 0x0c, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // Escape + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // EscapeIntermediate Collect + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + // Ground EscDispatch + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + // DcsEntry Nop + 0x05, + // Ground EscDispatch + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + // SosPmApcString Nop + 0x0e, + // Ground EscDispatch + 0x4c, 0x4c, + // CsiEntry Nop + 0x01, + // Ground EscDispatch + 0x4c, + // OscString Nop + 0x0d, + // SosPmApcString Nop + 0x0e, 0x0e, + // Ground EscDispatch + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // EscapeIntermediate + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // Anywhere Collect + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + // Ground EscDispatch + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // Ground + [ + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, + // Anywhere Print + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + // Anywhere Nop + 0x00, + // Anywhere Execute + 0x50, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Utf8 BeginUtf8 + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // OscString + [ + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Ground Nop + 0x0c, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, + // Anywhere OscPut + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + ], + // SosPmApcString + [ + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, + // Anywhere Ignore + 0x70, + // Anywhere Nop + 0x00, 0x00, + // Anywhere Ignore + 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // Ground Nop + 0x0c, + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + // Utf8 + [ + // Anywhere Nop + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], +]; diff --git a/tools/vendor/anstyle-query/.cargo-checksum.json b/tools/vendor/anstyle-query/.cargo-checksum.json new file mode 100644 index 0000000000..d564c4ee18 --- /dev/null +++ b/tools/vendor/anstyle-query/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"f59adccd8ea63dbc3aabdeb0520620695916f51f5306d1bb89f5008f7ad74724","Cargo.lock":"477d4354569c8a359d9056ab89ed2782a0a5cf609bb1f46e5da02c7059858e20","Cargo.toml":"478a0950938a0e6eea2bb824607c056c9ac517a45716841fe940b6e3488323b7","Cargo.toml.orig":"fab7c65e55f307103a392c58f7027a43c1b37918ae8f5e715dcb842140d693d0","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"9ed87a71a298ed4925210e66dd06c69f40600c1df97fd082d1763c2220c9f2f1","examples/query.rs":"fca5f5f48a20d282982a4de584dd79470375d89bf990447b0c6f24e842956297","src/lib.rs":"4ce20ab732c39c004a4d768567e4ad93758eaf402262b22ef009386950232c28","src/windows.rs":"76a8355df494a8152395377b7b9568615ea8fd9d6ab8ec998c6de1deb271697e"},"package":"40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"} \ No newline at end of file diff --git a/tools/vendor/anstyle-query/.cargo_vcs_info.json b/tools/vendor/anstyle-query/.cargo_vcs_info.json new file mode 100644 index 0000000000..d9e5ef25cc --- /dev/null +++ b/tools/vendor/anstyle-query/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "368a8719474357f9d54be800b4163c9074561e37" + }, + "path_in_vcs": "crates/anstyle-query" +} \ No newline at end of file diff --git a/tools/vendor/anstyle-query/Cargo.lock b/tools/vendor/anstyle-query/Cargo.lock new file mode 100644 index 0000000000..eb68f5b62e --- /dev/null +++ b/tools/vendor/anstyle-query/Cargo.lock @@ -0,0 +1,90 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstyle-query" +version = "1.1.5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" diff --git a/tools/vendor/anstyle-query/Cargo.toml b/tools/vendor/anstyle-query/Cargo.toml new file mode 100644 index 0000000000..1268520e55 --- /dev/null +++ b/tools/vendor/anstyle-query/Cargo.toml @@ -0,0 +1,173 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.66.0" +name = "anstyle-query" +version = "1.1.5" +build = false +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "Cargo.lock", + "LICENSE*", + "README.md", + "examples/**/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Look up colored console capabilities" +readme = "README.md" +keywords = [ + "cli", + "color", + "no-std", + "terminal", + "ansi", +] +categories = ["command-line-interface"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-cli/anstyle.git" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", + "--generate-link-to-definition", +] + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "Unreleased" +replace = "{{version}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = '\.\.\.HEAD' +replace = "...{{tag_name}}" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "ReleaseDate" +replace = "{{date}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +## [Unreleased] - ReleaseDate +""" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD""" +exactly = 1 + +[lib] +name = "anstyle_query" +path = "src/lib.rs" + +[[example]] +name = "query" +path = "examples/query.rs" + +[target."cfg(windows)".dependencies.windows-sys] +version = ">=0.60.2, <0.62" +features = [ + "Win32_System_Console", + "Win32_Foundation", +] + +[lints.clippy] +bool_assert_comparison = "allow" +branches_sharing_code = "allow" +checked_conversions = "warn" +collapsible_else_if = "allow" +create_dir = "warn" +dbg_macro = "warn" +debug_assert_with_mut_call = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +fallible_impl_from = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp_const = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +imprecise_flops = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +invalid_upcast_comparisons = "warn" +large_digit_groups = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +let_and_return = "allow" +linkedlist = "warn" +lossy_float_literal = "warn" +macro_use_imports = "warn" +mem_forget = "warn" +mutex_integer = "warn" +needless_continue = "allow" +needless_for_each = "warn" +negative_feature_names = "warn" +path_buf_push_overwrite = "warn" +ptr_as_ptr = "warn" +rc_mutex = "warn" +redundant_feature_names = "warn" +ref_option_ref = "warn" +rest_pat_in_fully_bound_structs = "warn" +result_large_err = "allow" +same_functions_in_if_condition = "warn" +self_named_module_files = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" +string_add = "warn" +string_add_assign = "warn" +string_lit_as_bytes = "warn" +todo = "warn" +trait_duplication_in_bounds = "warn" +uninlined_format_args = "warn" +verbose_file_reads = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" + +[lints.rust] +unnameable_types = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[lints.rust.rust_2018_idioms] +level = "warn" +priority = -1 diff --git a/tools/vendor/anstyle-query/Cargo.toml.orig b/tools/vendor/anstyle-query/Cargo.toml.orig new file mode 100644 index 0000000000..084f20f526 --- /dev/null +++ b/tools/vendor/anstyle-query/Cargo.toml.orig @@ -0,0 +1,30 @@ +[package] +name = "anstyle-query" +version = "1.1.5" +description = "Look up colored console capabilities" +categories = ["command-line-interface"] +keywords = ["cli", "color", "no-std", "terminal", "ansi"] +repository.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = ">=0.60.2, <0.62", features = ["Win32_System_Console", "Win32_Foundation"] } + +[lints] +workspace = true diff --git a/tools/vendor/anstyle-query/LICENSE-APACHE b/tools/vendor/anstyle-query/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/tools/vendor/anstyle-query/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/tools/vendor/anstyle-query/LICENSE-MIT b/tools/vendor/anstyle-query/LICENSE-MIT new file mode 100644 index 0000000000..a2d01088b6 --- /dev/null +++ b/tools/vendor/anstyle-query/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/vendor/anstyle-query/README.md b/tools/vendor/anstyle-query/README.md new file mode 100644 index 0000000000..cedce61621 --- /dev/null +++ b/tools/vendor/anstyle-query/README.md @@ -0,0 +1,25 @@ +# anstyle-query + +> **Low level terminal capability lookups** + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/anstyle-query.svg) +[![Crates Status](https://img.shields.io/crates/v/anstyle-query.svg)](https://crates.io/crates/anstyle-query) + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## [Contribute](../../CONTRIBUTING.md) + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual-licensed as above, without any additional terms or +conditions. + +[Documentation]: https://docs.rs/anstyle-query diff --git a/tools/vendor/anstyle-query/examples/query.rs b/tools/vendor/anstyle-query/examples/query.rs new file mode 100644 index 0000000000..e5d66205a8 --- /dev/null +++ b/tools/vendor/anstyle-query/examples/query.rs @@ -0,0 +1,26 @@ +//! Report a terminal's capabilities + +fn main() { + println!("clicolor: {:?}", anstyle_query::clicolor()); + println!("clicolor_force: {}", anstyle_query::clicolor_force()); + println!("no_color: {}", anstyle_query::no_color()); + println!( + "term_supports_ansi_color: {}", + anstyle_query::term_supports_ansi_color() + ); + println!( + "term_supports_color: {}", + anstyle_query::term_supports_color() + ); + println!("truecolor: {}", anstyle_query::truecolor()); + println!( + "enable_ansi_colors: {:?}", + anstyle_query::windows::enable_ansi_colors() + ); + #[cfg(windows)] + println!( + " enable_virtual_terminal_processing: {:?}", + anstyle_query::windows::enable_virtual_terminal_processing() + ); + println!("is_ci: {:?}", anstyle_query::is_ci()); +} diff --git a/tools/vendor/anstyle-query/src/lib.rs b/tools/vendor/anstyle-query/src/lib.rs new file mode 100644 index 0000000000..f17570a161 --- /dev/null +++ b/tools/vendor/anstyle-query/src/lib.rs @@ -0,0 +1,163 @@ +//! Low level terminal capability lookups + +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs)] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] + +pub mod windows; + +/// Check [CLICOLOR] status +/// +/// - When `true`, ANSI colors are supported and should be used when the program isn't piped, +/// similar to [`term_supports_color`] +/// - When `false`, don’t output ANSI color escape codes, similar to [`no_color`] +/// +/// See also: +/// - [terminfo](https://crates.io/crates/terminfo) or [term](https://crates.io/crates/term) for +/// checking termcaps +/// - [termbg](https://crates.io/crates/termbg) for detecting background color +/// +/// [CLICOLOR]: https://bixense.com/clicolors/ +#[inline] +pub fn clicolor() -> Option { + let value = std::env::var_os("CLICOLOR")?; + Some(value != "0") +} + +/// Check [CLICOLOR_FORCE] status +/// +/// ANSI colors should be enabled no matter what. +/// +/// [CLICOLOR_FORCE]: https://bixense.com/clicolors/ +#[inline] +pub fn clicolor_force() -> bool { + non_empty(std::env::var_os("CLICOLOR_FORCE").as_deref()) +} + +/// Check [NO_COLOR] status +/// +/// When `true`, should prevent the addition of ANSI color. +/// +/// User-level configuration files and per-instance command-line arguments should override +/// [NO_COLOR]. A user should be able to export `$NO_COLOR` in their shell configuration file as a +/// default, but configure a specific program in its configuration file to specifically enable +/// color. +/// +/// [NO_COLOR]: https://no-color.org/ +#[inline] +pub fn no_color() -> bool { + non_empty(std::env::var_os("NO_COLOR").as_deref()) +} + +/// Check `TERM` for color support +#[inline] +pub fn term_supports_color() -> bool { + #[cfg(not(windows))] + { + match std::env::var_os("TERM") { + // If TERM isn't set, then we are in a weird environment that + // probably doesn't support colors. + None => return false, + Some(k) => { + if k == "dumb" { + return false; + } + } + } + true + } + #[cfg(windows)] + { + // On Windows, if TERM isn't set, then we shouldn't automatically + // assume that colors aren't allowed. This is unlike Unix environments + // where TERM is more rigorously set. + if let Some(k) = std::env::var_os("TERM") { + if k == "dumb" { + return false; + } + } + true + } +} + +/// Check `TERM` for ANSI color support +/// +/// On Windows, you might need to also check [`windows::enable_ansi_colors`] as ANSI color support +/// is opt-in, rather than assumed. +#[inline] +pub fn term_supports_ansi_color() -> bool { + #[cfg(not(windows))] + { + term_supports_color() + } + #[cfg(windows)] + { + match std::env::var_os("TERM") { + None => return false, + Some(k) => { + // cygwin doesn't seem to support ANSI escape sequences + // and instead has its own variety. However, the Windows + // console API may be available. + if k == "dumb" || k == "cygwin" { + return false; + } + } + } + true + } +} + +/// Check [COLORTERM] for truecolor support +/// +/// [COLORTERM]: https://github.com/termstandard/colors +#[inline] +pub fn truecolor() -> bool { + let value = std::env::var_os("COLORTERM"); + let value = value.as_deref().unwrap_or_default(); + value == "truecolor" || value == "24bit" +} + +/// Report whether this is running in CI +/// +/// CI is a common environment where, despite being piped, ansi color codes are supported +/// +/// This is not as exhaustive as you'd find in a crate like `is_ci` but it should work in enough +/// cases. +#[inline] +pub fn is_ci() -> bool { + // Assuming its CI based on presence because who would be setting `CI=false`? + // + // This makes it easier to all of the potential values when considering our known values: + // - Gitlab and Github set it to `true` + // - Woodpecker sets it to `woodpecker` + std::env::var_os("CI").is_some() +} + +fn non_empty(var: Option<&std::ffi::OsStr>) -> bool { + !var.unwrap_or_default().is_empty() +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn non_empty_not_present() { + assert!(!non_empty(None)); + } + + #[test] + fn non_empty_empty() { + assert!(!non_empty(Some(std::ffi::OsStr::new("")))); + } + + #[test] + fn non_empty_texty() { + assert!(non_empty(Some(std::ffi::OsStr::new("hello")))); + } +} + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/tools/vendor/anstyle-query/src/windows.rs b/tools/vendor/anstyle-query/src/windows.rs new file mode 100644 index 0000000000..048272217e --- /dev/null +++ b/tools/vendor/anstyle-query/src/windows.rs @@ -0,0 +1,79 @@ +//! Windows-specific style queries + +#[cfg(windows)] +mod windows_console { + use std::os::windows::io::AsRawHandle; + use std::os::windows::io::RawHandle; + + use windows_sys::Win32::Foundation::HANDLE; + use windows_sys::Win32::System::Console::CONSOLE_MODE; + use windows_sys::Win32::System::Console::ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + fn enable_vt(handle: RawHandle) -> std::io::Result<()> { + unsafe { + let handle: HANDLE = handle as HANDLE; + if handle.is_null() { + return Err(std::io::Error::new( + std::io::ErrorKind::BrokenPipe, + "console is detached", + )); + } + + let mut dwmode: CONSOLE_MODE = 0; + if windows_sys::Win32::System::Console::GetConsoleMode(handle, &mut dwmode) == 0 { + return Err(std::io::Error::last_os_error()); + } + + dwmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + if windows_sys::Win32::System::Console::SetConsoleMode(handle, dwmode) == 0 { + return Err(std::io::Error::last_os_error()); + } + + Ok(()) + } + } + + pub(crate) fn enable_virtual_terminal_processing() -> std::io::Result<()> { + let stdout = std::io::stdout(); + let stdout_handle = stdout.as_raw_handle(); + let stderr = std::io::stderr(); + let stderr_handle = stderr.as_raw_handle(); + + enable_vt(stdout_handle)?; + if stdout_handle != stderr_handle { + enable_vt(stderr_handle)?; + } + + Ok(()) + } + + #[inline] + pub(crate) fn enable_ansi_colors() -> Option { + Some( + enable_virtual_terminal_processing() + .map(|_| true) + .unwrap_or(false), + ) + } +} + +#[cfg(not(windows))] +mod windows_console { + #[inline] + pub(crate) fn enable_ansi_colors() -> Option { + None + } +} + +/// Enable ANSI escape codes ([`ENABLE_VIRTUAL_TERMINAL_PROCESSING`](https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences#output-sequences)) +/// +/// For non-windows systems, returns `None` +pub fn enable_ansi_colors() -> Option { + windows_console::enable_ansi_colors() +} + +/// Raw `ENABLE_VIRTUAL_TERMINAL_PROCESSING` on stdout/stderr +#[cfg(windows)] +pub fn enable_virtual_terminal_processing() -> std::io::Result<()> { + windows_console::enable_virtual_terminal_processing() +} diff --git a/tools/vendor/anstyle-wincon/.cargo-checksum.json b/tools/vendor/anstyle-wincon/.cargo-checksum.json new file mode 100644 index 0000000000..d70787c79e --- /dev/null +++ b/tools/vendor/anstyle-wincon/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"9d39f51788117eb8ff1e40f7e664b63450737ec11d5670e1d5b3fc13d45e5032","Cargo.lock":"fabba837ae654e97f42dd56a61fc8606e7c37bf54dee47e93dfc4e093db3c6a6","Cargo.toml":"be7526c599f7d291150912990e4a70cef1e691c96c300c06c784d310dc00efb3","Cargo.toml.orig":"6be136b355f517efe523de76cdc120b0a7d943418b9bf25bbbc75da5a314dc73","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"b979881246703593aad26da21f5d467c03c35142d6f5965f7e7253cb89695c9f","examples/dump-wincon.rs":"f585b378e151f0489465cd769ab49e59665dcc3cb17c9dd12a9893ba186edd48","examples/set-wincon.rs":"b8862ad2c5c8e834932c6f3baf64c5c65058021805e6fecc989ec50288a87c51","src/ansi.rs":"765d868d6efd1324c21a1c778a3a3be4c6fa9fc3191b415858e0a4d2b8f01a3f","src/lib.rs":"faa64326e95cdbff9b999adafcfdbc8e576859537272200cebdb630e8cfd7d22","src/stream.rs":"8b0a852b1c43d9b483154a7820edd30f658409349f9db339eb18e873aafd6b32","src/windows.rs":"ef7a56c7bc4436a46c93ce85220e5c03c0ca82fbe945521360ea9ecffce4291d"},"package":"291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"} \ No newline at end of file diff --git a/tools/vendor/anstyle-wincon/.cargo_vcs_info.json b/tools/vendor/anstyle-wincon/.cargo_vcs_info.json new file mode 100644 index 0000000000..fd91068ea2 --- /dev/null +++ b/tools/vendor/anstyle-wincon/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "368a8719474357f9d54be800b4163c9074561e37" + }, + "path_in_vcs": "crates/anstyle-wincon" +} \ No newline at end of file diff --git a/tools/vendor/anstyle-wincon/Cargo.lock b/tools/vendor/anstyle-wincon/Cargo.lock new file mode 100644 index 0000000000..119e51ec12 --- /dev/null +++ b/tools/vendor/anstyle-wincon/Cargo.lock @@ -0,0 +1,120 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +dependencies = [ + "anstyle", + "lexopt", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "lexopt" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7" + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.56.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aab899efe6ce4fe821f6dda30c02d7041c79f147598ab4b60197f181e12d001" +dependencies = [ + "once_cell", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" diff --git a/tools/vendor/anstyle-wincon/Cargo.toml b/tools/vendor/anstyle-wincon/Cargo.toml new file mode 100644 index 0000000000..c64597d512 --- /dev/null +++ b/tools/vendor/anstyle-wincon/Cargo.toml @@ -0,0 +1,186 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.66.0" +name = "anstyle-wincon" +version = "3.0.11" +build = false +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "Cargo.lock", + "LICENSE*", + "README.md", + "examples/**/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Styling legacy Windows terminals" +readme = "README.md" +keywords = [ + "ansi", + "terminal", + "color", + "windows", +] +categories = ["command-line-interface"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-cli/anstyle.git" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = [ + "--cfg", + "docsrs", + "--generate-link-to-definition", +] +targets = ["x86_64-pc-windows-msvc"] + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "Unreleased" +replace = "{{version}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = '\.\.\.HEAD' +replace = "...{{tag_name}}" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "ReleaseDate" +replace = "{{date}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +## [Unreleased] - ReleaseDate +""" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD""" +exactly = 1 + +[lib] +name = "anstyle_wincon" +path = "src/lib.rs" + +[[example]] +name = "dump-wincon" +path = "examples/dump-wincon.rs" + +[[example]] +name = "set-wincon" +path = "examples/set-wincon.rs" + +[dependencies.anstyle] +version = "1.0.0" + +[dev-dependencies.lexopt] +version = "0.3.1" + +[target."cfg(windows)".dependencies.once_cell_polyfill] +version = "1.56.1" + +[target."cfg(windows)".dependencies.windows-sys] +version = ">=0.60.2, <0.62" +features = [ + "Win32_System_Console", + "Win32_Foundation", +] + +[lints.clippy] +bool_assert_comparison = "allow" +branches_sharing_code = "allow" +checked_conversions = "warn" +collapsible_else_if = "allow" +create_dir = "warn" +dbg_macro = "warn" +debug_assert_with_mut_call = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +fallible_impl_from = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp_const = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +imprecise_flops = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +invalid_upcast_comparisons = "warn" +large_digit_groups = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +let_and_return = "allow" +linkedlist = "warn" +lossy_float_literal = "warn" +macro_use_imports = "warn" +mem_forget = "warn" +mutex_integer = "warn" +needless_continue = "allow" +needless_for_each = "warn" +negative_feature_names = "warn" +path_buf_push_overwrite = "warn" +ptr_as_ptr = "warn" +rc_mutex = "warn" +redundant_feature_names = "warn" +ref_option_ref = "warn" +rest_pat_in_fully_bound_structs = "warn" +result_large_err = "allow" +same_functions_in_if_condition = "warn" +self_named_module_files = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" +string_add = "warn" +string_add_assign = "warn" +string_lit_as_bytes = "warn" +todo = "warn" +trait_duplication_in_bounds = "warn" +uninlined_format_args = "warn" +verbose_file_reads = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" + +[lints.rust] +unnameable_types = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[lints.rust.rust_2018_idioms] +level = "warn" +priority = -1 diff --git a/tools/vendor/anstyle-wincon/Cargo.toml.orig b/tools/vendor/anstyle-wincon/Cargo.toml.orig new file mode 100644 index 0000000000..15d8c4bed1 --- /dev/null +++ b/tools/vendor/anstyle-wincon/Cargo.toml.orig @@ -0,0 +1,38 @@ +[package] +name = "anstyle-wincon" +version = "3.0.11" +description = "Styling legacy Windows terminals" +categories = ["command-line-interface"] +keywords = ["ansi", "terminal", "color", "windows"] +repository.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] +targets = ["x86_64-pc-windows-msvc"] + +[package.metadata.release] +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[dependencies] +anstyle = { version = "1.0.0", path = "../anstyle" } + +[dev-dependencies] +lexopt = "0.3.1" + +[target.'cfg(windows)'.dependencies] +windows-sys = { version = ">=0.60.2, <0.62", features = ["Win32_System_Console", "Win32_Foundation"] } +once_cell_polyfill = "1.56.1" + +[lints] +workspace = true diff --git a/tools/vendor/anstyle-wincon/LICENSE-APACHE b/tools/vendor/anstyle-wincon/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/tools/vendor/anstyle-wincon/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/tools/vendor/anstyle-wincon/LICENSE-MIT b/tools/vendor/anstyle-wincon/LICENSE-MIT new file mode 100644 index 0000000000..a2d01088b6 --- /dev/null +++ b/tools/vendor/anstyle-wincon/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/vendor/anstyle-wincon/README.md b/tools/vendor/anstyle-wincon/README.md new file mode 100644 index 0000000000..cb7918997c --- /dev/null +++ b/tools/vendor/anstyle-wincon/README.md @@ -0,0 +1,30 @@ +# anstyle-wincon + +> Styling legacy Windows terminals + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/anstyle-wincon.svg) +[![Crates Status](https://img.shields.io/crates/v/anstyle-wincon.svg)](https://crates.io/crates/anstyle-wincon) + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## [Contribute](../../CONTRIBUTING.md) + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual-licensed as above, without any additional terms or +conditions. + +### Special Thanks + +[burntsushi](https://github.com/burntsushi) for [termcolor](https://github.com/burntsushi/termcolor) as I don't know Windows either :) + +[Crates.io]: https://crates.io/crates/anstyle-wincon +[Documentation]: https://docs.rs/anstyle-wincon diff --git a/tools/vendor/anstyle-wincon/examples/dump-wincon.rs b/tools/vendor/anstyle-wincon/examples/dump-wincon.rs new file mode 100644 index 0000000000..fce11c6900 --- /dev/null +++ b/tools/vendor/anstyle-wincon/examples/dump-wincon.rs @@ -0,0 +1,142 @@ +//! Write colored text using wincon API calls + +use anstyle_wincon::WinconStream as _; + +fn main() -> Result<(), lexopt::Error> { + let args = Args::parse()?; + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + for fixed in 0..16 { + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + if fixed == 7 || fixed == 15 { + let _ = stdout.write_colored(None, None, &b"\n"[..]); + } + } + + for fixed in 16..232 { + let col = (fixed - 16) % 36; + if col == 0 { + let _ = stdout.write_colored(None, None, &b"\n"[..]); + } + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + let _ = stdout.write_colored(None, None, &b"\n"[..]); + let _ = stdout.write_colored(None, None, &b"\n"[..]); + for fixed in 232..=255 { + let style = style(fixed, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + let _ = stdout.write_colored(None, None, &b"\n"[..]); + + Ok(()) +} + +fn style( + color: impl Into, + layer: Layer, + effects: anstyle::Effects, +) -> anstyle::Style { + let color = color.into(); + (match layer { + Layer::Fg => anstyle::Style::new().fg_color(Some(color)), + Layer::Bg => anstyle::Style::new().bg_color(Some(color)), + Layer::Underline => anstyle::Style::new().underline_color(Some(color)), + }) | effects +} + +fn print_number( + stdout: &mut std::io::StdoutLock<'static>, + fixed: u8, + style: anstyle::Style, +) -> std::io::Result<()> { + let fg = style.get_fg_color().and_then(|c| match c { + anstyle::Color::Ansi(c) => Some(c), + anstyle::Color::Ansi256(c) => c.into_ansi(), + anstyle::Color::Rgb(_) => None, + }); + let bg = style.get_bg_color().and_then(|c| match c { + anstyle::Color::Ansi(c) => Some(c), + anstyle::Color::Ansi256(c) => c.into_ansi(), + anstyle::Color::Rgb(_) => None, + }); + + stdout + .write_colored(fg, bg, format!("{fixed:>3X}").as_bytes()) + .map(|_| ()) +} + +#[derive(Default)] +struct Args { + effects: anstyle::Effects, + layer: Layer, +} + +#[derive(Copy, Clone, Default)] +enum Layer { + #[default] + Fg, + Bg, + Underline, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("layer") => { + res.layer = args.value()?.parse_with(|s| match s { + "fg" => Ok(Layer::Fg), + "bg" => Ok(Layer::Bg), + "underline" => Ok(Layer::Underline), + _ => Err("expected values fg, bg, underline"), + })?; + } + Long("effect") => { + const EFFECTS: [(&str, anstyle::Effects); 12] = [ + ("bold", anstyle::Effects::BOLD), + ("dimmed", anstyle::Effects::DIMMED), + ("italic", anstyle::Effects::ITALIC), + ("underline", anstyle::Effects::UNDERLINE), + ("double_underline", anstyle::Effects::UNDERLINE), + ("curly_underline", anstyle::Effects::CURLY_UNDERLINE), + ("dotted_underline", anstyle::Effects::DOTTED_UNDERLINE), + ("dashed_underline", anstyle::Effects::DASHED_UNDERLINE), + ("blink", anstyle::Effects::BLINK), + ("invert", anstyle::Effects::INVERT), + ("hidden", anstyle::Effects::HIDDEN), + ("strikethrough", anstyle::Effects::STRIKETHROUGH), + ]; + let effect = args.value()?.parse_with(|s| { + EFFECTS + .into_iter() + .find(|(name, _)| *name == s) + .map(|(_, effect)| effect) + .ok_or_else(|| { + format!( + "expected one of {}", + EFFECTS + .into_iter() + .map(|(n, _)| n) + .collect::>() + .join(", ") + ) + }) + })?; + res.effects = res.effects.insert(effect); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/tools/vendor/anstyle-wincon/examples/set-wincon.rs b/tools/vendor/anstyle-wincon/examples/set-wincon.rs new file mode 100644 index 0000000000..14224d9f14 --- /dev/null +++ b/tools/vendor/anstyle-wincon/examples/set-wincon.rs @@ -0,0 +1,61 @@ +//! Interactively manipulate wincon colors + +#![cfg_attr(not(windows), allow(dead_code))] + +#[cfg(not(windows))] +fn main() { + panic!("unsupported"); +} + +#[cfg(windows)] +fn main() -> Result<(), lexopt::Error> { + use anstyle_wincon::WinconStream as _; + + let args = Args::parse()?; + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + let fg = args.fg.and_then(|c| c.into_ansi()); + let bg = args.bg.and_then(|c| c.into_ansi()); + + let _ = stdout.write_colored(fg, bg, b""); + + #[allow(clippy::mem_forget)] + std::mem::forget(stdout); + + Ok(()) +} + +#[derive(Default)] +struct Args { + fg: Option, + bg: Option, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("fg") => { + res.fg = Some( + args.value()? + .parse_with(|s| s.parse::().map(anstyle::Ansi256Color))?, + ); + } + Long("bg") => { + res.fg = Some( + args.value()? + .parse_with(|s| s.parse::().map(anstyle::Ansi256Color))?, + ); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/tools/vendor/anstyle-wincon/src/ansi.rs b/tools/vendor/anstyle-wincon/src/ansi.rs new file mode 100644 index 0000000000..48c2c1e255 --- /dev/null +++ b/tools/vendor/anstyle-wincon/src/ansi.rs @@ -0,0 +1,25 @@ +//! Low-level ANSI-styling + +/// Write ANSI colored text to the stream +pub fn write_colored( + stream: &mut S, + fg: Option, + bg: Option, + data: &[u8], +) -> std::io::Result { + let non_default = fg.is_some() || bg.is_some(); + + if non_default { + if let Some(fg) = fg { + write!(stream, "{}", fg.render_fg())?; + } + if let Some(bg) = bg { + write!(stream, "{}", bg.render_bg())?; + } + } + let written = stream.write(data)?; + if non_default { + write!(stream, "{}", anstyle::Reset.render())?; + } + Ok(written) +} diff --git a/tools/vendor/anstyle-wincon/src/lib.rs b/tools/vendor/anstyle-wincon/src/lib.rs new file mode 100644 index 0000000000..7be030d4e1 --- /dev/null +++ b/tools/vendor/anstyle-wincon/src/lib.rs @@ -0,0 +1,25 @@ +//! Styling legacy Windows terminals +//! +//! See [`WinconStream`] +//! +//! This fills a similar role as [`winapi-util`](https://crates.io/crates/winapi-util) does for +//! [`termcolor`](https://crates.io/crates/termcolor) with the differences +//! - Uses `windows-sys` rather than `winapi` +//! - Uses [`anstyle`](https://crates.io/crates/termcolor) rather than defining its own types +//! - More focused, smaller + +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs)] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] + +pub mod ansi; +mod stream; +#[cfg(windows)] +pub mod windows; + +pub use stream::WinconStream; + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/tools/vendor/anstyle-wincon/src/stream.rs b/tools/vendor/anstyle-wincon/src/stream.rs new file mode 100644 index 0000000000..9692c7c21e --- /dev/null +++ b/tools/vendor/anstyle-wincon/src/stream.rs @@ -0,0 +1,163 @@ +/// Extend `std::io::Write` with wincon styling +pub trait WinconStream { + /// Write colored text to the stream + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result; +} + +impl WinconStream for &mut T { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + (**self).write_colored(fg, bg, data) + } +} + +impl WinconStream for Box { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + (**self).write_colored(fg, bg, data) + } +} + +impl WinconStream for dyn std::io::Write { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } +} + +impl WinconStream for dyn std::io::Write + Send { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } +} + +impl WinconStream for dyn std::io::Write + Send + Sync { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } +} + +impl WinconStream for std::fs::File { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } +} + +impl WinconStream for Vec { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } +} + +impl WinconStream for std::io::Stdout { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + // Ensure exclusive access + self.lock().write_colored(fg, bg, data) + } +} + +impl WinconStream for std::io::Stderr { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + // Ensure exclusive access + self.lock().write_colored(fg, bg, data) + } +} + +#[cfg(not(windows))] +mod platform { + impl super::WinconStream for std::io::StdoutLock<'_> { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } + } + + impl super::WinconStream for std::io::StderrLock<'_> { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + crate::ansi::write_colored(self, fg, bg, data) + } + } +} + +#[cfg(windows)] +mod platform { + impl super::WinconStream for std::io::StdoutLock<'_> { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + let initial = crate::windows::stdout_initial_colors(); + crate::windows::write_colored(self, fg, bg, data, initial) + } + } + + impl super::WinconStream for std::io::StderrLock<'_> { + fn write_colored( + &mut self, + fg: Option, + bg: Option, + data: &[u8], + ) -> std::io::Result { + let initial = crate::windows::stderr_initial_colors(); + crate::windows::write_colored(self, fg, bg, data, initial) + } + } +} diff --git a/tools/vendor/anstyle-wincon/src/windows.rs b/tools/vendor/anstyle-wincon/src/windows.rs new file mode 100644 index 0000000000..27dcd5c765 --- /dev/null +++ b/tools/vendor/anstyle-wincon/src/windows.rs @@ -0,0 +1,260 @@ +//! Low-level wincon-styling + +use std::os::windows::io::AsHandle; +use std::os::windows::io::AsRawHandle; + +type StdioColorResult = std::io::Result<(anstyle::AnsiColor, anstyle::AnsiColor)>; +type StdioColorInnerResult = Result<(anstyle::AnsiColor, anstyle::AnsiColor), inner::IoError>; + +/// Cached [`get_colors`] call for [`std::io::stdout`] +pub fn stdout_initial_colors() -> StdioColorResult { + static INITIAL: once_cell_polyfill::sync::OnceLock = + once_cell_polyfill::sync::OnceLock::new(); + (*INITIAL.get_or_init(|| get_colors_(&std::io::stdout()))).map_err(Into::into) +} + +/// Cached [`get_colors`] call for [`std::io::stderr`] +pub fn stderr_initial_colors() -> StdioColorResult { + static INITIAL: once_cell_polyfill::sync::OnceLock = + once_cell_polyfill::sync::OnceLock::new(); + (*INITIAL.get_or_init(|| get_colors_(&std::io::stderr()))).map_err(Into::into) +} + +/// Apply colors to future writes +/// +/// **Note:** Make sure any buffers are first flushed or else these colors will apply +pub fn set_colors( + stream: &mut S, + fg: anstyle::AnsiColor, + bg: anstyle::AnsiColor, +) -> std::io::Result<()> { + set_colors_(stream, fg, bg).map_err(Into::into) +} + +fn set_colors_( + stream: &mut S, + fg: anstyle::AnsiColor, + bg: anstyle::AnsiColor, +) -> Result<(), inner::IoError> { + let handle = stream.as_handle(); + let handle = handle.as_raw_handle(); + let attributes = inner::set_colors(fg, bg); + inner::set_console_text_attributes(handle, attributes) +} + +/// Get the colors currently active on the console +pub fn get_colors(stream: &S) -> StdioColorResult { + get_colors_(stream).map_err(Into::into) +} + +fn get_colors_(stream: &S) -> StdioColorInnerResult { + let handle = stream.as_handle(); + let handle = handle.as_raw_handle(); + let info = inner::get_screen_buffer_info(handle)?; + let (fg, bg) = inner::get_colors(&info); + Ok((fg, bg)) +} + +pub(crate) fn write_colored( + stream: &mut S, + fg: Option, + bg: Option, + data: &[u8], + initial: StdioColorResult, +) -> std::io::Result { + let (initial_fg, initial_bg) = initial?; + let non_default = fg.is_some() || bg.is_some(); + + if non_default { + let fg = fg.unwrap_or(initial_fg); + let bg = bg.unwrap_or(initial_bg); + // Ensure everything is written with the last set of colors before applying the next set + stream.flush()?; + set_colors(stream, fg, bg)?; + } + let written = stream.write(data)?; + if non_default { + // Ensure everything is written with the last set of colors before applying the next set + stream.flush()?; + set_colors(stream, initial_fg, initial_bg)?; + } + Ok(written) +} + +mod inner { + use std::os::windows::io::RawHandle; + + use windows_sys::Win32::Foundation::HANDLE; + use windows_sys::Win32::System::Console::CONSOLE_CHARACTER_ATTRIBUTES; + use windows_sys::Win32::System::Console::CONSOLE_SCREEN_BUFFER_INFO; + use windows_sys::Win32::System::Console::FOREGROUND_BLUE; + use windows_sys::Win32::System::Console::FOREGROUND_GREEN; + use windows_sys::Win32::System::Console::FOREGROUND_INTENSITY; + use windows_sys::Win32::System::Console::FOREGROUND_RED; + + const FOREGROUND_CYAN: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_BLUE | FOREGROUND_GREEN; + const FOREGROUND_MAGENTA: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_BLUE | FOREGROUND_RED; + const FOREGROUND_YELLOW: CONSOLE_CHARACTER_ATTRIBUTES = FOREGROUND_GREEN | FOREGROUND_RED; + const FOREGROUND_WHITE: CONSOLE_CHARACTER_ATTRIBUTES = + FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED; + + #[derive(Copy, Clone, Debug)] + pub(crate) enum IoError { + BrokenPipe, + RawOs(i32), + } + + impl From for std::io::Error { + fn from(io: IoError) -> Self { + match io { + IoError::BrokenPipe => { + std::io::Error::new(std::io::ErrorKind::BrokenPipe, "console is detached") + } + IoError::RawOs(code) => std::io::Error::from_raw_os_error(code), + } + } + } + + impl IoError { + fn last_os_error() -> Self { + Self::RawOs(std::io::Error::last_os_error().raw_os_error().unwrap()) + } + } + + pub(crate) fn get_screen_buffer_info( + handle: RawHandle, + ) -> Result { + unsafe { + let handle: HANDLE = handle as HANDLE; + if handle.is_null() { + return Err(IoError::BrokenPipe); + } + + let mut info: CONSOLE_SCREEN_BUFFER_INFO = std::mem::zeroed(); + if windows_sys::Win32::System::Console::GetConsoleScreenBufferInfo(handle, &mut info) + != 0 + { + Ok(info) + } else { + Err(IoError::last_os_error()) + } + } + } + + pub(crate) fn set_console_text_attributes( + handle: RawHandle, + attributes: CONSOLE_CHARACTER_ATTRIBUTES, + ) -> Result<(), IoError> { + unsafe { + let handle: HANDLE = handle as HANDLE; + if handle.is_null() { + return Err(IoError::BrokenPipe); + } + + if windows_sys::Win32::System::Console::SetConsoleTextAttribute(handle, attributes) != 0 + { + Ok(()) + } else { + Err(IoError::last_os_error()) + } + } + } + + pub(crate) fn get_colors( + info: &CONSOLE_SCREEN_BUFFER_INFO, + ) -> (anstyle::AnsiColor, anstyle::AnsiColor) { + let attributes = info.wAttributes; + let bg = from_nibble(attributes >> 4); + let fg = from_nibble(attributes); + (fg, bg) + } + + pub(crate) fn set_colors( + fg: anstyle::AnsiColor, + bg: anstyle::AnsiColor, + ) -> CONSOLE_CHARACTER_ATTRIBUTES { + to_nibble(bg) << 4 | to_nibble(fg) + } + + fn from_nibble(color: CONSOLE_CHARACTER_ATTRIBUTES) -> anstyle::AnsiColor { + if color & FOREGROUND_WHITE == FOREGROUND_WHITE { + // 3 bits high + anstyle::AnsiColor::White + } else if color & FOREGROUND_CYAN == FOREGROUND_CYAN { + // 2 bits high + anstyle::AnsiColor::Cyan + } else if color & FOREGROUND_YELLOW == FOREGROUND_YELLOW { + // 2 bits high + anstyle::AnsiColor::Yellow + } else if color & FOREGROUND_MAGENTA == FOREGROUND_MAGENTA { + // 2 bits high + anstyle::AnsiColor::Magenta + } else if color & FOREGROUND_RED == FOREGROUND_RED { + // 1 bit high + anstyle::AnsiColor::Red + } else if color & FOREGROUND_GREEN == FOREGROUND_GREEN { + // 1 bit high + anstyle::AnsiColor::Green + } else if color & FOREGROUND_BLUE == FOREGROUND_BLUE { + // 1 bit high + anstyle::AnsiColor::Blue + } else { + // 0 bits high + anstyle::AnsiColor::Black + } + .bright(color & FOREGROUND_INTENSITY == FOREGROUND_INTENSITY) + } + + fn to_nibble(color: anstyle::AnsiColor) -> CONSOLE_CHARACTER_ATTRIBUTES { + let mut attributes = 0; + attributes |= match color.bright(false) { + anstyle::AnsiColor::Black => 0, + anstyle::AnsiColor::Red => FOREGROUND_RED, + anstyle::AnsiColor::Green => FOREGROUND_GREEN, + anstyle::AnsiColor::Yellow => FOREGROUND_YELLOW, + anstyle::AnsiColor::Blue => FOREGROUND_BLUE, + anstyle::AnsiColor::Magenta => FOREGROUND_MAGENTA, + anstyle::AnsiColor::Cyan => FOREGROUND_CYAN, + anstyle::AnsiColor::White => FOREGROUND_WHITE, + anstyle::AnsiColor::BrightBlack + | anstyle::AnsiColor::BrightRed + | anstyle::AnsiColor::BrightGreen + | anstyle::AnsiColor::BrightYellow + | anstyle::AnsiColor::BrightBlue + | anstyle::AnsiColor::BrightMagenta + | anstyle::AnsiColor::BrightCyan + | anstyle::AnsiColor::BrightWhite => unreachable!("brights were toggled off"), + }; + if color.is_bright() { + attributes |= FOREGROUND_INTENSITY; + } + attributes + } + + #[test] + fn to_from_nibble() { + const COLORS: [anstyle::AnsiColor; 16] = [ + anstyle::AnsiColor::Black, + anstyle::AnsiColor::Red, + anstyle::AnsiColor::Green, + anstyle::AnsiColor::Yellow, + anstyle::AnsiColor::Blue, + anstyle::AnsiColor::Magenta, + anstyle::AnsiColor::Cyan, + anstyle::AnsiColor::White, + anstyle::AnsiColor::BrightBlack, + anstyle::AnsiColor::BrightRed, + anstyle::AnsiColor::BrightGreen, + anstyle::AnsiColor::BrightYellow, + anstyle::AnsiColor::BrightBlue, + anstyle::AnsiColor::BrightMagenta, + anstyle::AnsiColor::BrightCyan, + anstyle::AnsiColor::BrightWhite, + ]; + for expected in COLORS { + let nibble = to_nibble(expected); + let actual = from_nibble(nibble); + assert_eq!(expected, actual, "Intermediate: {nibble}"); + } + } +} diff --git a/tools/vendor/anstyle/.cargo-checksum.json b/tools/vendor/anstyle/.cargo-checksum.json new file mode 100644 index 0000000000..3e3b749d8f --- /dev/null +++ b/tools/vendor/anstyle/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{".cargo_vcs_info.json":"aa43c3d60cc3c1c3aca59bdbae57e2c8b73e413a84d70f6b7f6a0199dc961d03","Cargo.lock":"1687b9a301bc75e53a81d37c3db86088f5c2f64a5f234d485713b1e802595de5","Cargo.toml":"983467ed60784b38b4610f7c5ebff4179ba0bb17858b1d090ca9778657ef3b28","Cargo.toml.orig":"1fa4f97c2bc8feccf3d6647b12bd00188da2f5c6fe8fe5b61245fc868eb6a678","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"6efb0476a1cc085077ed49357026d8c173bf33017278ef440f222fb9cbcb66e6","README.md":"015245c48ad8fb28bc4b2ed85a992a6e1182aa7fd633ecaac8f69b229d2aacab","examples/dump-style.rs":"a6c89b70be79594485312ec4670886ea9f4bebbf2f39fedfbd16d92745824f82","src/color.rs":"c048b9724c7907decdbaa8654890fdf354121055e5330b2d23f027d81d945ab5","src/effect.rs":"ed72ba456c4804ff6669f41ee0754bf8e2d974c2217e3eeac0d4d23202b81289","src/lib.rs":"0b3ac694950781211aee56f48129317880c1c3056b0b7639f0ea6cddb0201c6c","src/macros.rs":"0c90b45626fe8331d5b3326abb831f4ba6e04bcc975b1b9c01e465715050caa2","src/reset.rs":"456baf708f7d595369d2d852427d1891208a9fad5e21291be3217c4e69114faf","src/style.rs":"6f5eee7892f10df47bc07dd8f5715ee5d0c438cba53b63b72dce0843423b42bd"},"package":"5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"} \ No newline at end of file diff --git a/tools/vendor/anstyle/.cargo_vcs_info.json b/tools/vendor/anstyle/.cargo_vcs_info.json new file mode 100644 index 0000000000..3b2c25691e --- /dev/null +++ b/tools/vendor/anstyle/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "14dd743496d1614f8261a093ce755f26d8e2069d" + }, + "path_in_vcs": "crates/anstyle" +} \ No newline at end of file diff --git a/tools/vendor/anstyle/Cargo.lock b/tools/vendor/anstyle/Cargo.lock new file mode 100644 index 0000000000..67daab0d6f --- /dev/null +++ b/tools/vendor/anstyle/Cargo.lock @@ -0,0 +1,226 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +dependencies = [ + "anstyle 1.0.10", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle" +version = "1.0.13" +dependencies = [ + "lexopt", + "snapbox", +] + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle 1.0.10", + "windows-sys 0.59.0", +] + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2736dd548daf35f50d261bbad35a83890bb9b461797f15de528485fbf206ab15" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "lexopt" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + +[[package]] +name = "snapbox" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881f1849454828a68363dd288b7a0a071e55e2a4356d2c38b567db18a9be0d9f" +dependencies = [ + "anstream", + "anstyle 1.0.10", + "normalize-line-endings", + "similar", + "snapbox-macros", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" +dependencies = [ + "anstream", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/tools/vendor/anstyle/Cargo.toml b/tools/vendor/anstyle/Cargo.toml new file mode 100644 index 0000000000..45168cc2ab --- /dev/null +++ b/tools/vendor/anstyle/Cargo.toml @@ -0,0 +1,177 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.66.0" +name = "anstyle" +version = "1.0.13" +build = false +include = [ + "build.rs", + "src/**/*", + "Cargo.toml", + "Cargo.lock", + "LICENSE*", + "README.md", + "examples/**/*", +] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "ANSI text styling" +readme = "README.md" +keywords = [ + "ansi", + "terminal", + "color", + "no_std", +] +categories = ["command-line-interface"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-cli/anstyle.git" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--generate-link-to-definition"] + +[package.metadata.release] +tag-prefix = "" + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "Unreleased" +replace = "{{version}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = '\.\.\.HEAD' +replace = "...{{tag_name}}" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "ReleaseDate" +replace = "{{date}}" +min = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +## [Unreleased] - ReleaseDate +""" +exactly = 1 + +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "" +replace = """ + +[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD""" +exactly = 1 + +[features] +default = ["std"] +std = [] + +[lib] +name = "anstyle" +path = "src/lib.rs" + +[[example]] +name = "dump-style" +path = "examples/dump-style.rs" + +[dependencies] + +[dev-dependencies.lexopt] +version = "0.3.0" + +[dev-dependencies.snapbox] +version = "0.6.5" + +[lints.clippy] +bool_assert_comparison = "allow" +branches_sharing_code = "allow" +checked_conversions = "warn" +collapsible_else_if = "allow" +create_dir = "warn" +dbg_macro = "warn" +debug_assert_with_mut_call = "warn" +doc_markdown = "warn" +empty_enum = "warn" +enum_glob_use = "warn" +expl_impl_clone_on_copy = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +fallible_impl_from = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +float_cmp_const = "warn" +fn_params_excessive_bools = "warn" +from_iter_instead_of_collect = "warn" +if_same_then_else = "allow" +implicit_clone = "warn" +imprecise_flops = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +invalid_upcast_comparisons = "warn" +large_digit_groups = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +let_and_return = "allow" +linkedlist = "warn" +lossy_float_literal = "warn" +macro_use_imports = "warn" +mem_forget = "warn" +mutex_integer = "warn" +needless_continue = "allow" +needless_for_each = "warn" +negative_feature_names = "warn" +path_buf_push_overwrite = "warn" +ptr_as_ptr = "warn" +rc_mutex = "warn" +redundant_feature_names = "warn" +ref_option_ref = "warn" +rest_pat_in_fully_bound_structs = "warn" +result_large_err = "allow" +same_functions_in_if_condition = "warn" +self_named_module_files = "warn" +semicolon_if_nothing_returned = "warn" +str_to_string = "warn" +string_add = "warn" +string_add_assign = "warn" +string_lit_as_bytes = "warn" +string_to_string = "warn" +todo = "warn" +trait_duplication_in_bounds = "warn" +uninlined_format_args = "warn" +verbose_file_reads = "warn" +wildcard_imports = "warn" +zero_sized_map_values = "warn" + +[lints.rust] +unnameable_types = "warn" +unreachable_pub = "warn" +unsafe_op_in_unsafe_fn = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[lints.rust.rust_2018_idioms] +level = "warn" +priority = -1 diff --git a/tools/vendor/anstyle/Cargo.toml.orig b/tools/vendor/anstyle/Cargo.toml.orig new file mode 100644 index 0000000000..a08fe0af4e --- /dev/null +++ b/tools/vendor/anstyle/Cargo.toml.orig @@ -0,0 +1,38 @@ +[package] +name = "anstyle" +version = "1.0.13" +description = "ANSI text styling" +categories = ["command-line-interface"] +keywords = ["ansi", "terminal", "color", "no_std"] +repository.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +include.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--generate-link-to-definition"] + +[package.metadata.release] +tag-prefix = "" +pre-release-replacements = [ + {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1}, + {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, + {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1}, + {file="CHANGELOG.md", search="", replace="\n## [Unreleased] - ReleaseDate\n", exactly=1}, + {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/rust-cli/anstyle/compare/{{tag_name}}...HEAD", exactly=1}, +] + +[features] +default = ["std"] +std = [] + +[dependencies] + +[dev-dependencies] +lexopt = "0.3.0" +snapbox = "0.6.5" + +[lints] +workspace = true diff --git a/tools/vendor/anstyle/LICENSE-APACHE b/tools/vendor/anstyle/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/tools/vendor/anstyle/LICENSE-APACHE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/tools/vendor/anstyle/LICENSE-MIT b/tools/vendor/anstyle/LICENSE-MIT new file mode 100644 index 0000000000..a2d01088b6 --- /dev/null +++ b/tools/vendor/anstyle/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) Individual contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/vendor/anstyle/README.md b/tools/vendor/anstyle/README.md new file mode 100644 index 0000000000..99ea5e1a10 --- /dev/null +++ b/tools/vendor/anstyle/README.md @@ -0,0 +1,42 @@ +# anstyle + +> ANSI text styling + +*A portmanteau of "ansi style"* + +[![Documentation](https://img.shields.io/badge/docs-master-blue.svg)][Documentation] +![License](https://img.shields.io/crates/l/anstyle.svg) +[![Crates Status](https://img.shields.io/crates/v/anstyle.svg)](https://crates.io/crates/anstyle) + +`anstyle` provides core types describing [ANSI styling escape +codes](https://en.wikipedia.org/wiki/ANSI_escape_code) for interoperability +between crates. For example, this would allow a crate to provide an API for +customizing the colors used without putting the underlying text styling crate +in the API. + +For integration with your text styling crate, see: +- [anstyle-termcolor](crates/termcolor) +- [anstyle-owo-colors](crates/owo) +- [anstyle-yansi](crates/yansi) + +General utilities: +- [anstyle-git](crates/git): Parse Git style descriptions + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +## [Contribute](../../CONTRIBUTING.md) + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual-licensed as above, without any additional terms or +conditions. + +[Crates.io]: https://crates.io/crates/anstyle +[Documentation]: https://docs.rs/anstyle diff --git a/tools/vendor/anstyle/examples/dump-style.rs b/tools/vendor/anstyle/examples/dump-style.rs new file mode 100644 index 0000000000..2e539eb645 --- /dev/null +++ b/tools/vendor/anstyle/examples/dump-style.rs @@ -0,0 +1,134 @@ +//! Write ANSI escape code colored text + +use std::io::Write; + +fn main() -> Result<(), lexopt::Error> { + let args = Args::parse()?; + let stdout = std::io::stdout(); + let mut stdout = stdout.lock(); + + for fixed in 0..16 { + let color = anstyle::Ansi256Color(fixed) + .into_ansi() + .expect("4-bit range used"); + let style = style(color, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + if fixed == 7 || fixed == 15 { + let _ = writeln!(&mut stdout); + } + } + + for fixed in 16..232 { + let col = (fixed - 16) % 36; + if col == 0 { + let _ = writeln!(stdout); + } + let color = anstyle::Ansi256Color(fixed); + let style = style(color, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + let _ = writeln!(stdout); + let _ = writeln!(stdout); + for fixed in 232..=255 { + let color = anstyle::Ansi256Color(fixed); + let style = style(color, args.layer, args.effects); + let _ = print_number(&mut stdout, fixed, style); + } + + let _ = writeln!(stdout); + + Ok(()) +} + +fn style( + color: impl Into, + layer: Layer, + effects: anstyle::Effects, +) -> anstyle::Style { + let color = color.into(); + (match layer { + Layer::Fg => anstyle::Style::new().fg_color(Some(color)), + Layer::Bg => anstyle::Style::new().bg_color(Some(color)), + Layer::Underline => anstyle::Style::new().underline_color(Some(color)), + }) | effects +} + +fn print_number( + stdout: &mut std::io::StdoutLock<'_>, + fixed: u8, + style: anstyle::Style, +) -> std::io::Result<()> { + write!(stdout, "{style}{fixed:>3X}{style:#}",) +} + +#[derive(Default)] +struct Args { + effects: anstyle::Effects, + layer: Layer, +} + +#[derive(Copy, Clone, Default)] +enum Layer { + #[default] + Fg, + Bg, + Underline, +} + +impl Args { + fn parse() -> Result { + use lexopt::prelude::*; + + let mut res = Args::default(); + + let mut args = lexopt::Parser::from_env(); + while let Some(arg) = args.next()? { + match arg { + Long("layer") => { + res.layer = args.value()?.parse_with(|s| match s { + "fg" => Ok(Layer::Fg), + "bg" => Ok(Layer::Bg), + "underline" => Ok(Layer::Underline), + _ => Err("expected values fg, bg, underline"), + })?; + } + Long("effect") => { + const EFFECTS: [(&str, anstyle::Effects); 12] = [ + ("bold", anstyle::Effects::BOLD), + ("dimmed", anstyle::Effects::DIMMED), + ("italic", anstyle::Effects::ITALIC), + ("underline", anstyle::Effects::UNDERLINE), + ("double_underline", anstyle::Effects::DOUBLE_UNDERLINE), + ("curly_underline", anstyle::Effects::CURLY_UNDERLINE), + ("dotted_underline", anstyle::Effects::DOTTED_UNDERLINE), + ("dashed_underline", anstyle::Effects::DASHED_UNDERLINE), + ("blink", anstyle::Effects::BLINK), + ("invert", anstyle::Effects::INVERT), + ("hidden", anstyle::Effects::HIDDEN), + ("strikethrough", anstyle::Effects::STRIKETHROUGH), + ]; + let effect = args.value()?.parse_with(|s| { + EFFECTS + .into_iter() + .find(|(name, _)| *name == s) + .map(|(_, effect)| effect) + .ok_or_else(|| { + format!( + "expected one of {}", + EFFECTS + .into_iter() + .map(|(n, _)| n) + .collect::>() + .join(", ") + ) + }) + })?; + res.effects = res.effects.insert(effect); + } + _ => return Err(arg.unexpected()), + } + } + Ok(res) + } +} diff --git a/tools/vendor/anstyle/src/color.rs b/tools/vendor/anstyle/src/color.rs new file mode 100644 index 0000000000..a66dd530f7 --- /dev/null +++ b/tools/vendor/anstyle/src/color.rs @@ -0,0 +1,685 @@ +/// Any ANSI color code scheme +#[allow(clippy::exhaustive_enums)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Color { + /// Available 4-bit ANSI color palette codes + /// + /// The user's terminal defines the meaning of the each palette code. + Ansi(AnsiColor), + /// 256 (8-bit) color support + /// + /// - `0..16` are [`AnsiColor`] palette codes + /// - `0..232` map to [`RgbColor`] color values + /// - `232..` map to [`RgbColor`] gray-scale values + Ansi256(Ansi256Color), + /// 24-bit ANSI RGB color codes + Rgb(RgbColor), +} + +impl Color { + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub fn on(self, background: impl Into) -> crate::Style { + crate::Style::new() + .fg_color(Some(self)) + .bg_color(Some(background.into())) + } + + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub const fn on_default(self) -> crate::Style { + crate::Style::new().fg_color(Some(self)) + } + + /// Render the ANSI code for a foreground color + #[inline] + pub fn render_fg(self) -> impl core::fmt::Display + Copy { + match self { + Self::Ansi(color) => color.as_fg_buffer(), + Self::Ansi256(color) => color.as_fg_buffer(), + Self::Rgb(color) => color.as_fg_buffer(), + } + } + + #[inline] + #[cfg(feature = "std")] + pub(crate) fn write_fg_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + let buffer = match self { + Self::Ansi(color) => color.as_fg_buffer(), + Self::Ansi256(color) => color.as_fg_buffer(), + Self::Rgb(color) => color.as_fg_buffer(), + }; + buffer.write_to(write) + } + + /// Render the ANSI code for a background color + #[inline] + pub fn render_bg(self) -> impl core::fmt::Display + Copy { + match self { + Self::Ansi(color) => color.as_bg_buffer(), + Self::Ansi256(color) => color.as_bg_buffer(), + Self::Rgb(color) => color.as_bg_buffer(), + } + } + + #[inline] + #[cfg(feature = "std")] + pub(crate) fn write_bg_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + let buffer = match self { + Self::Ansi(color) => color.as_bg_buffer(), + Self::Ansi256(color) => color.as_bg_buffer(), + Self::Rgb(color) => color.as_bg_buffer(), + }; + buffer.write_to(write) + } + + #[inline] + pub(crate) fn render_underline(self) -> impl core::fmt::Display + Copy { + match self { + Self::Ansi(color) => color.as_underline_buffer(), + Self::Ansi256(color) => color.as_underline_buffer(), + Self::Rgb(color) => color.as_underline_buffer(), + } + } + + #[inline] + #[cfg(feature = "std")] + pub(crate) fn write_underline_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + let buffer = match self { + Self::Ansi(color) => color.as_underline_buffer(), + Self::Ansi256(color) => color.as_underline_buffer(), + Self::Rgb(color) => color.as_underline_buffer(), + }; + buffer.write_to(write) + } +} + +impl From for Color { + #[inline] + fn from(inner: AnsiColor) -> Self { + Self::Ansi(inner) + } +} + +impl From for Color { + #[inline] + fn from(inner: Ansi256Color) -> Self { + Self::Ansi256(inner) + } +} + +impl From for Color { + #[inline] + fn from(inner: RgbColor) -> Self { + Self::Rgb(inner) + } +} + +impl From for Color { + #[inline] + fn from(inner: u8) -> Self { + Self::Ansi256(inner.into()) + } +} + +impl From<(u8, u8, u8)> for Color { + #[inline] + fn from(inner: (u8, u8, u8)) -> Self { + Self::Rgb(inner.into()) + } +} + +/// Available 4-bit ANSI color palette codes +/// +/// The user's terminal defines the meaning of the each palette code. +#[allow(clippy::exhaustive_enums)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(u8)] +pub enum AnsiColor { + /// Black: #0 (foreground code `30`, background code `40`). + Black, + + /// Red: #1 (foreground code `31`, background code `41`). + Red, + + /// Green: #2 (foreground code `32`, background code `42`). + Green, + + /// Yellow: #3 (foreground code `33`, background code `43`). + Yellow, + + /// Blue: #4 (foreground code `34`, background code `44`). + Blue, + + /// Magenta: #5 (foreground code `35`, background code `45`). + Magenta, + + /// Cyan: #6 (foreground code `36`, background code `46`). + Cyan, + + /// White: #7 (foreground code `37`, background code `47`). + White, + + /// Bright black: #0 (foreground code `90`, background code `100`). + BrightBlack, + + /// Bright red: #1 (foreground code `91`, background code `101`). + BrightRed, + + /// Bright green: #2 (foreground code `92`, background code `102`). + BrightGreen, + + /// Bright yellow: #3 (foreground code `93`, background code `103`). + BrightYellow, + + /// Bright blue: #4 (foreground code `94`, background code `104`). + BrightBlue, + + /// Bright magenta: #5 (foreground code `95`, background code `105`). + BrightMagenta, + + /// Bright cyan: #6 (foreground code `96`, background code `106`). + BrightCyan, + + /// Bright white: #7 (foreground code `97`, background code `107`). + BrightWhite, +} + +impl AnsiColor { + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub fn on(self, background: impl Into) -> crate::Style { + crate::Style::new() + .fg_color(Some(self.into())) + .bg_color(Some(background.into())) + } + + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub const fn on_default(self) -> crate::Style { + crate::Style::new().fg_color(Some(Color::Ansi(self))) + } + + /// Render the ANSI code for a foreground color + #[inline] + pub fn render_fg(self) -> impl core::fmt::Display + Copy { + NullFormatter(self.as_fg_str()) + } + + #[inline] + fn as_fg_str(&self) -> &'static str { + match self { + Self::Black => escape!("3", "0"), + Self::Red => escape!("3", "1"), + Self::Green => escape!("3", "2"), + Self::Yellow => escape!("3", "3"), + Self::Blue => escape!("3", "4"), + Self::Magenta => escape!("3", "5"), + Self::Cyan => escape!("3", "6"), + Self::White => escape!("3", "7"), + Self::BrightBlack => escape!("9", "0"), + Self::BrightRed => escape!("9", "1"), + Self::BrightGreen => escape!("9", "2"), + Self::BrightYellow => escape!("9", "3"), + Self::BrightBlue => escape!("9", "4"), + Self::BrightMagenta => escape!("9", "5"), + Self::BrightCyan => escape!("9", "6"), + Self::BrightWhite => escape!("9", "7"), + } + } + + #[inline] + fn as_fg_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default().write_str(self.as_fg_str()) + } + + /// Render the ANSI code for a background color + #[inline] + pub fn render_bg(self) -> impl core::fmt::Display + Copy { + NullFormatter(self.as_bg_str()) + } + + #[inline] + fn as_bg_str(&self) -> &'static str { + match self { + Self::Black => escape!("4", "0"), + Self::Red => escape!("4", "1"), + Self::Green => escape!("4", "2"), + Self::Yellow => escape!("4", "3"), + Self::Blue => escape!("4", "4"), + Self::Magenta => escape!("4", "5"), + Self::Cyan => escape!("4", "6"), + Self::White => escape!("4", "7"), + Self::BrightBlack => escape!("10", "0"), + Self::BrightRed => escape!("10", "1"), + Self::BrightGreen => escape!("10", "2"), + Self::BrightYellow => escape!("10", "3"), + Self::BrightBlue => escape!("10", "4"), + Self::BrightMagenta => escape!("10", "5"), + Self::BrightCyan => escape!("10", "6"), + Self::BrightWhite => escape!("10", "7"), + } + } + + #[inline] + fn as_bg_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default().write_str(self.as_bg_str()) + } + + #[inline] + fn as_underline_buffer(&self) -> DisplayBuffer { + // No per-color codes; must delegate to `Ansi256Color` + Ansi256Color::from(*self).as_underline_buffer() + } + + /// Change the color to/from bright + #[must_use] + #[inline] + pub fn bright(self, yes: bool) -> Self { + if yes { + match self { + Self::Black => Self::BrightBlack, + Self::Red => Self::BrightRed, + Self::Green => Self::BrightGreen, + Self::Yellow => Self::BrightYellow, + Self::Blue => Self::BrightBlue, + Self::Magenta => Self::BrightMagenta, + Self::Cyan => Self::BrightCyan, + Self::White => Self::BrightWhite, + Self::BrightBlack => self, + Self::BrightRed => self, + Self::BrightGreen => self, + Self::BrightYellow => self, + Self::BrightBlue => self, + Self::BrightMagenta => self, + Self::BrightCyan => self, + Self::BrightWhite => self, + } + } else { + match self { + Self::Black => self, + Self::Red => self, + Self::Green => self, + Self::Yellow => self, + Self::Blue => self, + Self::Magenta => self, + Self::Cyan => self, + Self::White => self, + Self::BrightBlack => Self::Black, + Self::BrightRed => Self::Red, + Self::BrightGreen => Self::Green, + Self::BrightYellow => Self::Yellow, + Self::BrightBlue => Self::Blue, + Self::BrightMagenta => Self::Magenta, + Self::BrightCyan => Self::Cyan, + Self::BrightWhite => Self::White, + } + } + } + + /// Report whether the color is bright + #[inline] + pub fn is_bright(self) -> bool { + match self { + Self::Black => false, + Self::Red => false, + Self::Green => false, + Self::Yellow => false, + Self::Blue => false, + Self::Magenta => false, + Self::Cyan => false, + Self::White => false, + Self::BrightBlack => true, + Self::BrightRed => true, + Self::BrightGreen => true, + Self::BrightYellow => true, + Self::BrightBlue => true, + Self::BrightMagenta => true, + Self::BrightCyan => true, + Self::BrightWhite => true, + } + } +} + +/// 256 (8-bit) color support +/// +/// - `0..16` are [`AnsiColor`] palette codes +/// - `0..232` map to [`RgbColor`] color values +/// - `232..` map to [`RgbColor`] gray-scale values +#[allow(clippy::exhaustive_structs)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct Ansi256Color(pub u8); + +impl Ansi256Color { + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub fn on(self, background: impl Into) -> crate::Style { + crate::Style::new() + .fg_color(Some(self.into())) + .bg_color(Some(background.into())) + } + + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub const fn on_default(self) -> crate::Style { + crate::Style::new().fg_color(Some(Color::Ansi256(self))) + } + + /// Get the raw value + #[inline] + pub const fn index(self) -> u8 { + self.0 + } + + /// Convert to [`AnsiColor`] when there is a 1:1 mapping + #[inline] + pub const fn into_ansi(self) -> Option { + match self.index() { + 0 => Some(AnsiColor::Black), + 1 => Some(AnsiColor::Red), + 2 => Some(AnsiColor::Green), + 3 => Some(AnsiColor::Yellow), + 4 => Some(AnsiColor::Blue), + 5 => Some(AnsiColor::Magenta), + 6 => Some(AnsiColor::Cyan), + 7 => Some(AnsiColor::White), + 8 => Some(AnsiColor::BrightBlack), + 9 => Some(AnsiColor::BrightRed), + 10 => Some(AnsiColor::BrightGreen), + 11 => Some(AnsiColor::BrightYellow), + 12 => Some(AnsiColor::BrightBlue), + 13 => Some(AnsiColor::BrightMagenta), + 14 => Some(AnsiColor::BrightCyan), + 15 => Some(AnsiColor::BrightWhite), + _ => None, + } + } + + /// Losslessly convert from [`AnsiColor`] + #[inline] + pub const fn from_ansi(color: AnsiColor) -> Self { + match color { + AnsiColor::Black => Self(0), + AnsiColor::Red => Self(1), + AnsiColor::Green => Self(2), + AnsiColor::Yellow => Self(3), + AnsiColor::Blue => Self(4), + AnsiColor::Magenta => Self(5), + AnsiColor::Cyan => Self(6), + AnsiColor::White => Self(7), + AnsiColor::BrightBlack => Self(8), + AnsiColor::BrightRed => Self(9), + AnsiColor::BrightGreen => Self(10), + AnsiColor::BrightYellow => Self(11), + AnsiColor::BrightBlue => Self(12), + AnsiColor::BrightMagenta => Self(13), + AnsiColor::BrightCyan => Self(14), + AnsiColor::BrightWhite => Self(15), + } + } + + /// Render the ANSI code for a foreground color + #[inline] + pub fn render_fg(self) -> impl core::fmt::Display + Copy { + self.as_fg_buffer() + } + + #[inline] + fn as_fg_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default() + .write_str("\x1B[38;5;") + .write_code(self.index()) + .write_str("m") + } + + /// Render the ANSI code for a background color + #[inline] + pub fn render_bg(self) -> impl core::fmt::Display + Copy { + self.as_bg_buffer() + } + + #[inline] + fn as_bg_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default() + .write_str("\x1B[48;5;") + .write_code(self.index()) + .write_str("m") + } + + #[inline] + fn as_underline_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default() + .write_str("\x1B[58;5;") + .write_code(self.index()) + .write_str("m") + } +} + +impl From for Ansi256Color { + #[inline] + fn from(inner: u8) -> Self { + Self(inner) + } +} + +impl From for Ansi256Color { + #[inline] + fn from(inner: AnsiColor) -> Self { + Self::from_ansi(inner) + } +} + +/// 24-bit ANSI RGB color codes +#[allow(clippy::exhaustive_structs)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct RgbColor(pub u8, pub u8, pub u8); + +impl RgbColor { + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub fn on(self, background: impl Into) -> crate::Style { + crate::Style::new() + .fg_color(Some(self.into())) + .bg_color(Some(background.into())) + } + + /// Create a [`Style`][crate::Style] with this as the foreground + #[inline] + pub const fn on_default(self) -> crate::Style { + crate::Style::new().fg_color(Some(Color::Rgb(self))) + } + + /// Red + #[inline] + pub const fn r(self) -> u8 { + self.0 + } + + /// Green + #[inline] + pub const fn g(self) -> u8 { + self.1 + } + + /// Blue + #[inline] + pub const fn b(self) -> u8 { + self.2 + } + + /// Render the ANSI code for a foreground color + #[inline] + pub fn render_fg(self) -> impl core::fmt::Display + Copy { + self.as_fg_buffer() + } + + #[inline] + fn as_fg_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default() + .write_str("\x1B[38;2;") + .write_code(self.r()) + .write_str(";") + .write_code(self.g()) + .write_str(";") + .write_code(self.b()) + .write_str("m") + } + + /// Render the ANSI code for a background color + #[inline] + pub fn render_bg(self) -> impl core::fmt::Display + Copy { + self.as_bg_buffer() + } + + #[inline] + fn as_bg_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default() + .write_str("\x1B[48;2;") + .write_code(self.r()) + .write_str(";") + .write_code(self.g()) + .write_str(";") + .write_code(self.b()) + .write_str("m") + } + + #[inline] + fn as_underline_buffer(&self) -> DisplayBuffer { + DisplayBuffer::default() + .write_str("\x1B[58;2;") + .write_code(self.r()) + .write_str(";") + .write_code(self.g()) + .write_str(";") + .write_code(self.b()) + .write_str("m") + } +} + +impl From<(u8, u8, u8)> for RgbColor { + #[inline] + fn from(inner: (u8, u8, u8)) -> Self { + let (r, g, b) = inner; + Self(r, g, b) + } +} + +const DISPLAY_BUFFER_CAPACITY: usize = 19; + +#[derive(Copy, Clone, Default, Debug)] +struct DisplayBuffer { + buffer: [u8; DISPLAY_BUFFER_CAPACITY], + len: usize, +} + +impl DisplayBuffer { + #[must_use] + #[inline(never)] + fn write_str(mut self, part: &'static str) -> Self { + for (i, b) in part.as_bytes().iter().enumerate() { + self.buffer[self.len + i] = *b; + } + self.len += part.len(); + self + } + + #[must_use] + #[inline(never)] + fn write_code(mut self, code: u8) -> Self { + let c1: u8 = (code / 100) % 10; + let c2: u8 = (code / 10) % 10; + let c3: u8 = code % 10; + + let mut printed = false; + if c1 != 0 { + printed = true; + self.buffer[self.len] = b'0' + c1; + self.len += 1; + } + if c2 != 0 || printed { + self.buffer[self.len] = b'0' + c2; + self.len += 1; + } + // If we received a zero value we must still print a value. + self.buffer[self.len] = b'0' + c3; + self.len += 1; + + self + } + + #[inline] + fn as_str(&self) -> &str { + // SAFETY: Only `&str` can be written to the buffer + #[allow(unsafe_code)] + unsafe { + core::str::from_utf8_unchecked(&self.buffer[0..self.len]) + } + } + + #[inline] + #[cfg(feature = "std")] + fn write_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + write.write_all(self.as_str().as_bytes()) + } +} + +impl core::fmt::Display for DisplayBuffer { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(self.as_str()) + } +} + +#[derive(Copy, Clone, Default, Debug)] +struct NullFormatter(&'static str); + +impl core::fmt::Display for NullFormatter { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(self.0) + } +} + +#[cfg(test)] +#[cfg(feature = "std")] +mod test { + use super::*; + + #[test] + fn max_display_buffer() { + let c = RgbColor(255, 255, 255); + let actual = c.render_fg().to_string(); + assert_eq!(actual, "\u{1b}[38;2;255;255;255m"); + assert_eq!(actual.len(), DISPLAY_BUFFER_CAPACITY); + } + + #[test] + fn print_size_of() { + use core::mem::size_of; + dbg!(size_of::()); + dbg!(size_of::()); + dbg!(size_of::()); + dbg!(size_of::()); + dbg!(size_of::()); + } + + #[test] + fn no_align() { + #[track_caller] + fn assert_no_align(d: impl core::fmt::Display) { + let expected = format!("{d}"); + let actual = format!("{d:<10}"); + assert_eq!(expected, actual); + } + + assert_no_align(AnsiColor::White.render_fg()); + assert_no_align(AnsiColor::White.render_bg()); + assert_no_align(Ansi256Color(0).render_fg()); + assert_no_align(Ansi256Color(0).render_bg()); + assert_no_align(RgbColor(0, 0, 0).render_fg()); + assert_no_align(RgbColor(0, 0, 0).render_bg()); + assert_no_align(Color::Ansi(AnsiColor::White).render_fg()); + assert_no_align(Color::Ansi(AnsiColor::White).render_bg()); + } +} diff --git a/tools/vendor/anstyle/src/effect.rs b/tools/vendor/anstyle/src/effect.rs new file mode 100644 index 0000000000..4a076d4ef2 --- /dev/null +++ b/tools/vendor/anstyle/src/effect.rs @@ -0,0 +1,404 @@ +/// A set of text effects +/// +/// # Examples +/// +/// ```rust +/// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE; +/// ``` +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Effects(u16); + +impl Effects { + /// No [`Effects`] applied + const PLAIN: Self = Effects(0); + + #[allow(missing_docs)] + pub const BOLD: Self = Effects(1 << 0); + #[allow(missing_docs)] + pub const DIMMED: Self = Effects(1 << 1); + /// Not widely supported. Sometimes treated as inverse or blink + pub const ITALIC: Self = Effects(1 << 2); + /// Style extensions exist for Kitty, VTE, mintty and iTerm2. + pub const UNDERLINE: Self = Effects(1 << 3); + #[allow(missing_docs)] + pub const DOUBLE_UNDERLINE: Self = Effects(1 << 4); + #[allow(missing_docs)] + pub const CURLY_UNDERLINE: Self = Effects(1 << 5); + #[allow(missing_docs)] + pub const DOTTED_UNDERLINE: Self = Effects(1 << 6); + #[allow(missing_docs)] + pub const DASHED_UNDERLINE: Self = Effects(1 << 7); + #[allow(missing_docs)] + pub const BLINK: Self = Effects(1 << 8); + /// Swap foreground and background colors; inconsistent emulation + pub const INVERT: Self = Effects(1 << 9); + #[allow(missing_docs)] + pub const HIDDEN: Self = Effects(1 << 10); + /// Characters legible but marked as if for deletion. Not supported in Terminal.app + pub const STRIKETHROUGH: Self = Effects(1 << 11); + + /// No effects enabled + /// + /// # Examples + /// + /// ```rust + /// let effects = anstyle::Effects::new(); + /// ``` + #[inline] + pub const fn new() -> Self { + Self::PLAIN + } + + /// Check if no effects are enabled + /// + /// # Examples + /// + /// ```rust + /// let effects = anstyle::Effects::new(); + /// assert!(effects.is_plain()); + /// + /// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE; + /// assert!(!effects.is_plain()); + /// ``` + #[inline] + pub const fn is_plain(self) -> bool { + self.0 == Self::PLAIN.0 + } + + /// Returns `true` if all of the effects in `other` are contained within `self`. + /// + /// # Examples + /// + /// ```rust + /// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE; + /// assert!(effects.contains(anstyle::Effects::BOLD)); + /// + /// let effects = anstyle::Effects::new(); + /// assert!(!effects.contains(anstyle::Effects::BOLD)); + /// ``` + #[inline(always)] + pub const fn contains(self, other: Effects) -> bool { + (other.0 & self.0) == other.0 + } + + /// Inserts the specified effects in-place. + /// + /// # Examples + /// + /// ```rust + /// let effects = anstyle::Effects::new().insert(anstyle::Effects::new()); + /// assert!(effects.is_plain()); + /// + /// let effects = anstyle::Effects::new().insert(anstyle::Effects::BOLD); + /// assert!(effects.contains(anstyle::Effects::BOLD)); + /// ``` + #[inline(always)] + #[must_use] + pub const fn insert(mut self, other: Effects) -> Self { + self.0 |= other.0; + self + } + + /// Removes the specified effects in-place. + /// + /// # Examples + /// + /// ```rust + /// let effects = (anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE).remove(anstyle::Effects::BOLD); + /// assert!(!effects.contains(anstyle::Effects::BOLD)); + /// assert!(effects.contains(anstyle::Effects::UNDERLINE)); + /// ``` + #[inline(always)] + #[must_use] + pub const fn remove(mut self, other: Effects) -> Self { + self.0 &= !other.0; + self + } + + /// Reset all effects in-place + /// ```rust + /// let effects = (anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE).clear(); + /// assert!(!effects.contains(anstyle::Effects::BOLD)); + /// assert!(!effects.contains(anstyle::Effects::UNDERLINE)); + /// ``` + #[inline(always)] + #[must_use] + pub const fn clear(self) -> Self { + Self::new() + } + + /// Enable or disable the specified effects depending on the passed value. + /// + /// # Examples + /// + /// ```rust + /// let effects = anstyle::Effects::new().set(anstyle::Effects::BOLD, true); + /// assert!(effects.contains(anstyle::Effects::BOLD)); + /// ``` + #[inline] + #[must_use] + pub const fn set(self, other: Self, enable: bool) -> Self { + if enable { + self.insert(other) + } else { + self.remove(other) + } + } + + /// Iterate over enabled effects + #[inline(always)] + pub fn iter(self) -> EffectIter { + EffectIter { + index: 0, + effects: self, + } + } + + /// Iterate over enabled effect indices + #[inline(always)] + pub(crate) fn index_iter(self) -> EffectIndexIter { + EffectIndexIter { + index: 0, + effects: self, + } + } + + /// Render the ANSI code + #[inline] + pub fn render(self) -> impl core::fmt::Display + Copy { + EffectsDisplay(self) + } + + #[inline] + #[cfg(feature = "std")] + pub(crate) fn write_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + for index in self.index_iter() { + write.write_all(METADATA[index].escape.as_bytes())?; + } + Ok(()) + } +} + +/// # Examples +/// +/// ```rust +/// let effects = anstyle::Effects::new(); +/// assert_eq!(format!("{:?}", effects), "Effects()"); +/// +/// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE; +/// assert_eq!(format!("{:?}", effects), "Effects(BOLD | UNDERLINE)"); +/// ``` +impl core::fmt::Debug for Effects { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Effects(")?; + for (i, index) in self.index_iter().enumerate() { + if i != 0 { + write!(f, " | ")?; + } + write!(f, "{}", METADATA[index].name)?; + } + write!(f, ")")?; + Ok(()) + } +} + +/// # Examples +/// +/// ```rust +/// let effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE; +/// assert_eq!(format!("{:?}", effects), "Effects(BOLD | UNDERLINE)"); +/// ``` +impl core::ops::BitOr for Effects { + type Output = Self; + + #[inline(always)] + fn bitor(self, rhs: Self) -> Self { + self.insert(rhs) + } +} + +/// # Examples +/// +/// ```rust +/// let mut effects = anstyle::Effects::BOLD; +/// effects |= anstyle::Effects::UNDERLINE; +/// assert_eq!(format!("{:?}", effects), "Effects(BOLD | UNDERLINE)"); +/// ``` +impl core::ops::BitOrAssign for Effects { + #[inline] + fn bitor_assign(&mut self, other: Self) { + *self = self.insert(other); + } +} + +/// # Examples +/// +/// ```rust +/// let effects = (anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE) - anstyle::Effects::BOLD; +/// assert_eq!(format!("{:?}", effects), "Effects(UNDERLINE)"); +/// ``` +impl core::ops::Sub for Effects { + type Output = Self; + + #[inline] + fn sub(self, other: Self) -> Self { + self.remove(other) + } +} + +/// # Examples +/// +/// ```rust +/// let mut effects = anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE; +/// effects -= anstyle::Effects::BOLD; +/// assert_eq!(format!("{:?}", effects), "Effects(UNDERLINE)"); +/// ``` +impl core::ops::SubAssign for Effects { + #[inline] + fn sub_assign(&mut self, other: Self) { + *self = self.remove(other); + } +} + +pub(crate) struct Metadata { + pub(crate) name: &'static str, + pub(crate) escape: &'static str, +} + +pub(crate) const METADATA: [Metadata; 12] = [ + Metadata { + name: "BOLD", + escape: escape!("1"), + }, + Metadata { + name: "DIMMED", + escape: escape!("2"), + }, + Metadata { + name: "ITALIC", + escape: escape!("3"), + }, + Metadata { + name: "UNDERLINE", + escape: escape!("4"), + }, + Metadata { + name: "DOUBLE_UNDERLINE", + escape: escape!("21"), + }, + Metadata { + name: "CURLY_UNDERLINE", + escape: escape!("4:3"), + }, + Metadata { + name: "DOTTED_UNDERLINE", + escape: escape!("4:4"), + }, + Metadata { + name: "DASHED_UNDERLINE", + escape: escape!("4:5"), + }, + Metadata { + name: "BLINK", + escape: escape!("5"), + }, + Metadata { + name: "INVERT", + escape: escape!("7"), + }, + Metadata { + name: "HIDDEN", + escape: escape!("8"), + }, + Metadata { + name: "STRIKETHROUGH", + escape: escape!("9"), + }, +]; + +#[derive(Copy, Clone, Default, Debug)] +struct EffectsDisplay(Effects); + +impl core::fmt::Display for EffectsDisplay { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + for index in self.0.index_iter() { + f.write_str(METADATA[index].escape)?; + } + Ok(()) + } +} + +/// Enumerate each enabled value in [`Effects`] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct EffectIter { + index: usize, + effects: Effects, +} + +impl Iterator for EffectIter { + type Item = Effects; + + fn next(&mut self) -> Option { + while self.index < METADATA.len() { + let index = self.index; + self.index += 1; + + let effect = Effects(1 << index); + if self.effects.contains(effect) { + return Some(effect); + } + } + + None + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub(crate) struct EffectIndexIter { + index: usize, + effects: Effects, +} + +impl Iterator for EffectIndexIter { + type Item = usize; + + fn next(&mut self) -> Option { + while self.index < METADATA.len() { + let index = self.index; + self.index += 1; + + let effect = Effects(1 << index); + if self.effects.contains(effect) { + return Some(index); + } + } + + None + } +} + +#[cfg(test)] +#[cfg(feature = "std")] +mod test { + use super::*; + + #[test] + fn print_size_of() { + use core::mem::size_of; + dbg!(size_of::()); + dbg!(size_of::()); + } + + #[test] + fn no_align() { + #[track_caller] + fn assert_no_align(d: impl core::fmt::Display) { + let expected = format!("{d}"); + let actual = format!("{d:<10}"); + assert_eq!(expected, actual); + } + + assert_no_align(Effects::BOLD.render()); + } +} diff --git a/tools/vendor/anstyle/src/lib.rs b/tools/vendor/anstyle/src/lib.rs new file mode 100644 index 0000000000..f1449fc573 --- /dev/null +++ b/tools/vendor/anstyle/src/lib.rs @@ -0,0 +1,70 @@ +//! ANSI Text Styling +//! +//! *A portmanteau of "ansi style"* +//! +//! `anstyle` provides core types describing [ANSI styling escape +//! codes](https://en.wikipedia.org/wiki/ANSI_escape_code) for interoperability +//! between crates. +//! +//! Example use cases: +//! - An argument parser allowing callers to define the colors used in the help-output without +//! putting the text formatting crate in the public API +//! - A style description parser that can work with any text formatting crate +//! +//! Priorities: +//! 1. API stability +//! 2. Low compile-time and binary-size overhead +//! 3. `const` friendly API for callers to statically define their stylesheet +//! +//! For integration with text styling crate, see: +//! - [anstyle-ansi-term](https://docs.rs/anstyle-ansi-term) +//! - [anstyle-crossterm](https://docs.rs/anstyle-crossterm) +//! - [anstyle-owo-colors](https://docs.rs/anstyle-owo-colors) +//! - [anstyle-termcolor](https://docs.rs/anstyle-termcolor) +//! - [anstyle-yansi](https://docs.rs/anstyle-yansi) +//! +//! User-styling parsers: +//! - [anstyle-git](https://docs.rs/anstyle-git): Parse Git style descriptions +//! - [anstyle-ls](https://docs.rs/anstyle-ls): Parse `LS_COLORS` style descriptions +//! +//! Convert to other formats +//! - [anstream](https://docs.rs/anstream): A simple cross platform library for writing colored text to a terminal +//! - [anstyle-roff](https://docs.rs/anstyle-roff): For converting to ROFF +//! - [anstyle-syntect](https://docs.rs/anstyle-syntect): For working with syntax highlighting +//! +//! Utilities +//! - [anstyle-lossy](https://docs.rs/anstyle-lossy): Convert between `anstyle::Color` types +//! - [anstyle-parse](https://docs.rs/anstyle-parse): Parsing ANSI Style Escapes +//! - [anstyle-wincon](https://docs.rs/anstyle-wincon): Styling legacy Microsoft terminals +//! +//! # Examples +//! +//! The core type is [`Style`]: +//! ```rust +//! let style = anstyle::Style::new().bold(); +//! ``` + +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![warn(missing_docs)] +#![warn(clippy::std_instead_of_core)] +#![warn(clippy::std_instead_of_alloc)] +#![warn(clippy::print_stderr)] +#![warn(clippy::print_stdout)] + +#[macro_use] +mod macros; + +mod color; +mod effect; +mod reset; +mod style; + +pub use color::*; +pub use effect::*; +pub use reset::*; +pub use style::*; + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/tools/vendor/anstyle/src/macros.rs b/tools/vendor/anstyle/src/macros.rs new file mode 100644 index 0000000000..f19666e6c3 --- /dev/null +++ b/tools/vendor/anstyle/src/macros.rs @@ -0,0 +1,5 @@ +macro_rules! escape { + ($($inner:expr),*) => { + concat!("\x1B[", $($inner),*, "m") + }; +} diff --git a/tools/vendor/anstyle/src/reset.rs b/tools/vendor/anstyle/src/reset.rs new file mode 100644 index 0000000000..b581e16d6b --- /dev/null +++ b/tools/vendor/anstyle/src/reset.rs @@ -0,0 +1,47 @@ +/// Reset terminal formatting +#[allow(clippy::exhaustive_structs)] +#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Reset; + +impl Reset { + /// Render the ANSI code + /// + /// `Reset` also implements `Display` directly, so calling this method is optional. + #[inline] + pub fn render(self) -> impl core::fmt::Display + Copy { + self + } +} + +impl core::fmt::Display for Reset { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(RESET) + } +} + +pub(crate) const RESET: &str = "\x1B[0m"; + +#[cfg(test)] +#[cfg(feature = "std")] +mod test { + use super::*; + + #[test] + fn print_size_of() { + use core::mem::size_of; + dbg!(size_of::()); + } + + #[test] + fn no_align() { + #[track_caller] + fn assert_no_align(d: impl core::fmt::Display) { + let expected = format!("{d}"); + let actual = format!("{d:<10}"); + assert_eq!(expected, actual); + } + + assert_no_align(Reset); + assert_no_align(Reset.render()); + } +} diff --git a/tools/vendor/anstyle/src/style.rs b/tools/vendor/anstyle/src/style.rs new file mode 100644 index 0000000000..7cc2bd5792 --- /dev/null +++ b/tools/vendor/anstyle/src/style.rs @@ -0,0 +1,437 @@ +use crate::reset::RESET; + +/// ANSI Text styling +/// +/// You can print a `Style` to render the corresponding ANSI code. +/// Using the alternate flag `#` will render the ANSI reset code, if needed. +/// Together, this makes it convenient to render styles using inline format arguments. +/// +/// # Examples +/// +/// ```rust +/// let style = anstyle::Style::new().bold(); +/// +/// let value = 42; +/// println!("{style}{value}{style:#}"); +/// ``` +#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Style { + fg: Option, + bg: Option, + underline: Option, + effects: crate::Effects, +} + +/// # Core +impl Style { + /// No effects enabled + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new(); + /// ``` + #[inline] + pub const fn new() -> Self { + Self { + fg: None, + bg: None, + underline: None, + effects: crate::Effects::new(), + } + } + + /// Set foreground color + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().fg_color(Some(anstyle::AnsiColor::Red.into())); + /// ``` + #[must_use] + #[inline] + pub const fn fg_color(mut self, fg: Option) -> Self { + self.fg = fg; + self + } + + /// Set background color + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().bg_color(Some(anstyle::AnsiColor::Red.into())); + /// ``` + #[must_use] + #[inline] + pub const fn bg_color(mut self, bg: Option) -> Self { + self.bg = bg; + self + } + + /// Set underline color + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().underline_color(Some(anstyle::AnsiColor::Red.into())); + /// ``` + #[must_use] + #[inline] + pub const fn underline_color(mut self, underline: Option) -> Self { + self.underline = underline; + self + } + + /// Set text effects + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().effects(anstyle::Effects::BOLD | anstyle::Effects::UNDERLINE); + /// ``` + #[must_use] + #[inline] + pub const fn effects(mut self, effects: crate::Effects) -> Self { + self.effects = effects; + self + } + + /// Render the ANSI code + /// + /// `Style` also implements `Display` directly, so calling this method is optional. + #[inline] + pub fn render(self) -> impl core::fmt::Display + Copy { + StyleDisplay(self) + } + + fn fmt_to(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + use core::fmt::Display as _; + + self.effects.render().fmt(f)?; + + if let Some(fg) = self.fg { + fg.render_fg().fmt(f)?; + } + + if let Some(bg) = self.bg { + bg.render_bg().fmt(f)?; + } + + if let Some(underline) = self.underline { + underline.render_underline().fmt(f)?; + } + + Ok(()) + } + + /// Write the ANSI code + #[inline] + #[cfg(feature = "std")] + pub fn write_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + self.effects.write_to(write)?; + + if let Some(fg) = self.fg { + fg.write_fg_to(write)?; + } + + if let Some(bg) = self.bg { + bg.write_bg_to(write)?; + } + + if let Some(underline) = self.underline { + underline.write_underline_to(write)?; + } + + Ok(()) + } + + /// Renders the relevant [`Reset`][crate::Reset] code + /// + /// Unlike [`Reset::render`][crate::Reset::render], this will elide the code if there is nothing to reset. + #[inline] + pub fn render_reset(self) -> impl core::fmt::Display + Copy { + if self != Self::new() { + RESET + } else { + "" + } + } + + /// Write the relevant [`Reset`][crate::Reset] code + /// + /// Unlike [`Reset::render`][crate::Reset::render], this will elide the code if there is nothing to reset. + #[inline] + #[cfg(feature = "std")] + pub fn write_reset_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> { + if self != Self::new() { + write.write_all(RESET.as_bytes()) + } else { + Ok(()) + } + } +} + +/// # Convenience +impl Style { + /// Apply `bold` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().bold(); + /// ``` + #[must_use] + #[inline] + pub const fn bold(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::BOLD); + self + } + + /// Apply `dimmed` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().dimmed(); + /// ``` + #[must_use] + #[inline] + pub const fn dimmed(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::DIMMED); + self + } + + /// Apply `italic` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().italic(); + /// ``` + #[must_use] + #[inline] + pub const fn italic(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::ITALIC); + self + } + + /// Apply `underline` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().underline(); + /// ``` + #[must_use] + #[inline] + pub const fn underline(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::UNDERLINE); + self + } + + /// Apply `blink` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().blink(); + /// ``` + #[must_use] + #[inline] + pub const fn blink(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::BLINK); + self + } + + /// Apply `invert` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().invert(); + /// ``` + #[must_use] + #[inline] + pub const fn invert(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::INVERT); + self + } + + /// Apply `hidden` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().hidden(); + /// ``` + #[must_use] + #[inline] + pub const fn hidden(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::HIDDEN); + self + } + + /// Apply `strikethrough` effect + /// + /// # Examples + /// + /// ```rust + /// let style = anstyle::Style::new().strikethrough(); + /// ``` + #[must_use] + #[inline] + pub const fn strikethrough(mut self) -> Self { + self.effects = self.effects.insert(crate::Effects::STRIKETHROUGH); + self + } +} + +/// # Reflection +impl Style { + /// Get the foreground color + #[inline] + pub const fn get_fg_color(self) -> Option { + self.fg + } + + /// Get the background color + #[inline] + #[allow(missing_docs)] + pub const fn get_bg_color(self) -> Option { + self.bg + } + + #[inline] + #[allow(missing_docs)] + pub const fn get_underline_color(self) -> Option { + self.underline + } + + #[inline] + #[allow(missing_docs)] + pub const fn get_effects(self) -> crate::Effects { + self.effects + } + + /// Check if no styling is enabled + #[inline] + pub const fn is_plain(self) -> bool { + self.fg.is_none() + && self.bg.is_none() + && self.underline.is_none() + && self.effects.is_plain() + } +} + +/// # Examples +/// +/// ```rust +/// let style: anstyle::Style = anstyle::Effects::BOLD.into(); +/// ``` +impl From for Style { + #[inline] + fn from(effects: crate::Effects) -> Self { + Self::new().effects(effects) + } +} + +/// # Examples +/// +/// ```rust +/// let style = anstyle::Style::new() | anstyle::Effects::BOLD.into(); +/// ``` +impl core::ops::BitOr for Style { + type Output = Self; + + #[inline(always)] + fn bitor(mut self, rhs: crate::Effects) -> Self { + self.effects |= rhs; + self + } +} + +/// # Examples +/// +/// ```rust +/// let mut style = anstyle::Style::new(); +/// style |= anstyle::Effects::BOLD.into(); +/// ``` +impl core::ops::BitOrAssign for Style { + #[inline] + fn bitor_assign(&mut self, other: crate::Effects) { + self.effects |= other; + } +} + +/// # Examples +/// +/// ```rust +/// let style = anstyle::Style::new().bold().underline() - anstyle::Effects::BOLD.into(); +/// ``` +impl core::ops::Sub for Style { + type Output = Self; + + #[inline] + fn sub(mut self, other: crate::Effects) -> Self { + self.effects -= other; + self + } +} + +/// # Examples +/// +/// ```rust +/// let mut style = anstyle::Style::new().bold().underline(); +/// style -= anstyle::Effects::BOLD.into(); +/// ``` +impl core::ops::SubAssign for Style { + #[inline] + fn sub_assign(&mut self, other: crate::Effects) { + self.effects -= other; + } +} + +/// # Examples +/// +/// ```rust +/// let effects = anstyle::Effects::BOLD; +/// assert_eq!(anstyle::Style::new().effects(effects), effects); +/// assert_ne!(anstyle::Effects::UNDERLINE | effects, effects); +/// assert_ne!(anstyle::RgbColor(0, 0, 0).on_default() | effects, effects); +/// ``` +impl PartialEq for Style { + #[inline] + fn eq(&self, other: &crate::Effects) -> bool { + let other = Self::from(*other); + *self == other + } +} + +impl core::fmt::Display for Style { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + self.render_reset().fmt(f) + } else { + self.fmt_to(f) + } + } +} + +#[derive(Copy, Clone, Default, Debug)] +struct StyleDisplay(Style); + +impl core::fmt::Display for StyleDisplay { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.0.fmt_to(f) + } +} + +#[test] +#[cfg(feature = "std")] +fn print_size_of() { + use core::mem::size_of; + dbg!(size_of::