summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Andreas Benkard <code@mail.matthias.benkard.de>2025-08-13 19:06:31 +0200
committerMatthias Andreas Benkard <code@mail.matthias.benkard.de>2025-08-13 19:06:31 +0200
commit0f00400df98327dc01681567dc2313a9c6e57953 (patch)
treece4a6af92cc6026b16a95945eb05f394933ec2aa
parentab36c1b5178ee0e7934b1c5cdcf2ccfccc3514bb (diff)
Remove the Rust version.
-rw-r--r--Cargo.lock1012
-rw-r--r--Cargo.toml22
-rw-r--r--src/main.rs844
3 files changed, 0 insertions, 1878 deletions
diff --git a/Cargo.lock b/Cargo.lock
deleted file mode 100644
index feca255..0000000
--- a/Cargo.lock
+++ /dev/null
@@ -1,1012 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "addr2line"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler2"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
-
-[[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
-
-[[package]]
-name = "backtrace"
-version = "0.3.75"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
-dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "bitflags"
-version = "2.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
-
-[[package]]
-name = "cfg-if"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
-
-[[package]]
-name = "cfg_aliases"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
-
-[[package]]
-name = "clipboard-win"
-version = "5.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
-dependencies = [
- "error-code",
-]
-
-[[package]]
-name = "color-eyre"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d"
-dependencies = [
- "backtrace",
- "color-spantrace",
- "eyre",
- "indenter",
- "once_cell",
- "owo-colors",
- "tracing-error",
-]
-
-[[package]]
-name = "color-spantrace"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427"
-dependencies = [
- "once_cell",
- "owo-colors",
- "tracing-core",
- "tracing-error",
-]
-
-[[package]]
-name = "convert_case"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7"
-dependencies = [
- "unicode-segmentation",
-]
-
-[[package]]
-name = "crossterm"
-version = "0.29.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
-dependencies = [
- "bitflags",
- "crossterm_winapi",
- "derive_more",
- "document-features",
- "mio",
- "parking_lot",
- "rustix",
- "signal-hook",
- "signal-hook-mio",
- "winapi",
-]
-
-[[package]]
-name = "crossterm_winapi"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "csv"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
-dependencies = [
- "csv-core",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "csv-core"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "derive_more"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
-dependencies = [
- "derive_more-impl",
-]
-
-[[package]]
-name = "derive_more-impl"
-version = "2.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
-dependencies = [
- "convert_case",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "dirs-next"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
-dependencies = [
- "cfg-if",
- "dirs-sys-next",
-]
-
-[[package]]
-name = "dirs-sys-next"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
-dependencies = [
- "libc",
- "redox_users",
- "winapi",
-]
-
-[[package]]
-name = "document-features"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
-dependencies = [
- "litrs",
-]
-
-[[package]]
-name = "dosage"
-version = "0.1.0"
-dependencies = [
- "color-eyre",
- "crossterm",
- "eyre",
- "prettytable-rs",
- "regex",
- "rustyline",
- "thiserror 2.0.12",
-]
-
-[[package]]
-name = "encode_unicode"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
-
-[[package]]
-name = "endian-type"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
-
-[[package]]
-name = "errno"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
-dependencies = [
- "libc",
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "error-code"
-version = "3.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
-
-[[package]]
-name = "eyre"
-version = "0.6.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
-dependencies = [
- "indenter",
- "once_cell",
-]
-
-[[package]]
-name = "fd-lock"
-version = "4.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
-dependencies = [
- "cfg-if",
- "rustix",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "gimli"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-
-[[package]]
-name = "hermit-abi"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
-
-[[package]]
-name = "home"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "indenter"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
-
-[[package]]
-name = "is-terminal"
-version = "0.4.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
-dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
-
-[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
-[[package]]
-name = "libc"
-version = "0.2.174"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
-
-[[package]]
-name = "libredox"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
-dependencies = [
- "bitflags",
- "libc",
-]
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
-
-[[package]]
-name = "litrs"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
-
-[[package]]
-name = "lock_api"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
-[[package]]
-name = "log"
-version = "0.4.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
-
-[[package]]
-name = "memchr"
-version = "2.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.8.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
-dependencies = [
- "adler2",
-]
-
-[[package]]
-name = "mio"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
-dependencies = [
- "libc",
- "log",
- "wasi",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "nibble_vec"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
-dependencies = [
- "smallvec",
-]
-
-[[package]]
-name = "nix"
-version = "0.30.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
-dependencies = [
- "bitflags",
- "cfg-if",
- "cfg_aliases",
- "libc",
-]
-
-[[package]]
-name = "object"
-version = "0.36.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.21.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
-
-[[package]]
-name = "owo-colors"
-version = "4.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e"
-
-[[package]]
-name = "parking_lot"
-version = "0.12.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
-dependencies = [
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.9.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall",
- "smallvec",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
-
-[[package]]
-name = "prettytable-rs"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a"
-dependencies = [
- "csv",
- "encode_unicode",
- "is-terminal",
- "lazy_static",
- "term",
- "unicode-width 0.1.14",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.95"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "radix_trie"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
-dependencies = [
- "endian-type",
- "nibble_vec",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.5.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7251471db004e509f4e75a62cca9435365b5ec7bcdff530d612ac7c87c44a792"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "redox_users"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
-dependencies = [
- "getrandom",
- "libredox",
- "thiserror 1.0.69",
-]
-
-[[package]]
-name = "regex"
-version = "1.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
-
-[[package]]
-name = "rustix"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.60.2",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.21"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
-
-[[package]]
-name = "rustyline"
-version = "16.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62fd9ca5ebc709e8535e8ef7c658eb51457987e48c98ead2be482172accc408d"
-dependencies = [
- "bitflags",
- "cfg-if",
- "clipboard-win",
- "fd-lock",
- "home",
- "libc",
- "log",
- "memchr",
- "nix",
- "radix_trie",
- "unicode-segmentation",
- "unicode-width 0.2.1",
- "utf8parse",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
-
-[[package]]
-name = "scopeguard"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-
-[[package]]
-name = "serde"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "sharded-slab"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
-dependencies = [
- "lazy_static",
-]
-
-[[package]]
-name = "signal-hook"
-version = "0.3.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
-dependencies = [
- "libc",
- "signal-hook-registry",
-]
-
-[[package]]
-name = "signal-hook-mio"
-version = "0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
-dependencies = [
- "libc",
- "mio",
- "signal-hook",
-]
-
-[[package]]
-name = "signal-hook-registry"
-version = "1.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.15.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
-
-[[package]]
-name = "syn"
-version = "2.0.104"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "term"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
-dependencies = [
- "dirs-next",
- "rustversion",
- "winapi",
-]
-
-[[package]]
-name = "thiserror"
-version = "1.0.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
-dependencies = [
- "thiserror-impl 1.0.69",
-]
-
-[[package]]
-name = "thiserror"
-version = "2.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
-dependencies = [
- "thiserror-impl 2.0.12",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "2.0.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "thread_local"
-version = "1.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "tracing"
-version = "0.1.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
-dependencies = [
- "pin-project-lite",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
-dependencies = [
- "once_cell",
- "valuable",
-]
-
-[[package]]
-name = "tracing-error"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db"
-dependencies = [
- "tracing",
- "tracing-subscriber",
-]
-
-[[package]]
-name = "tracing-subscriber"
-version = "0.3.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
-dependencies = [
- "sharded-slab",
- "thread_local",
- "tracing-core",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
-
-[[package]]
-name = "unicode-width"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
-
-[[package]]
-name = "unicode-width"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
-
-[[package]]
-name = "valuable"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
-
-[[package]]
-name = "wasi"
-version = "0.11.1+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.60.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
-dependencies = [
- "windows-targets 0.53.2",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.53.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
-dependencies = [
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
diff --git a/Cargo.toml b/Cargo.toml
deleted file mode 100644
index 4ba529e..0000000
--- a/Cargo.toml
+++ /dev/null
@@ -1,22 +0,0 @@
-[package]
-name = "dosage"
-version = "0.1.0"
-edition = "2024"
-
-[profile.release]
-lto = true
-opt-level = "z"
-strip = true
-codegen-units = 1
-#panic = "abort"
-
-[dependencies]
-color-eyre = "0.6"
-eyre = "0.6"
-thiserror = "2"
-crossterm = "0.29.0"
-prettytable-rs = "0.10.0"
-rustyline = "16"
-regex = "1.11.1"
-#crossbeam = "0.8.4"
-#termwiz = "0.23"
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 8b9229e..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,844 +0,0 @@
-use crossterm::{cursor, execute, terminal};
-use eyre::{Result, bail};
-use regex::Regex;
-use rustyline::DefaultEditor;
-use rustyline::error::ReadlineError;
-use std::collections::{LinkedList, VecDeque};
-use std::io;
-use std::io::Write;
-use std::path::{Component, Path, PathBuf};
-use std::sync::mpsc::{Receiver, SyncSender, sync_channel};
-use std::thread::spawn;
-
-const STDOUT_BUFFER_SIZE: usize = 1024;
-const STDERR_BUFFER_SIZE: usize = 1024;
-
-fn main() -> Result<()> {
- color_eyre::install()?;
-
- let mut line_editor = DefaultEditor::new()?;
- let mut prompt_spec = "$p$g";
-
- loop {
- let cwd = std::env::current_dir()?;
- let full_cwd = format_path(&cwd);
- let mut interpolated_prompt = prompt_spec.replace("$p", &full_cwd).replace("$g", ">");
- interpolated_prompt.push_str(" ");
-
- let line = match line_editor.readline(&interpolated_prompt) {
- Ok(line) => line,
- Err(ReadlineError::Eof) => break,
- Err(err) => return Err(err.into()),
- };
-
- let Ok(command) = Command::parse(&line) else {
- eprintln!("unrecognized command: {}", line);
- continue;
- };
-
- line_editor.add_history_entry(&line)?;
- let Ok(CommandReceivers {
- stdout,
- stderr,
- status,
- }) = command.run()
- else {
- eprintln!("unimplemented command: {}", line);
- continue;
- };
-
- // print stdout, stderr interleaved until status produces something
- let stdout_writer = spawn(move || {
- loop {
- let Ok(bytes) = stdout.recv() else {
- break;
- };
- let mut out = io::stderr();
- out.write_all(bytes.as_slice())
- .expect("stdout write failed");
- out.flush().expect("stdout flush failed");
- }
- });
-
- let stderr_writer = spawn(move || {
- loop {
- let Ok(bytes) = stderr.recv() else {
- break;
- };
- let mut out = io::stderr();
- out.write_all(bytes.as_slice())
- .expect("stderr write failed");
- out.flush().expect("stdout flush failed");
- }
- });
-
- stdout_writer.join().expect("stdout writer thread failed");
- stderr_writer.join().expect("stderr writer thread failed");
-
- let command_result = status
- .recv()
- .expect("failed to receive exit status from command");
-
- match command_result {
- CommandStatus::ExitShell => break,
- CommandStatus::Code(_) => {}
- }
- }
-
- Ok(())
-}
-
-/// Turns "/home/mulk/foo/longfilenames/excellent.text" into "C:\\HOME\\MULK\\FOO\\LONGFILE~1\\EXCELL~1.TEX"
-fn format_path(p: &Path) -> String {
- use std::path::Component::*;
-
- let mut prefix: Option<String> = None;
- let mut components = Vec::new();
-
- for component in p.components() {
- match component {
- Normal(c) => {
- let s = c.to_string_lossy().to_uppercase();
- let s_parts: Vec<&str> = s.splitn(2, '.').collect();
-
- let mut name: String;
- let mut ext: Option<String>;
- if s_parts.len() == 1 {
- name = s.clone();
- ext = None;
- } else {
- name = s_parts[0].into();
- ext = Some(s_parts[1].into());
- }
-
- let mut result = String::new();
-
- if name.len() > 8 || ext.as_ref().map_or(false, |e| e.len() > 3) {
- name = name.chars().take(6).collect::<String>();
- name.push_str("~1");
- }
- result.push_str(&name.to_uppercase());
-
- if let Some(mut e) = ext {
- if e.len() > 3 {
- e = e.chars().take(3).collect::<String>();
- }
- result.push_str(".");
- result.push_str(&e.to_uppercase());
- }
-
- components.push(result);
- }
-
- Prefix(c) => prefix = Some(component.as_os_str().to_string_lossy().to_uppercase()),
-
- RootDir => {
- if prefix.is_none() {
- prefix = Some("C:".into())
- }
- components.push("".into());
- }
-
- CurDir => components.push(".".into()),
-
- ParentDir => components.push("..".into()),
- }
- }
-
- let mut result = String::new();
- if let Some(p) = prefix {
- result.push_str(&p)
- };
- result.push_str(&components.join("\\"));
- result
-}
-
-#[derive(Debug)]
-enum FileSpec {
- Con,
- Lpt1,
- Lpt2,
- Lpt3,
- Prn,
- Path(PathBuf),
-}
-
-#[derive(Debug)]
-enum RedirectType {
- OutputOverwrite, // >
- OutputAppend, // >>
- InputFrom, // <
-}
-
-#[derive(Debug)]
-struct Redirect {
- redirect_type: RedirectType,
- target: FileSpec,
-}
-
-#[derive(Debug)]
-enum Command {
- Pipe {
- left: Box<Command>,
- right: Box<Command>,
- },
- Redirect {
- command: Box<Command>,
- redirects: Vec<Redirect>,
- },
- External {
- program: String,
- args: Vec<String>,
- },
- Builtin(BuiltinCommand),
- Empty,
-}
-
-#[derive(Debug)]
-enum CommandStatus {
- Code(u16),
- ExitShell,
-}
-
-struct CommandReceivers {
- stdout: Receiver<Vec<u8>>,
- stderr: Receiver<Vec<u8>>,
- status: Receiver<CommandStatus>,
-}
-
-struct CommandSenders {
- stdout: SyncSender<Vec<u8>>,
- stderr: SyncSender<Vec<u8>>,
- status: SyncSender<CommandStatus>,
-}
-
-struct CommandContext {
- senders: CommandSenders,
- receivers: CommandReceivers,
-}
-
-impl CommandContext {
- fn new() -> Self {
- let (sout, rout) = sync_channel(STDOUT_BUFFER_SIZE);
- let (serr, rerr) = sync_channel(STDERR_BUFFER_SIZE);
- let (sexit, rexit) = sync_channel(1);
-
- Self {
- senders: CommandSenders {
- stdout: sout,
- stderr: serr,
- status: sexit,
- },
- receivers: CommandReceivers {
- stdout: rout,
- stderr: rerr,
- status: rexit,
- },
- }
- }
-
- fn split(self) -> (CommandSenders, CommandReceivers) {
- (self.senders, self.receivers)
- }
-}
-
-impl Command {
- pub(crate) fn run(&self) -> Result<CommandReceivers> {
- use crate::BuiltinCommand::*;
- use crate::Command::*;
- use crate::CommandStatus::*;
-
- let (senders, receivers) = CommandContext::new().split();
- let CommandSenders {
- stdout,
- stderr,
- status: status,
- } = senders;
-
- match self {
- Empty => {
- status.send(Code(0))?;
- }
-
- Builtin(EchoText { message }) => {
- stdout.send(message.bytes().collect())?;
- stdout.send(b"\n".into())?;
- status.send(Code(0))?;
- }
-
- Builtin(Cls) => {
- let mut stdout_handle = io::stdout();
- execute!(stdout_handle, terminal::Clear(terminal::ClearType::All))?;
- execute!(stdout_handle, cursor::MoveTo(0, 0))?;
- status.send(Code(0))?;
- }
-
- Builtin(Exit) => {
- status.send(ExitShell)?;
- }
-
- _ => bail!("Command::run not implemented for {:?}", self),
- }
-
- Ok(receivers)
- }
-}
-
-#[derive(Debug)]
-enum BuiltinCommand {
- // File-oriented
- Copy {
- from: FileSpec,
- to: FileSpec,
- },
- Deltree {
- path: PathBuf,
- },
- Dir {
- path: PathBuf,
- },
- Fc,
- Find,
- Mkdir {
- path: PathBuf,
- },
- Move,
- Remove {
- path: PathBuf,
- },
- Rename {
- from: FileSpec,
- to: FileSpec,
- },
- Replace,
- Rmdir {
- path: PathBuf,
- },
- Sort,
- Tree {
- path: PathBuf,
- },
- Type {
- file: FileSpec,
- },
- Xcopy {
- from: FileSpec,
- to: FileSpec,
- recursive: bool,
- },
-
- // Shell-oriented
- Append,
- Chdir {
- path: PathBuf,
- },
- EchoOff,
- EchoOn,
- EchoPlain,
- EchoText {
- message: String,
- },
- Exit,
- PathGet,
- PathSet {
- value: String,
- },
- PromptGet,
- PromptSet {
- message: String,
- },
- Set {
- name: String,
- value: String,
- },
- Setver,
- Ver,
-
- // Utilities
- Date,
- Time,
-
- // Screen-oriented
- Cls,
- More,
-
- // Dummies
- Verify,
- Fastopen,
- Smartdrv,
- Sizer,
-
- // For later
- Assign,
- Attrib,
- Chkdsk,
- Doskey,
- Dosshell,
- Edit,
- Fasthelp,
- Help,
- Join,
- Mem,
- Power,
- Subst,
- Truename,
-
- // For much later, if ever
- Break,
- Chcp,
- Ctty,
- Defrag,
- Diskcopy,
- Emm386,
- Fdisk,
- Format,
- Interlnk,
- Keyb,
- Label,
- Mode,
- Msav,
- Msbackup,
- Mscdex,
- Msd,
- Print,
- Qbasic,
- Restore,
- Scandisk,
- Share,
- Sys,
- Undelete,
- Unformat,
- Vol,
- Vsafe,
-
- // Scripting
- Call,
- Choice,
- Echo,
- For,
- Goto,
- If,
- Pause,
- Prompt,
- Rem {
- message: String,
- },
- Shift,
-}
-
-#[derive(Debug, Clone, PartialEq)]
-enum Token {
- Word(String),
- Pipe,
- RedirectOut, // >
- RedirectAppend, // >>
- RedirectIn, // <
- Newline,
- Eof,
-}
-
-struct Lexer {
- input: Vec<char>,
- position: usize,
- current_char: Option<char>,
-}
-
-impl Lexer {
- fn new(input: &str) -> Self {
- let chars: Vec<char> = input.chars().collect();
- let current_char = chars.get(0).copied();
-
- Self {
- input: chars,
- position: 0,
- current_char,
- }
- }
-
- fn advance(&mut self) {
- self.position += 1;
- self.current_char = self.input.get(self.position).copied();
- }
-
- fn peek(&self) -> Option<char> {
- self.input.get(self.position + 1).copied()
- }
-
- fn skip_whitespace(&mut self) {
- while let Some(ch) = self.current_char {
- if ch.is_whitespace() && ch != '\n' {
- self.advance();
- } else {
- break;
- }
- }
- }
-
- fn read_word(&mut self) -> String {
- let mut word = String::new();
- let mut in_quotes = false;
- let mut quote_char = '"';
-
- while let Some(ch) = self.current_char {
- match ch {
- // Handle quotes
- '"' | '\'' if !in_quotes => {
- in_quotes = true;
- quote_char = ch;
- self.advance();
- },
- ch if in_quotes && ch == quote_char => {
- in_quotes = false;
- self.advance();
- },
- // Stop at special characters when not in quotes
- '|' | '>' | '<' | '\n' if !in_quotes => {
- break;
- },
- // Stop at whitespace when not in quotes
- ch if !in_quotes && ch.is_whitespace() => {
- break;
- },
- // Regular character
- _ => {
- word.push(ch);
- self.advance();
- }
- }
- }
-
- word
- }
-
- fn next_token(&mut self) -> Token {
- loop {
- match self.current_char {
- None => return Token::Eof,
-
- Some('\n') => {
- self.advance();
- return Token::Newline;
- },
-
- Some(ch) if ch.is_whitespace() => {
- self.skip_whitespace();
- continue;
- },
-
- Some('|') => {
- self.advance();
- return Token::Pipe;
- },
-
- Some('>') => {
- self.advance();
- if self.current_char == Some('>') {
- self.advance();
- return Token::RedirectAppend;
- } else {
- return Token::RedirectOut;
- }
- },
-
- Some('<') => {
- self.advance();
- return Token::RedirectIn;
- },
-
- Some(_) => {
- let word = self.read_word();
- if word.is_empty() {
- // This shouldn't happen, but just in case
- self.advance();
- continue;
- }
- return Token::Word(word);
- }
- }
- }
- }
-
- fn tokenize(&mut self) -> Vec<Token> {
- let mut tokens = Vec::new();
-
- loop {
- let token = self.next_token();
- let is_eof = matches!(token, Token::Eof);
- tokens.push(token);
- if is_eof {
- break;
- }
- }
-
- tokens
- }
-}
-
-struct Parser {
- tokens: Vec<Token>,
- position: usize,
-}
-
-impl Parser {
- fn new(tokens: Vec<Token>) -> Self {
- Self {
- tokens,
- position: 0,
- }
- }
-
- fn current_token(&self) -> &Token {
- self.tokens.get(self.position).unwrap_or(&Token::Eof)
- }
-
- fn advance(&mut self) {
- if self.position < self.tokens.len() {
- self.position += 1;
- }
- }
-
- fn expect_word(&mut self) -> Result<String> {
- match self.current_token() {
- Token::Word(word) => {
- let result = word.clone();
- self.advance();
- Ok(result)
- },
- token => Err(eyre::eyre!("Expected word, found {:?}", token)),
- }
- }
-
- fn parse_command(&mut self) -> Result<Command> {
- self.parse_pipeline()
- }
-
- fn parse_pipeline(&mut self) -> Result<Command> {
- let mut left = self.parse_redirected_command()?;
-
- while matches!(self.current_token(), Token::Pipe) {
- self.advance(); // consume |
- let right = self.parse_redirected_command()?;
- left = Command::Pipe {
- left: Box::new(left),
- right: Box::new(right),
- };
- }
-
- Ok(left)
- }
-
- fn parse_redirected_command(&mut self) -> Result<Command> {
- let mut command = self.parse_simple_command()?;
- let mut redirects = Vec::new();
-
- while matches!(self.current_token(), Token::RedirectOut | Token::RedirectAppend | Token::RedirectIn) {
- let redirect_type = match self.current_token() {
- Token::RedirectOut => RedirectType::OutputOverwrite,
- Token::RedirectAppend => RedirectType::OutputAppend,
- Token::RedirectIn => RedirectType::InputFrom,
- _ => unreachable!(),
- };
-
- self.advance(); // consume redirect token
-
- let target_str = self.expect_word()?;
- let target = parse_filespec(&target_str);
-
- redirects.push(Redirect {
- redirect_type,
- target,
- });
- }
-
- if redirects.is_empty() {
- Ok(command)
- } else {
- Ok(Command::Redirect {
- command: Box::new(command),
- redirects,
- })
- }
- }
-
- fn parse_simple_command(&mut self) -> Result<Command> {
- use BuiltinCommand::*;
- use Command::*;
-
- if matches!(self.current_token(), Token::Eof | Token::Newline) {
- return Ok(Empty);
- }
-
- let command_name = self.expect_word()?;
- let mut args = Vec::new();
-
- // Collect arguments until we hit a special token
- while matches!(self.current_token(), Token::Word(_)) {
- if let Token::Word(arg) = self.current_token() {
- args.push(arg.clone());
- self.advance();
- }
- }
-
- match command_name.to_uppercase().as_str() {
- "ECHO" => {
- if args.is_empty() {
- Ok(Builtin(EchoPlain))
- } else {
- match args[0].to_uppercase().as_str() {
- "ON" if args.len() == 1 => Ok(Builtin(EchoOn)),
- "OFF" if args.len() == 1 => Ok(Builtin(EchoOff)),
- _ => Ok(Builtin(EchoText {
- message: args.join(" "),
- })),
- }
- }
- },
-
- "CLS" => Ok(Builtin(Cls)),
-
- "EXIT" => Ok(Builtin(Exit)),
-
- "MORE" => Ok(Builtin(More)),
-
- "VERIFY" => Ok(Builtin(Verify)),
-
- // File-oriented commands
- "COPY" => {
- if args.len() >= 2 {
- Ok(Builtin(Copy {
- from: parse_filespec(&args[0]),
- to: parse_filespec(&args[1]),
- }))
- } else {
- Err(eyre::eyre!("COPY requires source and destination"))
- }
- },
-
- "DIR" => Ok(Builtin(Dir {
- path: if args.is_empty() {
- PathBuf::from(".")
- } else {
- PathBuf::from(&args[0])
- },
- })),
-
- "TYPE" => {
- if args.is_empty() {
- Err(eyre::eyre!("TYPE requires a filename"))
- } else {
- Ok(Builtin(Type {
- file: parse_filespec(&args[0]),
- }))
- }
- },
-
- "CD" | "CHDIR" => Ok(Builtin(Chdir {
- path: if args.is_empty() {
- std::env::current_dir()?
- } else {
- PathBuf::from(&args[0])
- },
- })),
-
- "MKDIR" | "MD" => {
- if args.is_empty() {
- Err(eyre::eyre!("MKDIR requires a directory name"))
- } else {
- Ok(Builtin(Mkdir {
- path: PathBuf::from(&args[0]),
- }))
- }
- },
-
- "RMDIR" | "RD" => {
- if args.is_empty() {
- Err(eyre::eyre!("RMDIR requires a directory name"))
- } else {
- Ok(Builtin(Rmdir {
- path: PathBuf::from(&args[0]),
- }))
- }
- },
-
- "DEL" | "ERASE" => {
- if args.is_empty() {
- Err(eyre::eyre!("DEL requires a filename"))
- } else {
- Ok(Builtin(Remove {
- path: PathBuf::from(&args[0]),
- }))
- }
- },
-
- "REM" => Ok(Builtin(Rem {
- message: args.join(" "),
- })),
-
- "VER" => Ok(Builtin(Ver)),
-
- "DATE" => Ok(Builtin(Date)),
-
- "TIME" => Ok(Builtin(Time)),
-
- "PATH" => {
- if args.is_empty() {
- Ok(Builtin(PathGet))
- } else {
- Ok(Builtin(PathSet {
- value: args.join(" "),
- }))
- }
- },
-
- "SET" => {
- if args.is_empty() {
- Err(eyre::eyre!("SET requires variable name"))
- } else {
- let full_arg = args.join(" ");
- if let Some(eq_pos) = full_arg.find('=') {
- let name = full_arg[..eq_pos].trim().to_string();
- let value = full_arg[eq_pos + 1..].trim().to_string();
- Ok(Builtin(Set { name, value }))
- } else {
- Err(eyre::eyre!("SET requires variable=value format"))
- }
- }
- },
-
- // Drive change (like C:, D:, etc.)
- _ if command_name.len() == 2 && command_name.ends_with(':') => Ok(Empty),
-
- // External command
- _ => Ok(External {
- program: command_name,
- args,
- }),
- }
- }
-}
-
-fn parse_filespec(p0: &str) -> FileSpec {
- match p0 {
- "CON" => FileSpec::Con,
- "LPT1" => FileSpec::Lpt1,
- "LPT2" => FileSpec::Lpt2,
- "LPT3" => FileSpec::Lpt3,
- "PRN" => FileSpec::Prn,
- _ => FileSpec::Path(PathBuf::from(p0)),
- }
-}
-
-impl Command {
- fn parse(input: &str) -> Result<Command> {
- let trimmed = input.trim();
- if trimmed.is_empty() {
- return Ok(Command::Empty);
- }
-
- let mut lexer = Lexer::new(trimmed);
- let tokens = lexer.tokenize();
-
- let mut parser = Parser::new(tokens);
- parser.parse_command()
- }
-}