mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00:00
Improve signature infrastructure
The `config` command uses different kinds of named arguments, which illustrates how it works.
This commit is contained in:
parent
9df8a261ab
commit
69effbc9e7
36 changed files with 673 additions and 208 deletions
77
Cargo.lock
generated
77
Cargo.lock
generated
|
@ -29,6 +29,17 @@ dependencies = [
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "app_dirs"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
|
@ -169,6 +180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-integer 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-integer 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -832,6 +844,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iovec"
|
name = "iovec"
|
||||||
|
@ -842,6 +857,11 @@ dependencies = [
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-match"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.7.11"
|
version = "0.7.11"
|
||||||
|
@ -1053,6 +1073,7 @@ name = "nu"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"byte-unit 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byte-unit 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1089,6 +1110,8 @@ dependencies = [
|
||||||
"sysinfo 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sysinfo 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1160,6 +1183,15 @@ name = "numtoa"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ole32-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "onig"
|
name = "onig"
|
||||||
version = "4.3.2"
|
version = "4.3.2"
|
||||||
|
@ -1648,6 +1680,15 @@ name = "shell-words"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shell32-sys"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
@ -1903,6 +1944,30 @@ dependencies = [
|
||||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml-query"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"toml-query_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml-query_derive"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"darling 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ucd-util"
|
name = "ucd-util"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -2020,6 +2085,11 @@ dependencies = [
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xdg"
|
||||||
|
version = "2.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xi-unicode"
|
name = "xi-unicode"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -2043,6 +2113,7 @@ dependencies = [
|
||||||
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
||||||
"checksum ansi_colours 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0f302a81afc6a7f4350c04f0ba7cfab529cc009bca3324b3fb5764e6add8b6"
|
"checksum ansi_colours 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0f302a81afc6a7f4350c04f0ba7cfab529cc009bca3324b3fb5764e6add8b6"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum app_dirs 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e73a24bad9bd6a94d6395382a6c69fe071708ae4409f763c5475e14ee896313d"
|
||||||
"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
|
"checksum arc-swap 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "bc4662175ead9cd84451d5c35070517777949a2ed84551764129cedb88384841"
|
||||||
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
|
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
|
||||||
"checksum array-macro 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4ff37a25fb442a1fecfd399be0dde685558bca30fb998420532889a36852d2"
|
"checksum array-macro 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4ff37a25fb442a1fecfd399be0dde685558bca30fb998420532889a36852d2"
|
||||||
|
@ -2135,6 +2206,7 @@ dependencies = [
|
||||||
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
"checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||||
|
"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
|
||||||
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
|
"checksum itertools 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
|
||||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||||
|
@ -2169,6 +2241,7 @@ dependencies = [
|
||||||
"checksum num-traits 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d9c79c952a4a139f44a0fe205c4ee66ce239c0e6ce72cd935f5f7e2f717549dd"
|
"checksum num-traits 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d9c79c952a4a139f44a0fe205c4ee66ce239c0e6ce72cd935f5f7e2f717549dd"
|
||||||
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
|
||||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||||
|
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
|
||||||
"checksum onig 4.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a646989adad8a19f49be2090374712931c3a59835cb5277b4530f48b417f26e7"
|
"checksum onig 4.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a646989adad8a19f49be2090374712931c3a59835cb5277b4530f48b417f26e7"
|
||||||
"checksum onig_sys 69.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388410bf5fa341f10e58e6db3975f4bea1ac30247dd79d37a9e5ced3cb4cc3b0"
|
"checksum onig_sys 69.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388410bf5fa341f10e58e6db3975f4bea1ac30247dd79d37a9e5ced3cb4cc3b0"
|
||||||
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
|
||||||
|
@ -2224,6 +2297,7 @@ dependencies = [
|
||||||
"checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f"
|
"checksum serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "101b495b109a3e3ca8c4cbe44cf62391527cdfb6ba15821c5ce80bcd5ea23f9f"
|
||||||
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
|
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
|
||||||
"checksum shell-words 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39acde55a154c4cd3ae048ac78cc21c25f3a0145e44111b523279113dce0d94a"
|
"checksum shell-words 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39acde55a154c4cd3ae048ac78cc21c25f3a0145e44111b523279113dce0d94a"
|
||||||
|
"checksum shell32-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ee04b46101f57121c9da2b151988283b6beb79b34f5bb29a58ee48cb695122c"
|
||||||
"checksum signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "72ab58f1fda436857e6337dcb6a5aaa34f16c5ddc87b3a8b6ef7a212f90b9c5a"
|
"checksum signal-hook 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "72ab58f1fda436857e6337dcb6a5aaa34f16c5ddc87b3a8b6ef7a212f90b9c5a"
|
||||||
"checksum signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cded4ffa32146722ec54ab1f16320568465aa922aa9ab4708129599740da85d7"
|
"checksum signal-hook-registry 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cded4ffa32146722ec54ab1f16320568465aa922aa9ab4708129599740da85d7"
|
||||||
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
@ -2252,6 +2326,8 @@ dependencies = [
|
||||||
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
|
"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926"
|
||||||
"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2"
|
"checksum tokio-threadpool 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72558af20be886ea124595ea0f806dd5703b8958e4705429dd58b3d8231f72f2"
|
||||||
"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
|
"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
|
||||||
|
"checksum toml-query 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a24369a1894ac8224efcfd567c3d141aea360292f49888e7ec7dcc316527aebb"
|
||||||
|
"checksum toml-query_derive 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c99ca245ec273c7e75c8ee58f47b882d0146f3c2c8495158082c6671e8b5335"
|
||||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||||
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
|
@ -2271,6 +2347,7 @@ dependencies = [
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
|
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
|
||||||
"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
|
"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
|
||||||
|
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||||
"checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1"
|
"checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1"
|
||||||
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
||||||
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
|
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
|
||||||
|
|
|
@ -11,7 +11,7 @@ edition = "2018"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustyline = "4.1.0"
|
rustyline = "4.1.0"
|
||||||
sysinfo = "0.8.4"
|
sysinfo = "0.8.4"
|
||||||
chrono = "0.4.6"
|
chrono = { version = "0.4.6", features = ["serde"] }
|
||||||
chrono-tz = "0.5.1"
|
chrono-tz = "0.5.1"
|
||||||
derive-new = "0.5.6"
|
derive-new = "0.5.6"
|
||||||
prettytable-rs = "0.8.0"
|
prettytable-rs = "0.8.0"
|
||||||
|
@ -21,7 +21,7 @@ conch-parser = "0.1.1"
|
||||||
nom = "5.0.0-beta1"
|
nom = "5.0.0-beta1"
|
||||||
subprocess = "0.1.18"
|
subprocess = "0.1.18"
|
||||||
dunce = "1.0.0"
|
dunce = "1.0.0"
|
||||||
indexmap = "1.0.2"
|
indexmap = { version = "1.0.2", features = ["serde-1"] }
|
||||||
chrono-humanize = "0.0.11"
|
chrono-humanize = "0.0.11"
|
||||||
byte-unit = "2.1.0"
|
byte-unit = "2.1.0"
|
||||||
ordered-float = "1.0.2"
|
ordered-float = "1.0.2"
|
||||||
|
@ -44,6 +44,9 @@ getset = "0.0.7"
|
||||||
logos = "0.10.0-rc2"
|
logos = "0.10.0-rc2"
|
||||||
logos-derive = "0.10.0-rc2"
|
logos-derive = "0.10.0-rc2"
|
||||||
language-reporting = "0.3.0"
|
language-reporting = "0.3.0"
|
||||||
|
app_dirs = "1.2.1"
|
||||||
|
toml = "0.5.1"
|
||||||
|
toml-query = "0.9.0"
|
||||||
|
|
||||||
[dependencies.pancurses]
|
[dependencies.pancurses]
|
||||||
version = "0.16"
|
version = "0.16"
|
||||||
|
|
|
@ -60,6 +60,7 @@ pub async fn cli() -> Result<(), Box<Error>> {
|
||||||
command("to-array", to_array::to_array),
|
command("to-array", to_array::to_array),
|
||||||
command("to-json", to_json::to_json),
|
command("to-json", to_json::to_json),
|
||||||
Arc::new(Where),
|
Arc::new(Where),
|
||||||
|
Arc::new(Config),
|
||||||
command("sort-by", sort_by::sort_by),
|
command("sort-by", sort_by::sort_by),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ crate mod cd;
|
||||||
crate mod classified;
|
crate mod classified;
|
||||||
crate mod column;
|
crate mod column;
|
||||||
crate mod command;
|
crate mod command;
|
||||||
|
crate mod config;
|
||||||
crate mod from_json;
|
crate mod from_json;
|
||||||
crate mod ls;
|
crate mod ls;
|
||||||
crate mod open;
|
crate mod open;
|
||||||
|
@ -22,5 +23,6 @@ crate mod view;
|
||||||
crate mod where_;
|
crate mod where_;
|
||||||
|
|
||||||
crate use command::command;
|
crate use command::command;
|
||||||
|
crate use config::Config;
|
||||||
crate use to_array::stream_to_array;
|
crate use to_array::stream_to_array;
|
||||||
crate use where_::Where;
|
crate use where_::Where;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::prelude::*;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let target = match args.args.first() {
|
let target = match args.positional.first() {
|
||||||
// TODO: This needs better infra
|
// TODO: This needs better infra
|
||||||
None => return Err(ShellError::string(format!("cd must take one arg"))),
|
None => return Err(ShellError::string(format!("cd must take one arg"))),
|
||||||
Some(v) => v.as_string()?.clone(),
|
Some(v) => v.as_string()?.clone(),
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::parser::registry::Args;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bytes::{BufMut, BytesMut};
|
use bytes::{BufMut, BytesMut};
|
||||||
use futures_codec::{Decoder, Encoder, Framed};
|
use futures_codec::{Decoder, Encoder, Framed};
|
||||||
|
@ -80,7 +81,7 @@ crate enum ClassifiedCommand {
|
||||||
|
|
||||||
crate struct InternalCommand {
|
crate struct InternalCommand {
|
||||||
crate command: Arc<dyn Command>,
|
crate command: Arc<dyn Command>,
|
||||||
crate args: Vec<Value>,
|
crate args: Args,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InternalCommand {
|
impl InternalCommand {
|
||||||
|
|
|
@ -4,11 +4,11 @@ use crate::object::Value;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.args.is_empty() {
|
if args.positional.is_empty() {
|
||||||
return Err(ShellError::string("select requires a field"));
|
return Err(ShellError::string("select requires a field"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
|
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||||
let fields = fields?;
|
let fields = fields?;
|
||||||
|
|
||||||
let objects = args
|
let objects = args
|
||||||
|
|
|
@ -7,20 +7,22 @@ use std::path::PathBuf;
|
||||||
pub struct CommandArgs {
|
pub struct CommandArgs {
|
||||||
pub host: Arc<Mutex<dyn Host + Send>>,
|
pub host: Arc<Mutex<dyn Host + Send>>,
|
||||||
pub env: Arc<Mutex<Environment>>,
|
pub env: Arc<Mutex<Environment>>,
|
||||||
pub args: Vec<Value>,
|
pub positional: Vec<Value>,
|
||||||
|
pub named: indexmap::IndexMap<String, Value>,
|
||||||
pub input: InputStream,
|
pub input: InputStream,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandArgs {
|
impl CommandArgs {
|
||||||
crate fn from_context(
|
crate fn from_context(
|
||||||
ctx: &'caller mut Context,
|
ctx: &'caller mut Context,
|
||||||
args: Vec<Value>,
|
positional: Vec<Value>,
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
) -> CommandArgs {
|
) -> CommandArgs {
|
||||||
CommandArgs {
|
CommandArgs {
|
||||||
host: ctx.host.clone(),
|
host: ctx.host.clone(),
|
||||||
env: ctx.env.clone(),
|
env: ctx.env.clone(),
|
||||||
args,
|
positional,
|
||||||
|
named: indexmap::IndexMap::default(),
|
||||||
input,
|
input,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
117
src/commands/config.rs
Normal file
117
src/commands/config.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::object::config;
|
||||||
|
use crate::object::Value;
|
||||||
|
use crate::parser::registry::{NamedType, NamedValue};
|
||||||
|
use crate::parser::CommandConfig;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use log::trace;
|
||||||
|
|
||||||
|
pub struct Config;
|
||||||
|
|
||||||
|
impl Command for Config {
|
||||||
|
fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
config(args)
|
||||||
|
}
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"config"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config(&self) -> CommandConfig {
|
||||||
|
let mut named: IndexMap<String, NamedType> = IndexMap::new();
|
||||||
|
named.insert("set".to_string(), NamedType::Optional(NamedValue::Tuple));
|
||||||
|
named.insert("get".to_string(), NamedType::Optional(NamedValue::Single));
|
||||||
|
named.insert("clear".to_string(), NamedType::Switch);
|
||||||
|
|
||||||
|
named.insert(
|
||||||
|
"remove".to_string(),
|
||||||
|
NamedType::Optional(NamedValue::Single),
|
||||||
|
);
|
||||||
|
|
||||||
|
CommandConfig {
|
||||||
|
name: self.name().to_string(),
|
||||||
|
mandatory_positional: vec![],
|
||||||
|
optional_positional: vec![],
|
||||||
|
rest_positional: false,
|
||||||
|
named,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
|
let mut result = crate::object::config::config()?;
|
||||||
|
|
||||||
|
trace!("{:#?}", args.positional);
|
||||||
|
trace!("{:#?}", args.named);
|
||||||
|
|
||||||
|
if let Some(v) = args.named.get("get") {
|
||||||
|
let key = v.as_string()?;
|
||||||
|
let value = result
|
||||||
|
.get(&key)
|
||||||
|
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
futures::stream::once(futures::future::ready(ReturnValue::Value(value.clone())))
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = args.named.get("set") {
|
||||||
|
if let Ok((key, value)) = v.as_pair() {
|
||||||
|
result.insert(key.as_string()?, value.clone());
|
||||||
|
|
||||||
|
config::write_config(&result)?;
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||||
|
result.into(),
|
||||||
|
))))
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(_) = args.named.get("clear") {
|
||||||
|
result.clear();
|
||||||
|
|
||||||
|
config::write_config(&result)?;
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||||
|
result.into(),
|
||||||
|
))))
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = args.named.get("remove") {
|
||||||
|
let key = v.as_string()?;
|
||||||
|
|
||||||
|
if result.contains_key(&key) {
|
||||||
|
result.remove(&key);
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::string(&format!(
|
||||||
|
"{} does not exist in config",
|
||||||
|
key
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||||
|
result.into(),
|
||||||
|
))))
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.positional.len() == 0 {
|
||||||
|
return Ok(
|
||||||
|
futures::stream::once(futures::future::ready(ReturnValue::Value(Value::Object(
|
||||||
|
result.into(),
|
||||||
|
))))
|
||||||
|
.boxed(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ShellError::string(format!("Unimplemented")))
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ use std::path::PathBuf;
|
||||||
pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
||||||
let mut full_path = PathBuf::from(cwd);
|
let mut full_path = PathBuf::from(cwd);
|
||||||
match &args.args[0] {
|
match &args.positional[0] {
|
||||||
Value::Primitive(Primitive::String(s)) => full_path.push(s),
|
Value::Primitive(Primitive::String(s)) => full_path.push(s),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,9 @@ pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let contents = std::fs::read_to_string(&full_path).unwrap();
|
let contents = std::fs::read_to_string(&full_path).unwrap();
|
||||||
|
|
||||||
let mut stream = VecDeque::new();
|
let mut stream = VecDeque::new();
|
||||||
stream.push_back(ReturnValue::Value(Value::Primitive(Primitive::String(contents))));
|
stream.push_back(ReturnValue::Value(Value::Primitive(Primitive::String(
|
||||||
|
contents,
|
||||||
|
))));
|
||||||
|
|
||||||
Ok(stream.boxed())
|
Ok(stream.boxed())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,11 @@ use crate::object::Value;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.args.is_empty() {
|
if args.positional.is_empty() {
|
||||||
return Err(ShellError::string("select requires a field"));
|
return Err(ShellError::string("select requires a field"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
|
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||||
let fields = fields?;
|
let fields = fields?;
|
||||||
|
|
||||||
let stream = args
|
let stream = args
|
||||||
|
|
|
@ -8,7 +8,10 @@ fn get_member(path: &str, obj: &Value) -> Option<Value> {
|
||||||
match current.get_data_by_key(p) {
|
match current.get_data_by_key(p) {
|
||||||
Some(v) => current = v,
|
Some(v) => current = v,
|
||||||
None => {
|
None => {
|
||||||
return Some(Value::Error(Box::new(ShellError::string(format!("Object field name not found: {}", p)))))
|
return Some(Value::Error(Box::new(ShellError::string(format!(
|
||||||
|
"Object field name not found: {}",
|
||||||
|
p
|
||||||
|
)))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +20,11 @@ fn get_member(path: &str, obj: &Value) -> Option<Value> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn select(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.args.is_empty() {
|
if args.positional.is_empty() {
|
||||||
return Err(ShellError::string("select requires a field"));
|
return Err(ShellError::string("select requires a field"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let fields: Result<Vec<String>, _> = args.args.iter().map(|a| a.as_string()).collect();
|
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||||
let fields = fields?;
|
let fields = fields?;
|
||||||
|
|
||||||
let stream = args
|
let stream = args
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
|
|
||||||
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.args.is_empty() {
|
if args.positional.is_empty() {
|
||||||
return Err(ShellError::string("size requires at least one file"));
|
return Err(ShellError::string("size requires at least one file"));
|
||||||
}
|
}
|
||||||
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
let cwd = args.env.lock().unwrap().cwd().to_path_buf();
|
||||||
|
@ -14,7 +14,7 @@ pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
|
||||||
let mut list = VecDeque::new();
|
let mut list = VecDeque::new();
|
||||||
for name in args.args {
|
for name in args.positional {
|
||||||
let name = name.as_string()?;
|
let name = name.as_string()?;
|
||||||
let path = cwd.join(&name);
|
let path = cwd.join(&name);
|
||||||
let mut file = File::open(path)?;
|
let mut file = File::open(path)?;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn skip(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn skip(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let amount = args.args[0].as_i64()?;
|
let amount = args.positional[0].as_i64()?;
|
||||||
|
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::errors::ShellError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let fields: Result<Vec<_>, _> = args.args.iter().map(|a| a.as_string()).collect();
|
let fields: Result<Vec<_>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||||
let fields = fields?;
|
let fields = fields?;
|
||||||
|
|
||||||
let output = args.input.collect::<Vec<_>>();
|
let output = args.input.collect::<Vec<_>>();
|
||||||
|
|
|
@ -7,7 +7,7 @@ use log::debug;
|
||||||
|
|
||||||
pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
let args = args.args;
|
let args = args.positional;
|
||||||
|
|
||||||
Ok(input
|
Ok(input
|
||||||
.map(move |v| match v {
|
.map(move |v| match v {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::prelude::*;
|
||||||
// TODO: "Amount remaining" wrapper
|
// TODO: "Amount remaining" wrapper
|
||||||
|
|
||||||
pub fn take(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn take(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let amount = args.args[0].as_i64()?;
|
let amount = args.positional[0].as_i64()?;
|
||||||
|
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::prelude::*;
|
||||||
use prettyprint::PrettyPrinter;
|
use prettyprint::PrettyPrinter;
|
||||||
|
|
||||||
pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn view(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
let target = match args.args.first() {
|
let target = match args.positional.first() {
|
||||||
// TODO: This needs better infra
|
// TODO: This needs better infra
|
||||||
None => return Err(ShellError::string(format!("cat must take one arg"))),
|
None => return Err(ShellError::string(format!("cat must take one arg"))),
|
||||||
Some(v) => v.as_string()?.clone(),
|
Some(v) => v.as_string()?.clone(),
|
||||||
|
|
|
@ -25,11 +25,11 @@ impl Command for Where {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
pub fn r#where(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||||
if args.args.is_empty() {
|
if args.positional.is_empty() {
|
||||||
return Err(ShellError::string("select requires a field"));
|
return Err(ShellError::string("select requires a field"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let block = args.args[0].as_block()?;
|
let block = args.positional[0].as_block()?;
|
||||||
let input = args.input;
|
let input = args.input;
|
||||||
|
|
||||||
let objects = input.filter_map(move |item| {
|
let objects = input.filter_map(move |item| {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::parser::{CommandConfig, CommandRegistry};
|
use crate::parser::{Args, CommandConfig, CommandRegistry};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
@ -47,13 +47,14 @@ impl Context {
|
||||||
crate fn run_command(
|
crate fn run_command(
|
||||||
&mut self,
|
&mut self,
|
||||||
command: Arc<dyn Command>,
|
command: Arc<dyn Command>,
|
||||||
arg_list: Vec<Value>,
|
args: Args,
|
||||||
input: InputStream,
|
input: InputStream,
|
||||||
) -> Result<OutputStream, ShellError> {
|
) -> Result<OutputStream, ShellError> {
|
||||||
let command_args = CommandArgs {
|
let command_args = CommandArgs {
|
||||||
host: self.host.clone(),
|
host: self.host.clone(),
|
||||||
env: self.env.clone(),
|
env: self.env.clone(),
|
||||||
args: arg_list,
|
positional: args.positional,
|
||||||
|
named: args.named,
|
||||||
input,
|
input,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
4
src/env/host.rs
vendored
4
src/env/host.rs
vendored
|
@ -1,7 +1,8 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use language_reporting::termcolor;
|
use language_reporting::termcolor;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub trait Host {
|
pub trait Host: Debug {
|
||||||
fn out_terminal(&self) -> Box<term::StdoutTerminal>;
|
fn out_terminal(&self) -> Box<term::StdoutTerminal>;
|
||||||
fn err_terminal(&self) -> Box<term::StderrTerminal>;
|
fn err_terminal(&self) -> Box<term::StderrTerminal>;
|
||||||
|
|
||||||
|
@ -38,6 +39,7 @@ impl Host for Box<dyn Host> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
crate struct BasicHost;
|
crate struct BasicHost;
|
||||||
|
|
||||||
impl Host for BasicHost {
|
impl Host for BasicHost {
|
||||||
|
|
|
@ -3,10 +3,10 @@ use crate::parser::lexer::{Span, SpannedToken};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use language_reporting::Diagnostic;
|
use language_reporting::Diagnostic;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_derive::Serialize;
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
|
||||||
pub enum ShellError {
|
pub enum ShellError {
|
||||||
String(StringError),
|
String(StringError),
|
||||||
Diagnostic(ShellDiagnostic, String),
|
Diagnostic(ShellDiagnostic, String),
|
||||||
|
@ -85,7 +85,20 @@ impl Serialize for ShellDiagnostic {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new, Clone, Serialize)]
|
impl Deserialize<'de> for ShellDiagnostic {
|
||||||
|
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(ShellDiagnostic {
|
||||||
|
diagnostic: Diagnostic::new(
|
||||||
|
language_reporting::Severity::Error,
|
||||||
|
"deserialize not implemented for ShellDiagnostic",
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new, Clone, Serialize, Deserialize)]
|
||||||
pub struct StringError {
|
pub struct StringError {
|
||||||
title: String,
|
title: String,
|
||||||
error: Value,
|
error: Value,
|
||||||
|
@ -137,3 +150,12 @@ impl std::convert::From<nom::Err<(&str, nom::error::ErrorKind)>> for ShellError
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<toml::ser::Error> for ShellError {
|
||||||
|
fn from(input: toml::ser::Error) -> ShellError {
|
||||||
|
ShellError::String(StringError {
|
||||||
|
title: format!("{:?}", input),
|
||||||
|
error: Value::nothing(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -47,8 +47,6 @@ fn evaluate_reference(r: &ast::Variable, scope: &Scope) -> Result<Value, ShellEr
|
||||||
|
|
||||||
match r {
|
match r {
|
||||||
It => Ok(scope.it.copy()),
|
It => Ok(scope.it.copy()),
|
||||||
True => Ok(Value::boolean(true)),
|
|
||||||
False => Ok(Value::boolean(false)),
|
|
||||||
Other(s) => Err(ShellError::string(&format!(
|
Other(s) => Err(ShellError::string(&format!(
|
||||||
"Unimplemented variable reference: {}",
|
"Unimplemented variable reference: {}",
|
||||||
s
|
s
|
||||||
|
|
|
@ -24,6 +24,10 @@ impl TableView {
|
||||||
let item = &values[0];
|
let item = &values[0];
|
||||||
let descs = item.data_descriptors();
|
let descs = item.data_descriptors();
|
||||||
|
|
||||||
|
if descs.len() == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let headers: Vec<String> = descs.iter().map(|d| d.name.display().to_string()).collect();
|
let headers: Vec<String> = descs.iter().map(|d| d.name.display().to_string()).collect();
|
||||||
|
|
||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
crate mod base;
|
crate mod base;
|
||||||
|
crate mod config;
|
||||||
crate mod desc;
|
crate mod desc;
|
||||||
crate mod dict;
|
crate mod dict;
|
||||||
crate mod files;
|
crate mod files;
|
||||||
crate mod process;
|
crate mod process;
|
||||||
|
crate mod serialization;
|
||||||
crate mod types;
|
crate mod types;
|
||||||
|
|
||||||
crate use base::{Primitive, Value};
|
crate use base::{Primitive, Value};
|
||||||
|
|
|
@ -10,12 +10,27 @@ use derive_new::new;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde_derive::Serialize;
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
type OF64 = OrderedFloat<f64>;
|
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, new)]
|
||||||
|
pub struct OF64 {
|
||||||
|
crate inner: OrderedFloat<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
impl OF64 {
|
||||||
|
crate fn into_inner(&self) -> f64 {
|
||||||
|
self.inner.into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f64> for OF64 {
|
||||||
|
fn from(float: f64) -> Self {
|
||||||
|
OF64::new(OrderedFloat(float))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Deserialize)]
|
||||||
pub enum Primitive {
|
pub enum Primitive {
|
||||||
Nothing,
|
Nothing,
|
||||||
Int(i64),
|
Int(i64),
|
||||||
|
@ -35,7 +50,7 @@ impl Serialize for Primitive {
|
||||||
match self {
|
match self {
|
||||||
Primitive::Nothing => serializer.serialize_i32(0),
|
Primitive::Nothing => serializer.serialize_i32(0),
|
||||||
Primitive::Int(i) => serializer.serialize_i64(*i),
|
Primitive::Int(i) => serializer.serialize_i64(*i),
|
||||||
Primitive::Float(f) => serializer.serialize_f64(f.into_inner()),
|
Primitive::Float(OF64 { inner: f }) => serializer.serialize_f64(f.into_inner()),
|
||||||
Primitive::Bytes(b) => serializer.serialize_u128(*b),
|
Primitive::Bytes(b) => serializer.serialize_u128(*b),
|
||||||
Primitive::String(ref s) => serializer.serialize_str(s),
|
Primitive::String(ref s) => serializer.serialize_str(s),
|
||||||
Primitive::Boolean(b) => serializer.serialize_bool(*b),
|
Primitive::Boolean(b) => serializer.serialize_bool(*b),
|
||||||
|
@ -63,7 +78,7 @@ impl Primitive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Primitive::Int(i) => format!("{}", i),
|
Primitive::Int(i) => format!("{}", i),
|
||||||
Primitive::Float(f) => format!("{:.*}", 2, f.into_inner()),
|
Primitive::Float(OF64 { inner: f }) => format!("{:.*}", 2, f.into_inner()),
|
||||||
Primitive::String(s) => format!("{}", s),
|
Primitive::String(s) => format!("{}", s),
|
||||||
Primitive::Boolean(b) => match (b, field_name) {
|
Primitive::Boolean(b) => match (b, field_name) {
|
||||||
(true, None) => format!("Yes"),
|
(true, None) => format!("Yes"),
|
||||||
|
@ -97,6 +112,17 @@ impl Serialize for Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deserialize<'de> for Block {
|
||||||
|
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(Block::new(ast::Expression::Leaf(ast::Leaf::String(
|
||||||
|
format!("Unserializable block"),
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn invoke(&self, value: &Value) -> Result<Value, ShellError> {
|
pub fn invoke(&self, value: &Value) -> Result<Value, ShellError> {
|
||||||
let scope = Scope::new(value.copy());
|
let scope = Scope::new(value.copy());
|
||||||
|
@ -115,21 +141,6 @@ pub enum Value {
|
||||||
Error(Box<ShellError>),
|
Error(Box<ShellError>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Value {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Value::Primitive(p) => p.serialize(serializer),
|
|
||||||
Value::Object(o) => o.serialize(serializer),
|
|
||||||
Value::List(l) => l.serialize(serializer),
|
|
||||||
Value::Block(b) => b.serialize(serializer),
|
|
||||||
Value::Error(e) => e.serialize(serializer),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
crate fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
crate fn data_descriptors(&self) -> Vec<DataDescriptor> {
|
||||||
match self {
|
match self {
|
||||||
|
@ -207,6 +218,24 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
crate fn is_string(&self, expected: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
Value::Primitive(Primitive::String(s)) if s == expected => true,
|
||||||
|
other => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn as_pair(&self) -> Result<(Value, Value), ShellError> {
|
||||||
|
match self {
|
||||||
|
Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
|
||||||
|
other => Err(ShellError::string(format!(
|
||||||
|
"Expected pair, got {:?}",
|
||||||
|
other
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crate fn as_string(&self) -> Result<String, ShellError> {
|
crate fn as_string(&self) -> Result<String, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Primitive(Primitive::String(s)) => Ok(s.to_string()),
|
Value::Primitive(Primitive::String(s)) => Ok(s.to_string()),
|
||||||
|
@ -280,8 +309,7 @@ impl Value {
|
||||||
Value::Primitive(Primitive::Float(s.into()))
|
Value::Primitive(Primitive::Float(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
crate fn boolean(s: impl Into<bool>) -> Value {
|
||||||
crate fn bool(s: impl Into<bool>) -> Value {
|
|
||||||
Value::Primitive(Primitive::Boolean(s.into()))
|
Value::Primitive(Primitive::Boolean(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,6 +317,16 @@ impl Value {
|
||||||
Value::Primitive(Primitive::Date(s.into()))
|
Value::Primitive(Primitive::Date(s.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
crate fn date_from_str(s: &str) -> Result<Value, ShellError> {
|
||||||
|
let date = DateTime::parse_from_rfc3339(s)
|
||||||
|
.map_err(|err| ShellError::string(&format!("Date parse error: {}", err)))?;
|
||||||
|
|
||||||
|
let date = date.with_timezone(&chrono::offset::Utc);
|
||||||
|
|
||||||
|
Ok(Value::Primitive(Primitive::Date(date)))
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
crate fn system_date_result(s: Result<SystemTime, std::io::Error>) -> Value {
|
crate fn system_date_result(s: Result<SystemTime, std::io::Error>) -> Value {
|
||||||
match s {
|
match s {
|
||||||
|
@ -297,10 +335,6 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn boolean(s: impl Into<bool>) -> Value {
|
|
||||||
Value::Primitive(Primitive::Boolean(s.into()))
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn nothing() -> Value {
|
crate fn nothing() -> Value {
|
||||||
Value::Primitive(Primitive::Nothing)
|
Value::Primitive(Primitive::Nothing)
|
||||||
}
|
}
|
||||||
|
|
60
src/object/config.rs
Normal file
60
src/object/config.rs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use app_dirs::*;
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
use log::trace;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::fs::{self, OpenOptions};
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
const APP_INFO: AppInfo = AppInfo {
|
||||||
|
name: "nu",
|
||||||
|
author: "nu shell developers",
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct Config {
|
||||||
|
#[serde(flatten)]
|
||||||
|
extra: IndexMap<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn write_config(map: &IndexMap<String, Value>) -> Result<(), ShellError> {
|
||||||
|
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||||
|
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||||
|
|
||||||
|
let filename = location.join("config.toml");
|
||||||
|
touch(&filename)?;
|
||||||
|
|
||||||
|
let contents = toml::to_string(&Config { extra: map.clone() })?;
|
||||||
|
|
||||||
|
fs::write(&filename, &contents)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn config() -> Result<IndexMap<String, Value>, ShellError> {
|
||||||
|
let location = app_root(AppDataType::UserConfig, &APP_INFO)
|
||||||
|
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
|
||||||
|
|
||||||
|
let filename = location.join("config.toml");
|
||||||
|
touch(&filename)?;
|
||||||
|
|
||||||
|
trace!("config file = {}", filename.display());
|
||||||
|
|
||||||
|
let contents = fs::read_to_string(filename)
|
||||||
|
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
|
||||||
|
|
||||||
|
let parsed: Config = toml::from_str(&contents)
|
||||||
|
.map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
|
||||||
|
|
||||||
|
Ok(parsed.extra)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A simple implementation of `% touch path` (ignores existing files)
|
||||||
|
fn touch(path: &Path) -> io::Result<()> {
|
||||||
|
match OpenOptions::new().create(true).write(true).open(path) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::object::types::{AnyShell, Type};
|
use crate::object::types::Type;
|
||||||
use derive_new::new;
|
use derive_new::new;
|
||||||
use serde::{Serialize, Serializer};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
|
||||||
pub enum DescriptorName {
|
pub enum DescriptorName {
|
||||||
String(String),
|
String(String),
|
||||||
ValueOf,
|
ValueOf,
|
||||||
|
@ -31,23 +31,11 @@ impl DescriptorName {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, new)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash, new)]
|
||||||
pub struct DataDescriptor {
|
pub struct DataDescriptor {
|
||||||
crate name: DescriptorName,
|
crate name: DescriptorName,
|
||||||
crate readonly: bool,
|
crate readonly: bool,
|
||||||
crate ty: Box<dyn Type>,
|
crate ty: Type,
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for DataDescriptor {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
match self.name {
|
|
||||||
DescriptorName::String(ref s) => serializer.serialize_str(s),
|
|
||||||
DescriptorName::ValueOf => serializer.serialize_str("value_of")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for DataDescriptor {
|
impl From<&str> for DataDescriptor {
|
||||||
|
@ -55,7 +43,7 @@ impl From<&str> for DataDescriptor {
|
||||||
DataDescriptor {
|
DataDescriptor {
|
||||||
name: DescriptorName::String(input.to_string()),
|
name: DescriptorName::String(input.to_string()),
|
||||||
readonly: true,
|
readonly: true,
|
||||||
ty: Box::new(AnyShell),
|
ty: Type::Any,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,49 +53,23 @@ impl From<String> for DataDescriptor {
|
||||||
DataDescriptor {
|
DataDescriptor {
|
||||||
name: DescriptorName::String(input),
|
name: DescriptorName::String(input),
|
||||||
readonly: true,
|
readonly: true,
|
||||||
ty: Box::new(AnyShell),
|
ty: Type::Any,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for DataDescriptor {
|
|
||||||
fn eq(&self, other: &DataDescriptor) -> bool {
|
|
||||||
self.name == other.name && self.readonly == other.readonly && self.ty.equal(&*other.ty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::hash::Hash for DataDescriptor {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.name.hash(state);
|
|
||||||
self.readonly.hash(state);
|
|
||||||
self.ty.id().hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for DataDescriptor {}
|
|
||||||
|
|
||||||
impl DescriptorName {
|
impl DescriptorName {
|
||||||
crate fn for_string_name(name: impl Into<String>) -> DescriptorName {
|
crate fn for_string_name(name: impl Into<String>) -> DescriptorName {
|
||||||
DescriptorName::String(name.into())
|
DescriptorName::String(name.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for DataDescriptor {
|
|
||||||
fn clone(&self) -> DataDescriptor {
|
|
||||||
DataDescriptor {
|
|
||||||
name: self.name.clone(),
|
|
||||||
readonly: self.readonly,
|
|
||||||
ty: self.ty.copy(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DataDescriptor {
|
impl DataDescriptor {
|
||||||
crate fn value_of() -> DataDescriptor {
|
crate fn value_of() -> DataDescriptor {
|
||||||
DataDescriptor {
|
DataDescriptor {
|
||||||
name: DescriptorName::ValueOf,
|
name: DescriptorName::ValueOf,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
ty: Box::new(AnyShell),
|
ty: Type::Any,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +77,7 @@ impl DataDescriptor {
|
||||||
DataDescriptor {
|
DataDescriptor {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
readonly: true,
|
readonly: true,
|
||||||
ty: Box::new(AnyShell),
|
ty: Type::Any,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,10 +86,6 @@ impl DataDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn copy(&self) -> DataDescriptor {
|
crate fn copy(&self) -> DataDescriptor {
|
||||||
DataDescriptor {
|
self.clone()
|
||||||
name: self.name.clone(),
|
|
||||||
readonly: self.readonly,
|
|
||||||
ty: self.ty.copy(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,28 +2,16 @@ use crate::prelude::*;
|
||||||
|
|
||||||
use crate::object::DataDescriptor;
|
use crate::object::DataDescriptor;
|
||||||
use crate::object::{Primitive, Value};
|
use crate::object::{Primitive, Value};
|
||||||
|
use derive_new::new;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use serde::ser::{Serialize, Serializer, SerializeMap};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::cmp::{Ordering, PartialOrd};
|
use std::cmp::{Ordering, PartialOrd};
|
||||||
|
|
||||||
#[derive(Debug, Default, Eq, PartialEq, Clone)]
|
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)]
|
||||||
pub struct Dictionary {
|
pub struct Dictionary {
|
||||||
entries: IndexMap<DataDescriptor, Value>,
|
entries: IndexMap<DataDescriptor, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Dictionary {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let mut map = serializer.serialize_map(Some(self.entries.len()))?;
|
|
||||||
for (k, v) in &self.entries {
|
|
||||||
map.serialize_entry(&k, &v)?;
|
|
||||||
}
|
|
||||||
map.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialOrd for Dictionary {
|
impl PartialOrd for Dictionary {
|
||||||
// TODO: FIXME
|
// TODO: FIXME
|
||||||
fn partial_cmp(&self, _other: &Dictionary) -> Option<Ordering> {
|
fn partial_cmp(&self, _other: &Dictionary) -> Option<Ordering> {
|
||||||
|
@ -31,6 +19,18 @@ impl PartialOrd for Dictionary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<IndexMap<String, Value>> for Dictionary {
|
||||||
|
fn from(input: IndexMap<String, Value>) -> Dictionary {
|
||||||
|
let mut out = IndexMap::default();
|
||||||
|
|
||||||
|
for (key, value) in input {
|
||||||
|
out.insert(DataDescriptor::for_string_name(key), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::new(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Ord for Dictionary {
|
impl Ord for Dictionary {
|
||||||
// TODO: FIXME
|
// TODO: FIXME
|
||||||
fn cmp(&self, _other: &Dictionary) -> Ordering {
|
fn cmp(&self, _other: &Dictionary) -> Ordering {
|
||||||
|
|
111
src/object/serialization.rs
Normal file
111
src/object/serialization.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
use crate::object::base::OF64;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use ordered_float::OrderedFloat;
|
||||||
|
use serde::de::{self, Visitor};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
struct OF64Visitor;
|
||||||
|
|
||||||
|
impl Visitor<'_> for OF64Visitor {
|
||||||
|
type Value = OF64;
|
||||||
|
|
||||||
|
fn visit_f64<E>(self, value: f64) -> Result<OF64, E> {
|
||||||
|
Ok(OF64::new(OrderedFloat(value)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_f32<E>(self, value: f32) -> Result<OF64, E> {
|
||||||
|
Ok(OF64::new(OrderedFloat(value as f64)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a float")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for OF64 {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<OF64, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_f64(OF64Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Value {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Value::Primitive(p) => p.serialize(serializer),
|
||||||
|
Value::Object(o) => o.serialize(serializer),
|
||||||
|
Value::List(l) => l.serialize(serializer),
|
||||||
|
Value::Block(b) => b.serialize(serializer),
|
||||||
|
Value::Error(e) => e.serialize(serializer),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ValueVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for ValueVisitor {
|
||||||
|
type Value = Value;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a shell value")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i32<E>(self, value: i32) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Value::int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Value::int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u32<E>(self, value: u32) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Value::int(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
// TODO: Handle overflow better
|
||||||
|
Ok(Value::int(value as i64))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Value::string(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
Ok(Value::boolean(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Value {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Value, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_any(ValueVisitor)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,7 @@
|
||||||
use std::any::Any;
|
use derive_new::new;
|
||||||
use std::fmt::Debug;
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub trait Type: Debug + Send {
|
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash, new)]
|
||||||
fn as_any(&self) -> &dyn Any;
|
pub enum Type {
|
||||||
fn equal(&self, other: &dyn Type) -> bool;
|
Any,
|
||||||
fn id(&self) -> u64;
|
|
||||||
fn copy(&self) -> Box<Type>;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
|
||||||
pub struct AnyShell;
|
|
||||||
|
|
||||||
impl Type for AnyShell {
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self as &dyn Any
|
|
||||||
}
|
|
||||||
|
|
||||||
fn equal(&self, other: &dyn Type) -> bool {
|
|
||||||
other.as_any().is::<AnyShell>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy(&self) -> Box<Type> {
|
|
||||||
Box::new(AnyShell)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ crate mod registry;
|
||||||
crate mod span;
|
crate mod span;
|
||||||
|
|
||||||
crate use ast::{ParsedCommand, Pipeline};
|
crate use ast::{ParsedCommand, Pipeline};
|
||||||
crate use registry::{CommandConfig, CommandRegistry};
|
crate use registry::{Args, CommandConfig, CommandRegistry};
|
||||||
|
|
||||||
use crate::errors::ShellError;
|
use crate::errors::ShellError;
|
||||||
use lexer::Lexer;
|
use lexer::Lexer;
|
||||||
|
|
|
@ -85,6 +85,13 @@ impl Expression {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn is_flag(&self, value: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
Expression::Flag(Flag::Longhand(f)) if value == f => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
|
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, new)]
|
||||||
|
@ -151,17 +158,22 @@ impl Path {
|
||||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub enum Variable {
|
pub enum Variable {
|
||||||
It,
|
It,
|
||||||
True,
|
|
||||||
False,
|
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Variable {
|
impl Variable {
|
||||||
|
crate fn from_str(input: &str) -> Expression {
|
||||||
|
match input {
|
||||||
|
"it" => Expression::VariableReference(Variable::It),
|
||||||
|
"true" => Expression::Leaf(Leaf::Boolean(true)),
|
||||||
|
"false" => Expression::Leaf(Leaf::Boolean(false)),
|
||||||
|
other => Expression::VariableReference(Variable::Other(other.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn print(&self) -> String {
|
fn print(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Variable::It => format!("$it"),
|
Variable::It => format!("$it"),
|
||||||
Variable::True => format!("$true"),
|
|
||||||
Variable::False => format!("$false"),
|
|
||||||
Variable::Other(s) => format!("${}", s),
|
Variable::Other(s) => format!("${}", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,18 +183,6 @@ impl Variable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Variable {
|
|
||||||
type Err = ();
|
|
||||||
fn from_str(input: &str) -> Result<Self, <Self as std::str::FromStr>::Err> {
|
|
||||||
Ok(match input {
|
|
||||||
"it" => Variable::It,
|
|
||||||
"true" => Variable::True,
|
|
||||||
"false" => Variable::False,
|
|
||||||
other => Variable::Other(other.to_string()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||||
pub struct BarePath {
|
pub struct BarePath {
|
||||||
head: String,
|
head: String,
|
||||||
|
|
|
@ -65,8 +65,8 @@ Expr: Expression = {
|
||||||
<PathHead>
|
<PathHead>
|
||||||
}
|
}
|
||||||
|
|
||||||
Variable: Variable = {
|
Variable: Expression = {
|
||||||
"$" <"variable"> => Variable::from_str(<>.as_slice()).unwrap(),
|
"$" <"variable"> => Variable::from_str(<>.as_slice()),
|
||||||
}
|
}
|
||||||
|
|
||||||
Member: String = {
|
Member: String = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// auto-generated: "lalrpop 0.17.0"
|
// auto-generated: "lalrpop 0.17.0"
|
||||||
// sha256: efaf89a1d956869b47a3f5daff048341c19934c68ad5e1ed9fe8e5c4222d2
|
// sha256: 327a2eaaded6615e365add5d44719ae0dd3217f5b0fc3ba130f052328c2bd439
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use crate::parser::ast::*;
|
use crate::parser::ast::*;
|
||||||
|
@ -41,7 +41,6 @@ mod __parse__Pipeline {
|
||||||
Variant10(i64),
|
Variant10(i64),
|
||||||
Variant11(Operator),
|
Variant11(Operator),
|
||||||
Variant12(Pipeline),
|
Variant12(Pipeline),
|
||||||
Variant13(Variable),
|
|
||||||
}
|
}
|
||||||
const __ACTION: &'static [i8] = &[
|
const __ACTION: &'static [i8] = &[
|
||||||
// State 0
|
// State 0
|
||||||
|
@ -1364,17 +1363,6 @@ mod __parse__Pipeline {
|
||||||
_ => panic!("symbol type mismatch")
|
_ => panic!("symbol type mismatch")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn __pop_Variant13<
|
|
||||||
'input,
|
|
||||||
>(
|
|
||||||
__symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>
|
|
||||||
) -> (usize, Variable, usize)
|
|
||||||
{
|
|
||||||
match __symbols.pop().unwrap() {
|
|
||||||
(__l, __Symbol::Variant13(__v), __r) => (__l, __v, __r),
|
|
||||||
_ => panic!("symbol type mismatch")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn __pop_Variant10<
|
fn __pop_Variant10<
|
||||||
'input,
|
'input,
|
||||||
>(
|
>(
|
||||||
|
@ -2022,7 +2010,7 @@ mod __parse__Pipeline {
|
||||||
) -> (usize, usize)
|
) -> (usize, usize)
|
||||||
{
|
{
|
||||||
// Leaf = Variable => ActionFn(9);
|
// Leaf = Variable => ActionFn(9);
|
||||||
let __sym0 = __pop_Variant13(__symbols);
|
let __sym0 = __pop_Variant6(__symbols);
|
||||||
let __start = __sym0.0.clone();
|
let __start = __sym0.0.clone();
|
||||||
let __end = __sym0.2.clone();
|
let __end = __sym0.2.clone();
|
||||||
let __nt = super::__action9::<>(__sym0);
|
let __nt = super::__action9::<>(__sym0);
|
||||||
|
@ -2393,7 +2381,7 @@ mod __parse__Pipeline {
|
||||||
let __start = __sym0.0.clone();
|
let __start = __sym0.0.clone();
|
||||||
let __end = __sym1.2.clone();
|
let __end = __sym1.2.clone();
|
||||||
let __nt = super::__action25::<>(__sym0, __sym1);
|
let __nt = super::__action25::<>(__sym0, __sym1);
|
||||||
__symbols.push((__start, __Symbol::Variant13(__nt), __end));
|
__symbols.push((__start, __Symbol::Variant6(__nt), __end));
|
||||||
(2, 25)
|
(2, 25)
|
||||||
}
|
}
|
||||||
pub(crate) fn __reduce52<
|
pub(crate) fn __reduce52<
|
||||||
|
@ -2522,7 +2510,7 @@ fn __action8<
|
||||||
fn __action9<
|
fn __action9<
|
||||||
'input,
|
'input,
|
||||||
>(
|
>(
|
||||||
(_, __0, _): (usize, Variable, usize),
|
(_, __0, _): (usize, Expression, usize),
|
||||||
) -> Expression
|
) -> Expression
|
||||||
{
|
{
|
||||||
Expression::VariableReference(__0)
|
Expression::VariableReference(__0)
|
||||||
|
@ -2679,9 +2667,9 @@ fn __action25<
|
||||||
>(
|
>(
|
||||||
(_, _, _): (usize, SpannedToken<'input>, usize),
|
(_, _, _): (usize, SpannedToken<'input>, usize),
|
||||||
(_, __0, _): (usize, SpannedToken<'input>, usize),
|
(_, __0, _): (usize, SpannedToken<'input>, usize),
|
||||||
) -> Variable
|
) -> Expression
|
||||||
{
|
{
|
||||||
Variable::from_str(__0.as_slice()).unwrap()
|
Variable::from_str(__0.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __action26<
|
fn __action26<
|
||||||
|
|
|
@ -5,10 +5,21 @@ use indexmap::IndexMap;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum NamedType {
|
pub enum NamedType {
|
||||||
Switch(String),
|
Switch,
|
||||||
Single(String),
|
Mandatory(NamedValue),
|
||||||
Array(String),
|
Optional(NamedValue),
|
||||||
Block(String),
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum NamedValue {
|
||||||
|
Single,
|
||||||
|
Tuple,
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
Block,
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
Array,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -62,13 +73,55 @@ pub struct CommandConfig {
|
||||||
crate named: IndexMap<String, NamedType>,
|
crate named: IndexMap<String, NamedType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Args {
|
||||||
|
pub positional: Vec<Value>,
|
||||||
|
pub named: IndexMap<String, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
impl CommandConfig {
|
impl CommandConfig {
|
||||||
crate fn evaluate_args(
|
crate fn evaluate_args(
|
||||||
&self,
|
&self,
|
||||||
mut args: impl Iterator<Item = &'expr ast::Expression>,
|
args: impl Iterator<Item = &'expr ast::Expression>,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
) -> Result<Vec<Value>, ShellError> {
|
) -> Result<Args, ShellError> {
|
||||||
let mut results: Vec<Value> = vec![];
|
let mut positional: Vec<Value> = vec![];
|
||||||
|
let mut named: IndexMap<String, Value> = IndexMap::default();
|
||||||
|
|
||||||
|
let mut args: Vec<ast::Expression> = args.cloned().collect();
|
||||||
|
|
||||||
|
for (key, ty) in self.named.iter() {
|
||||||
|
let index = args.iter().position(|a| a.is_flag(&key));
|
||||||
|
|
||||||
|
match (index, ty) {
|
||||||
|
(Some(i), NamedType::Switch) => {
|
||||||
|
args.remove(i);
|
||||||
|
named.insert(key.clone(), Value::boolean(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, NamedType::Switch) => {}
|
||||||
|
|
||||||
|
(Some(i), NamedType::Optional(v)) => {
|
||||||
|
args.remove(i);
|
||||||
|
named.insert(key.clone(), extract_named(&mut args, i, v)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, NamedType::Optional(_)) => {}
|
||||||
|
|
||||||
|
(Some(i), NamedType::Mandatory(v)) => {
|
||||||
|
args.remove(i);
|
||||||
|
named.insert(key.clone(), extract_named(&mut args, i, v)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
(None, NamedType::Mandatory(_)) => {
|
||||||
|
return Err(ShellError::string(&format!(
|
||||||
|
"Expected mandatory argument {}, but it was missing",
|
||||||
|
key
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut args = args.into_iter();
|
||||||
|
|
||||||
for param in &self.mandatory_positional {
|
for param in &self.mandatory_positional {
|
||||||
let arg = args.next();
|
let arg = args.next();
|
||||||
|
@ -84,21 +137,25 @@ impl CommandConfig {
|
||||||
Some(arg) => param.evaluate(arg.clone(), scope)?,
|
Some(arg) => param.evaluate(arg.clone(), scope)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
results.push(value);
|
positional.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.rest_positional {
|
if self.rest_positional {
|
||||||
let rest: Result<Vec<Value>, _> =
|
let rest: Result<Vec<Value>, _> =
|
||||||
args.map(|i| evaluate_expr(i, &Scope::empty())).collect();
|
args.map(|i| evaluate_expr(&i, &Scope::empty())).collect();
|
||||||
results.extend(rest?);
|
positional.extend(rest?);
|
||||||
} else {
|
} else {
|
||||||
match args.next() {
|
let rest: Vec<ast::Expression> = args.collect();
|
||||||
None => {}
|
|
||||||
Some(_) => return Err(ShellError::string("Too many arguments")),
|
if rest.len() > 0 {
|
||||||
|
return Err(ShellError::string(&format!(
|
||||||
|
"Too many arguments, extras: {:?}",
|
||||||
|
rest
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(results)
|
Ok(Args { positional, named })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -107,6 +164,49 @@ impl CommandConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_named(
|
||||||
|
v: &mut Vec<ast::Expression>,
|
||||||
|
position: usize,
|
||||||
|
ty: &NamedValue,
|
||||||
|
) -> Result<Value, ShellError> {
|
||||||
|
match ty {
|
||||||
|
NamedValue::Single => {
|
||||||
|
let expr = v.remove(position);
|
||||||
|
expect_simple_expr(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValue::Tuple => {
|
||||||
|
let expr = v.remove(position);
|
||||||
|
let next = v.remove(position);
|
||||||
|
|
||||||
|
let list = vec![expect_simple_expr(expr)?, expect_simple_expr(next)?];
|
||||||
|
Ok(Value::List(list))
|
||||||
|
}
|
||||||
|
|
||||||
|
other => Err(ShellError::string(&format!(
|
||||||
|
"Unimplemented named argument {:?}",
|
||||||
|
other
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expect_simple_expr(expr: ast::Expression) -> Result<Value, ShellError> {
|
||||||
|
match expr {
|
||||||
|
ast::Expression::Leaf(l) => Ok(match l {
|
||||||
|
ast::Leaf::Bare(s) => Value::string(s.to_string()),
|
||||||
|
ast::Leaf::String(s) => Value::string(s),
|
||||||
|
ast::Leaf::Boolean(b) => Value::boolean(b),
|
||||||
|
ast::Leaf::Int(i) => Value::int(i),
|
||||||
|
}),
|
||||||
|
|
||||||
|
// TODO: Diagnostic
|
||||||
|
other => Err(ShellError::string(&format!(
|
||||||
|
"Expected a value, found {}",
|
||||||
|
other.print()
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait CommandRegistry {
|
pub trait CommandRegistry {
|
||||||
fn get(&self, name: &str) -> CommandConfig;
|
fn get(&self, name: &str) -> CommandConfig;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue