Snap for 9696334 from c4b065dc13ef646bd4d068a48244f9ee300709f6 to udc-release

Change-Id: Id3683a97c5702d80a320a5eaecdaef129dbd3fc3
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..d2d567b
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,5 @@
+{
+  "git": {
+    "sha1": "378ac7461ecac29fde9e10df7b08359d1315a9ad"
+  }
+}
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..8049644
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,74 @@
+// This file is generated by cargo2android.py --config cargo2android.json.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+rust_test {
+    name: "anes_test_src_lib",
+    host_supported: true,
+    crate_name: "anes",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.1.6",
+    srcs: ["src/lib.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
+    edition: "2018",
+    features: [
+        "bitflags",
+        "parser",
+    ],
+    rustlibs: [
+        "libbitflags",
+        "libcriterion",
+        "liblibc",
+    ],
+}
+
+rust_test {
+    name: "anes_test_tests_tests",
+    host_supported: true,
+    crate_name: "tests",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.1.6",
+    srcs: ["tests/tests.rs"],
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    test_options: {
+        unit_test: true,
+    },
+    edition: "2018",
+    features: [
+        "bitflags",
+        "parser",
+    ],
+    rustlibs: [
+        "libanes",
+        "libbitflags",
+        "libcriterion",
+        "liblibc",
+    ],
+}
+
+rust_library {
+    name: "libanes",
+    host_supported: true,
+    crate_name: "anes",
+    cargo_env_compat: true,
+    cargo_pkg_version: "0.1.6",
+    srcs: ["src/lib.rs"],
+    edition: "2018",
+    features: [
+        "bitflags",
+        "parser",
+    ],
+    rustlibs: [
+        "libbitflags",
+    ],
+    apex_available: [
+        "//apex_available:platform",
+        "//apex_available:anyapex",
+    ],
+}
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..b359a6d
--- /dev/null
+++ b/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/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..9ae35a0
--- /dev/null
+++ b/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 <[email protected]>"]
+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/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..51fd1d3
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,37 @@
+[package]
+name = "anes"
+version = "0.1.6"
+authors = ["Robert Vojta <[email protected]>"]
+edition = "2018"
+description = "ANSI Escape Sequences provider & parser"
+repository = "https://github.com/zrzka/anes-rs"
+documentation = "https://docs.rs/anes/"
+license = "MIT OR Apache-2.0"
+keywords = ["terminal", "ansi", "sequence", "code", "parser"]
+exclude = ["target", "Cargo.lock"]
+readme = "README.md"
+
+[lib]
+bench = false
+
+[badges]
+maintenance = { status = "actively-developed" }
+
+[package.metadata.docs.rs]
+all-features = true
+
+[features]
+default = []
+parser = ["bitflags"]
+
+[dependencies]
+bitflags = { version = "1.2", optional = true }
+
+[dev-dependencies]
+criterion = "0.3"
+libc = "0.2.66"
+
+[[bench]]
+name = "bench_main"
+harness = false
+required-features = ["parser"]
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE
\ No newline at end of file
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..fc87cce
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,20 @@
+name: "anes"
+description: "()"
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://crates.io/crates/anes"
+  }
+  url {
+    type: ARCHIVE
+    value: "https://static.crates.io/crates/anes/anes-0.1.6.crate"
+  }
+  version: "0.1.6"
+  # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2023
+    month: 2
+    day: 16
+  }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6a3c236
--- /dev/null
+++ b/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/benches/bench_main.rs b/benches/bench_main.rs
new file mode 100644
index 0000000..79aea4a
--- /dev/null
+++ b/benches/bench_main.rs
@@ -0,0 +1,5 @@
+use criterion::criterion_main;
+
+mod benchmarks;
+
+criterion_main!(benchmarks::parser::benches);
diff --git a/benches/benchmarks/mod.rs b/benches/benchmarks/mod.rs
new file mode 100644
index 0000000..67c567f
--- /dev/null
+++ b/benches/benchmarks/mod.rs
@@ -0,0 +1 @@
+pub mod parser;
diff --git a/benches/benchmarks/parser.rs b/benches/benchmarks/parser.rs
new file mode 100644
index 0000000..2aa63aa
--- /dev/null
+++ b/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/cargo2android.json b/cargo2android.json
new file mode 100644
index 0000000..fb02735
--- /dev/null
+++ b/cargo2android.json
@@ -0,0 +1,6 @@
+{
+  "device": true,
+  "run": true,
+  "features": "parser",
+  "tests": true
+}
diff --git a/examples/execute.rs b/examples/execute.rs
new file mode 100644
index 0000000..df781fc
--- /dev/null
+++ b/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/examples/parser.rs b/examples/parser.rs
new file mode 100644
index 0000000..a5ec5b6
--- /dev/null
+++ b/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/examples/queue.rs b/examples/queue.rs
new file mode 100644
index 0000000..0b2c712
--- /dev/null
+++ b/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/examples/sequence.rs b/examples/sequence.rs
new file mode 100644
index 0000000..d038f58
--- /dev/null
+++ b/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/examples/stdout.rs b/examples/stdout.rs
new file mode 100644
index 0000000..9b5be72
--- /dev/null
+++ b/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/examples/string.rs b/examples/string.rs
new file mode 100644
index 0000000..bd81c36
--- /dev/null
+++ b/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/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..99dfc8c
--- /dev/null
+++ b/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/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..1955214
--- /dev/null
+++ b/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/src/parser.rs b/src/parser.rs
new file mode 100644
index 0000000..be87b29
--- /dev/null
+++ b/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/src/parser/engine.rs b/src/parser/engine.rs
new file mode 100644
index 0000000..645208d
--- /dev/null
+++ b/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/src/parser/parsers.rs b/src/parser/parsers.rs
new file mode 100644
index 0000000..9bb9acb
--- /dev/null
+++ b/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/src/parser/types.rs b/src/parser/types.rs
new file mode 100644
index 0000000..66b6561
--- /dev/null
+++ b/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/src/sequences.rs b/src/sequences.rs
new file mode 100644
index 0000000..c660800
--- /dev/null
+++ b/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/src/sequences/attribute.rs b/src/sequences/attribute.rs
new file mode 100644
index 0000000..30961ff
--- /dev/null
+++ b/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/src/sequences/buffer.rs b/src/sequences/buffer.rs
new file mode 100644
index 0000000..053195a
--- /dev/null
+++ b/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/src/sequences/color.rs b/src/sequences/color.rs
new file mode 100644
index 0000000..b019f0f
--- /dev/null
+++ b/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/src/sequences/cursor.rs b/src/sequences/cursor.rs
new file mode 100644
index 0000000..37abc3b
--- /dev/null
+++ b/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/src/sequences/terminal.rs b/src/sequences/terminal.rs
new file mode 100644
index 0000000..74eada6
--- /dev/null
+++ b/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/tests/parser/cursor.rs b/tests/parser/cursor.rs
new file mode 100644
index 0000000..250ee48
--- /dev/null
+++ b/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/tests/parser/key.rs b/tests/parser/key.rs
new file mode 100644
index 0000000..cd87c9d
--- /dev/null
+++ b/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/tests/parser/mod.rs b/tests/parser/mod.rs
new file mode 100644
index 0000000..ecddcdd
--- /dev/null
+++ b/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/tests/parser/mouse/mod.rs b/tests/parser/mouse/mod.rs
new file mode 100644
index 0000000..dc53361
--- /dev/null
+++ b/tests/parser/mouse/mod.rs
@@ -0,0 +1,2 @@
+mod rxvt;
+mod xterm;
diff --git a/tests/parser/mouse/rxvt.rs b/tests/parser/mouse/rxvt.rs
new file mode 100644
index 0000000..47f43a5
--- /dev/null
+++ b/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/tests/parser/mouse/xterm.rs b/tests/parser/mouse/xterm.rs
new file mode 100644
index 0000000..47293d6
--- /dev/null
+++ b/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/tests/tests.rs b/tests/tests.rs
new file mode 100644
index 0000000..f60dbff
--- /dev/null
+++ b/tests/tests.rs
@@ -0,0 +1,2 @@
+#[cfg(feature = "parser")]
+mod parser;