diff options
Diffstat (limited to 'vendor/anes')
32 files changed, 3991 insertions, 0 deletions
diff --git a/vendor/anes/.cargo-checksum.json b/vendor/anes/.cargo-checksum.json new file mode 100644 index 000000000..fdade59a8 --- /dev/null +++ b/vendor/anes/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"78337c7d3e66a43267874a3dd15c7905bb0c80a4cfaca60252d44c7ab227f44c","Cargo.toml":"42baf88fbaa6a98da7fd05e7e5359d5519616c07f3792cd6d706f813081df19b","README.md":"b62c8554d456263c75b49d19bf668360789a1275d6bdd7cbe0364cb45427e711","benches/bench_main.rs":"e939f601e2b18fe00669da87f424fea173902afec0503941e68ede91d82f08d8","benches/benchmarks/mod.rs":"f8f66738af5c094c9ec72cc8b72e011a69d17a7a4f92496d34619961276dc967","benches/benchmarks/parser.rs":"b1a19e318fd1372e58abfd7db3057beab3a68c010fff092687d6f9e8c3eeb860","examples/execute.rs":"1336352942b5c3d84f57ba67784d78d0e75b3f5c5fc54d99de9b45aeba8fccf1","examples/parser.rs":"a72dce6d2944727ba78cf84b3b101757698c11d0526d8add808bf7e7eaac2523","examples/queue.rs":"5d1e8d0fd6cab1b5f5af905f480ea9098762255bccbf35dd9eef22a4fe9b7895","examples/sequence.rs":"ed12c0abb7492780994fa9f4a74311488a1e7ce7be061d6ec5799e0268ab3835","examples/stdout.rs":"cec899e816b0506bd1e9b6016817c83d459c29760887d0c487602102191143fd","examples/string.rs":"f910b0bd029073d5e458563d7fc593c4b3cc769fe7414d488800960c743f85f7","src/lib.rs":"39759e1e85c88c5268de2da4e11ed9acd9ba2ca14f64bfe89208453fa42e593d","src/macros.rs":"bb00a25cb6ae5b182d8d4307da2ee2dfd1b80db4426458fadd3eceeec6aa7906","src/parser.rs":"0ece1535baa662a8d4167e31a0a2e64cb0d6531aa120b04b0d6be83659af109d","src/parser/engine.rs":"d7eb6d2e0b1c0d41296d19059749fafefc638a51516669e485a9931c488e03cc","src/parser/parsers.rs":"23194e1e8a433ecb83abd2c6dc9daf33266d4a854045da0c59d4b8a6364cc5fc","src/parser/types.rs":"1e7bad18dda69b3bf4ce79d205e6d09c4ed5ef3a54b2da2da5b96e818c412d42","src/sequences.rs":"4ac6ccecd343f49b51435cc7b6daf56632437059f724e36bce374866f1087088","src/sequences/attribute.rs":"e55e384eeae9b9cd7def691990f9c95403f8aef4f7c27d9a0587fdfee37b9d3d","src/sequences/buffer.rs":"c434a246b122ef538be94cb43ffc75b507b3bf26a7eed4349ece44219c50c74a","src/sequences/color.rs":"58542ccf93fe013607b48b7cbd02c71bf7a53db62eca7c903a87039356560bce","src/sequences/cursor.rs":"76f6be496347759e56753a561bab96ec12f60dfab66360b84ea5d77927fb878e","src/sequences/terminal.rs":"3cd9cc7eeae62a19b5db49366430579f508289374026e60430797665c6975289","tests/parser/cursor.rs":"4dda22b7cd8c1fd3fadf3c9a26215cc2968c5e8105271e4313bd1c043e6752d6","tests/parser/key.rs":"5251732569eb1cf9f602fa9f47de33290ed33e4636ae572dfee04d1f272a81ef","tests/parser/mod.rs":"584766faacab21ddb1f1e7f4e4d50240c4e1c44876c50c8cc765d3c5f9d5e3b8","tests/parser/mouse/mod.rs":"b9a88b281331dc428ece06a9287b2c952ff3e0202267bece408b458343d8a1ab","tests/parser/mouse/rxvt.rs":"bfa589fd2c2a4b6b4835da279df42b6c31466464d441449330e2d2ef1db1132f","tests/parser/mouse/xterm.rs":"5993dbe9492b7f72990b43e32053c4c135af29790f6aa954e72fe5d759631f9b","tests/tests.rs":"cfba0744806bdbf6003ec8995ea9b9063db16977bd8b6f0204625e99003075f2"},"package":"4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"}
\ No newline at end of file diff --git a/vendor/anes/Cargo.lock b/vendor/anes/Cargo.lock new file mode 100644 index 000000000..b359a6d36 --- /dev/null +++ b/vendor/anes/Cargo.lock @@ -0,0 +1,511 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "anes" +version = "0.1.6" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bstr" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cast" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getrandom" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memoffset" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xoshiro" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinytemplate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" +"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" +"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" +"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" +"checksum crossbeam-queue 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfd6515864a82d2f877b42813d4553292c6659498c9a2aa31bab5a15243c2700" +"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +"checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" +"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" +"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" +"checksum rayon 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43739f8831493b276363637423d3622d4bd6394ab6f0a9c4a552e208aeb7fddd" +"checksum rayon-core 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8bf17de6f23b05473c437eb958b9c850bfc8af0961fe17b4cc92d5a627b4791" +"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" +"checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" +"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" +"checksum syn 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f89693ae015201f8de93fd96bde2d065f8bfc3f97ce006d5bc9f900b97c0c7c0" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/anes/Cargo.toml b/vendor/anes/Cargo.toml new file mode 100644 index 000000000..9ae35a0b3 --- /dev/null +++ b/vendor/anes/Cargo.toml @@ -0,0 +1,48 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "anes" +version = "0.1.6" +authors = ["Robert Vojta <rvojta@me.com>"] +exclude = ["target", "Cargo.lock"] +description = "ANSI Escape Sequences provider & parser" +documentation = "https://docs.rs/anes/" +readme = "README.md" +keywords = ["terminal", "ansi", "sequence", "code", "parser"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/zrzka/anes-rs" +[package.metadata.docs.rs] +all-features = true + +[lib] +bench = false + +[[bench]] +name = "bench_main" +harness = false +required-features = ["parser"] +[dependencies.bitflags] +version = "1.2" +optional = true +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.libc] +version = "0.2.66" + +[features] +default = [] +parser = ["bitflags"] +[badges.maintenance] +status = "actively-developed" diff --git a/vendor/anes/README.md b/vendor/anes/README.md new file mode 100644 index 000000000..6a3c23676 --- /dev/null +++ b/vendor/anes/README.md @@ -0,0 +1,129 @@ +[![Stable Status][actions-stable-badge]][actions-link] +[![Beta Status][actions-beta-badge]][actions-link] +[![Nightly Status][actions-nightly-badge]][actions-link] +[![crates.io][crates-badge]][crates-link] +[![docs.rs][docs-badge]][docs-link] +[![MIT][mit-license-badge]][mit-license-link] +[![Apache 2.0][apache-license-badge]][apache-license-link] +![LOC][loc-badge] + +# ANSI Escape Sequences provider & parser + +A Rust library which provides an ANSI escape sequences (or codes, whatever you like more) +and a parser allowing you to parse data from the STDIN (or `/dev/tty`) in the raw mode. + +## Sequences provider + +### Terminal support + +Not all ANSI escape sequences are supported by all terminals. You can use the +[interactive-test](https://github.com/zrzka/anes-rs/tree/master/interactive-test) to test them. +Checkout the repository and then: + +```bash +$ cd anes-rs +$ cargo run --bin interactive-test +``` + +### Examples + +<details> +<summary> +Click to show Cargo.toml. +</summary> + +```toml +[dependencies] +anes = "0.1" +``` + +</details> +<p></p> + + +An example how to retrieve the ANSI escape sequence as a `String`: + +```rust +use anes::SaveCursorPosition; + +fn main() { + let string = format!("{}", SaveCursorPosition); + assert_eq!(&string, "\x1B7"); +} +``` + +An example how to use the ANSI escape sequence: + +```rust +use std::io::{Result, Write}; + +use anes::execute; + +fn main() -> Result<()> { + let mut stdout = std::io::stdout(); + execute!( + &mut stdout, + anes::SaveCursorPosition, + anes::MoveCursorTo(10, 10), + anes::RestoreCursorPosition + )?; + Ok(()) +} +``` + +## Sequences parser + +You have to enable `parser` feature in order to use the parser. It's disabled by default. + +### Examples + +<details> +<summary> +Click to show Cargo.toml. +</summary> + +```toml +[dependencies] +anes = { version = "0.1", features = ["parser"] } +``` + +</details> +<p></p> + +An example how to parse cursor position: + +```rust +use anes::parser::{Parser, Sequence}; + +let mut parser = Parser::default(); +parser.advance(b"\x1B[20;10R", false); + +assert_eq!(Some(Sequence::CursorPosition(10, 20)), parser.next()); +assert!(parser.next().is_none()); +``` + +## License + +The ANES crate is dual-licensed under [Apache 2.0][apache-license-link] and +[MIT][mit-license-link] terms. + +Copyrights in the ANES project are retained by their contributors. No +copyright assignment is required to contribute to the ANES project. + +[actions-stable-badge]: https://github.com/zrzka/anes-rs/workflows/stable/badge.svg +[actions-beta-badge]: https://github.com/zrzka/anes-rs/workflows/beta/badge.svg +[actions-nightly-badge]: https://github.com/zrzka/anes-rs/workflows/nightly/badge.svg +[actions-link]: https://github.com/zrzka/anes-rs/actions + +[crates-badge]: https://img.shields.io/crates/v/anes.svg +[crates-link]: https://crates.io/crates/anes + +[docs-badge]: https://docs.rs/anes/badge.svg +[docs-link]: https://docs.rs/anes + +[mit-license-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[mit-license-link]: ./LICENSE-MIT +[apache-license-badge]: https://img.shields.io/badge/license-Apache2-blue.svg +[apache-license-link]: /LICENSE-APACHE + +[loc-badge]: https://tokei.rs/b1/github/zrzka/anes-rs?category=code diff --git a/vendor/anes/benches/bench_main.rs b/vendor/anes/benches/bench_main.rs new file mode 100644 index 000000000..79aea4a76 --- /dev/null +++ b/vendor/anes/benches/bench_main.rs @@ -0,0 +1,5 @@ +use criterion::criterion_main; + +mod benchmarks; + +criterion_main!(benchmarks::parser::benches); diff --git a/vendor/anes/benches/benchmarks/mod.rs b/vendor/anes/benches/benchmarks/mod.rs new file mode 100644 index 000000000..67c567fa0 --- /dev/null +++ b/vendor/anes/benches/benchmarks/mod.rs @@ -0,0 +1 @@ +pub mod parser; diff --git a/vendor/anes/benches/benchmarks/parser.rs b/vendor/anes/benches/benchmarks/parser.rs new file mode 100644 index 000000000..2aa63aaa7 --- /dev/null +++ b/vendor/anes/benches/benchmarks/parser.rs @@ -0,0 +1,20 @@ +use criterion::{black_box, criterion_group, Criterion}; + +use anes::parser::Parser; + +pub fn parser(c: &mut Criterion) { + const XTERM_MOUSE: &str = "\x1B[<28;20;10;m"; + + let mut parser = Parser::default(); + + c.bench_function("advance and consume", |b| { + let input = XTERM_MOUSE.as_bytes(); + + b.iter(|| { + parser.advance(black_box(input), black_box(true)); + while let Some(_) = parser.next() {} + }) + }); +} + +criterion_group!(benches, parser); diff --git a/vendor/anes/examples/execute.rs b/vendor/anes/examples/execute.rs new file mode 100644 index 000000000..df781fc74 --- /dev/null +++ b/vendor/anes/examples/execute.rs @@ -0,0 +1,15 @@ +/// An example how to execute the ANSI escape sequence. +use std::io::{Result, Write}; + +use anes::execute; + +fn main() -> Result<()> { + let mut stdout = std::io::stdout(); + execute!( + &mut stdout, + anes::SaveCursorPosition, + anes::MoveCursorTo(10, 10), + anes::RestoreCursorPosition + )?; + Ok(()) +} diff --git a/vendor/anes/examples/parser.rs b/vendor/anes/examples/parser.rs new file mode 100644 index 000000000..a5ec5b6dd --- /dev/null +++ b/vendor/anes/examples/parser.rs @@ -0,0 +1,106 @@ +/// An example how to use the ANSI escape sequence parser. +use std::io::{Read, Result, Write}; + +use anes::{ + self, execute, + parser::{KeyCode, Parser, Sequence}, + queue, +}; +use libc::termios as Termios; + +const HELP: &str = r#"ANES parser example + +* Hit `Esc` to quit +* Hit 'c' to ask for cursor position +* Use your mouse or type anything +"#; + +fn main() -> Result<()> { + let mut w = std::io::stdout(); + queue!( + w, + anes::SwitchBufferToAlternate, + anes::HideCursor, + anes::EnableMouseEvents + )?; + for line in HELP.split('\n') { + queue!(w, line, anes::MoveCursorToNextLine(1))?; + } + w.flush()?; + + let saved_attributes = get_termios()?; + let mut attributes = saved_attributes; + make_raw(&mut attributes); + set_termios(attributes)?; + + let mut stdin = std::io::stdin(); + let mut stdin_buffer = [0u8; 1024]; + let mut parser = Parser::default(); + + loop { + if let Ok(size) = stdin.read(&mut stdin_buffer) { + parser.advance(&stdin_buffer[..size], false); + + let mut break_outer_loop = false; + + while let Some(sequence) = parser.next() { + match sequence { + Sequence::Key(KeyCode::Esc, _) => { + break_outer_loop = true; + break; + } + Sequence::Key(KeyCode::Char('c'), _) => { + execute!(w, anes::ReportCursorPosition)? + } + _ => execute!( + w, + anes::ClearLine::Left, + anes::MoveCursorToColumn(1), + format!("{:?}", sequence), + )?, + } + } + + if break_outer_loop { + break; + } + } + } + + set_termios(saved_attributes)?; + + execute!( + w, + anes::DisableMouseEvents, + anes::ShowCursor, + anes::SwitchBufferToNormal + )?; + Ok(()) +} + +// +// RAW mode +// + +fn get_termios() -> Result<Termios> { + unsafe { + let mut termios = std::mem::zeroed(); + if libc::tcgetattr(libc::STDIN_FILENO, &mut termios) != -1 { + Ok(termios) + } else { + Err(std::io::Error::last_os_error()) + } + } +} + +fn set_termios(termios: Termios) -> Result<()> { + if unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &termios) } != -1 { + Ok(()) + } else { + Err(std::io::Error::last_os_error()) + } +} + +fn make_raw(termios: &mut Termios) { + unsafe { libc::cfmakeraw(termios) } +} diff --git a/vendor/anes/examples/queue.rs b/vendor/anes/examples/queue.rs new file mode 100644 index 000000000..0b2c7120d --- /dev/null +++ b/vendor/anes/examples/queue.rs @@ -0,0 +1,18 @@ +/// An example how to queue & flush the ANSI escape sequence. +use std::io::{Result, Write}; + +use anes::queue; + +fn main() -> Result<()> { + let mut stdout = std::io::stdout(); + queue!( + &mut stdout, + anes::SaveCursorPosition, + anes::MoveCursorTo(10, 10) + )?; + + queue!(&mut stdout, anes::RestoreCursorPosition,)?; + + // ANSI sequences are not executed until you flush it! + stdout.flush() +} diff --git a/vendor/anes/examples/sequence.rs b/vendor/anes/examples/sequence.rs new file mode 100644 index 000000000..d038f5851 --- /dev/null +++ b/vendor/anes/examples/sequence.rs @@ -0,0 +1,42 @@ +/// An example how to create custom ANSI sequences. +use anes::{csi, esc, sequence}; + +fn static_unit_struct() { + sequence!( + /// Documentation string is also supported. + struct Foo => csi!("foo") + ); + + assert_eq!(&format!("{}", Foo), "\x1B[foo"); +} + +fn dynamic_struct() { + sequence!( + /// Documentation string is also supported. + struct Foo(u16, u16) => + |this, f| write!(f, esc!("{};{}"), this.0, this.1) + ); + + assert_eq!(&format!("{}", Foo(5, 10)), "\x1B5;10"); +} + +fn static_enum() { + sequence!( + /// Documentation string is also supported. + enum Foo { + /// Documentation string is also supported. + Bar => esc!("bar"), + /// Documentation string is also supported. + Baz => csi!("baz"), + } + ); + + assert_eq!(&format!("{}", Foo::Bar), "\x1Bbar"); + assert_eq!(&format!("{}", Foo::Baz), "\x1B[baz"); +} + +fn main() { + static_unit_struct(); + dynamic_struct(); + static_enum(); +} diff --git a/vendor/anes/examples/stdout.rs b/vendor/anes/examples/stdout.rs new file mode 100644 index 000000000..9b5be7257 --- /dev/null +++ b/vendor/anes/examples/stdout.rs @@ -0,0 +1,12 @@ +/// An example how to use the ANSI escape sequence. +use std::io::{Result, Write}; + +use anes; + +fn main() -> Result<()> { + let mut stdout = std::io::stdout(); + write!(stdout, "{}", anes::SaveCursorPosition)?; + write!(stdout, "{}", anes::RestoreCursorPosition)?; + stdout.flush()?; + Ok(()) +} diff --git a/vendor/anes/examples/string.rs b/vendor/anes/examples/string.rs new file mode 100644 index 000000000..bd81c368e --- /dev/null +++ b/vendor/anes/examples/string.rs @@ -0,0 +1,7 @@ +//! An example how to retrieve the ANSI escape sequence as a `String`. +use anes::SaveCursorPosition; + +fn main() { + let string = format!("{}", SaveCursorPosition); + assert_eq!(&string, "\x1B7"); +} diff --git a/vendor/anes/src/lib.rs b/vendor/anes/src/lib.rs new file mode 100644 index 000000000..99dfc8c08 --- /dev/null +++ b/vendor/anes/src/lib.rs @@ -0,0 +1,76 @@ +//! # ANSI Escape Sequences provider & parser +//! +//! ## Sequences provider +//! +//! The `anes` crate provides ANSI escape sequences you can use to control the terminal +//! cursor (show, hide, ...), colors (foreground, background), display attributes (bold, ...) +//! and many others. +//! +//! Every sequence implements the standard library [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html) +//! trait. It means that these sequences can be used in macros like +//! [`format!`](https://doc.rust-lang.org/std/macro.format.html) or +//! [`write!`](https://doc.rust-lang.org/std/macro.write.html). +//! +//! Ask if you need more sequences or use the [`sequence!`](macro.sequence.html) macro to create +//! your own sequences. +//! +//! +//! ### Terminal Support +//! +//! Not all ANSI escape sequences are supported by all terminals. You can use the +//! [interactive-test](https://github.com/zrzka/anes-rs/tree/master/interactive-test) to test them. +//! +//! ### Examples +//! +//! Retrieve the sequence as a `String`: +//! +//! ```rust +//! use anes::SaveCursorPosition; +//! +//! let string = format!("{}", SaveCursorPosition); +//! assert_eq!(&string, "\x1B7"); +//! ``` +//! +//! Execute the sequence on the standard output: +//! +//! ```rust +//! use std::io::{Result, Write}; +//! +//! use anes::execute; +//! +//! fn main() -> Result<()> { +//! let mut stdout = std::io::stdout(); +//! execute!(&mut stdout, anes::ResetAttributes) +//! } +//! ``` +//! +//! ## Sequences parser +//! +//! Parser isn't available with default features. You have to enable `parser` feature if you'd like to use it. +//! You can learn more about this feature in the [`parser`](parser/index.html) module documentation. +#![warn(rust_2018_idioms)] +#![deny(unused_imports, unused_must_use)] + +// Keep it first to load all the macros before other modules. +#[macro_use] +mod macros; + +pub use self::sequences::{ + attribute::{Attribute, ResetAttributes, SetAttribute}, + buffer::{ + ClearBuffer, ClearLine, ScrollBufferDown, ScrollBufferUp, SwitchBufferToAlternate, + SwitchBufferToNormal, + }, + color::{Color, SetBackgroundColor, SetForegroundColor}, + cursor::{ + DisableCursorBlinking, EnableCursorBlinking, HideCursor, MoveCursorDown, MoveCursorLeft, + MoveCursorRight, MoveCursorTo, MoveCursorToColumn, MoveCursorToNextLine, + MoveCursorToPreviousLine, MoveCursorUp, ReportCursorPosition, RestoreCursorPosition, + SaveCursorPosition, ShowCursor, + }, + terminal::{DisableMouseEvents, EnableMouseEvents, ResizeTextArea}, +}; + +#[cfg(feature = "parser")] +pub mod parser; +mod sequences; diff --git a/vendor/anes/src/macros.rs b/vendor/anes/src/macros.rs new file mode 100644 index 000000000..1955214fc --- /dev/null +++ b/vendor/anes/src/macros.rs @@ -0,0 +1,437 @@ +/// Creates a control sequence. +/// +/// This macro prepends provided sequence with the control sequence introducer `ESC [` (`\x1B[`). +/// +/// # Examples +/// +/// ``` +/// use anes::csi; +/// +/// assert_eq!(csi!("?1049h"), "\x1B[?1049h"); +/// ``` +#[macro_export] +macro_rules! csi { + ($($arg:expr),*) => { concat!("\x1B[", $($arg),*) }; +} + +/// Creates an escape sequence. +/// +/// This macro prepends provided sequence with the `ESC` (`\x1B`) character. +/// +/// # Examples +/// +/// ``` +/// use anes::esc; +/// +/// assert_eq!(esc!("7"), "\x1B7"); +/// ``` +#[macro_export] +macro_rules! esc { + ($($arg:expr),*) => { concat!("\x1B", $($arg),*) }; +} + +/// Creates a select graphic rendition sequence. +/// +/// This macro prepends provided sequence with the `ESC[` (`\x1B[`) character and appends `m` character. +/// +/// Also known as Set Graphics Rendition on Linux. +/// +/// # Examples +/// +/// ``` +/// use anes::sgr; +/// +/// assert_eq!(sgr!("0"), "\x1B[0m"); +/// ``` +#[macro_export] +macro_rules! sgr { + ($($arg:expr),*) => { concat!("\x1B[", $($arg),* , "m") }; +} + +/// Creates an ANSI sequence. +/// +/// You can use this macro to create your own ANSI sequence. All `anes` sequences are +/// created with this macro. +/// +/// # Examples +/// +/// An unit struct: +/// +/// ``` +/// use anes::{esc, sequence}; +/// +/// sequence!( +/// /// Saves the cursor position. +/// struct SaveCursorPosition => esc!("7") +/// ); +/// +/// assert_eq!(&format!("{}", SaveCursorPosition), "\x1B7"); +/// ``` +/// +/// An enum: +/// +/// ``` +/// use anes::{csi, sequence}; +/// +/// sequence!( +/// /// Clears part of the buffer. +/// enum ClearBuffer { +/// /// Clears from the cursor position to end of the screen. +/// Below => csi!("J"), +/// /// Clears from the cursor position to beginning of the screen. +/// Above => csi!("1J"), +/// /// Clears the entire buffer. +/// All => csi!("2J"), +/// /// Clears the entire buffer and all saved lines in the scrollback buffer. +/// SavedLines => csi!("3J"), +/// } +/// ); +/// +/// assert_eq!(&format!("{}", ClearBuffer::Below), "\x1B[J"); +/// assert_eq!(&format!("{}", ClearBuffer::Above), "\x1B[1J"); +/// assert_eq!(&format!("{}", ClearBuffer::All), "\x1B[2J"); +/// assert_eq!(&format!("{}", ClearBuffer::SavedLines), "\x1B[3J"); +/// ``` +/// +/// A struct: +/// +/// ``` +/// use anes::{csi, sequence}; +/// +/// sequence!( +/// /// Moves the cursor to the given location (column, row). +/// /// +/// /// # Notes +/// /// +/// /// Top/left cell is represented as `1, 1`. +/// struct MoveCursorTo(u16, u16) => +/// |this, f| write!(f, csi!("{};{}H"), this.0, this.1) +/// ); +/// +/// assert_eq!(&format!("{}", MoveCursorTo(10, 5)), "\x1B[10;5H"); +/// ``` +#[macro_export] +macro_rules! sequence { + // Static unit struct + ( + $(#[$meta:meta])* + struct $name:ident => $value:expr + ) => { + $(#[$meta])* + #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] + pub struct $name; + + impl ::std::fmt::Display for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, $value) + } + } + }; + // Static enum + ( + $(#[$meta:meta])* + enum $name:ident { + $( + $(#[$variant_meta:meta])* + $variant:ident => $variant_value:expr + ),* + $(,)? + } + ) => { + $(#[$meta])* + #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] + pub enum $name { + $( + $(#[$variant_meta])* + $variant, + )* + } + + impl ::std::fmt::Display for $name { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "{}", match self { + $( + $name::$variant => $variant_value, + )* + }) + } + } + }; + // Dynamic struct + ( + $(#[$meta:meta])* + struct $type:ident( + $($fields:ty),* + $(,)? + ) + => + $write:expr + ) => { + $(#[$meta])* + #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] + pub struct $type($(pub $fields),*); + + impl ::std::fmt::Display for $type { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + let write: &dyn Fn(&Self, &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result = + &$write; + write(self, f) + } + } + }; +} + +/// Queues ANSI escape sequence(s). +/// +/// What does queue mean exactly? All sequences are queued with the +/// `write!($dst, "{}", $sequence)` macro without calling the +/// [`flush`](https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush) method. +/// +/// Check the [`execute!`](macro.execute.html) macro if you'd like execute them +/// immediately (call the `flush` method after all sequences were queued). +/// +/// # Examples +/// +/// ```no_run +/// use std::io::{Result, Write}; +/// +/// use anes::queue; +/// +/// fn main() -> Result<()> { +/// let mut stdout = std::io::stdout(); +/// queue!( +/// &mut stdout, +/// anes::SaveCursorPosition, +/// anes::MoveCursorTo(10, 10) +/// )?; +/// +/// queue!(&mut stdout, anes::RestoreCursorPosition,)?; +/// +/// // ANSI sequences are not executed until you flush it! +/// stdout.flush() +/// } +/// ``` +#[macro_export] +macro_rules! queue { + ($dst:expr, $($sequence:expr),* $(,)?) => {{ + let mut error = None; + + $( + if let Err(e) = write!($dst, "{}", $sequence) { + error = Some(e); + } + )* + + if let Some(error) = error { + Err(error) + } else { + Ok(()) + } + }} +} + +/// Executes ANSI escape sequence(s). +/// +/// What does execute mean exactly? All sequences are queued with the +/// `write!($dst, "{}", $sequence)` macro and then the +/// [`flush`](https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush) method +/// is called. +/// +/// Check the [`queue!`](macro.queue.html) macro if you'd like queue sequences +/// and execute them later. +/// +/// ```no_run +/// use std::io::{Result, Write}; +/// +/// use anes::execute; +/// +/// fn main() -> Result<()> { +/// let mut stdout = std::io::stdout(); +/// execute!( +/// &mut stdout, +/// anes::SaveCursorPosition, +/// anes::MoveCursorTo(10, 10), +/// anes::RestoreCursorPosition +/// )?; +/// Ok(()) +/// } +/// ``` +#[macro_export] +macro_rules! execute { + ($dst:expr, $($sequence:expr),* $(,)?) => {{ + if let Err(e) = $crate::queue!($dst, $($sequence),*) { + Err(e) + } else { + $dst.flush() + } + }} +} + +#[cfg(test)] +macro_rules! test_sequences { + ( + $( + $name:ident( + $($left:expr => $right:expr),* + $(,)? + ) + ),* + $(,)? + ) => { + #[cfg(test)] + mod tests { + use super::*; + + $( + #[test] + fn $name() { + $( + assert_eq!(&format!("{}", $left), $right); + )* + } + )* + } + } +} + +#[cfg(test)] +mod tests { + use std::io::{Error, ErrorKind, Write}; + + #[test] + fn csi() { + assert_eq!(csi!("foo"), "\x1B[foo"); + } + + #[test] + fn esc() { + assert_eq!(esc!("bar"), "\x1Bbar"); + } + + #[test] + fn sgr() { + assert_eq!(sgr!("bar"), "\x1B[barm"); + } + + #[test] + fn static_struct_sequence() { + sequence!( + struct TestSeq => csi!("foo") + ); + + assert_eq!(&format!("{}", TestSeq), "\x1B[foo"); + } + + #[test] + fn static_enum_sequence() { + sequence!( + enum TestSeq { + Foo => csi!("foo"), + Bar => esc!("bar"), + } + ); + + assert_eq!(&format!("{}", TestSeq::Foo), "\x1B[foo"); + assert_eq!(&format!("{}", TestSeq::Bar), "\x1Bbar"); + } + + #[test] + fn dynamic_struct_sequence() { + sequence!( + struct TestSeq(u16) => + |this, f| write!(f, csi!("foo{}bar"), this.0) + ); + + assert_eq!(&format!("{}", TestSeq(10)), "\x1B[foo10bar"); + } + + #[test] + fn queue_allows_trailing_comma() { + let mut writer = Writer::default(); + + assert!(queue!(&mut writer, "foo",).is_ok()); + assert_eq!(&writer.buffer, "foo"); + } + + #[test] + fn queue_writes_single_sequence() { + let mut writer = Writer::default(); + + assert!(queue!(&mut writer, "foo").is_ok()); + assert_eq!(&writer.buffer, "foo"); + } + + #[test] + fn queue_writes_multiple_sequences() { + let mut writer = Writer::default(); + + assert!(queue!(&mut writer, "foo", "bar", "baz").is_ok()); + assert_eq!(&writer.buffer, "foobarbaz"); + } + + #[test] + fn queue_does_not_flush() { + let mut writer = Writer::default(); + + assert!(queue!(&mut writer, "foo").is_ok()); + assert!(!writer.flushed); + assert!(writer.flushed_buffer.is_empty()); + } + + #[test] + fn execute_allows_trailing_comma() { + let mut writer = Writer::default(); + + assert!(execute!(&mut writer, "foo",).is_ok()); + assert_eq!(&writer.flushed_buffer, "foo"); + } + + #[test] + fn execute_writes_single_sequence() { + let mut writer = Writer::default(); + + assert!(execute!(&mut writer, "foo").is_ok()); + assert_eq!(&writer.flushed_buffer, "foo"); + } + + #[test] + fn execute_writes_multiple_sequences() { + let mut writer = Writer::default(); + + assert!(execute!(&mut writer, "foo", "bar", "baz").is_ok()); + assert_eq!(&writer.flushed_buffer, "foobarbaz"); + } + + #[test] + fn execute_does_flush() { + let mut writer = Writer::default(); + + assert!(execute!(&mut writer, "foo").is_ok()); + assert!(writer.flushed); + assert_eq!(&writer.flushed_buffer, "foo"); + assert!(writer.buffer.is_empty()); + } + + #[derive(Default)] + struct Writer { + buffer: String, + flushed_buffer: String, + flushed: bool, + } + + impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> Result<usize, Error> { + let s = std::str::from_utf8(buf).map_err(|_| ErrorKind::InvalidData)?; + + self.buffer.push_str(s); + Ok(s.len()) + } + + fn flush(&mut self) -> Result<(), Error> { + self.flushed_buffer = self.buffer.clone(); + self.buffer = String::new(); + self.flushed = true; + Ok(()) + } + } +} diff --git a/vendor/anes/src/parser.rs b/vendor/anes/src/parser.rs new file mode 100644 index 000000000..be87b2986 --- /dev/null +++ b/vendor/anes/src/parser.rs @@ -0,0 +1,252 @@ +//! An ANSI escape sequence parser module. +//! +//! **This module is not available with default features. You have to enable `parser` feature +//! if you'd like to use it.** +//! +//! # Parser +//! +//! The ANSI escape sequence parser parses input data in two steps: +//! +//! * transforms input data into valid characters, generic csi & escape sequences, throws away invalid data, +//! * give them meaning, throws away sequences without known meaning. +//! +//! ## First step +//! +//! State machine implementation for the first step is inspired by the +//! [A parser for DEC’s ANSI-compatible video terminals](https://vt100.net/emu/dec_ansi_parser) article +//! and the [vte](https://crates.io/crates/vte) crate. The goal of this step is to transform an input +//! data into characters, generic csi & escape sequences, validate them and throw away malformed input. +//! +//! An example of valid csi sequence: `b"\x1B[20;10R"`. Output of the first step will be: +//! +//! * valid csi sequence +//! * with two parameters `[20, 10]` +//! * and the final character `R`. +//! +//! ## Second step +//! +//! An input of this step is output of the first one. We know that the final character `R` represents +//! cursor position and two parameters should be provided. They were provided, we can give it a +//! meaning and return `Sequence::CursorPosition(10, 20)`. +//! +//! All sequences without known meaning are discarded. +//! +//! ## Implementation +//! +//! Both steps are considered as an implementation detail and there's no plan to make them +//! publicly available. +//! +//! The `parser` module provides the [`Parser`](struct.Parser.html) structure you can feed with +//! the [`advance`](struct.Parser.html#method.advance) method. It also implements the standard +//! library `Iterator<Item = Sequence>` trait which allows you to consume valid sequences with +//! known meaning via the `next()` method. Check the [`Sequence`](enum.Sequence.html) enum to learn +//! what this module can parse. +use std::collections::VecDeque; + +use engine::{Engine, Provide}; +pub use types::{KeyCode, KeyModifiers, Mouse, MouseButton, Sequence}; + +mod engine; +mod parsers; +pub(crate) mod types; + +/// An ANSI escape sequence parser. +/// +/// `Parser` implements the `Iterator<Item = Sequence>` trait, thus you can use the +/// `next()` method to consume all valid sequences with known meaning. +/// +/// # Examples +/// +/// Parse cursor position: +/// +/// ``` +/// use anes::parser::{Parser, Sequence}; +/// +/// let mut parser = Parser::default(); +/// parser.advance(b"\x1B[20;10R", false); +/// +/// assert_eq!(Some(Sequence::CursorPosition(10, 20)), parser.next()); +/// assert!(parser.next().is_none()); +/// ``` +/// +/// Parse keyboard event: +/// +/// ``` +/// use anes::parser::{KeyCode, KeyModifiers, Parser, Sequence}; +/// +/// let mut parser = Parser::default(); +/// parser.advance("𐌼a".as_bytes(), false); +/// +/// assert_eq!(Some(Sequence::Key(KeyCode::Char('𐌼'), KeyModifiers::empty())), parser.next()); +/// assert_eq!(Some(Sequence::Key(KeyCode::Char('a'), KeyModifiers::empty())), parser.next()); +/// assert!(parser.next().is_none()); +/// ``` +#[derive(Default)] +pub struct Parser { + engine: Engine, + provider: SequenceProvider, +} + +impl Parser { + /// Advances parser state machine with additional input data. + /// + /// # Arguments + /// + /// * `buffer` - input data (stdin in raw mode, etc.) + /// * `more` - more input data available right now + /// + /// It's crucial to provide correct `more` value in order to receive `KeyCode::Esc` events + /// as soon as possible. + /// + /// # Examples + /// + /// Esc key: + /// + /// ``` + /// use anes::parser::{KeyCode, KeyModifiers, Parser, Sequence}; + /// + /// let mut parser = Parser::default(); + /// // User pressed Esc key & nothing else which means that there's no additional input available + /// // aka no possible escape sequence = `KeyCode::Esc` dispatched. + /// parser.advance(&[0x1b], false); + /// + /// assert_eq!(Some(Sequence::Key(KeyCode::Esc, KeyModifiers::empty())), parser.next()); + /// assert!(parser.next().is_none()); + /// ``` + /// + /// Possible escape sequence: + /// + /// ``` + /// use anes::parser::{KeyCode, KeyModifiers, Parser, Sequence}; + /// + /// let mut parser = Parser::default(); + /// // User pressed F1 = b"\x1BOP" + /// + /// // Every escape sequence starts with Esc (0x1b). There's more input available + /// // aka possible escape sequence = `KeyCode::Esc` isn't dispatched even when the parser + /// // doesn't know rest of the sequence. + /// parser.advance(&[0x1b], true); + /// assert!(parser.next().is_none()); + /// + /// // Advance parser with rest of the sequence + /// parser.advance(&[b'O', b'P'], false); + /// assert_eq!(Some(Sequence::Key(KeyCode::F(1), KeyModifiers::empty())), parser.next()); + /// assert!(parser.next().is_none()); + /// ``` + pub fn advance(&mut self, buffer: &[u8], more: bool) { + let len = buffer.len(); + for (idx, byte) in buffer.iter().enumerate() { + self.engine + .advance(&mut self.provider, *byte, idx < len - 1 || more); + } + } +} + +impl Iterator for Parser { + type Item = Sequence; + + fn next(&mut self) -> Option<Self::Item> { + self.provider.next() + } +} + +#[derive(Default)] +struct SequenceProvider { + esc_o: bool, + seqs: VecDeque<Sequence>, +} + +impl Iterator for SequenceProvider { + type Item = Sequence; + + fn next(&mut self) -> Option<Self::Item> { + self.seqs.pop_front() + } +} + +impl Provide for SequenceProvider { + fn provide_char(&mut self, ch: char) { + // eprintln!("dispatch_char: {}", ch); + + if let Some(seq) = parsers::parse_char(ch, self.esc_o) { + self.seqs.push_back(seq); + } + self.esc_o = false; + } + + fn provide_esc_sequence(&mut self, ch: char) { + if ch == 'O' { + // Exception + // + // Esc O - dispatched as an escape sequence followed by single character (P-S) representing + // F1-F4 keys. We store Esc O flag only which is then used in the dispatch_char method. + self.esc_o = true; + } else { + self.esc_o = false; + if let Some(seq) = parsers::parse_esc_sequence(ch) { + self.seqs.push_back(seq); + } + } + } + + fn provide_csi_sequence(&mut self, parameters: &[u64], ignored_count: usize, ch: char) { + if let Some(seq) = parsers::parse_csi_sequence(parameters, ignored_count, ch) { + self.seqs.push_back(seq); + } + + self.esc_o = false; + } +} + +#[cfg(test)] +mod tests { + use super::Parser; + + #[test] + fn dispatch_char() { + let mut parser = Parser::default(); + parser.advance(&[b'a'], false); + assert!(parser.next().is_some()); + } + + #[test] + fn dispatch_esc_sequence() { + let mut parser = Parser::default(); + parser.advance(&[b'\x1B'], true); + assert!(parser.next().is_none()); + parser.advance(&[b'a'], false); + assert!(parser.next().is_some()); + } + + #[test] + fn does_not_dispatch_esc_sequence_with_upper_case_o() { + let mut parser = Parser::default(); + parser.advance(&[b'\x1B'], true); + assert!(parser.next().is_none()); + parser.advance(&[b'O'], true); + assert!(parser.next().is_none()); + } + + #[test] + fn dispatch_esc_with_upper_case_o_followed_by_char_as_single_sequence() { + let mut parser = Parser::default(); + parser.advance(&[b'\x1B'], true); + assert!(parser.next().is_none()); + parser.advance(&[b'O'], true); + assert!(parser.next().is_none()); + parser.advance(&[b'P'], false); + assert!(parser.next().is_some()); + assert!(parser.next().is_none()); + } + + #[test] + fn dispatch_csi_sequence() { + let mut parser = Parser::default(); + parser.advance(&[b'\x1B'], true); + assert!(parser.next().is_none()); + parser.advance(&[b'['], true); + assert!(parser.next().is_none()); + parser.advance(&[b'D'], false); + assert!(parser.next().is_some()); + } +} diff --git a/vendor/anes/src/parser/engine.rs b/vendor/anes/src/parser/engine.rs new file mode 100644 index 000000000..645208d37 --- /dev/null +++ b/vendor/anes/src/parser/engine.rs @@ -0,0 +1,614 @@ +// +// https://vt100.net/emu/dec_ansi_parser +// +// The parser is heavily inspired by the vte (https://crates.io/crates/vte) crate. +// Tried to use this crate, but it doesn't work for opposite way (terminal -> sequence), +// because there're couple of exceptions we have to handle and it doesn't make much +// sense to add them to the vte crate. An example is Esc key where we need to know if +// there's additional input available or not and then the decision is made if the +// Esc char is dispatched immediately (user hits just Esc key) or if it's an escape/csi/... +// sequence. +// +const MAX_PARAMETERS: usize = 30; +const DEFAULT_PARAMETER_VALUE: u64 = 0; +const MAX_UTF8_CODE_POINTS: usize = 4; + +/// A parser engine state. +/// +/// All these variant names come from the +/// [A parser for DEC’s ANSI-compatible video terminals](https://vt100.net/emu/dec_ansi_parser) +/// description. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum State { + /// Initial state. + Ground, + /// Escape sequence started. + /// + /// `Esc` received with a flag that there's more data available. + Escape, + /// Escape sequence and we're collecting intermediates. + /// + /// # Notes + /// + /// This implementation doesn't collect intermediates. It just handles the state + /// to distinguish between (im)proper sequences. + EscapeIntermediate, + /// CSI sequence started. + /// + /// `Esc` followed by the `[` received. + CsiEntry, + /// CSI sequence should be consumed, but not dispatched. + CsiIgnore, + /// CSI sequence and we're collecting parameters. + CsiParameter, + /// CSI sequence and we're collecting intermediates. + /// + /// # Notes + /// + /// This implementation doesn't collect intermediates. It just handles the state + /// to distinguish between (im)proper sequences. + CsiIntermediate, + /// Possible UTF-8 sequence and we're collecting UTF-8 code points. + Utf8, +} + +pub(crate) trait Provide { + fn provide_char(&mut self, ch: char); + + fn provide_esc_sequence(&mut self, ch: char); + + fn provide_csi_sequence(&mut self, parameters: &[u64], ignored_count: usize, ch: char); +} + +pub(crate) struct Engine { + parameters: [u64; MAX_PARAMETERS], + parameters_count: usize, + parameter: u64, + ignored_parameters_count: usize, + state: State, + utf8_points: [u8; MAX_UTF8_CODE_POINTS], + utf8_points_count: usize, + utf8_points_expected_count: usize, +} + +impl Default for Engine { + fn default() -> Self { + Engine { + parameters: [DEFAULT_PARAMETER_VALUE; MAX_PARAMETERS], + parameters_count: 0, + parameter: DEFAULT_PARAMETER_VALUE, + ignored_parameters_count: 0, + state: State::Ground, + utf8_points: [0; MAX_UTF8_CODE_POINTS], + utf8_points_count: 0, + utf8_points_expected_count: 0, + } + } +} + +impl Engine { + fn set_state(&mut self, state: State) { + if let State::Ground = state { + self.parameters_count = 0; + self.parameter = DEFAULT_PARAMETER_VALUE; + self.ignored_parameters_count = 0; + self.utf8_points_count = 0; + self.utf8_points_expected_count = 0; + } + self.state = state; + } + + fn store_parameter(&mut self) { + if self.parameters_count < MAX_PARAMETERS { + self.parameters[self.parameters_count] = self.parameter; + self.parameters_count += 1; + } else { + self.ignored_parameters_count += 1; + } + self.parameter = DEFAULT_PARAMETER_VALUE; + } + + fn handle_possible_esc(&mut self, provider: &mut dyn Provide, byte: u8, more: bool) -> bool { + if byte != 0x1B { + return false; + } + + match (self.state, more) { + // More input means possible Esc sequence, just switch state and wait + (State::Ground, true) => self.set_state(State::Escape), + + // No more input means Esc key, dispatch it + (State::Ground, false) => provider.provide_char('\x1B'), + + // More input means possible Esc sequence, dispatch the previous Esc char + (State::Escape, true) => provider.provide_char('\x1B'), + + // No more input means Esc key, dispatch the previous & current Esc char + (State::Escape, false) => { + provider.provide_char('\x1B'); + provider.provide_char('\x1B'); + self.set_state(State::Ground); + } + + // Discard any state + // More input means possible Esc sequence + (_, true) => self.set_state(State::Escape), + + // Discard any state + // No more input means Esc key, dispatch it + (_, false) => { + provider.provide_char('\x1B'); + self.set_state(State::Ground); + } + } + + true + } + + fn handle_possible_utf8_code_points(&mut self, provider: &mut dyn Provide, byte: u8) -> bool { + if byte & 0b1000_0000 == 0b0000_0000 { + provider.provide_char(byte as char); + true + } else if byte & 0b1110_0000 == 0b1100_0000 { + self.utf8_points_count = 1; + self.utf8_points[0] = byte; + self.utf8_points_expected_count = 2; + self.set_state(State::Utf8); + true + } else if byte & 0b1111_0000 == 0b1110_0000 { + self.utf8_points_count = 1; + self.utf8_points[0] = byte; + self.utf8_points_expected_count = 3; + self.set_state(State::Utf8); + true + } else if byte & 0b1111_1000 == 0b1111_0000 { + self.utf8_points_count = 1; + self.utf8_points[0] = byte; + self.utf8_points_expected_count = 4; + self.set_state(State::Utf8); + true + } else { + false + } + } + + fn advance_ground_state(&mut self, provider: &mut dyn Provide, byte: u8) { + if self.handle_possible_utf8_code_points(provider, byte) { + return; + } + + match byte { + 0x1B => unreachable!(), + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // Print + 0x20..=0x7F => provider.provide_char(byte as char), + + _ => {} + }; + } + + fn advance_escape_state(&mut self, provider: &mut dyn Provide, byte: u8) { + match byte { + 0x1B => unreachable!(), + + // Intermediate bytes to collect + 0x20..=0x2F => { + self.set_state(State::EscapeIntermediate); + } + + // Escape followed by '[' (0x5B) + // -> CSI sequence start + 0x5B => self.set_state(State::CsiEntry), + + // Escape sequence final character + 0x30..=0x4F | 0x51..=0x57 | 0x59 | 0x5A | 0x5C | 0x60..=0x7E => { + provider.provide_esc_sequence(byte as char); + self.set_state(State::Ground); + } + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // TODO Does it mean we should ignore the whole sequence? + // Ignore + 0x7F => {} + + // Other bytes are considered as invalid -> cancel whatever we have + _ => self.set_state(State::Ground), + }; + } + + fn advance_escape_intermediate_state(&mut self, provider: &mut dyn Provide, byte: u8) { + match byte { + 0x1B => unreachable!(), + + // Intermediate bytes to collect + 0x20..=0x2F => {} + + // Escape followed by '[' (0x5B) + // -> CSI sequence start + 0x5B => self.set_state(State::CsiEntry), + + // Escape sequence final character + 0x30..=0x5A | 0x5C..=0x7E => { + provider.provide_esc_sequence(byte as char); + self.set_state(State::Ground); + } + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // TODO Does it mean we should ignore the whole sequence? + // Ignore + 0x7F => {} + + // Other bytes are considered as invalid -> cancel whatever we have + _ => self.set_state(State::Ground), + }; + } + + fn advance_csi_entry_state(&mut self, provider: &mut dyn Provide, byte: u8) { + match byte { + 0x1B => unreachable!(), + + // Semicolon = parameter delimiter + 0x3B => { + self.store_parameter(); + self.set_state(State::CsiParameter); + } + + // '0' ..= '9' = parameter value + 0x30..=0x39 => { + self.parameter = (byte as u64) - 0x30; + self.set_state(State::CsiParameter); + } + + 0x3A => self.set_state(State::CsiIgnore), + + // CSI sequence final character + // -> dispatch CSI sequence + 0x40..=0x7E => { + provider.provide_csi_sequence( + &self.parameters[..self.parameters_count], + self.ignored_parameters_count, + byte as char, + ); + + self.set_state(State::Ground); + } + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // TODO Does it mean we should ignore the whole sequence? + // Ignore + 0x7F => {} + + // Collect rest as parameters + _ => { + self.parameter = byte as u64; + self.store_parameter(); + } + }; + } + + fn advance_csi_ignore_state(&mut self, provider: &mut dyn Provide, byte: u8) { + match byte { + 0x1B => unreachable!(), + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // TODO Does it mean we should ignore the whole sequence? + // Ignore + 0x20..=0x3F | 0x7F => {} + + 0x40..=0x7E => self.set_state(State::Ground), + + // Other bytes are considered as invalid -> cancel whatever we have + _ => self.set_state(State::Ground), + }; + } + + fn advance_csi_parameter_state(&mut self, provider: &mut dyn Provide, byte: u8) { + match byte { + 0x1B => unreachable!(), + + // '0' ..= '9' = parameter value + 0x30..=0x39 => { + self.parameter = self.parameter.saturating_mul(10); + self.parameter = self.parameter.saturating_add((byte as u64) - 0x30); + } + + // Semicolon = parameter delimiter + 0x3B => self.store_parameter(), + + // CSI sequence final character + // -> dispatch CSI sequence + 0x40..=0x7E => { + self.store_parameter(); + provider.provide_csi_sequence( + &self.parameters[..self.parameters_count], + self.ignored_parameters_count, + byte as char, + ); + + self.set_state(State::Ground); + } + + // Intermediates to collect + 0x20..=0x2F => { + self.store_parameter(); + self.set_state(State::CsiIntermediate); + } + + // Ignore + 0x3A | 0x3C..=0x3F => self.set_state(State::CsiIgnore), + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // TODO Does it mean we should ignore the whole sequence? + // Ignore + 0x7F => {} + + // Other bytes are considered as invalid -> cancel whatever we have + _ => self.set_state(State::Ground), + }; + } + + fn advance_csi_intermediate_state(&mut self, provider: &mut dyn Provide, byte: u8) { + match byte { + 0x1B => unreachable!(), + + // Intermediates to collect + 0x20..=0x2F => {} + + // CSI sequence final character + // -> dispatch CSI sequence + 0x40..=0x7E => { + provider.provide_csi_sequence( + &self.parameters[..self.parameters_count], + self.ignored_parameters_count, + byte as char, + ); + + self.set_state(State::Ground); + } + + // Execute + 0x00..=0x17 | 0x19 | 0x1C..=0x1F => provider.provide_char(byte as char), + + // TODO Does it mean we should ignore the whole sequence? + // Ignore + 0x7F => {} + + // Other bytes are considered as invalid -> cancel whatever we have + _ => self.set_state(State::Ground), + } + } + + fn advance_utf8_state(&mut self, provider: &mut dyn Provide, byte: u8) { + if byte & 0b1100_0000 != 0b1000_0000 { + self.set_state(State::Ground); + return; + } + + self.utf8_points[self.utf8_points_count] = byte; + self.utf8_points_count += 1; + + if self.utf8_points_count == self.utf8_points_expected_count { + if let Some(ch) = std::str::from_utf8(&self.utf8_points[..self.utf8_points_count]) + .ok() + .and_then(|s| s.chars().next()) + { + provider.provide_char(ch); + } + self.set_state(State::Ground); + } + } + + pub(crate) fn advance(&mut self, provider: &mut dyn Provide, byte: u8, more: bool) { + // eprintln!("advance: {:?} {} {}", self.state, byte, more); + + if self.handle_possible_esc(provider, byte, more) { + return; + } + + match self.state { + State::Ground => self.advance_ground_state(provider, byte), + State::Escape => self.advance_escape_state(provider, byte), + State::EscapeIntermediate => self.advance_escape_intermediate_state(provider, byte), + State::CsiEntry => self.advance_csi_entry_state(provider, byte), + State::CsiIgnore => self.advance_csi_ignore_state(provider, byte), + State::CsiParameter => self.advance_csi_parameter_state(provider, byte), + State::CsiIntermediate => self.advance_csi_intermediate_state(provider, byte), + State::Utf8 => self.advance_utf8_state(provider, byte), + }; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn esc_char() { + let mut engine = Engine::default(); + let mut provider = CharProvider::default(); + + // No more input means that the Esc character should be dispatched immediately + engine.advance(&mut provider, 0x1B, false); + assert_eq!(provider.chars, &['\x1B']); + + // There's more input so the machine should wait before dispatching Esc character + engine.advance(&mut provider, 0x1B, true); + assert_eq!(provider.chars, &['\x1B']); + + // Another Esc character, but no more input, machine should dispatch the postponed Esc + // character and the new one too. + engine.advance(&mut provider, 0x1B, false); + assert_eq!(provider.chars, &['\x1B', '\x1B', '\x1B']); + } + + #[test] + fn esc_without_intermediates() { + let mut engine = Engine::default(); + let mut provider = EscProvider::default(); + + let input = b"\x1B0\x1B~"; + advance(&mut engine, &mut provider, input, false); + + assert_eq!(provider.chars.len(), 2); + + assert_eq!(provider.chars[0], '0'); + + assert_eq!(provider.chars[1], '~'); + } + + #[test] + fn csi_without_parameters() { + let mut engine = Engine::default(); + let mut provider = CsiProvider::default(); + + let input = b"\x1B\x5Bm"; + advance(&mut engine, &mut provider, input, false); + + assert_eq!(provider.parameters.len(), 1); + assert_eq!(provider.parameters[0], &[]); + assert_eq!(provider.chars.len(), 1); + assert_eq!(provider.chars[0], 'm'); + } + + #[test] + fn csi_with_two_default_parameters() { + let mut engine = Engine::default(); + let mut provider = CsiProvider::default(); + + let input = b"\x1B\x5B;m"; + advance(&mut engine, &mut provider, input, false); + + assert_eq!(provider.parameters.len(), 1); + assert_eq!( + provider.parameters[0], + &[DEFAULT_PARAMETER_VALUE, DEFAULT_PARAMETER_VALUE] + ); + assert_eq!(provider.chars.len(), 1); + assert_eq!(provider.chars[0], 'm'); + } + + #[test] + fn csi_with_trailing_semicolon() { + let mut engine = Engine::default(); + let mut provider = CsiProvider::default(); + + let input = b"\x1B\x5B123;m"; + advance(&mut engine, &mut provider, input, false); + + assert_eq!(provider.parameters.len(), 1); + assert_eq!(provider.parameters[0], &[123, DEFAULT_PARAMETER_VALUE]); + assert_eq!(provider.chars.len(), 1); + assert_eq!(provider.chars[0], 'm'); + } + + #[test] + fn csi_max_parameters() { + let mut engine = Engine::default(); + let mut provider = CsiProvider::default(); + + let input = b"\x1B\x5B1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18;19;20;21;22;23;24;25;26;27;28;29;30m"; + advance(&mut engine, &mut provider, input, false); + + assert_eq!(provider.parameters.len(), 1); + assert_eq!(provider.parameters[0].len(), MAX_PARAMETERS); + assert_eq!( + provider.parameters[0], + &[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30 + ] + ); + assert_eq!(provider.chars.len(), 1); + assert_eq!(provider.chars[0], 'm'); + } + + #[test] + fn test_parse_utf8_character() { + let mut engine = Engine::default(); + let mut provider = CharProvider::default(); + + advance(&mut engine, &mut provider, &['a' as u8], false); + assert_eq!(provider.chars.len(), 1); + assert_eq!(provider.chars[0], 'a'); + + advance(&mut engine, &mut provider, &[0xC3, 0xB1], false); + assert_eq!(provider.chars.len(), 2); + assert_eq!(provider.chars[1], 'ñ'); + + advance(&mut engine, &mut provider, &[0xE2, 0x81, 0xA1], false); + assert_eq!(provider.chars.len(), 3); + assert_eq!(provider.chars[2], '\u{2061}'); + + advance(&mut engine, &mut provider, &[0xF0, 0x90, 0x8C, 0xBC], false); + assert_eq!(provider.chars.len(), 4); + assert_eq!(provider.chars[3], '𐌼'); + } + + fn advance(engine: &mut Engine, provider: &mut dyn Provide, bytes: &[u8], more: bool) { + let len = bytes.len(); + + for (i, byte) in bytes.iter().enumerate() { + engine.advance(provider, *byte, i < len - 1 || more); + } + } + + #[derive(Default)] + struct CharProvider { + chars: Vec<char>, + } + + impl Provide for CharProvider { + fn provide_char(&mut self, ch: char) { + self.chars.push(ch); + } + + fn provide_esc_sequence(&mut self, _ch: char) {} + + fn provide_csi_sequence(&mut self, _parameters: &[u64], _ignored_count: usize, _ch: char) {} + } + + #[derive(Default)] + struct CsiProvider { + parameters: Vec<Vec<u64>>, + chars: Vec<char>, + } + + impl Provide for CsiProvider { + fn provide_char(&mut self, _ch: char) {} + + fn provide_esc_sequence(&mut self, _ch: char) {} + + fn provide_csi_sequence(&mut self, parameters: &[u64], _ignored_count: usize, ch: char) { + self.parameters.push(parameters.to_vec()); + self.chars.push(ch); + } + } + + #[derive(Default)] + struct EscProvider { + chars: Vec<char>, + } + + impl Provide for EscProvider { + fn provide_char(&mut self, _ch: char) {} + + fn provide_esc_sequence(&mut self, ch: char) { + self.chars.push(ch); + } + + fn provide_csi_sequence(&mut self, _parameters: &[u64], _ignored_count: usize, _ch: char) {} + } +} diff --git a/vendor/anes/src/parser/parsers.rs b/vendor/anes/src/parser/parsers.rs new file mode 100644 index 000000000..9bb9acb4f --- /dev/null +++ b/vendor/anes/src/parser/parsers.rs @@ -0,0 +1,239 @@ +use super::types::{KeyCode, KeyModifiers, Mouse, MouseButton, Sequence}; + +pub(crate) fn parse_char(ch: char, esc_o: bool) -> Option<Sequence> { + if esc_o { + return match ch { + 'P'..='S' => Some(Sequence::Key( + KeyCode::F(ch as u8 - b'P' + 1), + KeyModifiers::empty(), + )), + _ => None, + }; + } + + let code = match ch { + '\r' | '\n' => KeyCode::Enter, + '\t' => KeyCode::Tab, + '\x7F' => KeyCode::BackTab, + '\x1B' => KeyCode::Esc, + '\0' => KeyCode::Null, + _ => KeyCode::Char(ch), + }; + Some(Sequence::Key(code, KeyModifiers::empty())) +} + +pub(crate) fn parse_esc_sequence(ch: char) -> Option<Sequence> { + // EscO[P-S] is handled in the Performer, see parse_char & esc_o argument + // No need to handle other cases here? It's just Alt+$char + Some(Sequence::Key(KeyCode::Char(ch), KeyModifiers::ALT)) +} + +pub(crate) fn parse_csi_sequence( + parameters: &[u64], + _ignored_count: usize, + ch: char, +) -> Option<Sequence> { + match ch { + 'A' => Some(Sequence::Key( + KeyCode::Up, + parse_csi_arrow_key_modifiers(parameters.first().cloned()), + )), + 'B' => Some(Sequence::Key( + KeyCode::Down, + parse_csi_arrow_key_modifiers(parameters.first().cloned()), + )), + 'C' => Some(Sequence::Key( + KeyCode::Right, + parse_csi_arrow_key_modifiers(parameters.first().cloned()), + )), + 'D' => Some(Sequence::Key( + KeyCode::Left, + parse_csi_arrow_key_modifiers(parameters.first().cloned()), + )), + 'H' => Some(Sequence::Key(KeyCode::Home, KeyModifiers::empty())), + 'F' => Some(Sequence::Key(KeyCode::End, KeyModifiers::empty())), + 'Z' => Some(Sequence::Key(KeyCode::BackTab, KeyModifiers::empty())), + 'R' => parse_csi_cursor_position(parameters), + 'm' => parse_csi_xterm_mouse(parameters, ch), + 'M' if parameters.first() == Some(&0x3C) => parse_csi_xterm_mouse(parameters, ch), + 'M' => parse_csi_rxvt_mouse(parameters), + '~' => parse_csi_tilde_key_code(parameters), + _ => None, + } +} + +fn parse_csi_arrow_key_modifiers(parameter: Option<u64>) -> KeyModifiers { + parse_key_modifiers(parameter.map(|x| x.saturating_sub(48))) +} + +fn parse_key_modifiers(parameter: Option<u64>) -> KeyModifiers { + if let Some(parameter) = parameter { + match parameter { + 2 => KeyModifiers::SHIFT, + 3 => KeyModifiers::ALT, + 4 => KeyModifiers::SHIFT | KeyModifiers::ALT, + 5 => KeyModifiers::CONTROL, + 6 => KeyModifiers::SHIFT | KeyModifiers::CONTROL, + 7 => KeyModifiers::ALT | KeyModifiers::CONTROL, + 8 => KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL, + 9 => KeyModifiers::META, + 10 => KeyModifiers::META | KeyModifiers::SHIFT, + 11 => KeyModifiers::META | KeyModifiers::ALT, + 12 => KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::ALT, + 13 => KeyModifiers::META | KeyModifiers::CONTROL, + 14 => KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::CONTROL, + 15 => KeyModifiers::META | KeyModifiers::ALT | KeyModifiers::CONTROL, + 16 => { + KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL + } + _ => KeyModifiers::empty(), + } + } else { + KeyModifiers::empty() + } +} + +fn parse_csi_tilde_key_code(parameters: &[u64]) -> Option<Sequence> { + if parameters.is_empty() { + return None; + } + + let modifiers = parse_key_modifiers(parameters.get(1).cloned()); + + let code = match parameters[0] { + 1 | 7 => KeyCode::Home, + 2 => KeyCode::Insert, + 3 => KeyCode::Delete, + 4 | 8 => KeyCode::End, + 5 => KeyCode::PageUp, + 6 => KeyCode::PageDown, + p @ 11..=15 => KeyCode::F(p as u8 - 10), + p @ 17..=21 => KeyCode::F(p as u8 - 11), + p @ 23..=24 => KeyCode::F(p as u8 - 12), + _ => return None, + }; + + Some(Sequence::Key(code, modifiers)) +} + +fn parse_csi_cursor_position(parameters: &[u64]) -> Option<Sequence> { + // ESC [ Cy ; Cx R + + if parameters.len() < 2 { + return None; + } + + let y = parameters[0] as u16; + let x = parameters[1] as u16; + + Some(Sequence::CursorPosition(x, y)) +} + +fn parse_csi_xterm_mouse(parameters: &[u64], ch: char) -> Option<Sequence> { + // ESC [ < Cb ; Cx ; Cy (;) (M or m) + + if parameters.len() < 4 { + return None; + } + + let cb = parameters[1] as u8; + let cx = parameters[2] as u16; + let cy = parameters[3] as u16; + + let up = match ch { + 'm' => true, + 'M' => false, + _ => return None, + }; + + let mut modifiers = KeyModifiers::empty(); + + if cb & 0b0000_0100 == 0b0000_0100 { + modifiers |= KeyModifiers::SHIFT; + } + + if cb & 0b0000_1000 == 0b0000_1000 { + modifiers |= KeyModifiers::ALT; + } + + if cb & 0b0001_0000 == 0b0001_0000 { + modifiers |= KeyModifiers::CONTROL; + } + + let mouse = if cb & 0b0100_0000 == 0b0100_0000 { + if cb & 0b0000_0001 == 0b0000_0001 { + Mouse::ScrollDown(cx, cy) + } else { + Mouse::ScrollUp(cx, cy) + } + } else { + let drag = cb & 0b0010_0000 == 0b0010_0000; + + match (cb & 0b0000_0011, up, drag) { + (0, true, _) => Mouse::Up(MouseButton::Left, cx, cy), + (0, false, false) => Mouse::Down(MouseButton::Left, cx, cy), + (0, false, true) => Mouse::Drag(MouseButton::Left, cx, cy), + (1, true, _) => Mouse::Up(MouseButton::Middle, cx, cy), + (1, false, false) => Mouse::Down(MouseButton::Middle, cx, cy), + (1, false, true) => Mouse::Drag(MouseButton::Middle, cx, cy), + (2, true, _) => Mouse::Up(MouseButton::Right, cx, cy), + (2, false, false) => Mouse::Down(MouseButton::Right, cx, cy), + (2, false, true) => Mouse::Drag(MouseButton::Right, cx, cy), + _ => return None, + } + }; + + Some(Sequence::Mouse(mouse, modifiers)) +} + +fn parse_csi_rxvt_mouse(parameters: &[u64]) -> Option<Sequence> { + // ESC [ Cb ; Cx ; Cy ; M + + if parameters.len() < 3 { + return None; + } + + let cb = parameters[0]; + let cx = parameters[1] as u16; + let cy = parameters[2] as u16; + + let mut modifiers = KeyModifiers::empty(); + + if cb & 0b0000_0100 == 0b0000_0100 { + modifiers |= KeyModifiers::SHIFT; + } + + if cb & 0b0000_1000 == 0b0000_1000 { + modifiers |= KeyModifiers::ALT; + } + + if cb & 0b0001_0000 == 0b0001_0000 { + modifiers |= KeyModifiers::CONTROL; + } + + let mouse = if cb & 0b0110_0000 == 0b0110_0000 { + if cb & 0b0000_0001 == 0b0000_0001 { + Mouse::ScrollDown(cx, cy) + } else { + Mouse::ScrollUp(cx, cy) + } + } else { + let drag = cb & 0b0100_0000 == 0b0100_0000; + + match (cb & 0b0000_0011, drag) { + (0b0000_0000, false) => Mouse::Down(MouseButton::Left, cx, cy), + (0b0000_0010, false) => Mouse::Down(MouseButton::Right, cx, cy), + (0b0000_0001, false) => Mouse::Down(MouseButton::Middle, cx, cy), + + (0b0000_0000, true) => Mouse::Drag(MouseButton::Left, cx, cy), + (0b0000_0010, true) => Mouse::Drag(MouseButton::Right, cx, cy), + (0b0000_0001, true) => Mouse::Drag(MouseButton::Middle, cx, cy), + + (0b0000_0011, false) => Mouse::Up(MouseButton::Any, cx, cy), + + _ => return None, + } + }; + + Some(Sequence::Mouse(mouse, modifiers)) +} diff --git a/vendor/anes/src/parser/types.rs b/vendor/anes/src/parser/types.rs new file mode 100644 index 000000000..66b6561fd --- /dev/null +++ b/vendor/anes/src/parser/types.rs @@ -0,0 +1,79 @@ +use bitflags::bitflags; + +/// A parsed ANSI escape sequence. +/// +/// Check the [`Parser`](struct.Parser.html) structure documentation for examples +/// how to retrieve these values. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum Sequence { + /// A keyboard event sequence. + Key(KeyCode, KeyModifiers), + /// A mouse event sequence. + Mouse(Mouse, KeyModifiers), + /// A cursor position (`x`, `y`). + /// + /// Top/left cell is represented as `Sequence::CursorPosition(1, 1)`. + CursorPosition(u16, u16), +} + +bitflags! { + /// A key modifiers. + pub struct KeyModifiers: u8 { + const SHIFT = 0b0000_0001; + const CONTROL = 0b0000_0010; + const ALT = 0b0000_0100; + const META = 0b0000_1000; + } +} + +/// A key code. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum KeyCode { + Backspace, + Enter, + Left, + Right, + Up, + Down, + Home, + End, + PageUp, + PageDown, + Tab, + BackTab, + Delete, + Insert, + F(u8), + Char(char), + Null, + Esc, +} + +/// A mouse event. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum Mouse { + /// A mouse button press. + Down(MouseButton, u16, u16), + /// A mouse button release. + Up(MouseButton, u16, u16), + /// A mouse movement with pressed button. + Drag(MouseButton, u16, u16), + /// A mouse wheel scrolled up. + ScrollUp(u16, u16), + /// A mouse wheel scrolled down. + ScrollDown(u16, u16), +} + +/// A mouse button. +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub enum MouseButton { + Left, + Right, + Middle, + /// This variant is provided only if [`Parser`](struct.Parser.html) doesn't know which + /// mouse button was pressed/released. + /// + /// An example is [rxvt](https://en.wikipedia.org/wiki/Rxvt) - it provides which mouse + /// button was pressed, but doesn't provide which mouse button was released. + Any, +} diff --git a/vendor/anes/src/sequences.rs b/vendor/anes/src/sequences.rs new file mode 100644 index 000000000..c66080045 --- /dev/null +++ b/vendor/anes/src/sequences.rs @@ -0,0 +1,5 @@ +pub(crate) mod attribute; +pub(crate) mod buffer; +pub(crate) mod color; +pub(crate) mod cursor; +pub(crate) mod terminal; diff --git a/vendor/anes/src/sequences/attribute.rs b/vendor/anes/src/sequences/attribute.rs new file mode 100644 index 000000000..30961ff4b --- /dev/null +++ b/vendor/anes/src/sequences/attribute.rs @@ -0,0 +1,133 @@ +use std::fmt; + +sequence!( + /// Resets all attributes. + /// + /// This sequence resets all attributes previously set by the: + /// + /// * [`SetAttribute`](struct.SetAttribute.html) + /// * [`SetForegroundColor`](struct.SetBackgroundColor.html) + /// * [`SetBackgroundColor`](struct.SetForegroundColor.html) + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ResetAttributes; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}", ResetAttributes); + /// ``` + struct ResetAttributes => sgr!("0") +); + +/// A display attribute. +/// +/// This is **NOT** a full ANSI sequence. `Attribute` must be used along with +/// the [`SetAttribute`](struct.SetAttribute.html). +/// +/// # Examples +/// +/// ```no_run +/// use std::io::{stdout, Write}; +/// use anes::{Attribute, SetAttribute}; +/// +/// let mut stdout = stdout(); +/// write!(stdout, "{}Bold text", SetAttribute(Attribute::Bold)); +/// ``` +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum Attribute { + /// Bold (increased) intensity. + Bold = 1, + /// Faint (decreased) intensity. + Faint = 2, + /// Normal intensity (turns off `Bold` and/or `Faint`). + Normal = 22, + + /// Italic. + Italic = 3, + /// Turns off `Italic`. + ItalicOff = 23, + + /// Underlined text. + Underline = 4, + /// Turns off `Underline`. + UnderlineOff = 24, + + /// Blinking text. + Blink = 5, + /// Turns off blinking text (`Blink`). + BlinkOff = 25, + + /// Reverse foreground & background colors. + Reverse = 7, + /// Turns off `Reverse`. + ReverseOff = 27, + + /// Concealed (hidden). + Conceal = 8, + /// Turns off `Conceal`. + ConcealOff = 28, + + /// Crossed. + Crossed = 9, + /// Turns off `Crossed`. + CrossedOff = 29, +} + +impl fmt::Display for Attribute { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", *self as i32) + } +} + +sequence!( + /// Sets the display attribute. + /// + /// See the [`Attribute`](enum.Attribute.html) enum for a list of attributes you can (un)set. + /// + /// The [`ResetAttributes`](struct.ResetAttributes.html) sequence can be used to turn off all + /// attributes. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{Attribute, SetAttribute}; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}Blinking text", SetAttribute(Attribute::Blink)); + /// ``` + struct SetAttribute(Attribute) => + |this, f| write!(f, sgr!("{}"), this.0) +); + +#[cfg(test)] +test_sequences!( + set_attribute( + SetAttribute(Attribute::Bold) => "\x1B[1m", + SetAttribute(Attribute::Faint) => "\x1B[2m", + SetAttribute(Attribute::Normal) => "\x1B[22m", + + SetAttribute(Attribute::Italic) => "\x1B[3m", + SetAttribute(Attribute::ItalicOff) => "\x1B[23m", + + SetAttribute(Attribute::Underline) => "\x1B[4m", + SetAttribute(Attribute::UnderlineOff) => "\x1B[24m", + + SetAttribute(Attribute::Blink) => "\x1B[5m", + SetAttribute(Attribute::BlinkOff) => "\x1B[25m", + + SetAttribute(Attribute::Reverse) => "\x1B[7m", + SetAttribute(Attribute::ReverseOff) => "\x1B[27m", + + SetAttribute(Attribute::Conceal) => "\x1B[8m", + SetAttribute(Attribute::ConcealOff) => "\x1B[28m", + + SetAttribute(Attribute::Crossed) => "\x1B[9m", + SetAttribute(Attribute::CrossedOff) => "\x1B[29m", + ), + reset_attributes( + ResetAttributes => "\x1B[0m", + ) +); diff --git a/vendor/anes/src/sequences/buffer.rs b/vendor/anes/src/sequences/buffer.rs new file mode 100644 index 000000000..053195af6 --- /dev/null +++ b/vendor/anes/src/sequences/buffer.rs @@ -0,0 +1,145 @@ +sequence!( + /// Switches to the alternate buffer. + /// + /// Use the [`SwitchBufferToNormal`](struct.SwitchBufferToNormal.html) sequence to switch + /// back to the normal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{SwitchBufferToAlternate, SwitchBufferToNormal}; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}", SwitchBufferToAlternate); + /// // Your app on alternate screen + /// write!(stdout, "{}", SwitchBufferToNormal); + /// ``` + struct SwitchBufferToAlternate => csi!("?1049h") +); + +sequence!( + /// Switches to the normal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{SwitchBufferToAlternate, SwitchBufferToNormal}; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}", SwitchBufferToAlternate); + /// // Your app on alternate screen + /// write!(stdout, "{}", SwitchBufferToNormal); + /// ``` + struct SwitchBufferToNormal => csi!("?1049l") +); + +sequence!( + /// Scrolls up by the given number of rows. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ScrollBufferUp; + /// + /// let mut stdout = stdout(); + /// // Scroll up by 5 lines + /// write!(stdout, "{}", ScrollBufferUp(5)); + /// ``` + struct ScrollBufferUp(u16) => + |this, f| write!(f, csi!("{}S"), this.0) +); + +sequence!( + /// Scrolls down by the given number of rows. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ScrollBufferDown; + /// + /// let mut stdout = stdout(); + /// // Scroll down by 10 lines + /// write!(stdout, "{}", ScrollBufferDown(10)); + /// ``` + struct ScrollBufferDown(u16) => + |this, f| write!(f, csi!("{}T"), this.0) +); + +sequence!( + /// Clears part of the line. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ClearLine; + /// + /// let mut stdout = stdout(); + /// // Clear the whole line + /// write!(stdout, "{}", ClearLine::All); + /// ``` + enum ClearLine { + /// Clears from the cursor position to end of the line. + Right => csi!("K"), + /// Clears from the cursor position to beginning of the line. + Left => csi!("1K"), + /// Clears the whole line. + All => csi!("2K"), + } +); + +sequence!( + /// Clears part of the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ClearBuffer; + /// + /// let mut stdout = stdout(); + /// // Clear the entire buffer + /// write!(stdout, "{}", ClearBuffer::All); + /// ``` + enum ClearBuffer { + /// Clears from the cursor position to end of the screen. + Below => csi!("J"), + /// Clears from the cursor position to beginning of the screen. + Above => csi!("1J"), + /// Clears the entire buffer. + All => csi!("2J"), + /// Clears the entire buffer and all saved lines in the scrollback buffer. + SavedLines => csi!("3J"), + } +); + +#[cfg(test)] +test_sequences!( + switch_buffer_to_alternate( + SwitchBufferToAlternate => "\x1B[?1049h", + ), + switch_buffer_to_main( + SwitchBufferToNormal => "\x1B[?1049l", + ), + scroll_buffer_up( + ScrollBufferUp(10) => "\x1B[10S", + ), + scroll_buffer_down( + ScrollBufferDown(10) => "\x1B[10T", + ), + clear_line( + ClearLine::Right => "\x1B[K", + ClearLine::Left => "\x1B[1K", + ClearLine::All => "\x1B[2K", + ), + clear_buffer( + ClearBuffer::Below => "\x1B[J", + ClearBuffer::Above => "\x1B[1J", + ClearBuffer::All => "\x1B[2J", + ClearBuffer::SavedLines => "\x1B[3J", + ), +); diff --git a/vendor/anes/src/sequences/color.rs b/vendor/anes/src/sequences/color.rs new file mode 100644 index 000000000..b019f0fdd --- /dev/null +++ b/vendor/anes/src/sequences/color.rs @@ -0,0 +1,189 @@ +use std::fmt; + +/// A color. +/// +/// This is **NOT** a full ANSI sequence. `Color` must be used along with +/// the: +/// +/// * [`SetBackgroundColor`](struct.SetBackgroundColor.html) +/// * [`SetForegroundColor`](struct.SetForegroundColor.html) +/// +/// # Examples +/// +/// ```no_run +/// use std::io::{stdout, Write}; +/// use anes::{Color, SetForegroundColor}; +/// +/// let mut stdout = stdout(); +/// // Set the foreground color to red +/// write!(stdout, "{}", SetForegroundColor(Color::Red)); +/// ``` +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum Color { + /// Default color. + Default, + /// Black color. + Black, + /// Dark red color. + DarkRed, + /// Dark green color. + DarkGreen, + /// Dark yellow color. + DarkYellow, + /// Dark blue color. + DarkBlue, + /// Dark magenta color. + DarkMagenta, + /// Dark cyan color. + DarkCyan, + /// Dark gray color. + /// + /// Also knows as light (bright) black. + DarkGray, + /// Light (bright) gray color. + /// + /// Also known as dark white. + Gray, + /// Light (bright) red color. + Red, + /// Light (bright) green color. + Green, + /// Light (bright) yellow color. + Yellow, + /// Light (bright) blue color. + Blue, + /// Light (bright) magenta color. + Magenta, + /// Light (bright) cyan color. + Cyan, + /// White color. + White, + /// A color from the predefined set of ANSI colors. + /// + /// ```text + /// 0 - 7: standard colors (as in ESC [ 30–37 m) + /// 8- 15: high intensity colors (as in ESC [ 90–97 m) + /// 16-231: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5) + /// 232-255: grayscale from black to white in 24 steps + /// ``` + /// + /// See [8-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) for more information. + Ansi(u8), + /// An RGB color. + /// + /// See [24-bit](https://en.wikipedia.org/wiki/ANSI_escape_code#24-bit) for more information. + Rgb(u8, u8, u8), +} + +impl fmt::Display for Color { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + // Color::Default is handled in the SetBackgroundColor & SetForegroundColor + Color::Default => Ok(()), + Color::Black => write!(f, "5;0"), + Color::DarkRed => write!(f, "5;1"), + Color::DarkGreen => write!(f, "5;2"), + Color::DarkYellow => write!(f, "5;3"), + Color::DarkBlue => write!(f, "5;4"), + Color::DarkMagenta => write!(f, "5;5"), + Color::DarkCyan => write!(f, "5;6"), + Color::Gray => write!(f, "5;7"), + Color::DarkGray => write!(f, "5;8"), + Color::Red => write!(f, "5;9"), + Color::Green => write!(f, "5;10"), + Color::Yellow => write!(f, "5;11"), + Color::Blue => write!(f, "5;12"), + Color::Magenta => write!(f, "5;13"), + Color::Cyan => write!(f, "5;14"), + Color::White => write!(f, "5;15"), + Color::Ansi(value) => write!(f, "5;{}", value), + Color::Rgb(r, g, b) => write!(f, "2;{};{};{}", r, g, b), + } + } +} + +sequence! { + /// Sets the foreground color. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{Color, SetForegroundColor}; + /// + /// let mut stdout = stdout(); + /// // Set the foreground color to blue + /// write!(stdout, "{}", SetForegroundColor(Color::Blue)); + /// ``` + struct SetForegroundColor(Color) => + |this, f| match this.0 { + Color::Default => write!(f, sgr!("39")), + _ => write!(f, sgr!("38;{}"), this.0), + } +} + +sequence! { + /// Sets the background color. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{Color, SetBackgroundColor}; + /// + /// let mut stdout = stdout(); + /// // Set the background color to yellow + /// write!(stdout, "{}", SetBackgroundColor(Color::Yellow)); + /// ``` + struct SetBackgroundColor(Color) => + |this, f| match this.0 { + Color::Default => write!(f, sgr!("49")), + _ => write!(f, sgr!("48;{}"), this.0), + } +} + +#[cfg(test)] +test_sequences!( + set_foreground_color( + SetForegroundColor(Color::Default) => "\x1B[39m", + SetForegroundColor(Color::Black) => "\x1B[38;5;0m", + SetForegroundColor(Color::DarkRed) => "\x1B[38;5;1m", + SetForegroundColor(Color::DarkGreen) => "\x1B[38;5;2m", + SetForegroundColor(Color::DarkYellow) => "\x1B[38;5;3m", + SetForegroundColor(Color::DarkBlue) => "\x1B[38;5;4m", + SetForegroundColor(Color::DarkMagenta) => "\x1B[38;5;5m", + SetForegroundColor(Color::DarkCyan) => "\x1B[38;5;6m", + SetForegroundColor(Color::DarkGray) => "\x1B[38;5;8m", + SetForegroundColor(Color::Gray) => "\x1B[38;5;7m", + SetForegroundColor(Color::Red) => "\x1B[38;5;9m", + SetForegroundColor(Color::Green) => "\x1B[38;5;10m", + SetForegroundColor(Color::Yellow) => "\x1B[38;5;11m", + SetForegroundColor(Color::Blue) => "\x1B[38;5;12m", + SetForegroundColor(Color::Magenta) => "\x1B[38;5;13m", + SetForegroundColor(Color::Cyan) => "\x1B[38;5;14m", + SetForegroundColor(Color::White) => "\x1B[38;5;15m", + SetForegroundColor(Color::Ansi(200)) => "\x1B[38;5;200m", + SetForegroundColor(Color::Rgb(1, 2, 3)) => "\x1B[38;2;1;2;3m", + ), + set_background_color( + SetBackgroundColor(Color::Default) => "\x1B[49m", + SetBackgroundColor(Color::Black) => "\x1B[48;5;0m", + SetBackgroundColor(Color::DarkRed) => "\x1B[48;5;1m", + SetBackgroundColor(Color::DarkGreen) => "\x1B[48;5;2m", + SetBackgroundColor(Color::DarkYellow) => "\x1B[48;5;3m", + SetBackgroundColor(Color::DarkBlue) => "\x1B[48;5;4m", + SetBackgroundColor(Color::DarkMagenta) => "\x1B[48;5;5m", + SetBackgroundColor(Color::DarkCyan) => "\x1B[48;5;6m", + SetBackgroundColor(Color::DarkGray) => "\x1B[48;5;8m", + SetBackgroundColor(Color::Gray) => "\x1B[48;5;7m", + SetBackgroundColor(Color::Red) => "\x1B[48;5;9m", + SetBackgroundColor(Color::Green) => "\x1B[48;5;10m", + SetBackgroundColor(Color::Yellow) => "\x1B[48;5;11m", + SetBackgroundColor(Color::Blue) => "\x1B[48;5;12m", + SetBackgroundColor(Color::Magenta) => "\x1B[48;5;13m", + SetBackgroundColor(Color::Cyan) => "\x1B[48;5;14m", + SetBackgroundColor(Color::White) => "\x1B[48;5;15m", + SetBackgroundColor(Color::Ansi(200)) => "\x1B[48;5;200m", + SetBackgroundColor(Color::Rgb(1, 2, 3)) => "\x1B[48;2;1;2;3m", + ) +); diff --git a/vendor/anes/src/sequences/cursor.rs b/vendor/anes/src/sequences/cursor.rs new file mode 100644 index 000000000..37abc3b19 --- /dev/null +++ b/vendor/anes/src/sequences/cursor.rs @@ -0,0 +1,352 @@ +//! A terminal cursor related ANSI escape sequences. + +sequence!( + /// Saves the cursor position. + /// + /// Use the [`RestoreCursorPosition`](struct.RestoreCursorPosition.html) sequence to + /// restore the cursor position. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{SaveCursorPosition, RestoreCursorPosition}; + /// + /// let mut stdout = stdout(); + /// // Save cursor position + /// write!(stdout, "{}", SaveCursorPosition); + /// + /// // Your app + /// + /// // Restore cursor position + /// write!(stdout, "{}", RestoreCursorPosition); + /// ``` + struct SaveCursorPosition => esc!("7") +); + +sequence!( + /// Restores the cursor position. + /// + /// Use the [`SaveCursorPosition`](struct.SaveCursorPosition.html) sequence to + /// save the cursor position. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{SaveCursorPosition, RestoreCursorPosition}; + /// + /// let mut stdout = stdout(); + /// // Save cursor position + /// write!(stdout, "{}", SaveCursorPosition); + /// + /// // Your app + /// + /// // Restore cursor position + /// write!(stdout, "{}", RestoreCursorPosition); + /// ``` + struct RestoreCursorPosition => esc!("8") +); + +sequence!( + /// Hides the cursor. + /// + /// Use the [`ShowCursor`](struct.ShowCursor.html) sequence to show the cursor. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::HideCursor; + /// + /// let mut stdout = stdout(); + /// // Hide cursor + /// write!(stdout, "{}", HideCursor); + /// ``` + struct HideCursor => csi!("?25l") +); + +sequence!( + /// Shows the cursor. + /// + /// Use the [`HideCursor`](struct.HideCursor.html) sequence to hide the cursor. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ShowCursor; + /// + /// let mut stdout = stdout(); + /// // Show cursor + /// write!(stdout, "{}", ShowCursor); + /// ``` + struct ShowCursor => csi!("?25h") +); + +sequence!( + /// Enables the cursor blinking. + /// + /// Use the [`DisableCursorBlinking`](struct.DisableCursorBlinking.html) sequence to disable + /// cursor blinking. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::EnableCursorBlinking; + /// + /// let mut stdout = stdout(); + /// // Enable cursor blinking + /// write!(stdout, "{}", EnableCursorBlinking); + /// ``` + struct EnableCursorBlinking => csi!("?12h") +); + +sequence!( + /// Disables the cursor blinking. + /// + /// Use the [`EnableCursorBlinking`](struct.EnableCursorBlinking.html) sequence to enable + /// cursor blinking. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::DisableCursorBlinking; + /// + /// let mut stdout = stdout(); + /// // Disable cursor blinking + /// write!(stdout, "{}", DisableCursorBlinking); + /// ``` + struct DisableCursorBlinking => csi!("?12l") +); + +sequence!( + /// Moves the cursor to the given location (column, row). + /// + /// # Notes + /// + /// Top/left cell is represented as `1, 1` (`column, row`). + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorTo; + /// + /// let mut stdout = stdout(); + /// // Move cursor to top left cell + /// write!(stdout, "{}", MoveCursorTo(1, 1)); + /// ``` + struct MoveCursorTo(u16, u16) => + |this, f| write!(f, csi!("{};{}H"), this.1, this.0) +); + +sequence!( + /// Moves the cursor up by the given number of rows. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorUp; + /// + /// let mut stdout = stdout(); + /// // Move cursor up by 5 rows + /// write!(stdout, "{}", MoveCursorUp(5)); + /// ``` + struct MoveCursorUp(u16) => + |this, f| write!(f, csi!("{}A"), this.0) +); + +sequence!( + /// Moves the cursor down by the given number of rows. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorDown; + /// + /// let mut stdout = stdout(); + /// // Move cursor down by 5 rows + /// write!(stdout, "{}", MoveCursorDown(5)); + /// ``` + struct MoveCursorDown(u16) => + |this, f| write!(f, csi!("{}B"), this.0) +); + +sequence!( + /// Moves the cursor right by the given number of columns. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorRight; + /// + /// let mut stdout = stdout(); + /// // Move cursor right by 5 columns + /// write!(stdout, "{}", MoveCursorRight(5)); + /// ``` + struct MoveCursorRight(u16) => + |this, f| write!(f, csi!("{}C"), this.0) +); + +sequence!( + /// Moves the cursor left by the given number of columns. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorLeft; + /// + /// let mut stdout = stdout(); + /// // Move cursor left by 5 columns + /// write!(stdout, "{}", MoveCursorLeft(5)); + /// ``` + struct MoveCursorLeft(u16) => + |this, f| write!(f, csi!("{}D"), this.0) +); + +sequence!( + /// Moves the cursor to beginning of line the given number of lines down. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorToNextLine; + /// + /// let mut stdout = stdout(); + /// // Move cursor down by 2 rows and the move it to the first column + /// write!(stdout, "{}", MoveCursorToNextLine(2)); + /// ``` + /// + /// The previous example does the same thing as the following one: + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{MoveCursorDown, MoveCursorToColumn}; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}{}", MoveCursorDown(2), MoveCursorToColumn(1)); + /// ``` + struct MoveCursorToNextLine(u16) => + |this, f| write!(f, csi!("{}E"), this.0) +); + +sequence!( + /// Moves the cursor to beginning of line the given number of lines up. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorToPreviousLine; + /// + /// let mut stdout = stdout(); + /// // Move cursor up by 2 rows and the move it to the first column + /// write!(stdout, "{}", MoveCursorToPreviousLine(2)); + /// ``` + /// + /// The previous example does the same thing as the following one: + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::{MoveCursorUp, MoveCursorToColumn}; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}{}", MoveCursorUp(2), MoveCursorToColumn(1)); + /// ``` + struct MoveCursorToPreviousLine(u16) => + |this, f| write!(f, csi!("{}F"), this.0) +); + +sequence!( + /// Moves the cursor to the given column. + /// + /// # Notes + /// + /// Beginning of the line (left cell) is represented as `1`. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::MoveCursorToColumn; + /// + /// let mut stdout = stdout(); + /// // Move cursor to the 10th column (same row) + /// write!(stdout, "{}", MoveCursorToColumn(10)); + /// ``` + struct MoveCursorToColumn(u16) => + |this, f| write!(f, csi!("{}G"), this.0) +); + +// TODO Enhance example with Parser to show how to retrieve it +sequence!( + /// Asks for the current cursor position. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ReportCursorPosition; + /// + /// let mut stdout = stdout(); + /// write!(stdout, "{}", ReportCursorPosition); + /// ``` + struct ReportCursorPosition => csi!("6n") +); + +#[cfg(test)] +test_sequences!( + save_cursor_position( + SaveCursorPosition => "\x1B7", + ), + restore_cursor_position( + RestoreCursorPosition => "\x1B8", + ), + hide_cursor( + HideCursor => "\x1B[?25l", + ), + show_cursor( + ShowCursor => "\x1B[?25h", + ), + disable_cursor_blinking( + DisableCursorBlinking => "\x1B[?12l", + ), + enable_cursor_blinking( + EnableCursorBlinking => "\x1B[?12h", + ), + move_cursor_up( + MoveCursorUp(10) => "\x1B[10A", + ), + move_cursor_down( + MoveCursorDown(10) => "\x1B[10B", + ), + move_cursor_right( + MoveCursorRight(10) => "\x1B[10C", + ), + move_cursor_left( + MoveCursorLeft(10) => "\x1B[10D", + ), + move_cursor_to( + MoveCursorTo(5, 10) => "\x1B[10;5H", + ), + move_cursor_to_next_line( + MoveCursorToNextLine(5) => "\x1B[5E", + ), + move_cursor_to_previous_line( + MoveCursorToPreviousLine(5) => "\x1B[5F", + ), + move_cursor_to_column( + MoveCursorToColumn(1) => "\x1B[1G", + ), + report_cursor_position( + ReportCursorPosition => "\x1B[6n", + ) +); diff --git a/vendor/anes/src/sequences/terminal.rs b/vendor/anes/src/sequences/terminal.rs new file mode 100644 index 000000000..74eada65b --- /dev/null +++ b/vendor/anes/src/sequences/terminal.rs @@ -0,0 +1,54 @@ +//! A terminal related ANSI escape sequences. + +sequence!( + /// Resizes the text area to the given width and height in characters. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{stdout, Write}; + /// use anes::ResizeTextArea; + /// + /// let mut stdout = stdout(); + /// // Resize the terminal to 80x25 + /// write!(stdout, "{}", ResizeTextArea(80, 25)); + /// ``` + struct ResizeTextArea(u16, u16) => + |this, f| write!(f, csi!("8;{};{}t"), this.1, this.0) +); + +sequence!( + /// Tells the terminal to start reporting mouse events. + /// + /// Mouse events are not reported by default. + struct EnableMouseEvents => concat!( + csi!("?1000h"), + csi!("?1002h"), + csi!("?1015h"), + csi!("?1006h") + ) +); + +sequence!( + /// Tells the terminal to stop reporting mouse events. + struct DisableMouseEvents => concat!( + csi!("?1006l"), + csi!("?1015l"), + csi!("?1002l"), + csi!("?1000l") + ) +); + +#[cfg(test)] +test_sequences!( + resize_text_area( + ResizeTextArea(80, 25) => "\x1B[8;25;80t", + ResizeTextArea(1, 1) => "\x1B[8;1;1t", + ), + enable_mouse_events( + EnableMouseEvents => "\x1B[?1000h\x1B[?1002h\x1B[?1015h\x1B[?1006h", + ), + disable_mouse_events( + DisableMouseEvents => "\x1B[?1006l\x1B[?1015l\x1B[?1002l\x1B[?1000l", + ) +); diff --git a/vendor/anes/tests/parser/cursor.rs b/vendor/anes/tests/parser/cursor.rs new file mode 100644 index 000000000..250ee48a6 --- /dev/null +++ b/vendor/anes/tests/parser/cursor.rs @@ -0,0 +1,8 @@ +use anes::parser::Sequence; + +use crate::test_sequences; + +#[test] +fn position() { + test_sequences!(b"\x1B[20;10R", Sequence::CursorPosition(10, 20),); +} diff --git a/vendor/anes/tests/parser/key.rs b/vendor/anes/tests/parser/key.rs new file mode 100644 index 000000000..cd87c9dd1 --- /dev/null +++ b/vendor/anes/tests/parser/key.rs @@ -0,0 +1,158 @@ +use anes::parser::{KeyCode, KeyModifiers, Sequence}; + +use crate::test_sequences; + +#[test] +fn esc_o_f_keys() { + test_sequences!( + b"\x1BOP", + Sequence::Key(KeyCode::F(1), KeyModifiers::empty()), + b"\x1BOQ", + Sequence::Key(KeyCode::F(2), KeyModifiers::empty()), + b"\x1BOR", + Sequence::Key(KeyCode::F(3), KeyModifiers::empty()), + b"\x1BOS", + Sequence::Key(KeyCode::F(4), KeyModifiers::empty()), + ); +} + +#[test] +fn csi_key_codes() { + test_sequences!( + b"\x1B[A", + Sequence::Key(KeyCode::Up, KeyModifiers::empty()), + b"\x1B[B", + Sequence::Key(KeyCode::Down, KeyModifiers::empty()), + b"\x1B[C", + Sequence::Key(KeyCode::Right, KeyModifiers::empty()), + b"\x1B[D", + Sequence::Key(KeyCode::Left, KeyModifiers::empty()), + b"\x1B[H", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + b"\x1B[F", + Sequence::Key(KeyCode::End, KeyModifiers::empty()), + b"\x1B[Z", + Sequence::Key(KeyCode::BackTab, KeyModifiers::empty()), + ); +} + +#[test] +fn csi_arrow_key_modifiers() { + test_sequences!( + b"\x1B[50A", + Sequence::Key(KeyCode::Up, KeyModifiers::SHIFT), + b"\x1B[53A", + Sequence::Key(KeyCode::Up, KeyModifiers::CONTROL), + ); +} + +#[test] +fn csi_tilde_key_modifiers() { + test_sequences!( + b"\x1B[1~", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + b"\x1B[1;0~", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + b"\x1B[1;1~", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + b"\x1B[1;2~", + Sequence::Key(KeyCode::Home, KeyModifiers::SHIFT), + b"\x1B[1;3~", + Sequence::Key(KeyCode::Home, KeyModifiers::ALT), + b"\x1B[1;4~", + Sequence::Key(KeyCode::Home, KeyModifiers::SHIFT | KeyModifiers::ALT), + b"\x1B[1;5~", + Sequence::Key(KeyCode::Home, KeyModifiers::CONTROL), + b"\x1B[1;6~", + Sequence::Key(KeyCode::Home, KeyModifiers::SHIFT | KeyModifiers::CONTROL), + b"\x1B[1;7~", + Sequence::Key(KeyCode::Home, KeyModifiers::ALT | KeyModifiers::CONTROL), + b"\x1B[1;8~", + Sequence::Key( + KeyCode::Home, + KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL + ), + b"\x1B[1;9~", + Sequence::Key(KeyCode::Home, KeyModifiers::META), + b"\x1B[1;10~", + Sequence::Key(KeyCode::Home, KeyModifiers::META | KeyModifiers::SHIFT), + b"\x1B[1;11~", + Sequence::Key(KeyCode::Home, KeyModifiers::META | KeyModifiers::ALT), + b"\x1B[1;12~", + Sequence::Key( + KeyCode::Home, + KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::ALT + ), + b"\x1B[1;13~", + Sequence::Key(KeyCode::Home, KeyModifiers::META | KeyModifiers::CONTROL), + b"\x1B[1;14~", + Sequence::Key( + KeyCode::Home, + KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::CONTROL + ), + b"\x1B[1;15~", + Sequence::Key( + KeyCode::Home, + KeyModifiers::META | KeyModifiers::ALT | KeyModifiers::CONTROL + ), + b"\x1B[1;16~", + Sequence::Key( + KeyCode::Home, + KeyModifiers::META | KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL + ), + b"\x1B[1;17~", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + ); +} + +#[test] +fn csi_tilde_f_keys() { + test_sequences!( + b"\x1B[11~", + Sequence::Key(KeyCode::F(1), KeyModifiers::empty()), + b"\x1B[12~", + Sequence::Key(KeyCode::F(2), KeyModifiers::empty()), + b"\x1B[13~", + Sequence::Key(KeyCode::F(3), KeyModifiers::empty()), + b"\x1B[14~", + Sequence::Key(KeyCode::F(4), KeyModifiers::empty()), + b"\x1B[15~", + Sequence::Key(KeyCode::F(5), KeyModifiers::empty()), + b"\x1B[17~", + Sequence::Key(KeyCode::F(6), KeyModifiers::empty()), + b"\x1B[18~", + Sequence::Key(KeyCode::F(7), KeyModifiers::empty()), + b"\x1B[19~", + Sequence::Key(KeyCode::F(8), KeyModifiers::empty()), + b"\x1B[20~", + Sequence::Key(KeyCode::F(9), KeyModifiers::empty()), + b"\x1B[21~", + Sequence::Key(KeyCode::F(10), KeyModifiers::empty()), + b"\x1B[23~", + Sequence::Key(KeyCode::F(11), KeyModifiers::empty()), + b"\x1B[24~", + Sequence::Key(KeyCode::F(12), KeyModifiers::empty()), + ); +} + +#[test] +fn csi_tilde_key_codes() { + test_sequences!( + b"\x1B[1~", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + b"\x1B[2~", + Sequence::Key(KeyCode::Insert, KeyModifiers::empty()), + b"\x1B[3~", + Sequence::Key(KeyCode::Delete, KeyModifiers::empty()), + b"\x1B[4~", + Sequence::Key(KeyCode::End, KeyModifiers::empty()), + b"\x1B[5~", + Sequence::Key(KeyCode::PageUp, KeyModifiers::empty()), + b"\x1B[6~", + Sequence::Key(KeyCode::PageDown, KeyModifiers::empty()), + b"\x1B[7~", + Sequence::Key(KeyCode::Home, KeyModifiers::empty()), + b"\x1B[8~", + Sequence::Key(KeyCode::End, KeyModifiers::empty()), + ); +} diff --git a/vendor/anes/tests/parser/mod.rs b/vendor/anes/tests/parser/mod.rs new file mode 100644 index 000000000..ecddcddb6 --- /dev/null +++ b/vendor/anes/tests/parser/mod.rs @@ -0,0 +1,25 @@ +#[macro_export] +macro_rules! test_sequence { + ($bytes:expr, $seq:expr) => { + let mut parser = ::anes::parser::Parser::default(); + parser.advance($bytes, false); + assert_eq!(parser.next(), Some($seq)); + }; +} + +#[macro_export] +macro_rules! test_sequences { + ( + $( + $bytes:expr, $seq:expr, + )* + ) => { + $( + test_sequence!($bytes, $seq); + )* + }; +} + +mod cursor; +mod key; +mod mouse; diff --git a/vendor/anes/tests/parser/mouse/mod.rs b/vendor/anes/tests/parser/mouse/mod.rs new file mode 100644 index 000000000..dc53361e4 --- /dev/null +++ b/vendor/anes/tests/parser/mouse/mod.rs @@ -0,0 +1,2 @@ +mod rxvt; +mod xterm; diff --git a/vendor/anes/tests/parser/mouse/rxvt.rs b/vendor/anes/tests/parser/mouse/rxvt.rs new file mode 100644 index 000000000..47f43a51c --- /dev/null +++ b/vendor/anes/tests/parser/mouse/rxvt.rs @@ -0,0 +1,152 @@ +use anes::parser::{KeyModifiers, Mouse, MouseButton, Sequence}; + +use crate::test_sequences; + +#[test] +fn button_down() { + test_sequences!( + b"\x1B[0;30;40;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 30, 40), + KeyModifiers::empty() + ), + b"\x1B[1;30;40;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Middle, 30, 40), + KeyModifiers::empty() + ), + b"\x1B[2;30;40;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Right, 30, 40), + KeyModifiers::empty() + ), + ); +} + +#[test] +fn button_down_with_modifiers() { + test_sequences!( + b"\x1B[4;30;40;M", + Sequence::Mouse(Mouse::Down(MouseButton::Left, 30, 40), KeyModifiers::SHIFT), + b"\x1B[5;30;40;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Middle, 30, 40), + KeyModifiers::SHIFT + ), + b"\x1B[6;30;40;M", + Sequence::Mouse(Mouse::Down(MouseButton::Right, 30, 40), KeyModifiers::SHIFT), + ); +} + +#[test] +fn button_up() { + test_sequences!( + b"\x1B[3;30;40;M", + Sequence::Mouse(Mouse::Up(MouseButton::Any, 30, 40), KeyModifiers::empty()), + ); +} + +#[test] +fn button_up_with_modifiers() { + test_sequences!( + b"\x1B[7;30;40;M", + Sequence::Mouse(Mouse::Up(MouseButton::Any, 30, 40), KeyModifiers::SHIFT), + ); +} + +#[test] +fn scroll() { + test_sequences!( + b"\x1B[96;30;40;M", + Sequence::Mouse(Mouse::ScrollUp(30, 40), KeyModifiers::empty()), + b"\x1B[97;30;40;M", + Sequence::Mouse(Mouse::ScrollDown(30, 40), KeyModifiers::empty()), + ); +} + +#[test] +fn scroll_with_modifiers() { + test_sequences!( + b"\x1B[100;30;40;M", + Sequence::Mouse(Mouse::ScrollUp(30, 40), KeyModifiers::SHIFT), + b"\x1B[101;30;40;M", + Sequence::Mouse(Mouse::ScrollDown(30, 40), KeyModifiers::SHIFT), + ); +} + +#[test] +fn drag() { + test_sequences!( + b"\x1B[64;30;40;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Left, 30, 40), + KeyModifiers::empty() + ), + b"\x1B[65;30;40;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Middle, 30, 40), + KeyModifiers::empty() + ), + b"\x1B[66;30;40;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Right, 30, 40), + KeyModifiers::empty() + ), + ); +} + +#[test] +fn drag_with_modifiers() { + test_sequences!( + b"\x1B[64;30;40;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Left, 30, 40), + KeyModifiers::empty() + ), + b"\x1B[65;30;40;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Middle, 30, 40), + KeyModifiers::empty() + ), + b"\x1B[66;30;40;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Right, 30, 40), + KeyModifiers::empty() + ), + ); +} + +#[test] +fn key_modifier_combinations() { + test_sequences!( + b"\x1B[4;20;10M", + Sequence::Mouse(Mouse::Down(MouseButton::Left, 20, 10), KeyModifiers::SHIFT), + b"\x1B[8;20;10M", + Sequence::Mouse(Mouse::Down(MouseButton::Left, 20, 10), KeyModifiers::ALT), + b"\x1B[16;20;10M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 20, 10), + KeyModifiers::CONTROL + ), + b"\x1B[12;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 20, 10), + KeyModifiers::SHIFT | KeyModifiers::ALT + ), + b"\x1B[20;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 20, 10), + KeyModifiers::SHIFT | KeyModifiers::CONTROL + ), + b"\x1B[24;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 20, 10), + KeyModifiers::ALT | KeyModifiers::CONTROL + ), + b"\x1B[28;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 20, 10), + KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL + ), + ); +} diff --git a/vendor/anes/tests/parser/mouse/xterm.rs b/vendor/anes/tests/parser/mouse/xterm.rs new file mode 100644 index 000000000..47293d69e --- /dev/null +++ b/vendor/anes/tests/parser/mouse/xterm.rs @@ -0,0 +1,154 @@ +use anes::parser::{KeyModifiers, Mouse, MouseButton, Sequence}; + +use crate::test_sequences; + +#[test] +fn button_down() { + test_sequences!( + b"\x1B[<0;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Left, 20, 10), + KeyModifiers::empty() + ), + b"\x1B[<1;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Middle, 20, 10), + KeyModifiers::empty() + ), + b"\x1B[<2;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Right, 20, 10), + KeyModifiers::empty() + ), + ); +} + +#[test] +fn button_down_with_key_modifiers() { + test_sequences!( + b"\x1B[<4;20;10;M", + Sequence::Mouse(Mouse::Down(MouseButton::Left, 20, 10), KeyModifiers::SHIFT), + b"\x1B[<5;20;10;M", + Sequence::Mouse( + Mouse::Down(MouseButton::Middle, 20, 10), + KeyModifiers::SHIFT + ), + b"\x1B[<6;20;10;M", + Sequence::Mouse(Mouse::Down(MouseButton::Right, 20, 10), KeyModifiers::SHIFT), + ); +} + +#[test] +fn button_up() { + test_sequences!( + b"\x1B[<0;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Left, 20, 10), KeyModifiers::empty()), + b"\x1B[<1;20;10;m", + Sequence::Mouse( + Mouse::Up(MouseButton::Middle, 20, 10), + KeyModifiers::empty() + ), + b"\x1B[<2;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Right, 20, 10), KeyModifiers::empty()), + ); +} + +#[test] +fn button_up_with_key_modifiers() { + test_sequences!( + b"\x1B[<4;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Left, 20, 10), KeyModifiers::SHIFT), + b"\x1B[<5;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Middle, 20, 10), KeyModifiers::SHIFT), + b"\x1B[<6;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Right, 20, 10), KeyModifiers::SHIFT), + ); +} + +#[test] +fn scroll() { + test_sequences!( + b"\x1B[<64;20;10;m", + Sequence::Mouse(Mouse::ScrollUp(20, 10), KeyModifiers::empty()), + b"\x1B[<65;20;10;m", + Sequence::Mouse(Mouse::ScrollDown(20, 10), KeyModifiers::empty()), + ); +} + +#[test] +fn scroll_with_key_modifiers() { + test_sequences!( + b"\x1B[<68;20;10;m", + Sequence::Mouse(Mouse::ScrollUp(20, 10), KeyModifiers::SHIFT), + b"\x1B[<69;20;10;m", + Sequence::Mouse(Mouse::ScrollDown(20, 10), KeyModifiers::SHIFT), + ); +} + +#[test] +fn drag() { + test_sequences!( + b"\x1B[<32;20;10;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Left, 20, 10), + KeyModifiers::empty() + ), + b"\x1B[<33;20;10;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Middle, 20, 10), + KeyModifiers::empty() + ), + b"\x1B[<34;20;10;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Right, 20, 10), + KeyModifiers::empty() + ), + ); +} + +#[test] +fn drag_with_key_modifiers() { + test_sequences!( + b"\x1B[<36;20;10;M", + Sequence::Mouse(Mouse::Drag(MouseButton::Left, 20, 10), KeyModifiers::SHIFT), + b"\x1B[<37;20;10;M", + Sequence::Mouse( + Mouse::Drag(MouseButton::Middle, 20, 10), + KeyModifiers::SHIFT, + ), + b"\x1B[<38;20;10;M", + Sequence::Mouse(Mouse::Drag(MouseButton::Right, 20, 10), KeyModifiers::SHIFT), + ); +} + +#[test] +fn key_modifier_combinations() { + test_sequences!( + b"\x1B[<4;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Left, 20, 10), KeyModifiers::SHIFT), + b"\x1B[<8;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Left, 20, 10), KeyModifiers::ALT), + b"\x1B[<16;20;10;m", + Sequence::Mouse(Mouse::Up(MouseButton::Left, 20, 10), KeyModifiers::CONTROL), + b"\x1B[<12;20;10;m", + Sequence::Mouse( + Mouse::Up(MouseButton::Left, 20, 10), + KeyModifiers::SHIFT | KeyModifiers::ALT + ), + b"\x1B[<20;20;10;m", + Sequence::Mouse( + Mouse::Up(MouseButton::Left, 20, 10), + KeyModifiers::SHIFT | KeyModifiers::CONTROL + ), + b"\x1B[<24;20;10;m", + Sequence::Mouse( + Mouse::Up(MouseButton::Left, 20, 10), + KeyModifiers::ALT | KeyModifiers::CONTROL + ), + b"\x1B[<28;20;10;m", + Sequence::Mouse( + Mouse::Up(MouseButton::Left, 20, 10), + KeyModifiers::SHIFT | KeyModifiers::ALT | KeyModifiers::CONTROL + ), + ); +} diff --git a/vendor/anes/tests/tests.rs b/vendor/anes/tests/tests.rs new file mode 100644 index 000000000..f60dbff23 --- /dev/null +++ b/vendor/anes/tests/tests.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "parser")] +mod parser; |