diff options
-rw-r--r-- | Cargo.lock | 468 | ||||
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | build.rs | 8 | ||||
-rw-r--r-- | src/commandline.lalrpop | 66 | ||||
-rw-r--r-- | src/error.rs | 42 | ||||
-rw-r--r-- | src/main.rs | 106 | ||||
-rw-r--r-- | src/path.rs | 319 | ||||
-rw-r--r-- | src/path/error.rs | 79 | ||||
-rw-r--r-- | src/path/parser.lalrpop | 92 | ||||
-rw-r--r-- | src/path/prelude.rs | 5 |
10 files changed, 16 insertions, 1178 deletions
diff --git a/Cargo.lock b/Cargo.lock index 66608c8..d6617b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,45 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "aho-corasick" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" -dependencies = [ - "memchr", -] - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" - -[[package]] -name = "ascii-canvas" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8eb72df928aafb99fe5d37b383f2fe25bd2a765e3e5f7c365916b6f2463a29" -dependencies = [ - "term", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] +version = 3 [[package]] name = "autocfg" @@ -48,77 +9,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" - -[[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "blake2b_simd" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] name = "bytes" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -143,114 +39,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "lazy_static", -] - -[[package]] -name = "diff" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "docopt" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f525a586d310c87df72ebcd98009e57f1cc030c8c268305287a476beb653969" -dependencies = [ - "lazy_static", - "regex", - "serde", - "strsim", -] - -[[package]] -name = "either" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" - -[[package]] -name = "ena" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" -dependencies = [ - "log", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fixedbitset" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "getrandom" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" - -[[package]] name = "hermit-abi" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -260,16 +48,6 @@ dependencies = [ ] [[package]] -name = "indexmap" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -279,61 +57,22 @@ dependencies = [ ] [[package]] -name = "itertools" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" -dependencies = [ - "either", -] - -[[package]] -name = "lalrpop" -version = "0.19.1" +name = "libc" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60fb56191fb8ed5311597e5750debe6779c9fdb487dbaa5ff302592897d7a2c8" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "docopt", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "regex", - "regex-syntax", - "serde", - "serde_derive", - "sha2", - "string_cache", - "term", - "unicode-xid", -] +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" [[package]] -name = "lalrpop-util" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6771161eff561647fad8bb7e745e002c304864fb8f436b52b30acda51fca4408" +name = "line-input" +version = "0.1.0" dependencies = [ - "regex", + "nix", + "pin-project", + "pin-utils", + "tokio", ] [[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" - -[[package]] name = "lock_api" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -380,12 +119,6 @@ dependencies = [ ] [[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] name = "nix" version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -423,12 +156,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] name = "parking_lot" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -448,31 +175,12 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall 0.2.8", + "redox_syscall", "smallvec", "winapi", ] [[package]] -name = "petgraph" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] name = "pin-project" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -505,12 +213,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] name = "proc-macro2" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -530,12 +232,6 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" @@ -544,97 +240,12 @@ dependencies = [ ] [[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom", - "redox_syscall 0.1.57", - "rust-argon2", -] - -[[package]] -name = "regex" -version = "1.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", - "thread_local", -] - -[[package]] -name = "regex-syntax" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" - -[[package]] -name = "rust-argon2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - -[[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "serde" -version = "1.0.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "shell" -version = "0.1.0" -dependencies = [ - "lalrpop", - "lalrpop-util", - "nix", - "pin-project", - "pin-utils", - "tokio", -] - -[[package]] name = "signal-hook-registry" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -644,37 +255,12 @@ dependencies = [ ] [[package]] -name = "siphasher" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" - -[[package]] name = "smallvec" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] -name = "string_cache" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a" -dependencies = [ - "lazy_static", - "new_debug_unreachable", - "phf_shared", - "precomputed-hash", - "serde", -] - -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - -[[package]] name = "syn" version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -686,26 +272,6 @@ dependencies = [ ] [[package]] -name = "term" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" -dependencies = [ - "byteorder", - "dirs", - "winapi", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - -[[package]] name = "tokio" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -737,24 +303,12 @@ dependencies = [ ] [[package]] -name = "typenum" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" - -[[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index a366077..21e43da 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ -[lib] +[package] name = "line-input" version = "0.1.0" authors = ["Irene Knapp <ireneista@gmail.com>"] -edition = "2018" +edition = "2021" +publish = false [dependencies] #futures = "0.3" -lalrpop-util = "0.19" nix = "0.19" pin-project = "1.0.4" pin-utils = "0.1.0" @@ -14,6 +14,3 @@ pin-utils = "0.1.0" [dependencies.tokio] version = "1.6.1" features = [ "full" ] - -[build-dependencies] -lalrpop = { version = "0.19", features = [ "lexer" ] } diff --git a/build.rs b/build.rs deleted file mode 100644 index 84151bf..0000000 --- a/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -extern crate lalrpop; - -fn main() { - let mut lalrpop = lalrpop::Configuration::new(); - lalrpop.emit_rerun_directives(true); - lalrpop.use_cargo_dir_conventions(); - lalrpop.process().unwrap(); -} diff --git a/src/commandline.lalrpop b/src/commandline.lalrpop deleted file mode 100644 index d52e741..0000000 --- a/src/commandline.lalrpop +++ /dev/null @@ -1,66 +0,0 @@ -grammar; - -pub Invocation: Vec<&'input str> = { - <WORD*>, -}; - -// Several of the regexps below make use of Unicode character classes. [1] is -// the official reference to Unicode classes, and [2] is a site that is useful -// for browsing to get an intuitive idea of what the classes mean. -// -// In maintaining these regexps, it's important to understand the structure -// of Unicode character classes. There are seven top-level categories, each -// with a single-character name (ie. "Z" for separators). Each top-level -// category has several subcategories which form an exhaustive partition of it; -// the subcategories have two-character names (ie. "Zs" for space separators). -// Every allocated codepoint is in exactly one top-level category and exactly -// one subcategory. -// -// It is important that these regexps exhaustively cover the entirety of -// Unicode, without omission; otherwise lalrpop's lexer will give InvalidToken -// errors for unrecognized characters. Overlaps will be less catastrophic, as -// they'll be resoved by the precedence rules, but for clarity's sake they -// should be avoided. -// -// [1] http://www.unicode.org/reports/tr44/#General_Category_Values -// [2] https://www.compart.com/en/unicode/category -// -match { - // Zs is the Unicode class for space separators. This includes the ASCII - // space character. - // - r"\p{Zs}+" => { }, - - // Zl is the Unicode class for line separators. Zp is the Unicode class for - // paragraph separators. Newline and carriage return are included individually - // here, since Unicode classifies them with the control characters rather than - // with the space characters. - // - r"[\p{Zl}\p{Zp}\n\r]" => NEWLINE, - - // This one recognizes exactly one character, the old-school double-quote. As - // tempting as it is to do something clever with character classes, shells have - // a long history of quoting syntaxes which are subtle and quick to anger, and - // for this project the decision is to be radically simple instead. - r#"["]"# => QUOTE, - - // This one matches any control character other than line feed and carriage - // return. The grammar doesn't reference control characters, but having a - // token for them makes the error messages more informative. - r"[\p{C}&&[^\n\r]]" => CONTROL, - - // Z is the unicode class for separators, which is exhaustively partitioned - // into line, paragraph, and space separators. Each of those subclasses is - // handled above. C is the class for control characters. This regexp tests - // for the intersection of the negation of these character classes, along - // with a negated class enumerating all the explicitly-recognized characters, - // which means it matches any character NOT in the regexps above. - // - // Note that, counterintuitively, line feed and carriage return are classified - // as control characters, not as line separators. Either way, this regexp would - // still exclude them, but the difference might be relevant when maintaining - // it. - // - r#"[\P{Z}&&\P{C}&&[^"]]+"# => WORD, -} - diff --git a/src/error.rs b/src/error.rs index 1d291ed..426ebf5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,21 +1,11 @@ #![forbid(unsafe_code)] -use crate::path::GenericPath; -use crate::path::error::{FileNameError, DirectoryNameError, PathError}; use crate::terminal::error::TerminalError; -type ParseError<'a> = - lalrpop_util::ParseError<usize, lalrpop_util::lexer::Token<'a>, &'a str>; - #[derive(Debug)] pub enum Error { IO(std::io::Error), - Parse(String), - FileName(FileNameError), - DirectoryName(DirectoryNameError), - Path(PathError), - PathEmpiricallyFile(GenericPath), Terminal(TerminalError), } @@ -25,14 +15,6 @@ impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::IO(e) => e.fmt(f), - Error::Parse(e) => e.fmt(f), - Error::FileName(e) => e.fmt(f), - Error::DirectoryName(e) => e.fmt(f), - Error::Path(e) => e.fmt(f), - Error::PathEmpiricallyFile(path) => - f.write_fmt(format_args!( - "There's a file at {}, not a directory.", - path)), Error::Terminal(e) => e.fmt(f), } } @@ -50,30 +32,6 @@ impl From<std::io::Error> for Error { } } -impl From<ParseError<'_>> for Error { - fn from(e: ParseError<'_>) -> Error { - Error::Parse(format!("{}", e)) - } -} - -impl From<FileNameError> for Error { - fn from(e: FileNameError) -> Error { - Error::FileName(e) - } -} - -impl From<DirectoryNameError> for Error { - fn from(e: DirectoryNameError) -> Error { - Error::DirectoryName(e) - } -} - -impl From<PathError> for Error { - fn from(e: PathError) -> Error { - Error::Path(e) - } -} - impl From<TerminalError> for Error { fn from(e: TerminalError) -> Error { Error::Terminal(e) diff --git a/src/main.rs b/src/main.rs index e94ce0c..9d8ed49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,18 +2,10 @@ use crate::result::Result; use crate::terminal::{Input, Terminal}; -use std::collections::HashMap; -use std::collections::HashSet; -use std::env; -use std::os::unix::fs::PermissionsExt; -use std::process::{self, Command}; +use std::process; use tokio::io::{self, AsyncWriteExt}; -#[macro_use] extern crate lalrpop_util; - -lalrpop_mod!(pub commandline); pub mod error; -pub mod path; pub mod result; pub mod terminal; @@ -67,101 +59,7 @@ async fn prompt() -> Result<()> { } -async fn execute(input: &str) -> Result<()> { - let invocation = commandline::InvocationParser::new().parse(input)?; - - match invocation.as_slice() { - ["environment", ..] => { - let environment = read_environment()?; - println!("{:?}", environment); - } - ["which", command_name, ..] => { - match find_executable_path(command_name)? { - Some(executable_path) => { - println!("{}", executable_path); - } - None => { - println!("Command not found: {}", command_name); - } - }; - }, - [command_name, ..] => { - match find_executable_path(command_name)? { - Some(executable_path) => { - let mut command = Command::new(executable_path.to_sys_path()); - - let arguments = &invocation[1..]; - command.args(arguments); - - let _status = command.status()?; - } - None => { - println!("Command not found: {}", command_name); - } - }; - }, - _ => { - println!("invocation '{:?}'", invocation); - } - } - +async fn execute(_input: &str) -> Result<()> { Ok(()) } - -fn read_environment() -> Result<HashMap<String,String>> { - Ok(env::vars().collect()) -} - - -fn get_environment(variable_name: &str) -> Result<Option<String>> { - Ok(env::vars() - .find(|(key, _)| key == variable_name) - .map(|(_, value)| value)) -} - - -fn get_search_paths() -> Result<Vec<path::AbsoluteDirectoryPath>> { - let paths = get_environment("PATH")?.unwrap_or_default(); - let paths = path::parse_path_list(&paths)?; - - let mut result = Vec::new(); - let mut seen = HashSet::new(); - for path in paths { - if seen.contains(&path) { - continue; - } - - seen.insert(path.clone()); - result.push(path); - } - - Ok(result) -} - - -fn find_executable_path(command_name: &str) - -> Result<Option<path::AbsoluteFilePath>> -{ - let file_name: path::FileName = command_name.parse()?; - let search_paths = get_search_paths()?; - - let mut executable_path: Option<path::AbsoluteFilePath> = None; - for search_path in &search_paths { - let candidate_path = search_path.concat_file_name(&file_name); - match candidate_path.to_sys_path().metadata() { - Ok(metadata) => { - if metadata.is_file() - && metadata.permissions().mode() & 0o111 != 0 - { - executable_path = Some(candidate_path); - break; - } - }, - Err(_) => { }, - } - } - - Ok(executable_path) -} - diff --git a/src/path.rs b/src/path.rs deleted file mode 100644 index 7df10b2..0000000 --- a/src/path.rs +++ /dev/null @@ -1,319 +0,0 @@ -/* - * We implement most aspects of paths independently, not relying on - * std::path, on the theory that path syntax is such an important part of a - * shell that it doesn't make sense to try to integrate with non-Unix syntaxes. - * However, we do use std::path to print individual path components, in order - * to get the benefit of its functionality for handling non-Unicode filenames. - */ - -#![forbid(unsafe_code)] -use crate::path::prelude::*; - -use std::str::FromStr; - - -lalrpop_mod!(pub parser, "/path/parser.rs"); -pub mod error; -pub mod prelude; - - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub struct AbsoluteDirectoryPath { - directory_names: Vec<DirectoryName>, -} - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub struct AbsoluteFilePath { - directory_names: Vec<DirectoryName>, - file_name: FileName, -} - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub struct FileName(String); - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub struct DirectoryName(String); - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub struct GenericPath { - components: Vec<GenericPathComponent>, - starts_with_slash: bool, - ends_with_slash: bool, -} - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub enum GenericPathComponent { - FileOrDirectoryName(String), - CurrentDirectory, - ParentDirectory, -} - - -impl std::fmt::Display for AbsoluteDirectoryPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for directory_name in &self.directory_names { - f.write_str("/")?; - directory_name.fmt(f)?; - } - - f.write_str("/")?; - - Ok(()) - } -} - - -impl std::fmt::Display for AbsoluteFilePath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for directory_name in &self.directory_names { - f.write_str("/")?; - directory_name.fmt(f)?; - } - - f.write_str("/")?; - - self.file_name.fmt(f)?; - - Ok(()) - } -} - - -impl std::fmt::Display for FileName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - FileName(name) => { - let std_path = std::path::Path::new(&name); - f.write_fmt(format_args!("{}", std_path.display()))?; - }, - } - - Ok(()) - } -} - - -impl std::fmt::Display for DirectoryName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DirectoryName(name) => { - let std_path = std::path::Path::new(&name); - f.write_fmt(format_args!("{}", std_path.display()))?; - }, - } - - Ok(()) - } -} - - -impl std::fmt::Display for GenericPath { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.starts_with_slash { - f.write_str("/")?; - } - - let mut is_first = true; - for component in &self.components { - if !is_first { - f.write_str("/")?; - } - - component.fmt(f)?; - - is_first = false; - } - - if self.ends_with_slash { - f.write_str("/")?; - } - - Ok(()) - } -} - - -impl std::fmt::Display for GenericPathComponent { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - GenericPathComponent::FileOrDirectoryName(name) => { - let std_path = std::path::Path::new(&name); - f.write_fmt(format_args!("{}", std_path.display()))?; - }, - GenericPathComponent::CurrentDirectory => { - f.write_str(".")?; - }, - GenericPathComponent::ParentDirectory => { - f.write_str("..")?; - }, - } - - Ok(()) - } -} - - -impl FromStr for FileName { - type Err = FileNameError; - - fn from_str(input: &str) -> std::result::Result<Self, Self::Err> { - if input.find('/').is_some() { - Err(FileNameError::ContainsSlash(input.to_string())) - } else { - Ok(FileName(input.to_string())) - } - } -} - - -impl FromStr for DirectoryName { - type Err = DirectoryNameError; - - fn from_str(input: &str) -> std::result::Result<Self, Self::Err> { - if input.find('/').is_some() { - Err(DirectoryNameError::ContainsSlash(input.to_string())) - } else { - Ok(DirectoryName(input.to_string())) - } - } -} - - -impl FromStr for GenericPathComponent { - type Err = PathError; - - fn from_str(input: &str) -> std::result::Result<Self, Self::Err> { - parser::PathComponentParser::new().parse(input).map_err( - |e| PathError::Parse(e.to_string())) - } -} - - -impl AbsoluteDirectoryPath { - pub fn to_sys_path(&self) -> std::path::PathBuf { - let mut result = std::path::PathBuf::new(); - result.push(format!("{}", self)); - result - } - - pub fn concat_file_name(&self, file_name: &FileName) -> AbsoluteFilePath { - AbsoluteFilePath { - directory_names: self.directory_names.clone(), - file_name: file_name.clone(), - } - } -} - - -impl AbsoluteFilePath { - pub fn to_sys_path(&self) -> std::path::PathBuf { - let mut result = std::path::PathBuf::new(); - result.push(format!("{}", self)); - result - } -} - - -pub fn parse_path_list(path_list: &str) - -> Result<Vec<AbsoluteDirectoryPath>> -{ - match parser::PathListParser::new().parse(path_list) { - Ok(parsed_paths) => { - let mut result = Vec::new(); - for generic_path in parsed_paths { - let path = absolute_directory_path(generic_path)?; - result.push(path); - } - Ok(result) - }, - Err(original_error) => { - match parser::PathListAllowingEmptyPathsParser::new() - .parse(path_list) - { - Ok(_) => { - Err(PathError::PathListHasEmptyComponents(path_list.to_string())) - }, - Err(_) => { - Err(PathError::Parse(original_error.to_string())) - }, - } - }, - } -} - - -pub fn absolute_directory_path(generic_path: GenericPath) - -> Result<AbsoluteDirectoryPath> -{ - if !generic_path.starts_with_slash { - return Err(PathError::PathLexicallyRelative(generic_path)); - } - - let mut flattened_components = Vec::new(); - for component in &generic_path.components { - match component { - GenericPathComponent::CurrentDirectory => { }, - GenericPathComponent::ParentDirectory => { - if flattened_components.len() > 0 { - flattened_components.pop(); - } else { - return Err(PathError::PathLexicallyInvalid(generic_path)); - } - }, - GenericPathComponent::FileOrDirectoryName(name) => { - flattened_components.push(DirectoryName(name.to_string())); - }, - } - } - - Ok(AbsoluteDirectoryPath { - directory_names: flattened_components, - }) -} - - -pub fn absolute_file_path(generic_path: GenericPath) - -> Result<AbsoluteFilePath> -{ - if !generic_path.starts_with_slash { - return Err(PathError::PathLexicallyRelative(generic_path)); - } - - if generic_path.ends_with_slash { - return Err(PathError::PathLexicallyDirectory(generic_path)); - } - - let mut iterator = generic_path.components.iter(); - - let file_name = match iterator.next_back() { - Some(GenericPathComponent::FileOrDirectoryName(name)) => { - FileName(name.to_string()) - } - _ => { - return Err(PathError::PathLexicallyInvalid(generic_path)); - } - }; - - let mut flattened_components = Vec::new(); - for component in &generic_path.components { - match component { - GenericPathComponent::CurrentDirectory => { }, - GenericPathComponent::ParentDirectory => { - if flattened_components.len() > 0 { - flattened_components.pop(); - } else { - return Err(PathError::PathLexicallyInvalid(generic_path)); - } - }, - GenericPathComponent::FileOrDirectoryName(name) => { - flattened_components.push(DirectoryName(name.to_string())); - }, - } - } - - Ok(AbsoluteFilePath { - directory_names: flattened_components, - file_name: file_name, - }) -} - diff --git a/src/path/error.rs b/src/path/error.rs deleted file mode 100644 index aee6e9f..0000000 --- a/src/path/error.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![forbid(unsafe_code)] - -use crate::path::GenericPath; - -pub type Result<T> = std::result::Result<T, PathError>; - - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub enum FileNameError { - ContainsSlash(String), -} - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub enum DirectoryNameError { - ContainsSlash(String), -} - -#[derive(Clone,Debug,Eq,Hash,Ord,PartialEq,PartialOrd)] -pub enum PathError { - Parse(String), - PathLexicallyDirectory(GenericPath), - PathLexicallyRelative(GenericPath), - PathLexicallyInvalid(GenericPath), - PathListHasEmptyComponents(String), -} - - -impl std::error::Error for FileNameError { } - -impl std::error::Error for DirectoryNameError { } - -impl std::error::Error for PathError { } - -impl std::fmt::Display for FileNameError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - FileNameError::ContainsSlash(s) => - f.write_fmt(format_args!( - "File names cannot contain slashes, but {:?} does.", s)), - } - } -} - -impl std::fmt::Display for DirectoryNameError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - DirectoryNameError::ContainsSlash(s) => - f.write_fmt(format_args!( - "File names cannot contain slashes, but {:?} does.", s)), - } - } -} - -impl std::fmt::Display for PathError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PathError::Parse(s) => - f.write_fmt(format_args!("Syntax error in path: {}", s)), - PathError::PathLexicallyDirectory(path) => - f.write_fmt(format_args!( - "The path {} ends in a slash, but is supposed to refer to a file, \ - not a directory.", - path)), - PathError::PathLexicallyRelative(path) => - f.write_fmt(format_args!( - "The path {} is relative, not absolute.", - path)), - PathError::PathLexicallyInvalid(path) => - f.write_fmt(format_args!( - "This isn't a valid path. {}", - path)), - PathError::PathListHasEmptyComponents(path_list) => - f.write_fmt(format_args!( - "Path list has empty components: {}", - path_list)), - } - } -} - diff --git a/src/path/parser.lalrpop b/src/path/parser.lalrpop deleted file mode 100644 index c41b3fd..0000000 --- a/src/path/parser.lalrpop +++ /dev/null @@ -1,92 +0,0 @@ -grammar; - -use crate::path::GenericPath; -use crate::path::GenericPathComponent; - -pub PathList: Vec<GenericPath> = { - => { - Vec::new() - }, - <mut left:(<PathNoColons> COLON)*> <right:PathNoColons> => { - left.push(right); - left - }, -}; - -pub PathListAllowingEmptyPaths: Vec<GenericPath> = { - => vec![GenericPath { - components: Vec::new(), - starts_with_slash: false, - ends_with_slash: false, - }], - PathNoColons => vec![<>], - <mut left:PathListAllowingEmptyPaths> COLON => { - left.push(GenericPath { - components: Vec::new(), - starts_with_slash: false, - ends_with_slash: false, - }); - left - }, - <mut left:PathListAllowingEmptyPaths> COLON <right:PathNoColons> => { - left.push(right); - left - }, -} - -pub PathNoColons: GenericPath = { - SLASH => GenericPath { - components: Vec::new(), - starts_with_slash: true, - ends_with_slash: true, - }, - <PathNoColons2> => GenericPath { - components: <>, - starts_with_slash: false, - ends_with_slash: false, - }, - <PathNoColons2> SLASH => GenericPath { - components: <>, - starts_with_slash: false, - ends_with_slash: true, - }, - SLASH <PathNoColons2> => GenericPath { - components: <>, - starts_with_slash: true, - ends_with_slash: false, - }, - SLASH <PathNoColons2> SLASH => GenericPath { - components: <>, - starts_with_slash: true, - ends_with_slash: true, - }, -} - -PathNoColons2: Vec<GenericPathComponent> = { - <PathComponent> => vec![<>], - <mut left:PathNoColons2> SLASH <right:PathComponent> => { - left.push(right); - left - } -} - -pub PathComponent: GenericPathComponent = { - DOT => GenericPathComponent::CurrentDirectory, - DOT_DOT => GenericPathComponent::ParentDirectory, - <PATH_COMPONENT_NO_COLONS> => - GenericPathComponent::FileOrDirectoryName(<>.to_string()) -} - -// Whitespace is not allowed. -match { - r"[^:/]+" => PATH_COMPONENT_NO_COLONS, - - r"/" => SLASH, - - ":" => COLON, - - "." => DOT, - - ".." => DOT_DOT, -} - diff --git a/src/path/prelude.rs b/src/path/prelude.rs deleted file mode 100644 index f7b23dd..0000000 --- a/src/path/prelude.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![forbid(unsafe_code)] - -pub use crate::path::error::{ - Result, DirectoryNameError, FileNameError, PathError}; - |