improvement: add parser for format strings (#1021)
This PR implements the parser of format strings described in #624.
This commit is contained in:
parent
3510bfe044
commit
22dc419a3e
|
@ -107,11 +107,40 @@ dependencies = [
|
|||
"constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byte-tools"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byte-unit"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.5.4"
|
||||
|
@ -230,6 +259,14 @@ dependencies = [
|
|||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "2.0.2"
|
||||
|
@ -277,6 +314,11 @@ dependencies = [
|
|||
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake-simd"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.6"
|
||||
|
@ -295,6 +337,14 @@ name = "foreign-types-shared"
|
|||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.2.1"
|
||||
|
@ -455,6 +505,11 @@ dependencies = [
|
|||
"libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "maplit"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
|
@ -561,6 +616,11 @@ name = "once_cell"
|
|||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "1.4.0"
|
||||
|
@ -628,6 +688,45 @@ name = "percent-encoding"
|
|||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_derive"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pest_meta"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.17"
|
||||
|
@ -876,6 +975,17 @@ dependencies = [
|
|||
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.2.0"
|
||||
|
@ -901,6 +1011,8 @@ dependencies = [
|
|||
"open 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"os_info 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"path-slash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pretty_env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -1031,6 +1143,11 @@ name = "typenum"
|
|||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
|
@ -1170,7 +1287,11 @@ dependencies = [
|
|||
"checksum battery 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "36a698e449024a5d18994a815998bf5e2e4bc1883e35a7d7ba95b6b69ee45907"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
|
||||
"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
|
||||
"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
|
||||
"checksum byte-unit 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6894a79550807490d9f19a138a6da0f8830e70c83e83402dd23f16fd6c479056"
|
||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
"checksum bytes 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1"
|
||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
|
@ -1185,15 +1306,18 @@ dependencies = [
|
|||
"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
|
||||
"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
|
||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
|
||||
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
|
||||
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
|
||||
"checksum doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
|
||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
|
||||
"checksum gethostname 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e692e296bfac1d2533ef168d0b60ff5897b8b70a4009276834014dd8924cc028"
|
||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||
"checksum git2 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ef222034f2069cfc5af01ce423574d3d9a3925bd4052912a14e5bcfd7ca9e47a"
|
||||
|
@ -1213,6 +1337,7 @@ dependencies = [
|
|||
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
|
||||
"checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
@ -1226,6 +1351,7 @@ dependencies = [
|
|||
"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
|
||||
"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||
"checksum open 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c283bf0114efea9e42f1a60edea9859e8c47528eae09d01df4b29c1e489cc48"
|
||||
"checksum openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)" = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52"
|
||||
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||
|
@ -1234,6 +1360,10 @@ dependencies = [
|
|||
"checksum os_info 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0ecb53e7b83e5016bf4ac041e15e02b0d240cb27072b19b651b0b4d8cd6bbda9"
|
||||
"checksum path-slash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0858af4d9136275541f4eac7be1af70add84cf356d901799b065ac1b8ff6e2f"
|
||||
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||
"checksum pest 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
|
||||
"checksum pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
"checksum pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
|
||||
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
"checksum pretty_env_logger 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
||||
|
@ -1264,6 +1394,7 @@ dependencies = [
|
|||
"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8"
|
||||
"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9"
|
||||
"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
|
||||
"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
|
||||
"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc"
|
||||
"checksum static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
@ -1277,6 +1408,7 @@ dependencies = [
|
|||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
|
||||
"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
|
||||
"checksum ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4"
|
||||
"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
|
||||
|
|
|
@ -49,6 +49,8 @@ sysinfo = "0.12.0"
|
|||
byte-unit = "3.0.3"
|
||||
starship_module_config_derive = { version = "0.1.0", path = "starship_module_config_derive" }
|
||||
yaml-rust = "0.4"
|
||||
pest = "^2.1"
|
||||
pest_derive = "^2.1"
|
||||
nom = "5.1.1"
|
||||
regex = "1.3.6"
|
||||
os_info = "2.0.2"
|
||||
|
|
|
@ -305,7 +305,7 @@ impl Default for SegmentConfig<'static> {
|
|||
- 'italic'
|
||||
- '<color>' (see the parse_color_string doc for valid color strings)
|
||||
*/
|
||||
fn parse_style_string(style_string: &str) -> Option<ansi_term::Style> {
|
||||
pub fn parse_style_string(style_string: &str) -> Option<ansi_term::Style> {
|
||||
style_string
|
||||
.split_whitespace()
|
||||
.fold(Some(ansi_term::Style::new()), |maybe_style, token| {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
pub mod model;
|
||||
mod parser;
|
||||
pub mod string_formatter;
|
||||
|
||||
pub use string_formatter::StringFormatter;
|
|
@ -0,0 +1,17 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
pub struct TextGroup<'a> {
|
||||
pub format: Vec<FormatElement<'a>>,
|
||||
pub style: Vec<StyleElement<'a>>,
|
||||
}
|
||||
|
||||
pub enum FormatElement<'a> {
|
||||
Text(Cow<'a, str>),
|
||||
Variable(Cow<'a, str>),
|
||||
TextGroup(TextGroup<'a>),
|
||||
}
|
||||
|
||||
pub enum StyleElement<'a> {
|
||||
Text(Cow<'a, str>),
|
||||
Variable(Cow<'a, str>),
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
use pest::{error::Error, iterators::Pair, Parser};
|
||||
|
||||
use super::model::*;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[grammar = "formatter/spec.pest"]
|
||||
struct IdentParser;
|
||||
|
||||
fn _parse_textgroup(textgroup: Pair<Rule>) -> TextGroup {
|
||||
let mut inner_rules = textgroup.into_inner();
|
||||
let format = inner_rules.next().unwrap();
|
||||
let style = inner_rules.next().unwrap();
|
||||
|
||||
TextGroup {
|
||||
format: _parse_format(format),
|
||||
style: _parse_style(style),
|
||||
}
|
||||
}
|
||||
|
||||
fn _parse_variable(variable: Pair<Rule>) -> &str {
|
||||
variable.into_inner().next().unwrap().as_str()
|
||||
}
|
||||
|
||||
fn _parse_text(text: Pair<Rule>) -> String {
|
||||
let mut result = String::new();
|
||||
for pair in text.into_inner() {
|
||||
result.push_str(pair.as_str());
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn _parse_format(format: Pair<Rule>) -> Vec<FormatElement> {
|
||||
let mut result: Vec<FormatElement> = Vec::new();
|
||||
|
||||
for pair in format.into_inner() {
|
||||
match pair.as_rule() {
|
||||
Rule::text => result.push(FormatElement::Text(_parse_text(pair).into())),
|
||||
Rule::variable => result.push(FormatElement::Variable(_parse_variable(pair).into())),
|
||||
Rule::textgroup => result.push(FormatElement::TextGroup(_parse_textgroup(pair))),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn _parse_style(style: Pair<Rule>) -> Vec<StyleElement> {
|
||||
let mut result: Vec<StyleElement> = Vec::new();
|
||||
|
||||
for pair in style.into_inner() {
|
||||
match pair.as_rule() {
|
||||
Rule::text => result.push(StyleElement::Text(_parse_text(pair).into())),
|
||||
Rule::variable => result.push(StyleElement::Variable(_parse_variable(pair).into())),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn parse(format: &str) -> Result<Vec<FormatElement>, Error<Rule>> {
|
||||
let pairs = IdentParser::parse(Rule::expression, format)?;
|
||||
let mut result: Vec<FormatElement> = Vec::new();
|
||||
|
||||
// Lifetime of Segment is the same as result
|
||||
for pair in pairs.take_while(|pair| pair.as_rule() != Rule::EOI) {
|
||||
match pair.as_rule() {
|
||||
Rule::text => result.push(FormatElement::Text(_parse_text(pair).into())),
|
||||
Rule::variable => result.push(FormatElement::Variable(_parse_variable(pair).into())),
|
||||
Rule::textgroup => result.push(FormatElement::TextGroup(_parse_textgroup(pair))),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
expression = _{ SOI ~ value* ~ EOI }
|
||||
value = _{ text | variable | textgroup }
|
||||
|
||||
variable = { "$" ~ variable_name }
|
||||
variable_name = @{ char+ }
|
||||
char = _{ 'a'..'z' | 'A'..'Z' | '0'..'9' | "_" }
|
||||
|
||||
text = { text_inner+ }
|
||||
text_inner = _{ text_inner_char | escape }
|
||||
text_inner_char = { !("[" | "]" | "(" | ")" | "$" | "\\") ~ ANY }
|
||||
escape = _{ "\\" ~ escaped_char }
|
||||
escaped_char = { "[" | "]" | "(" | ")" | "\\" | "$" }
|
||||
|
||||
textgroup = { "[" ~ format ~ "]" ~ "(" ~ style ~ ")" }
|
||||
format = { (variable | text | textgroup)* }
|
||||
style = { (variable | text)* }
|
|
@ -0,0 +1,252 @@
|
|||
use ansi_term::Style;
|
||||
use pest::error::Error;
|
||||
use rayon::prelude::*;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::config::parse_style_string;
|
||||
use crate::segment::Segment;
|
||||
|
||||
use super::model::*;
|
||||
use super::parser::{parse, Rule};
|
||||
|
||||
type VariableMapType = BTreeMap<String, Option<Vec<Segment>>>;
|
||||
|
||||
pub struct StringFormatter<'a> {
|
||||
format: Vec<FormatElement<'a>>,
|
||||
variables: VariableMapType,
|
||||
}
|
||||
|
||||
impl<'a> StringFormatter<'a> {
|
||||
/// Creates an instance of StringFormatter from a format string
|
||||
pub fn new(format: &'a str) -> Result<Self, Error<Rule>> {
|
||||
parse(format)
|
||||
.map(|format| {
|
||||
let variables = _get_variables(&format);
|
||||
(format, variables)
|
||||
})
|
||||
.map(|(format, variables)| Self { format, variables })
|
||||
}
|
||||
|
||||
/// Maps variable name to its value
|
||||
pub fn map(mut self, mapper: impl Fn(&str) -> Option<String> + Sync) -> Self {
|
||||
self.variables.par_iter_mut().for_each(|(key, value)| {
|
||||
*value = mapper(key).map(|value| vec![_new_segment(key.to_string(), value, None)]);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Maps variable name to an array of segments
|
||||
pub fn map_variables_to_segments(
|
||||
mut self,
|
||||
mapper: impl Fn(&str) -> Option<Vec<Segment>> + Sync,
|
||||
) -> Self {
|
||||
self.variables.par_iter_mut().for_each(|(key, value)| {
|
||||
*value = mapper(key);
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Parse the format string and consume self.
|
||||
pub fn parse(self, default_style: Option<Style>) -> Vec<Segment> {
|
||||
fn _parse_textgroup<'a>(
|
||||
textgroup: TextGroup<'a>,
|
||||
variables: &'a VariableMapType,
|
||||
) -> Vec<Segment> {
|
||||
let style = _parse_style(textgroup.style);
|
||||
_parse_format(textgroup.format, style, &variables)
|
||||
}
|
||||
|
||||
fn _parse_style(style: Vec<StyleElement>) -> Option<Style> {
|
||||
let style_string = style
|
||||
.iter()
|
||||
.flat_map(|style| match style {
|
||||
StyleElement::Text(text) => text.as_ref().chars(),
|
||||
StyleElement::Variable(variable) => {
|
||||
log::warn!(
|
||||
"Variable `{}` monitored in style string, which is not allowed",
|
||||
&variable
|
||||
);
|
||||
"".chars()
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
parse_style_string(&style_string)
|
||||
}
|
||||
|
||||
fn _parse_format<'a>(
|
||||
mut format: Vec<FormatElement<'a>>,
|
||||
style: Option<Style>,
|
||||
variables: &'a VariableMapType,
|
||||
) -> Vec<Segment> {
|
||||
let mut result: Vec<Segment> = Vec::new();
|
||||
|
||||
format.reverse();
|
||||
while let Some(el) = format.pop() {
|
||||
let mut segments = match el {
|
||||
FormatElement::Text(text) => {
|
||||
vec![_new_segment("_text".into(), text.into_owned(), style)]
|
||||
}
|
||||
FormatElement::TextGroup(textgroup) => {
|
||||
let textgroup = TextGroup {
|
||||
format: textgroup.format,
|
||||
style: textgroup.style,
|
||||
};
|
||||
_parse_textgroup(textgroup, &variables)
|
||||
}
|
||||
FormatElement::Variable(name) => variables
|
||||
.get(name.as_ref())
|
||||
.map(|segments| segments.clone().unwrap_or_default())
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
result.append(&mut segments);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
_parse_format(self.format, default_style, &self.variables)
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract variable names from an array of `FormatElement` into a `BTreeMap`
|
||||
fn _get_variables<'a>(format: &[FormatElement<'a>]) -> VariableMapType {
|
||||
let mut variables: VariableMapType = Default::default();
|
||||
|
||||
fn _push_variables_from_textgroup<'a>(
|
||||
variables: &mut VariableMapType,
|
||||
textgroup: &'a TextGroup<'a>,
|
||||
) {
|
||||
for el in &textgroup.format {
|
||||
match el {
|
||||
FormatElement::Variable(name) => _push_variable(variables, name.as_ref()),
|
||||
FormatElement::TextGroup(textgroup) => {
|
||||
_push_variables_from_textgroup(variables, &textgroup)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
for el in &textgroup.style {
|
||||
if let StyleElement::Variable(name) = el {
|
||||
_push_variable(variables, name.as_ref())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn _push_variable<'a>(variables: &mut VariableMapType, name: &'a str) {
|
||||
variables.insert(name.to_owned(), None);
|
||||
}
|
||||
|
||||
for el in format {
|
||||
match el {
|
||||
FormatElement::Variable(name) => _push_variable(&mut variables, name.as_ref()),
|
||||
FormatElement::TextGroup(textgroup) => {
|
||||
_push_variables_from_textgroup(&mut variables, &textgroup)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
variables
|
||||
}
|
||||
|
||||
/// Helper function to create a new segment
|
||||
fn _new_segment(name: String, value: String, style: Option<Style>) -> Segment {
|
||||
Segment {
|
||||
_name: name,
|
||||
value,
|
||||
style,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use ansi_term::Color;
|
||||
|
||||
// match_next(result: Iter<Segment>, value, style)
|
||||
macro_rules! match_next {
|
||||
($iter:ident, $value:literal, $($style:tt)+) => {
|
||||
let _next = $iter.next().unwrap();
|
||||
assert_eq!(_next.value, $value);
|
||||
assert_eq!(_next.style, $($style)+);
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_mapper(_: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_style() {
|
||||
const FORMAT_STR: &str = "text";
|
||||
let style = Some(Color::Red.bold());
|
||||
|
||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||
let result = formatter.parse(style);
|
||||
let mut result_iter = result.iter();
|
||||
match_next!(result_iter, "text", style);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_textgroup_text_only() {
|
||||
const FORMAT_STR: &str = "[text](red bold)";
|
||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||
let result = formatter.parse(None);
|
||||
let mut result_iter = result.iter();
|
||||
match_next!(result_iter, "text", Some(Color::Red.bold()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_variable_only() {
|
||||
const FORMAT_STR: &str = "$var1";
|
||||
|
||||
let formatter = StringFormatter::new(FORMAT_STR)
|
||||
.unwrap()
|
||||
.map(|variable| match variable {
|
||||
"var1" => Some("text1".to_owned()),
|
||||
_ => None,
|
||||
});
|
||||
let result = formatter.parse(None);
|
||||
let mut result_iter = result.iter();
|
||||
match_next!(result_iter, "text1", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escaped_chars() {
|
||||
const FORMAT_STR: &str = r#"\\\[\$text\]\(red bold\)"#;
|
||||
|
||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||
let result = formatter.parse(None);
|
||||
let mut result_iter = result.iter();
|
||||
match_next!(result_iter, r#"\[$text](red bold)"#, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_textgroup() {
|
||||
const FORMAT_STR: &str = "outer [middle [inner](blue)](red bold)";
|
||||
let outer_style = Some(Color::Green.normal());
|
||||
let middle_style = Some(Color::Red.bold());
|
||||
let inner_style = Some(Color::Blue.normal());
|
||||
|
||||
let formatter = StringFormatter::new(FORMAT_STR).unwrap().map(empty_mapper);
|
||||
let result = formatter.parse(outer_style);
|
||||
let mut result_iter = result.iter();
|
||||
match_next!(result_iter, "outer ", outer_style);
|
||||
match_next!(result_iter, "middle ", middle_style);
|
||||
match_next!(result_iter, "inner", inner_style);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_error() {
|
||||
// brackets without escape
|
||||
{
|
||||
const FORMAT_STR: &str = "[";
|
||||
assert!(StringFormatter::new(FORMAT_STR).is_err());
|
||||
}
|
||||
// Dollar without variable
|
||||
{
|
||||
const FORMAT_STR: &str = "$ ";
|
||||
assert!(StringFormatter::new(FORMAT_STR).is_err());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,11 @@
|
|||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
// Lib is present to allow for benchmarking
|
||||
pub mod config;
|
||||
pub mod configs;
|
||||
pub mod context;
|
||||
pub mod formatter;
|
||||
pub mod module;
|
||||
pub mod modules;
|
||||
pub mod print;
|
||||
|
|
|
@ -2,12 +2,15 @@ use std::time::SystemTime;
|
|||
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate pest_derive;
|
||||
|
||||
mod bug_report;
|
||||
mod config;
|
||||
mod configs;
|
||||
mod configure;
|
||||
mod context;
|
||||
mod formatter;
|
||||
mod init;
|
||||
mod module;
|
||||
mod modules;
|
||||
|
|
|
@ -99,6 +99,11 @@ impl<'a> Module<'a> {
|
|||
self.segments.last_mut().unwrap()
|
||||
}
|
||||
|
||||
/// Set segments in module
|
||||
pub fn set_segment(&mut self, segments: Vec<Segment>) {
|
||||
self.segments = segments;
|
||||
}
|
||||
|
||||
/// Get module's name
|
||||
pub fn get_name(&self) -> &String {
|
||||
&self._name
|
||||
|
|
|
@ -4,15 +4,16 @@ use std::fmt;
|
|||
/// A segment is a single configurable element in a module. This will usually
|
||||
/// contain a data point to provide context for the prompt's user
|
||||
/// (e.g. The version that software is running).
|
||||
#[derive(Clone)]
|
||||
pub struct Segment {
|
||||
/// The segment's name, to be used in configuration and logging.
|
||||
_name: String,
|
||||
pub _name: String,
|
||||
|
||||
/// The segment's style. If None, will inherit the style of the module containing it.
|
||||
style: Option<Style>,
|
||||
pub style: Option<Style>,
|
||||
|
||||
/// The string value of the current segment.
|
||||
value: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
|
|
Loading…
Reference in New Issue