Compare commits
1 Commits
main
...
revert-132
Author | SHA1 | Date | |
---|---|---|---|
|
70859ffe70 |
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
|
@ -26,13 +26,6 @@ updates:
|
|||
patterns:
|
||||
- "polars"
|
||||
- "polars-*"
|
||||
# uutils/coreutils also versions all their workspace crates the same at the moment
|
||||
# Most of them have bleeding edge version requirements (some not)
|
||||
# see: https://github.com/uutils/coreutils/blob/main/Cargo.toml
|
||||
uutils:
|
||||
patterns:
|
||||
- "uucore"
|
||||
- "uu_*"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
|
2
.github/workflows/nightly-build.yml
vendored
2
.github/workflows/nightly-build.yml
vendored
|
@ -161,7 +161,7 @@ jobs:
|
|||
# REF: https://github.com/marketplace/actions/gh-release
|
||||
# Create a release only in nushell/nightly repo
|
||||
- name: Publish Archive
|
||||
uses: softprops/action-gh-release@v2.0.8
|
||||
uses: softprops/action-gh-release@v2.0.6
|
||||
if: ${{ startsWith(github.repository, 'nushell/nightly') }}
|
||||
with:
|
||||
prerelease: true
|
||||
|
|
6
.github/workflows/release-pkg.nu
vendored
6
.github/workflows/release-pkg.nu
vendored
|
@ -161,12 +161,8 @@ if $os in ['macos-latest'] or $USE_UBUNTU {
|
|||
let releaseStem = $'($bin)-($version)-($target)'
|
||||
|
||||
print $'(char nl)Download less related stuffs...'; hr-line
|
||||
# todo: less-v661 is out but is released as a zip file. maybe we should switch to that and extract it?
|
||||
aria2c https://github.com/jftuga/less-Windows/releases/download/less-v608/less.exe -o less.exe
|
||||
# the below was renamed because it was failing to download for darren. it should work but it wasn't
|
||||
# todo: maybe we should get rid of this aria2c dependency and just use http get?
|
||||
#aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
|
||||
aria2c https://github.com/jftuga/less-Windows/blob/master/LICENSE -o LICENSE-for-less.txt
|
||||
aria2c https://raw.githubusercontent.com/jftuga/less-Windows/master/LICENSE -o LICENSE-for-less.txt
|
||||
|
||||
# Create Windows msi release package
|
||||
if (get-env _EXTRA_) == 'msi' {
|
||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -91,7 +91,7 @@ jobs:
|
|||
|
||||
# REF: https://github.com/marketplace/actions/gh-release
|
||||
- name: Publish Archive
|
||||
uses: softprops/action-gh-release@v2.0.8
|
||||
uses: softprops/action-gh-release@v2.0.6
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
with:
|
||||
draft: true
|
||||
|
|
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
|
@ -10,4 +10,4 @@ jobs:
|
|||
uses: actions/checkout@v4.1.7
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@v1.23.5
|
||||
uses: crate-ci/typos@v1.22.9
|
||||
|
|
192
Cargo.lock
generated
192
Cargo.lock
generated
|
@ -605,7 +605,7 @@ dependencies = [
|
|||
"encoding_rs",
|
||||
"log",
|
||||
"once_cell",
|
||||
"quick-xml 0.31.0",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"zip",
|
||||
]
|
||||
|
@ -1219,24 +1219,24 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2342,9 +2342,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.154"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
|
@ -2868,12 +2868,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"crossterm",
|
||||
"ctrlc",
|
||||
"dirs",
|
||||
"dirs-next",
|
||||
"log",
|
||||
"miette",
|
||||
"mimalloc",
|
||||
|
@ -2900,7 +2900,6 @@ dependencies = [
|
|||
"openssl",
|
||||
"pretty_assertions",
|
||||
"reedline",
|
||||
"regex",
|
||||
"rstest",
|
||||
"serde_json",
|
||||
"serial_test",
|
||||
|
@ -2913,16 +2912,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.1"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
|
||||
checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-cli"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossterm",
|
||||
|
@ -2957,7 +2956,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-base"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"miette",
|
||||
|
@ -2969,7 +2968,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-extra"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"heck 0.5.0",
|
||||
|
@ -2994,7 +2993,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nu-engine",
|
||||
|
@ -3006,7 +3005,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-plugin"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nu-engine",
|
||||
|
@ -3017,7 +3016,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-color-config"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-engine",
|
||||
|
@ -3029,7 +3028,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-command"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"alphanumeric-sort",
|
||||
"base64 0.22.1",
|
||||
|
@ -3047,7 +3046,7 @@ dependencies = [
|
|||
"deunicode",
|
||||
"dialoguer",
|
||||
"digest",
|
||||
"dirs",
|
||||
"dirs-next",
|
||||
"dtparse",
|
||||
"encoding_rs",
|
||||
"fancy-regex",
|
||||
|
@ -3094,7 +3093,7 @@ dependencies = [
|
|||
"pretty_assertions",
|
||||
"print-positions",
|
||||
"procfs",
|
||||
"quick-xml 0.31.0",
|
||||
"quick-xml",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"rand",
|
||||
|
@ -3139,7 +3138,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-derive-value"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro-error",
|
||||
|
@ -3150,19 +3149,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-explore"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"anyhow",
|
||||
|
@ -3187,19 +3184,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"doc-comment",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-json"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"linked-hash-map",
|
||||
"nu-path",
|
||||
"nu-test-support",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -3207,7 +3201,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-lsp"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"crossbeam-channel",
|
||||
|
@ -3228,7 +3222,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-parser"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"chrono",
|
||||
|
@ -3244,16 +3238,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"dirs-next",
|
||||
"omnipath",
|
||||
"pwd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix",
|
||||
|
@ -3261,7 +3255,6 @@ dependencies = [
|
|||
"nu-plugin-core",
|
||||
"nu-plugin-protocol",
|
||||
"nu-protocol",
|
||||
"nu-utils",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"typetag",
|
||||
|
@ -3269,7 +3262,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-core"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"log",
|
||||
|
@ -3283,7 +3276,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-engine"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nu-engine",
|
||||
|
@ -3291,7 +3284,6 @@ dependencies = [
|
|||
"nu-plugin-protocol",
|
||||
"nu-protocol",
|
||||
"nu-system",
|
||||
"nu-utils",
|
||||
"serde",
|
||||
"typetag",
|
||||
"windows 0.54.0",
|
||||
|
@ -3299,7 +3291,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"nu-protocol",
|
||||
|
@ -3311,7 +3303,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-test-support"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-cmd-lang",
|
||||
|
@ -3329,7 +3321,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"nu-ansi-term",
|
||||
|
@ -3338,18 +3330,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"brotli",
|
||||
"byte-unit",
|
||||
"chrono",
|
||||
"chrono-humanize",
|
||||
"convert_case",
|
||||
"dirs",
|
||||
"dirs-sys",
|
||||
"fancy-regex",
|
||||
"indexmap",
|
||||
"log",
|
||||
"lru",
|
||||
"miette",
|
||||
"nix",
|
||||
|
@ -3370,12 +3359,11 @@ dependencies = [
|
|||
"tempfile",
|
||||
"thiserror",
|
||||
"typetag",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-std"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"miette",
|
||||
|
@ -3386,7 +3374,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.12.1",
|
||||
|
@ -3404,7 +3392,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-table"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"nu-ansi-term",
|
||||
|
@ -3418,7 +3406,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-term-grid"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"nu-utils",
|
||||
"unicode-width",
|
||||
|
@ -3426,7 +3414,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-test-support"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
|
@ -3438,7 +3426,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"crossterm_winapi",
|
||||
"log",
|
||||
|
@ -3464,7 +3452,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_example"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"nu-cmd-lang",
|
||||
"nu-plugin",
|
||||
|
@ -3474,22 +3462,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_formats"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"eml-parser",
|
||||
"ical",
|
||||
"indexmap",
|
||||
"nu-plugin",
|
||||
"nu-plugin-test-support",
|
||||
"nu-protocol",
|
||||
"plist",
|
||||
"rust-ini",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_gstat"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"nu-plugin",
|
||||
|
@ -3498,7 +3484,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_inc"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
|
@ -3507,7 +3493,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_polars"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz 0.9.0",
|
||||
|
@ -3541,7 +3527,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_query"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"gjson",
|
||||
"nu-plugin",
|
||||
|
@ -3556,7 +3542,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_stress_internals"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"serde",
|
||||
|
@ -3682,7 +3668,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|||
|
||||
[[package]]
|
||||
name = "nuon"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fancy-regex",
|
||||
|
@ -3779,9 +3765,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
|||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "5.3.0"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a877bf6abd716642a53ef1b89fb498923a4afca5c754f9050b4d081c05c4b3"
|
||||
checksum = "9d2c909a3fce3bd80efef4cd1c6c056bd9376a8fe06fcfdbebaf32cb485a7e37"
|
||||
dependencies = [
|
||||
"is-wsl",
|
||||
"libc",
|
||||
|
@ -3790,9 +3776,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.66"
|
||||
version = "0.10.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1"
|
||||
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"cfg-if",
|
||||
|
@ -3831,9 +3817,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.103"
|
||||
version = "0.9.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6"
|
||||
checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
@ -3842,12 +3828,6 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.7.3"
|
||||
|
@ -4150,19 +4130,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plist"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"indexmap",
|
||||
"quick-xml 0.32.0",
|
||||
"serde",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polars"
|
||||
version = "0.41.2"
|
||||
|
@ -4831,15 +4798,6 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "1.0.3"
|
||||
|
@ -5029,8 +4987,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "reedline"
|
||||
version = "0.33.0"
|
||||
source = "git+https://github.com/nushell/reedline?branch=main#919292e40fd417e3da882692021961b444150c59"
|
||||
version = "0.32.0"
|
||||
source = "git+https://github.com/nushell/reedline?branch=main#480059a3f52cf919341cda88e8c544edd846bc73"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"chrono",
|
||||
|
@ -5244,9 +5202,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.5.0"
|
||||
version = "8.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0"
|
||||
checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
|
@ -5613,9 +5571,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "shadow-rs"
|
||||
version = "0.30.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d253e54681d4be0161e965db57974ae642a0b6aaeb18a999424c4dab062be8c5"
|
||||
checksum = "0a600f795d0894cda22235b44eea4b85c2a35b405f65523645ac8e35b306817a"
|
||||
dependencies = [
|
||||
"const_format",
|
||||
"is_debug",
|
||||
|
@ -5690,9 +5648,9 @@ checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
|
|||
|
||||
[[package]]
|
||||
name = "similar"
|
||||
version = "2.6.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e"
|
||||
checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640"
|
||||
|
||||
[[package]]
|
||||
name = "simplelog"
|
||||
|
@ -6507,9 +6465,9 @@ checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
|||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.10.0"
|
||||
version = "2.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea"
|
||||
checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"encoding_rs",
|
||||
|
@ -6666,9 +6624,9 @@ checksum = "425a23c7b7145bc7620c9c445817c37b1f78b6790aee9f208133f3c028975b60"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.10.0"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
|
||||
checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"serde",
|
||||
|
@ -6896,7 +6854,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml 0.31.0",
|
||||
"quick-xml",
|
||||
"quote",
|
||||
]
|
||||
|
||||
|
|
63
Cargo.toml
63
Cargo.toml
|
@ -10,8 +10,8 @@ homepage = "https://www.nushell.sh"
|
|||
license = "MIT"
|
||||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.78.0"
|
||||
version = "0.96.2"
|
||||
rust-version = "1.77.2"
|
||||
version = "0.95.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -83,8 +83,7 @@ ctrlc = "3.4"
|
|||
deunicode = "1.6.0"
|
||||
dialoguer = { default-features = false, version = "0.11" }
|
||||
digest = { default-features = false, version = "0.10" }
|
||||
dirs = "5.0"
|
||||
dirs-sys = "0.4"
|
||||
dirs-next = "2.0"
|
||||
dtparse = "2.0"
|
||||
encoding_rs = "0.8"
|
||||
fancy-regex = "0.13"
|
||||
|
@ -116,12 +115,12 @@ mockito = { version = "1.4", default-features = false }
|
|||
native-tls = "0.2"
|
||||
nix = { version = "0.28", default-features = false }
|
||||
notify-debouncer-full = { version = "0.3", default-features = false }
|
||||
nu-ansi-term = "0.50.1"
|
||||
nu-ansi-term = "0.50.0"
|
||||
num-format = "0.4"
|
||||
num-traits = "0.2"
|
||||
omnipath = "0.1"
|
||||
once_cell = "1.18"
|
||||
open = "5.3"
|
||||
open = "5.2"
|
||||
os_pipe = { version = "1.2", features = ["io_safety"] }
|
||||
pathdiff = "0.2"
|
||||
percent-encoding = "2"
|
||||
|
@ -138,7 +137,7 @@ quote = "1.0"
|
|||
rand = "0.8"
|
||||
ratatui = "0.26"
|
||||
rayon = "1.10"
|
||||
reedline = "0.33.0"
|
||||
reedline = "0.32.0"
|
||||
regex = "1.9.5"
|
||||
rmp = "0.8"
|
||||
rmp-serde = "1.3"
|
||||
|
@ -146,7 +145,7 @@ ropey = "1.6.1"
|
|||
roxmltree = "0.19"
|
||||
rstest = { version = "0.18", default-features = false }
|
||||
rusqlite = "0.31"
|
||||
rust-embed = "8.5.0"
|
||||
rust-embed = "8.4.0"
|
||||
same-file = "1.0"
|
||||
serde = { version = "1.0", default-features = false }
|
||||
serde_json = "1.0"
|
||||
|
@ -165,7 +164,7 @@ trash = "3.3"
|
|||
umask = "2.1"
|
||||
unicode-segmentation = "1.11"
|
||||
unicode-width = "0.1"
|
||||
ureq = { version = "2.10", default-features = false }
|
||||
ureq = { version = "2.9", default-features = false }
|
||||
url = "2.2"
|
||||
uu_cp = "0.0.27"
|
||||
uu_mkdir = "0.0.27"
|
||||
|
@ -174,36 +173,35 @@ uu_mv = "0.0.27"
|
|||
uu_whoami = "0.0.27"
|
||||
uu_uname = "0.0.27"
|
||||
uucore = "0.0.27"
|
||||
uuid = "1.10.0"
|
||||
uuid = "1.9.1"
|
||||
v_htmlescape = "0.15.0"
|
||||
wax = "0.6"
|
||||
which = "6.0.0"
|
||||
windows = "0.54"
|
||||
windows-sys = "0.48"
|
||||
winreg = "0.52"
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.96.2" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.96.2" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.96.2" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.96.2", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.96.2" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.96.2" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.96.2" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.96.2" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.96.2" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.96.2" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.96.2" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.96.2" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.96.2" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.96.2" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.96.2" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.96.2" }
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.95.1" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.95.1" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.95.1" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.95.1", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.95.1" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.95.1" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.95.1" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.95.1" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.95.1" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.95.1" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.95.1" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.95.1" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.95.1" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.95.1" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.95.1" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.95.1" }
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
crossterm = { workspace = true }
|
||||
ctrlc = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
dirs-next = { workspace = true }
|
||||
log = { workspace = true }
|
||||
miette = { workspace = true, features = ["fancy-no-backtrace", "fancy"] }
|
||||
mimalloc = { version = "0.1.42", default-features = false, optional = true }
|
||||
|
@ -227,14 +225,13 @@ nix = { workspace = true, default-features = false, features = [
|
|||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.96.2" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.96.2" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.96.2" }
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.95.1" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.95.1" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.95.1" }
|
||||
assert_cmd = "2.0"
|
||||
dirs = { workspace = true }
|
||||
dirs-next = { workspace = true }
|
||||
tango-bench = "0.5"
|
||||
pretty_assertions = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
serial_test = "3.1"
|
||||
tempfile = { workspace = true }
|
||||
|
|
29
SECURITY.md
29
SECURITY.md
|
@ -1,29 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
As a shell and programming language Nushell provides you with great powers and the potential to do dangerous things to your computer and data. Whenever there is a risk that a malicious actor can abuse a bug or a violation of documented behavior/assumptions in Nushell to harm you this is a *security* risk.
|
||||
We want to fix those issues without exposing our users to unnecessary risk. Thus we want to explain our security policy.
|
||||
Additional issues may be part of *safety* where the behavior of Nushell as designed and implemented can cause unintended harm or a bug causes damage without the involvement of a third party.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
As Nushell is still under very active pre-stable development, the only version the core team prioritizes for security and safety fixes is the [most recent version as published on GitHub](https://github.com/nushell/nushell/releases/latest).
|
||||
Only if you provide a strong reasoning and the necessary resources, will we consider blessing a backported fix with an official patch release for a previous version.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you suspect that a bug or behavior of Nushell can affect security or may be potentially exploitable, please report the issue to us in private.
|
||||
Either reach out to the core team on [our Discord server](https://discord.gg/NtAbbGn) to arrange a private channel or use the [GitHub vulnerability reporting form](https://github.com/nushell/nushell/security/advisories/new).
|
||||
Please try to answer the following questions:
|
||||
- How can we reach you for further questions?
|
||||
- What is the bug? Which system of Nushell may be affected?
|
||||
- Do you have proof-of-concept for a potential exploit or have you observed an exploit in the wild?
|
||||
- What is your assessment of the severity based on what could be impacted should the bug be exploited?
|
||||
- Are additional people aware of the issue or deserve credit for identifying the issue?
|
||||
|
||||
We will try to get back to you within a week with:
|
||||
- acknowledging the receipt of the report
|
||||
- an initial plan of how we want to address this including the primary points of contact for further communication
|
||||
- our preliminary assessment of how severe we judge the issue
|
||||
- a proposal for how we can coordinate responsible disclosure (e.g. how we ship the bugfix, if we need to coordinate with distribution maintainers, when you can release a blog post if you want to etc.)
|
||||
|
||||
For purely *safety* related issues where the impact is severe by direct user action instead of malicious input or third parties, feel free to open a regular issue. If we deem that there may be an additional *security* risk on a *safety* issue we may continue discussions in a restricted forum.
|
|
@ -45,10 +45,6 @@ fn setup_stack_and_engine_from_command(command: &str) -> (Stack, EngineState) {
|
|||
};
|
||||
|
||||
let mut stack = Stack::new();
|
||||
|
||||
// Support running benchmarks with IR mode
|
||||
stack.use_ir = std::env::var_os("NU_USE_IR").is_some();
|
||||
|
||||
evaluate_commands(
|
||||
&commands,
|
||||
&mut engine,
|
||||
|
|
|
@ -5,27 +5,27 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.96.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.95.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.95.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.96.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.96.2" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.96.2", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.96.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.96.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.95.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.95.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.95.1" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.95.1", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.95.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.95.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
This crate implements the core functionality of the interactive Nushell REPL and interfaces with `reedline`.
|
||||
Currently implements the syntax highlighting and completions logic.
|
||||
Furthermore includes a few commands that are specific to `reedline`
|
||||
|
||||
## Internal Nushell crate
|
||||
|
||||
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.
|
|
@ -67,7 +67,7 @@ impl Command for History {
|
|||
} else {
|
||||
let history_reader: Option<Box<dyn ReedlineHistory>> = match history.file_format {
|
||||
HistoryFileFormat::Sqlite => {
|
||||
SqliteBackedHistory::with_file(history_path.clone().into(), None, None)
|
||||
SqliteBackedHistory::with_file(history_path.clone(), None, None)
|
||||
.map(|inner| {
|
||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
||||
boxed
|
||||
|
@ -77,7 +77,7 @@ impl Command for History {
|
|||
|
||||
HistoryFileFormat::PlainText => FileBackedHistory::with_file(
|
||||
history.max_size as usize,
|
||||
history_path.clone().into(),
|
||||
history_path.clone(),
|
||||
)
|
||||
.map(|inner| {
|
||||
let boxed: Box<dyn ReedlineHistory> = Box::new(inner);
|
||||
|
@ -156,34 +156,58 @@ fn create_history_record(idx: usize, entry: HistoryItem, long: bool, head: Span)
|
|||
//2. Create a record of either short or long columns and values
|
||||
|
||||
let item_id_value = Value::int(
|
||||
entry
|
||||
.id
|
||||
.and_then(|id| id.to_string().parse::<i64>().ok())
|
||||
.unwrap_or_default(),
|
||||
match entry.id {
|
||||
Some(id) => {
|
||||
let ids = id.to_string();
|
||||
match ids.parse::<i64>() {
|
||||
Ok(i) => i,
|
||||
_ => 0i64,
|
||||
}
|
||||
}
|
||||
None => 0i64,
|
||||
},
|
||||
head,
|
||||
);
|
||||
let start_timestamp_value = Value::string(
|
||||
entry
|
||||
.start_timestamp
|
||||
.map(|time| time.to_string())
|
||||
.unwrap_or_default(),
|
||||
match entry.start_timestamp {
|
||||
Some(time) => time.to_string(),
|
||||
None => "".into(),
|
||||
},
|
||||
head,
|
||||
);
|
||||
let command_value = Value::string(entry.command_line, head);
|
||||
let session_id_value = Value::int(
|
||||
entry
|
||||
.session_id
|
||||
.and_then(|id| id.to_string().parse::<i64>().ok())
|
||||
.unwrap_or_default(),
|
||||
match entry.session_id {
|
||||
Some(sid) => {
|
||||
let sids = sid.to_string();
|
||||
match sids.parse::<i64>() {
|
||||
Ok(i) => i,
|
||||
_ => 0i64,
|
||||
}
|
||||
}
|
||||
None => 0i64,
|
||||
},
|
||||
head,
|
||||
);
|
||||
let hostname_value = Value::string(
|
||||
match entry.hostname {
|
||||
Some(host) => host,
|
||||
None => "".into(),
|
||||
},
|
||||
head,
|
||||
);
|
||||
let cwd_value = Value::string(
|
||||
match entry.cwd {
|
||||
Some(cwd) => cwd,
|
||||
None => "".into(),
|
||||
},
|
||||
head,
|
||||
);
|
||||
let hostname_value = Value::string(entry.hostname.unwrap_or_default(), head);
|
||||
let cwd_value = Value::string(entry.cwd.unwrap_or_default(), head);
|
||||
let duration_value = Value::duration(
|
||||
entry
|
||||
.duration
|
||||
.and_then(|d| d.as_nanos().try_into().ok())
|
||||
.unwrap_or(0),
|
||||
match entry.duration {
|
||||
Some(d) => d.as_nanos().try_into().unwrap_or(0),
|
||||
None => 0,
|
||||
},
|
||||
head,
|
||||
);
|
||||
let exit_status_value = Value::int(entry.exit_status.unwrap_or(0), head);
|
||||
|
|
|
@ -49,26 +49,22 @@ impl Command for KeybindingsList {
|
|||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let all_options = ["modifiers", "keycodes", "edits", "modes", "events"];
|
||||
|
||||
let presence = all_options
|
||||
.iter()
|
||||
.map(|option| call.has_flag(engine_state, stack, option))
|
||||
.collect::<Result<Vec<_>, ShellError>>()?;
|
||||
|
||||
let no_option_specified = presence.iter().all(|present| !*present);
|
||||
|
||||
let records = all_options
|
||||
.iter()
|
||||
.zip(presence)
|
||||
.filter(|(_, present)| no_option_specified || *present)
|
||||
.flat_map(|(option, _)| get_records(option, call.head))
|
||||
.collect();
|
||||
let records = if call.named_len() == 0 {
|
||||
let all_options = ["modifiers", "keycodes", "edits", "modes", "events"];
|
||||
all_options
|
||||
.iter()
|
||||
.flat_map(|argument| get_records(argument, call.head))
|
||||
.collect()
|
||||
} else {
|
||||
call.named_iter()
|
||||
.flat_map(|(argument, _, _)| get_records(argument.item.as_str(), call.head))
|
||||
.collect()
|
||||
};
|
||||
|
||||
Ok(Value::list(records, call.head).into_pipeline_data())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
completions::{Completer, CompletionOptions, MatchAlgorithm},
|
||||
completions::{Completer, CompletionOptions, MatchAlgorithm, SortBy},
|
||||
SuggestionKind,
|
||||
};
|
||||
use nu_parser::FlatShape;
|
||||
|
@ -99,9 +99,10 @@ impl CommandCompletion {
|
|||
suggestion: Suggestion {
|
||||
value: String::from_utf8_lossy(&x.0).to_string(),
|
||||
description: x.1,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span::new(span.start - offset, span.end - offset),
|
||||
append_whitespace: true,
|
||||
..Suggestion::default()
|
||||
},
|
||||
kind: Some(SuggestionKind::Command(x.2)),
|
||||
})
|
||||
|
@ -117,9 +118,11 @@ impl CommandCompletion {
|
|||
.map(move |x| SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: x,
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span::new(span.start - offset, span.end - offset),
|
||||
append_whitespace: true,
|
||||
..Suggestion::default()
|
||||
},
|
||||
// TODO: is there a way to create a test?
|
||||
kind: None,
|
||||
|
@ -133,9 +136,11 @@ impl CommandCompletion {
|
|||
results.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: format!("^{}", external.suggestion.value),
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: external.suggestion.span,
|
||||
append_whitespace: true,
|
||||
..Suggestion::default()
|
||||
},
|
||||
kind: external.kind,
|
||||
})
|
||||
|
@ -193,7 +198,11 @@ impl Completer for CommandCompletion {
|
|||
};
|
||||
|
||||
if !subcommands.is_empty() {
|
||||
return sort_suggestions(&String::from_utf8_lossy(&prefix), subcommands, options);
|
||||
return sort_suggestions(
|
||||
&String::from_utf8_lossy(&prefix),
|
||||
subcommands,
|
||||
SortBy::LevenshteinDistance,
|
||||
);
|
||||
}
|
||||
|
||||
let config = working_set.get_config();
|
||||
|
@ -218,7 +227,11 @@ impl Completer for CommandCompletion {
|
|||
vec![]
|
||||
};
|
||||
|
||||
sort_suggestions(&String::from_utf8_lossy(&prefix), commands, options)
|
||||
sort_suggestions(
|
||||
&String::from_utf8_lossy(&prefix),
|
||||
commands,
|
||||
SortBy::LevenshteinDistance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ impl NuCompleter {
|
|||
let options = CompletionOptions {
|
||||
case_sensitive: config.case_sensitive_completions,
|
||||
match_algorithm: config.completion_algorithm.into(),
|
||||
sort: config.completion_sort,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -444,11 +443,14 @@ pub fn map_value_completions<'a>(
|
|||
return Some(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: s,
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
kind: Some(SuggestionKind::Type(x.get_type())),
|
||||
});
|
||||
|
@ -458,11 +460,14 @@ pub fn map_value_completions<'a>(
|
|||
if let Ok(record) = x.as_record() {
|
||||
let mut suggestion = Suggestion {
|
||||
value: String::from(""), // Initialize with empty string
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
};
|
||||
|
||||
// Iterate the cols looking for `value` and `description`
|
||||
|
|
|
@ -2,18 +2,19 @@ use crate::{
|
|||
completions::{matches, CompletionOptions},
|
||||
SemanticSuggestion,
|
||||
};
|
||||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
use nu_ansi_term::Style;
|
||||
use nu_engine::env_to_string;
|
||||
use nu_path::{expand_to_real_path, home_dir};
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
CompletionSort, Span,
|
||||
levenshtein_distance, Span,
|
||||
};
|
||||
use nu_utils::get_ls_colors;
|
||||
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
|
||||
use std::path::{
|
||||
is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR,
|
||||
};
|
||||
|
||||
use super::MatchAlgorithm;
|
||||
use super::SortBy;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PathBuiltFromString {
|
||||
|
@ -21,21 +22,12 @@ pub struct PathBuiltFromString {
|
|||
isdir: bool,
|
||||
}
|
||||
|
||||
/// Recursively goes through paths that match a given `partial`.
|
||||
/// built: State struct for a valid matching path built so far.
|
||||
///
|
||||
/// `isdir`: whether the current partial path has a trailing slash.
|
||||
/// Parsing a path string into a pathbuf loses that bit of information.
|
||||
///
|
||||
/// want_directory: Whether we want only directories as completion matches.
|
||||
/// Some commands like `cd` can only be run on directories whereas others
|
||||
/// like `ls` can be run on regular files as well.
|
||||
pub fn complete_rec(
|
||||
fn complete_rec(
|
||||
partial: &[&str],
|
||||
built: &PathBuiltFromString,
|
||||
cwd: &Path,
|
||||
options: &CompletionOptions,
|
||||
want_directory: bool,
|
||||
dir: bool,
|
||||
isdir: bool,
|
||||
) -> Vec<PathBuiltFromString> {
|
||||
let mut completions = vec![];
|
||||
|
@ -45,7 +37,7 @@ pub fn complete_rec(
|
|||
let mut built = built.clone();
|
||||
built.parts.push(base.to_string());
|
||||
built.isdir = true;
|
||||
return complete_rec(rest, &built, cwd, options, want_directory, isdir);
|
||||
return complete_rec(rest, &built, cwd, options, dir, isdir);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,41 +58,24 @@ pub fn complete_rec(
|
|||
built.parts.push(entry_name.clone());
|
||||
built.isdir = entry_isdir;
|
||||
|
||||
if !want_directory || entry_isdir {
|
||||
if !dir || entry_isdir {
|
||||
entries.push((entry_name, built));
|
||||
}
|
||||
}
|
||||
|
||||
let prefix = partial.first().unwrap_or(&"");
|
||||
let sorted_entries = sort_completions(prefix, entries, options, |(entry, _)| entry);
|
||||
let sorted_entries = sort_completions(prefix, entries, SortBy::Ascending, |(entry, _)| entry);
|
||||
|
||||
for (entry_name, built) in sorted_entries {
|
||||
match partial.split_first() {
|
||||
Some((base, rest)) => {
|
||||
if matches(base, &entry_name, options) {
|
||||
// We use `isdir` to confirm that the current component has
|
||||
// at least one next component or a slash.
|
||||
// Serves as confirmation to ignore longer completions for
|
||||
// components in between.
|
||||
if !rest.is_empty() || isdir {
|
||||
completions.extend(complete_rec(
|
||||
rest,
|
||||
&built,
|
||||
cwd,
|
||||
options,
|
||||
want_directory,
|
||||
isdir,
|
||||
));
|
||||
completions.extend(complete_rec(rest, &built, cwd, options, dir, isdir));
|
||||
} else {
|
||||
completions.push(built);
|
||||
}
|
||||
}
|
||||
if entry_name.eq(base)
|
||||
&& matches!(options.match_algorithm, MatchAlgorithm::Prefix)
|
||||
&& isdir
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
completions.push(built);
|
||||
|
@ -118,16 +93,16 @@ enum OriginalCwd {
|
|||
}
|
||||
|
||||
impl OriginalCwd {
|
||||
fn apply(&self, mut p: PathBuiltFromString, path_separator: char) -> String {
|
||||
fn apply(&self, mut p: PathBuiltFromString) -> String {
|
||||
match self {
|
||||
Self::None => {}
|
||||
Self::Home => p.parts.insert(0, "~".to_string()),
|
||||
Self::Prefix(s) => p.parts.insert(0, s.clone()),
|
||||
};
|
||||
|
||||
let mut ret = p.parts.join(&path_separator.to_string());
|
||||
let mut ret = p.parts.join(MAIN_SEPARATOR_STR);
|
||||
if p.isdir {
|
||||
ret.push(path_separator);
|
||||
ret.push(SEP);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
@ -158,14 +133,6 @@ pub fn complete_item(
|
|||
) -> Vec<(nu_protocol::Span, String, Option<Style>)> {
|
||||
let partial = surround_remove(partial);
|
||||
let isdir = partial.ends_with(is_separator);
|
||||
|
||||
#[cfg(unix)]
|
||||
let path_separator = SEP;
|
||||
#[cfg(windows)]
|
||||
let path_separator = partial
|
||||
.chars()
|
||||
.rfind(|c: &char| is_separator(*c))
|
||||
.unwrap_or(SEP);
|
||||
let cwd_pathbuf = Path::new(cwd).to_path_buf();
|
||||
let ls_colors = (engine_state.config.use_ls_colors_completions
|
||||
&& engine_state.config.use_ansi_coloring)
|
||||
|
@ -203,7 +170,7 @@ pub fn complete_item(
|
|||
}
|
||||
Some(Component::Normal(home)) if home.to_string_lossy() == "~" => {
|
||||
components.next();
|
||||
cwd = home_dir().map(Into::into).unwrap_or(cwd_pathbuf);
|
||||
cwd = home_dir().unwrap_or(cwd_pathbuf);
|
||||
prefix_len = 1;
|
||||
original_cwd = OriginalCwd::Home;
|
||||
}
|
||||
|
@ -228,7 +195,7 @@ pub fn complete_item(
|
|||
)
|
||||
.into_iter()
|
||||
.map(|p| {
|
||||
let path = original_cwd.apply(p, path_separator);
|
||||
let path = original_cwd.apply(p);
|
||||
let style = ls_colors.as_ref().map(|lsc| {
|
||||
lsc.style_for_path_with_metadata(
|
||||
&path,
|
||||
|
@ -306,37 +273,33 @@ pub fn adjust_if_intermediate(
|
|||
pub fn sort_suggestions(
|
||||
prefix: &str,
|
||||
items: Vec<SemanticSuggestion>,
|
||||
options: &CompletionOptions,
|
||||
sort_by: SortBy,
|
||||
) -> Vec<SemanticSuggestion> {
|
||||
sort_completions(prefix, items, options, |it| &it.suggestion.value)
|
||||
sort_completions(prefix, items, sort_by, |it| &it.suggestion.value)
|
||||
}
|
||||
|
||||
/// # Arguments
|
||||
/// * `prefix` - What the user's typed, for sorting by fuzzy matcher score
|
||||
/// * `prefix` - What the user's typed, for sorting by Levenshtein distance
|
||||
pub fn sort_completions<T>(
|
||||
prefix: &str,
|
||||
mut items: Vec<T>,
|
||||
options: &CompletionOptions,
|
||||
sort_by: SortBy,
|
||||
get_value: fn(&T) -> &str,
|
||||
) -> Vec<T> {
|
||||
// Sort items
|
||||
if options.sort == CompletionSort::Smart && options.match_algorithm == MatchAlgorithm::Fuzzy {
|
||||
let mut matcher = SkimMatcherV2::default();
|
||||
if options.case_sensitive {
|
||||
matcher = matcher.respect_case();
|
||||
} else {
|
||||
matcher = matcher.ignore_case();
|
||||
};
|
||||
items.sort_by(|a, b| {
|
||||
let a_str = get_value(a);
|
||||
let b_str = get_value(b);
|
||||
let a_score = matcher.fuzzy_match(a_str, prefix).unwrap_or_default();
|
||||
let b_score = matcher.fuzzy_match(b_str, prefix).unwrap_or_default();
|
||||
b_score.cmp(&a_score).then(a_str.cmp(b_str))
|
||||
});
|
||||
} else {
|
||||
items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
|
||||
}
|
||||
match sort_by {
|
||||
SortBy::LevenshteinDistance => {
|
||||
items.sort_by(|a, b| {
|
||||
let a_distance = levenshtein_distance(prefix, get_value(a));
|
||||
let b_distance = levenshtein_distance(prefix, get_value(b));
|
||||
a_distance.cmp(&b_distance)
|
||||
});
|
||||
}
|
||||
SortBy::Ascending => {
|
||||
items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
|
||||
}
|
||||
SortBy::None => {}
|
||||
};
|
||||
|
||||
items
|
||||
}
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
use nu_parser::trim_quotes_str;
|
||||
use nu_protocol::{CompletionAlgorithm, CompletionSort};
|
||||
use nu_protocol::CompletionAlgorithm;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SortBy {
|
||||
LevenshteinDistance,
|
||||
Ascending,
|
||||
None,
|
||||
}
|
||||
|
||||
/// Describes how suggestions should be matched.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum MatchAlgorithm {
|
||||
/// Only show suggestions which begin with the given input
|
||||
///
|
||||
|
@ -89,7 +96,6 @@ pub struct CompletionOptions {
|
|||
pub case_sensitive: bool,
|
||||
pub positional: bool,
|
||||
pub match_algorithm: MatchAlgorithm,
|
||||
pub sort: CompletionSort,
|
||||
}
|
||||
|
||||
impl Default for CompletionOptions {
|
||||
|
@ -98,7 +104,6 @@ impl Default for CompletionOptions {
|
|||
case_sensitive: true,
|
||||
positional: true,
|
||||
match_algorithm: MatchAlgorithm::Prefix,
|
||||
sort: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
use crate::completions::{
|
||||
completer::map_value_completions, Completer, CompletionOptions, MatchAlgorithm,
|
||||
SemanticSuggestion,
|
||||
SemanticSuggestion, SortBy,
|
||||
};
|
||||
use nu_engine::eval_call;
|
||||
use nu_protocol::{
|
||||
ast::{Argument, Call, Expr, Expression},
|
||||
debugger::WithoutDebug,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
CompletionSort, PipelineData, Span, Type, Value,
|
||||
PipelineData, Span, Type, Value,
|
||||
};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use std::collections::HashMap;
|
||||
|
@ -18,6 +18,7 @@ pub struct CustomCompletion {
|
|||
stack: Stack,
|
||||
decl_id: usize,
|
||||
line: String,
|
||||
sort_by: SortBy,
|
||||
}
|
||||
|
||||
impl CustomCompletion {
|
||||
|
@ -26,6 +27,7 @@ impl CustomCompletion {
|
|||
stack,
|
||||
decl_id,
|
||||
line,
|
||||
sort_by: SortBy::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,6 +93,10 @@ impl Completer for CustomCompletion {
|
|||
.and_then(|val| val.as_bool().ok())
|
||||
.unwrap_or(false);
|
||||
|
||||
if should_sort {
|
||||
self.sort_by = SortBy::Ascending;
|
||||
}
|
||||
|
||||
custom_completion_options = Some(CompletionOptions {
|
||||
case_sensitive: options
|
||||
.get("case_sensitive")
|
||||
|
@ -108,11 +114,6 @@ impl Completer for CustomCompletion {
|
|||
.unwrap_or(MatchAlgorithm::Prefix),
|
||||
None => completion_options.match_algorithm,
|
||||
},
|
||||
sort: if should_sort {
|
||||
CompletionSort::Alphabetical
|
||||
} else {
|
||||
CompletionSort::Smart
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -123,11 +124,12 @@ impl Completer for CustomCompletion {
|
|||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let options = custom_completion_options
|
||||
.as_ref()
|
||||
.unwrap_or(completion_options);
|
||||
let suggestions = filter(&prefix, suggestions, completion_options);
|
||||
sort_suggestions(&String::from_utf8_lossy(&prefix), suggestions, options)
|
||||
let suggestions = if let Some(custom_completion_options) = custom_completion_options {
|
||||
filter(&prefix, suggestions, &custom_completion_options)
|
||||
} else {
|
||||
filter(&prefix, suggestions, completion_options)
|
||||
};
|
||||
sort_suggestions(&String::from_utf8_lossy(&prefix), suggestions, self.sort_by)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,12 +48,14 @@ impl Completer for DirectoryCompletion {
|
|||
.map(move |x| SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: x.1,
|
||||
description: None,
|
||||
style: x.2,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: x.0.start - offset,
|
||||
end: x.0.end - offset,
|
||||
},
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
// TODO????
|
||||
kind: None,
|
||||
|
|
|
@ -6,7 +6,7 @@ use nu_protocol::{
|
|||
use reedline::Suggestion;
|
||||
use std::path::{is_separator, Path, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR};
|
||||
|
||||
use super::{completion_common::sort_suggestions, SemanticSuggestion};
|
||||
use super::{completion_common::sort_suggestions, SemanticSuggestion, SortBy};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DotNuCompletion {}
|
||||
|
@ -116,13 +116,14 @@ impl Completer for DotNuCompletion {
|
|||
.map(move |x| SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: x.1,
|
||||
description: None,
|
||||
style: x.2,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: x.0.start - offset,
|
||||
end: x.0.end - offset,
|
||||
},
|
||||
append_whitespace: true,
|
||||
..Suggestion::default()
|
||||
},
|
||||
// TODO????
|
||||
kind: None,
|
||||
|
@ -130,6 +131,6 @@ impl Completer for DotNuCompletion {
|
|||
})
|
||||
.collect();
|
||||
|
||||
sort_suggestions(&prefix_str, output, options)
|
||||
sort_suggestions(&prefix_str, output, SortBy::Ascending)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,12 +53,14 @@ impl Completer for FileCompletion {
|
|||
.map(move |x| SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: x.1,
|
||||
description: None,
|
||||
style: x.2,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: x.0.start - offset,
|
||||
end: x.0.end - offset,
|
||||
},
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
// TODO????
|
||||
kind: None,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::completions::{completion_common::sort_suggestions, Completer, CompletionOptions};
|
||||
use crate::completions::{
|
||||
completion_common::sort_suggestions, Completer, CompletionOptions, SortBy,
|
||||
};
|
||||
use nu_protocol::{
|
||||
ast::{Expr, Expression},
|
||||
engine::{Stack, StateWorkingSet},
|
||||
|
@ -49,12 +51,13 @@ impl Completer for FlagCompletion {
|
|||
suggestion: Suggestion {
|
||||
value: String::from_utf8_lossy(&named).to_string(),
|
||||
description: Some(flag_desc.to_string()),
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
append_whitespace: true,
|
||||
..Suggestion::default()
|
||||
},
|
||||
// TODO????
|
||||
kind: None,
|
||||
|
@ -75,12 +78,13 @@ impl Completer for FlagCompletion {
|
|||
suggestion: Suggestion {
|
||||
value: String::from_utf8_lossy(&named).to_string(),
|
||||
description: Some(flag_desc.to_string()),
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
append_whitespace: true,
|
||||
..Suggestion::default()
|
||||
},
|
||||
// TODO????
|
||||
kind: None,
|
||||
|
@ -88,7 +92,7 @@ impl Completer for FlagCompletion {
|
|||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&String::from_utf8_lossy(&prefix), output, options);
|
||||
return sort_suggestions(&String::from_utf8_lossy(&prefix), output, SortBy::Ascending);
|
||||
}
|
||||
|
||||
vec![]
|
||||
|
|
|
@ -13,7 +13,7 @@ mod variable_completions;
|
|||
pub use base::{Completer, SemanticSuggestion, SuggestionKind};
|
||||
pub use command_completions::CommandCompletion;
|
||||
pub use completer::NuCompleter;
|
||||
pub use completion_options::{CompletionOptions, MatchAlgorithm};
|
||||
pub use completion_options::{CompletionOptions, MatchAlgorithm, SortBy};
|
||||
pub use custom_completions::CustomCompletion;
|
||||
pub use directory_completions::DirectoryCompletion;
|
||||
pub use dotnu_completions::DotNuCompletion;
|
||||
|
|
|
@ -9,7 +9,7 @@ use nu_protocol::{
|
|||
use reedline::Suggestion;
|
||||
use std::str;
|
||||
|
||||
use super::completion_common::sort_suggestions;
|
||||
use super::{completion_common::sort_suggestions, SortBy};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VariableCompletion {
|
||||
|
@ -72,7 +72,7 @@ impl Completer for VariableCompletion {
|
|||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
}
|
||||
} else {
|
||||
// No nesting provided, return all env vars
|
||||
|
@ -85,15 +85,18 @@ impl Completer for VariableCompletion {
|
|||
output.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: env_var.0,
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: current_span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
kind: Some(SuggestionKind::Type(env_var.1.get_type())),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,7 +120,7 @@ impl Completer for VariableCompletion {
|
|||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +142,7 @@ impl Completer for VariableCompletion {
|
|||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,8 +157,11 @@ impl Completer for VariableCompletion {
|
|||
output.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: builtin.to_string(),
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: current_span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
// TODO is there a way to get the VarId to get the type???
|
||||
kind: None,
|
||||
|
@ -178,8 +184,11 @@ impl Completer for VariableCompletion {
|
|||
output.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: String::from_utf8_lossy(v.0).to_string(),
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: current_span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
kind: Some(SuggestionKind::Type(
|
||||
working_set.get_variable(*v.1).ty.clone(),
|
||||
|
@ -206,8 +215,11 @@ impl Completer for VariableCompletion {
|
|||
output.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: String::from_utf8_lossy(v.0).to_string(),
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: current_span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
kind: Some(SuggestionKind::Type(
|
||||
working_set.get_variable(*v.1).ty.clone(),
|
||||
|
@ -217,7 +229,7 @@ impl Completer for VariableCompletion {
|
|||
}
|
||||
}
|
||||
|
||||
output = sort_suggestions(&prefix_str, output, options);
|
||||
output = sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
|
||||
output.dedup(); // TODO: Removes only consecutive duplicates, is it intended?
|
||||
|
||||
|
@ -243,8 +255,11 @@ fn nested_suggestions(
|
|||
output.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: col.clone(),
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: current_span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
kind: Some(kind.clone()),
|
||||
});
|
||||
|
@ -257,8 +272,11 @@ fn nested_suggestions(
|
|||
output.push(SemanticSuggestion {
|
||||
suggestion: Suggestion {
|
||||
value: column_name,
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: current_span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
},
|
||||
kind: Some(kind.clone()),
|
||||
});
|
||||
|
|
|
@ -192,8 +192,7 @@ pub fn add_plugin_file(
|
|||
} else if let Some(mut plugin_path) = nu_path::config_dir() {
|
||||
// Path to store plugins signatures
|
||||
plugin_path.push(storage_path);
|
||||
let mut plugin_path =
|
||||
canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path.into());
|
||||
let mut plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path);
|
||||
plugin_path.push(PLUGIN_FILE);
|
||||
let plugin_path = canonicalize_with(&plugin_path, &cwd).unwrap_or(plugin_path);
|
||||
engine_state.plugin_path = Some(plugin_path);
|
||||
|
@ -248,7 +247,7 @@ pub(crate) fn get_history_path(storage_path: &str, mode: HistoryFileFormat) -> O
|
|||
HistoryFileFormat::PlainText => HISTORY_FILE_TXT,
|
||||
HistoryFileFormat::Sqlite => HISTORY_FILE_SQLITE,
|
||||
});
|
||||
history_path.into()
|
||||
history_path
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,9 @@ pub fn evaluate_commands(
|
|||
// Parse the source code
|
||||
let (block, delta) = {
|
||||
if let Some(ref t_mode) = table_mode {
|
||||
Arc::make_mut(&mut engine_state.config).table_mode =
|
||||
t_mode.coerce_str()?.parse().unwrap_or_default();
|
||||
let mut config = engine_state.get_config().clone();
|
||||
config.table_mode = t_mode.coerce_str()?.parse().unwrap_or_default();
|
||||
engine_state.set_config(config);
|
||||
}
|
||||
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
@ -69,11 +70,6 @@ pub fn evaluate_commands(
|
|||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if let Some(err) = working_set.compile_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
// Not a fatal error, for now
|
||||
}
|
||||
|
||||
(output, working_set.render())
|
||||
};
|
||||
|
||||
|
|
|
@ -76,21 +76,12 @@ pub fn evaluate_file(
|
|||
trace!("parsing file: {}", file_path_str);
|
||||
let block = parse(&mut working_set, Some(file_path_str), &file, false);
|
||||
|
||||
if let Some(warning) = working_set.parse_warnings.first() {
|
||||
report_error(&working_set, warning);
|
||||
}
|
||||
|
||||
// If any parse errors were found, report the first error and exit.
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if let Some(err) = working_set.compile_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
// Not a fatal error, for now
|
||||
}
|
||||
|
||||
// Look for blocks whose name starts with "main" and replace it with the filename.
|
||||
for block in working_set.delta.blocks.iter_mut().map(Arc::make_mut) {
|
||||
if block.signature.name == "main" {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
mod commands;
|
||||
mod completions;
|
||||
mod config_files;
|
||||
|
|
|
@ -1,34 +1,25 @@
|
|||
use nu_engine::documentation::{get_flags_section, HelpStyle};
|
||||
use nu_protocol::{engine::EngineState, levenshtein_distance, Config};
|
||||
use nu_engine::documentation::get_flags_section;
|
||||
use nu_protocol::{engine::EngineState, levenshtein_distance};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use reedline::{Completer, Suggestion};
|
||||
use std::{fmt::Write, sync::Arc};
|
||||
|
||||
pub struct NuHelpCompleter {
|
||||
engine_state: Arc<EngineState>,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
pub struct NuHelpCompleter(Arc<EngineState>);
|
||||
|
||||
impl NuHelpCompleter {
|
||||
pub fn new(engine_state: Arc<EngineState>, config: Arc<Config>) -> Self {
|
||||
Self {
|
||||
engine_state,
|
||||
config,
|
||||
}
|
||||
pub fn new(engine_state: Arc<EngineState>) -> Self {
|
||||
Self(engine_state)
|
||||
}
|
||||
|
||||
fn completion_helper(&self, line: &str, pos: usize) -> Vec<Suggestion> {
|
||||
let folded_line = line.to_folded_case();
|
||||
|
||||
let mut help_style = HelpStyle::default();
|
||||
help_style.update_from_config(&self.engine_state, &self.config);
|
||||
|
||||
let mut commands = self
|
||||
.engine_state
|
||||
.0
|
||||
.get_decls_sorted(false)
|
||||
.into_iter()
|
||||
.filter_map(|(_, decl_id)| {
|
||||
let decl = self.engine_state.get_decl(decl_id);
|
||||
let decl = self.0.get_decl(decl_id);
|
||||
(decl.name().to_folded_case().contains(&folded_line)
|
||||
|| decl.usage().to_folded_case().contains(&folded_line)
|
||||
|| decl
|
||||
|
@ -63,8 +54,8 @@ impl NuHelpCompleter {
|
|||
let _ = write!(long_desc, "Usage:\r\n > {}\r\n", sig.call_signature());
|
||||
|
||||
if !sig.named.is_empty() {
|
||||
long_desc.push_str(&get_flags_section(&sig, &help_style, |v| {
|
||||
v.to_parsable_string(", ", &self.config)
|
||||
long_desc.push_str(&get_flags_section(Some(&*self.0.clone()), &sig, |v| {
|
||||
v.to_parsable_string(", ", &self.0.config)
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -80,7 +71,7 @@ impl NuHelpCompleter {
|
|||
let opt_suffix = if let Some(value) = &positional.default_value {
|
||||
format!(
|
||||
" (optional, default: {})",
|
||||
&value.to_parsable_string(", ", &self.config),
|
||||
&value.to_parsable_string(", ", &self.0.config),
|
||||
)
|
||||
} else {
|
||||
(" (optional)").to_string()
|
||||
|
@ -110,12 +101,13 @@ impl NuHelpCompleter {
|
|||
Suggestion {
|
||||
value: decl.name().into(),
|
||||
description: Some(long_desc),
|
||||
style: None,
|
||||
extra: Some(extra),
|
||||
span: reedline::Span {
|
||||
start: pos - line.len(),
|
||||
end: pos,
|
||||
},
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
@ -146,8 +138,7 @@ mod test {
|
|||
) {
|
||||
let engine_state =
|
||||
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context());
|
||||
let config = engine_state.get_config().clone();
|
||||
let mut completer = NuHelpCompleter::new(engine_state.into(), config);
|
||||
let mut completer = NuHelpCompleter::new(engine_state.into());
|
||||
let suggestions = completer.complete(line, end);
|
||||
|
||||
assert_eq!(
|
||||
|
|
|
@ -142,9 +142,10 @@ fn convert_to_suggestions(
|
|||
vec![Suggestion {
|
||||
value: text,
|
||||
description,
|
||||
style: None,
|
||||
extra,
|
||||
span,
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
}]
|
||||
}
|
||||
Value::List { vals, .. } => vals
|
||||
|
@ -153,6 +154,9 @@ fn convert_to_suggestions(
|
|||
.collect(),
|
||||
_ => vec![Suggestion {
|
||||
value: format!("Not a record: {value:?}"),
|
||||
description: None,
|
||||
style: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: if only_buffer_difference {
|
||||
pos - line.len()
|
||||
|
@ -165,7 +169,7 @@ fn convert_to_suggestions(
|
|||
line.len()
|
||||
},
|
||||
},
|
||||
..Suggestion::default()
|
||||
append_whitespace: false,
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use nu_engine::command_prelude::*;
|
||||
use reedline::{Highlighter, StyledText};
|
||||
|
||||
|
@ -35,10 +33,13 @@ impl Command for NuHighlight {
|
|||
let head = call.head;
|
||||
|
||||
let signals = engine_state.signals();
|
||||
let engine_state = std::sync::Arc::new(engine_state.clone());
|
||||
let config = engine_state.get_config().clone();
|
||||
|
||||
let highlighter = crate::NuHighlighter {
|
||||
engine_state: Arc::new(engine_state.clone()),
|
||||
stack: Arc::new(stack.clone()),
|
||||
engine_state,
|
||||
stack: std::sync::Arc::new(stack.clone()),
|
||||
config,
|
||||
};
|
||||
|
||||
input.map(
|
||||
|
|
|
@ -77,19 +77,13 @@ pub(crate) fn add_menus(
|
|||
mut line_editor: Reedline,
|
||||
engine_state_ref: Arc<EngineState>,
|
||||
stack: &Stack,
|
||||
config: Arc<Config>,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
//log::trace!("add_menus: config: {:#?}", &config);
|
||||
line_editor = line_editor.clear_menus();
|
||||
|
||||
for menu in &config.menus {
|
||||
line_editor = add_menu(
|
||||
line_editor,
|
||||
menu,
|
||||
engine_state_ref.clone(),
|
||||
stack,
|
||||
config.clone(),
|
||||
)?
|
||||
line_editor = add_menu(line_editor, menu, engine_state_ref.clone(), stack, config)?
|
||||
}
|
||||
|
||||
// Checking if the default menus have been added from the config file
|
||||
|
@ -106,7 +100,7 @@ pub(crate) fn add_menus(
|
|||
if !config
|
||||
.menus
|
||||
.iter()
|
||||
.any(|menu| menu.name.to_expanded_string("", &config) == name)
|
||||
.any(|menu| menu.name.to_expanded_string("", config) == name)
|
||||
{
|
||||
let (block, delta) = {
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
|
@ -143,7 +137,7 @@ pub(crate) fn add_menus(
|
|||
&menu,
|
||||
new_engine_state_ref.clone(),
|
||||
stack,
|
||||
config.clone(),
|
||||
config,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
@ -157,27 +151,27 @@ fn add_menu(
|
|||
menu: &ParsedMenu,
|
||||
engine_state: Arc<EngineState>,
|
||||
stack: &Stack,
|
||||
config: Arc<Config>,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
let span = menu.menu_type.span();
|
||||
if let Value::Record { val, .. } = &menu.menu_type {
|
||||
let layout = extract_value("layout", val, span)?.to_expanded_string("", &config);
|
||||
let layout = extract_value("layout", val, span)?.to_expanded_string("", config);
|
||||
|
||||
match layout.as_str() {
|
||||
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, &config),
|
||||
"columnar" => add_columnar_menu(line_editor, menu, engine_state, stack, config),
|
||||
"list" => add_list_menu(line_editor, menu, engine_state, stack, config),
|
||||
"ide" => add_ide_menu(line_editor, menu, engine_state, stack, config),
|
||||
"description" => add_description_menu(line_editor, menu, engine_state, stack, config),
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "columnar, list, ide or description".to_string(),
|
||||
value: menu.menu_type.to_abbreviated_string(&config),
|
||||
value: menu.menu_type.to_abbreviated_string(config),
|
||||
span: menu.menu_type.span(),
|
||||
}),
|
||||
}
|
||||
} else {
|
||||
Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "only record type".to_string(),
|
||||
value: menu.menu_type.to_abbreviated_string(&config),
|
||||
value: menu.menu_type.to_abbreviated_string(config),
|
||||
span: menu.menu_type.span(),
|
||||
})
|
||||
}
|
||||
|
@ -193,29 +187,6 @@ fn get_style(record: &Record, name: &str, span: Span) -> Option<Style> {
|
|||
})
|
||||
}
|
||||
|
||||
fn set_menu_style<M: MenuBuilder>(mut menu: M, style: &Value) -> M {
|
||||
let span = style.span();
|
||||
let Value::Record { val, .. } = &style else {
|
||||
return menu;
|
||||
};
|
||||
if let Some(style) = get_style(val, "text", span) {
|
||||
menu = menu.with_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_text", span) {
|
||||
menu = menu.with_selected_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "description_text", span) {
|
||||
menu = menu.with_description_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "match_text", span) {
|
||||
menu = menu.with_match_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_match_text", span) {
|
||||
menu = menu.with_selected_match_text_style(style);
|
||||
}
|
||||
menu
|
||||
}
|
||||
|
||||
// Adds a columnar menu to the editor engine
|
||||
pub(crate) fn add_columnar_menu(
|
||||
line_editor: Reedline,
|
||||
|
@ -254,7 +225,24 @@ pub(crate) fn add_columnar_menu(
|
|||
};
|
||||
}
|
||||
|
||||
columnar_menu = set_menu_style(columnar_menu, &menu.style);
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
if let Some(style) = get_style(val, "text", span) {
|
||||
columnar_menu = columnar_menu.with_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_text", span) {
|
||||
columnar_menu = columnar_menu.with_selected_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "description_text", span) {
|
||||
columnar_menu = columnar_menu.with_description_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "match_text", span) {
|
||||
columnar_menu = columnar_menu.with_match_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_match_text", span) {
|
||||
columnar_menu = columnar_menu.with_selected_match_text_style(style);
|
||||
}
|
||||
}
|
||||
|
||||
let marker = menu.marker.to_expanded_string("", config);
|
||||
columnar_menu = columnar_menu.with_marker(&marker);
|
||||
|
@ -294,9 +282,9 @@ pub(crate) fn add_list_menu(
|
|||
menu: &ParsedMenu,
|
||||
engine_state: Arc<EngineState>,
|
||||
stack: &Stack,
|
||||
config: Arc<Config>,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
let name = menu.name.to_expanded_string("", &config);
|
||||
let name = menu.name.to_expanded_string("", config);
|
||||
let mut list_menu = ListMenu::default().with_name(&name);
|
||||
|
||||
let span = menu.menu_type.span();
|
||||
|
@ -310,9 +298,20 @@ pub(crate) fn add_list_menu(
|
|||
};
|
||||
}
|
||||
|
||||
list_menu = set_menu_style(list_menu, &menu.style);
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
if let Some(style) = get_style(val, "text", span) {
|
||||
list_menu = list_menu.with_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_text", span) {
|
||||
list_menu = list_menu.with_selected_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "description_text", span) {
|
||||
list_menu = list_menu.with_description_text_style(style);
|
||||
}
|
||||
}
|
||||
|
||||
let marker = menu.marker.to_expanded_string("", &config);
|
||||
let marker = menu.marker.to_expanded_string("", config);
|
||||
list_menu = list_menu.with_marker(&marker);
|
||||
|
||||
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
|
||||
|
@ -338,7 +337,7 @@ pub(crate) fn add_list_menu(
|
|||
}
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "block or omitted value".to_string(),
|
||||
value: menu.source.to_abbreviated_string(&config),
|
||||
value: menu.source.to_abbreviated_string(config),
|
||||
span: menu.source.span(),
|
||||
}),
|
||||
}
|
||||
|
@ -350,10 +349,10 @@ pub(crate) fn add_ide_menu(
|
|||
menu: &ParsedMenu,
|
||||
engine_state: Arc<EngineState>,
|
||||
stack: &Stack,
|
||||
config: Arc<Config>,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
let span = menu.menu_type.span();
|
||||
let name = menu.name.to_expanded_string("", &config);
|
||||
let name = menu.name.to_expanded_string("", config);
|
||||
let mut ide_menu = IdeMenu::default().with_name(&name);
|
||||
|
||||
if let Value::Record { val, .. } = &menu.menu_type {
|
||||
|
@ -418,7 +417,7 @@ pub(crate) fn add_ide_menu(
|
|||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "bool or record".to_string(),
|
||||
value: border.to_abbreviated_string(&config),
|
||||
value: border.to_abbreviated_string(config),
|
||||
span: border.span(),
|
||||
});
|
||||
}
|
||||
|
@ -442,7 +441,7 @@ pub(crate) fn add_ide_menu(
|
|||
_ => {
|
||||
return Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "\"left\", \"right\" or \"prefer_right\"".to_string(),
|
||||
value: description_mode.to_abbreviated_string(&config),
|
||||
value: description_mode.to_abbreviated_string(config),
|
||||
span: description_mode.span(),
|
||||
});
|
||||
}
|
||||
|
@ -491,9 +490,26 @@ pub(crate) fn add_ide_menu(
|
|||
};
|
||||
}
|
||||
|
||||
ide_menu = set_menu_style(ide_menu, &menu.style);
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
if let Some(style) = get_style(val, "text", span) {
|
||||
ide_menu = ide_menu.with_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_text", span) {
|
||||
ide_menu = ide_menu.with_selected_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "description_text", span) {
|
||||
ide_menu = ide_menu.with_description_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "match_text", span) {
|
||||
ide_menu = ide_menu.with_match_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_match_text", span) {
|
||||
ide_menu = ide_menu.with_selected_match_text_style(style);
|
||||
}
|
||||
}
|
||||
|
||||
let marker = menu.marker.to_expanded_string("", &config);
|
||||
let marker = menu.marker.to_expanded_string("", config);
|
||||
ide_menu = ide_menu.with_marker(&marker);
|
||||
|
||||
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
|
||||
|
@ -519,7 +535,7 @@ pub(crate) fn add_ide_menu(
|
|||
}
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "block or omitted value".to_string(),
|
||||
value: menu.source.to_abbreviated_string(&config),
|
||||
value: menu.source.to_abbreviated_string(config),
|
||||
span,
|
||||
}),
|
||||
}
|
||||
|
@ -531,9 +547,9 @@ pub(crate) fn add_description_menu(
|
|||
menu: &ParsedMenu,
|
||||
engine_state: Arc<EngineState>,
|
||||
stack: &Stack,
|
||||
config: Arc<Config>,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
let name = menu.name.to_expanded_string("", &config);
|
||||
let name = menu.name.to_expanded_string("", config);
|
||||
let mut description_menu = DescriptionMenu::default().with_name(&name);
|
||||
|
||||
let span = menu.menu_type.span();
|
||||
|
@ -579,9 +595,20 @@ pub(crate) fn add_description_menu(
|
|||
};
|
||||
}
|
||||
|
||||
description_menu = set_menu_style(description_menu, &menu.style);
|
||||
let span = menu.style.span();
|
||||
if let Value::Record { val, .. } = &menu.style {
|
||||
if let Some(style) = get_style(val, "text", span) {
|
||||
description_menu = description_menu.with_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "selected_text", span) {
|
||||
description_menu = description_menu.with_selected_text_style(style);
|
||||
}
|
||||
if let Some(style) = get_style(val, "description_text", span) {
|
||||
description_menu = description_menu.with_description_text_style(style);
|
||||
}
|
||||
}
|
||||
|
||||
let marker = menu.marker.to_expanded_string("", &config);
|
||||
let marker = menu.marker.to_expanded_string("", config);
|
||||
description_menu = description_menu.with_marker(&marker);
|
||||
|
||||
let only_buffer_difference = menu.only_buffer_difference.as_bool()?;
|
||||
|
@ -590,7 +617,7 @@ pub(crate) fn add_description_menu(
|
|||
let span = menu.source.span();
|
||||
match &menu.source {
|
||||
Value::Nothing { .. } => {
|
||||
let completer = Box::new(NuHelpCompleter::new(engine_state, config));
|
||||
let completer = Box::new(NuHelpCompleter::new(engine_state));
|
||||
Ok(line_editor.with_menu(ReedlineMenu::WithCompleter {
|
||||
menu: Box::new(description_menu),
|
||||
completer,
|
||||
|
@ -611,7 +638,7 @@ pub(crate) fn add_description_menu(
|
|||
}
|
||||
_ => Err(ShellError::UnsupportedConfigValue {
|
||||
expected: "closure or omitted value".to_string(),
|
||||
value: menu.source.to_abbreviated_string(&config),
|
||||
value: menu.source.to_abbreviated_string(config),
|
||||
span: menu.source.span(),
|
||||
}),
|
||||
}
|
||||
|
|
|
@ -268,9 +268,6 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
|
|||
if let Err(err) = engine_state.merge_env(&mut stack, cwd) {
|
||||
report_error_new(engine_state, &err);
|
||||
}
|
||||
// Check whether $env.NU_USE_IR is set, so that the user can change it in the REPL
|
||||
// Temporary while IR eval is optional
|
||||
stack.use_ir = stack.has_env_var(engine_state, "NU_USE_IR");
|
||||
perf!("merge env", start_time, use_color);
|
||||
|
||||
start_time = std::time::Instant::now();
|
||||
|
@ -297,7 +294,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
|
|||
perf!("env-change hook", start_time, use_color);
|
||||
|
||||
let engine_reference = Arc::new(engine_state.clone());
|
||||
let config = stack.get_config(engine_state);
|
||||
let config = engine_state.get_config();
|
||||
|
||||
start_time = std::time::Instant::now();
|
||||
// Find the configured cursor shapes for each mode
|
||||
|
@ -323,6 +320,7 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
|
|||
engine_state: engine_reference.clone(),
|
||||
// STACK-REFERENCE 1
|
||||
stack: stack_arc.clone(),
|
||||
config: config.clone(),
|
||||
}))
|
||||
.with_validator(Box::new(NuValidator {
|
||||
engine_state: engine_reference.clone(),
|
||||
|
@ -338,7 +336,6 @@ fn loop_iteration(ctx: LoopContext) -> (bool, Stack, Reedline) {
|
|||
.with_cwd(Some(
|
||||
engine_state
|
||||
.cwd(None)
|
||||
.map(|cwd| cwd.into_std_path_buf())
|
||||
.unwrap_or_default()
|
||||
.to_string_lossy()
|
||||
.to_string(),
|
||||
|
@ -1337,26 +1334,20 @@ fn are_session_ids_in_sync() {
|
|||
#[cfg(test)]
|
||||
mod test_auto_cd {
|
||||
use super::{do_auto_cd, parse_operation, ReplOperation};
|
||||
use nu_path::AbsolutePath;
|
||||
use nu_protocol::engine::{EngineState, Stack};
|
||||
use std::path::Path;
|
||||
use tempfile::tempdir;
|
||||
|
||||
/// Create a symlink. Works on both Unix and Windows.
|
||||
#[cfg(any(unix, windows))]
|
||||
fn symlink(
|
||||
original: impl AsRef<AbsolutePath>,
|
||||
link: impl AsRef<AbsolutePath>,
|
||||
) -> std::io::Result<()> {
|
||||
let original = original.as_ref();
|
||||
let link = link.as_ref();
|
||||
|
||||
fn symlink(original: impl AsRef<Path>, link: impl AsRef<Path>) -> std::io::Result<()> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
std::os::unix::fs::symlink(original, link)
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if original.is_dir() {
|
||||
if original.as_ref().is_dir() {
|
||||
std::os::windows::fs::symlink_dir(original, link)
|
||||
} else {
|
||||
std::os::windows::fs::symlink_file(original, link)
|
||||
|
@ -1368,11 +1359,11 @@ mod test_auto_cd {
|
|||
/// `before`, and after `input` is parsed and evaluated, PWD should be
|
||||
/// changed to `after`.
|
||||
#[track_caller]
|
||||
fn check(before: impl AsRef<AbsolutePath>, input: &str, after: impl AsRef<AbsolutePath>) {
|
||||
fn check(before: impl AsRef<Path>, input: &str, after: impl AsRef<Path>) {
|
||||
// Setup EngineState and Stack.
|
||||
let mut engine_state = EngineState::new();
|
||||
let mut stack = Stack::new();
|
||||
stack.set_cwd(before.as_ref()).unwrap();
|
||||
stack.set_cwd(before).unwrap();
|
||||
|
||||
// Parse the input. It must be an auto-cd operation.
|
||||
let op = parse_operation(input.to_string(), &engine_state, &stack).unwrap();
|
||||
|
@ -1388,66 +1379,54 @@ mod test_auto_cd {
|
|||
// don't have to be byte-wise equal (on Windows, the 8.3 filename
|
||||
// conversion messes things up),
|
||||
let updated_cwd = std::fs::canonicalize(updated_cwd).unwrap();
|
||||
let after = std::fs::canonicalize(after.as_ref()).unwrap();
|
||||
let after = std::fs::canonicalize(after).unwrap();
|
||||
assert_eq!(updated_cwd, after);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_root() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let input = if cfg!(windows) { r"C:\" } else { "/" };
|
||||
let root = AbsolutePath::try_new(input).unwrap();
|
||||
check(tempdir, input, root);
|
||||
let root = if cfg!(windows) { r"C:\" } else { "/" };
|
||||
check(&tempdir, root, root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_tilde() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let home = nu_path::home_dir().unwrap();
|
||||
check(tempdir, "~", home);
|
||||
check(&tempdir, "~", home);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_dot() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
check(tempdir, ".", tempdir);
|
||||
check(&tempdir, ".", &tempdir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_double_dot() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let dir = tempdir.join("foo");
|
||||
let dir = tempdir.path().join("foo");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
check(dir, "..", tempdir);
|
||||
check(dir, "..", &tempdir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_triple_dot() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let dir = tempdir.join("foo").join("bar");
|
||||
let dir = tempdir.path().join("foo").join("bar");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
check(dir, "...", tempdir);
|
||||
check(dir, "...", &tempdir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_relative() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let foo = tempdir.join("foo");
|
||||
let bar = tempdir.join("bar");
|
||||
let foo = tempdir.path().join("foo");
|
||||
let bar = tempdir.path().join("bar");
|
||||
std::fs::create_dir_all(&foo).unwrap();
|
||||
std::fs::create_dir_all(&bar).unwrap();
|
||||
|
||||
let input = if cfg!(windows) { r"..\bar" } else { "../bar" };
|
||||
check(foo, input, bar);
|
||||
}
|
||||
|
@ -1455,35 +1434,32 @@ mod test_auto_cd {
|
|||
#[test]
|
||||
fn auto_cd_trailing_slash() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let dir = tempdir.join("foo");
|
||||
let dir = tempdir.path().join("foo");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
|
||||
let input = if cfg!(windows) { r"foo\" } else { "foo/" };
|
||||
check(tempdir, input, dir);
|
||||
check(&tempdir, input, dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auto_cd_symlink() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
|
||||
let dir = tempdir.join("foo");
|
||||
let dir = tempdir.path().join("foo");
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let link = tempdir.join("link");
|
||||
let link = tempdir.path().join("link");
|
||||
symlink(&dir, &link).unwrap();
|
||||
|
||||
let input = if cfg!(windows) { r".\link" } else { "./link" };
|
||||
check(tempdir, input, link);
|
||||
check(&tempdir, input, link);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "was not parsed into an auto-cd operation")]
|
||||
fn auto_cd_nonexistent_directory() {
|
||||
let tempdir = tempdir().unwrap();
|
||||
let tempdir = AbsolutePath::try_new(tempdir.path()).unwrap();
|
||||
let dir = tempdir.path().join("foo");
|
||||
|
||||
let dir = tempdir.join("foo");
|
||||
let input = if cfg!(windows) { r"foo\" } else { "foo/" };
|
||||
check(tempdir, input, dir);
|
||||
check(&tempdir, input, dir);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use nu_parser::{flatten_block, parse, FlatShape};
|
|||
use nu_protocol::{
|
||||
ast::{Block, Expr, Expression, PipelineRedirection, RecordItem},
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Span,
|
||||
Config, Span,
|
||||
};
|
||||
use reedline::{Highlighter, StyledText};
|
||||
use std::sync::Arc;
|
||||
|
@ -14,14 +14,15 @@ use std::sync::Arc;
|
|||
pub struct NuHighlighter {
|
||||
pub engine_state: Arc<EngineState>,
|
||||
pub stack: Arc<Stack>,
|
||||
pub config: Config,
|
||||
}
|
||||
|
||||
impl Highlighter for NuHighlighter {
|
||||
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
|
||||
trace!("highlighting: {}", line);
|
||||
|
||||
let config = self.stack.get_config(&self.engine_state);
|
||||
let highlight_resolved_externals = config.highlight_resolved_externals;
|
||||
let highlight_resolved_externals =
|
||||
self.engine_state.get_config().highlight_resolved_externals;
|
||||
let mut working_set = StateWorkingSet::new(&self.engine_state);
|
||||
let block = parse(&mut working_set, None, line.as_bytes(), false);
|
||||
let (shapes, global_span_offset) = {
|
||||
|
@ -87,7 +88,7 @@ impl Highlighter for NuHighlighter {
|
|||
.to_string();
|
||||
|
||||
let mut add_colored_token = |shape: &FlatShape, text: String| {
|
||||
output.push((get_shape_color(shape.as_str(), &config), text));
|
||||
output.push((get_shape_color(shape.as_str(), &self.config), text));
|
||||
};
|
||||
|
||||
match shape.1 {
|
||||
|
@ -127,9 +128,9 @@ impl Highlighter for NuHighlighter {
|
|||
let start = part.start - span.start;
|
||||
let end = part.end - span.start;
|
||||
let text = next_token[start..end].to_string();
|
||||
let mut style = get_shape_color(shape.as_str(), &config);
|
||||
let mut style = get_shape_color(shape.as_str(), &self.config);
|
||||
if highlight {
|
||||
style = get_matching_brackets_style(style, &config);
|
||||
style = get_matching_brackets_style(style, &self.config);
|
||||
}
|
||||
output.push((style, text));
|
||||
}
|
||||
|
@ -429,14 +430,6 @@ fn find_matching_block_end_in_expr(
|
|||
)
|
||||
}),
|
||||
|
||||
Expr::Collect(_, expr) => find_matching_block_end_in_expr(
|
||||
line,
|
||||
working_set,
|
||||
expr,
|
||||
global_span_offset,
|
||||
global_cursor_offset,
|
||||
),
|
||||
|
||||
Expr::Block(block_id)
|
||||
| Expr::Closure(block_id)
|
||||
| Expr::RowCondition(block_id)
|
||||
|
|
|
@ -262,11 +262,6 @@ fn evaluate_source(
|
|||
return Ok(Some(1));
|
||||
}
|
||||
|
||||
if let Some(err) = working_set.compile_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
// Not a fatal error, for now
|
||||
}
|
||||
|
||||
(output, working_set.render())
|
||||
};
|
||||
|
||||
|
@ -321,10 +316,16 @@ mod test {
|
|||
|
||||
let env = engine_state.render_env_vars();
|
||||
|
||||
assert!(matches!(env.get("FOO"), Some(&Value::String { val, .. }) if val == "foo"));
|
||||
assert!(matches!(env.get("SYMBOLS"), Some(&Value::String { val, .. }) if val == symbols));
|
||||
assert!(matches!(env.get(symbols), Some(&Value::String { val, .. }) if val == "symbols"));
|
||||
assert!(env.contains_key("PWD"));
|
||||
assert!(
|
||||
matches!(env.get(&"FOO".to_string()), Some(&Value::String { val, .. }) if val == "foo")
|
||||
);
|
||||
assert!(
|
||||
matches!(env.get(&"SYMBOLS".to_string()), Some(&Value::String { val, .. }) if val == symbols)
|
||||
);
|
||||
assert!(
|
||||
matches!(env.get(&symbols.to_string()), Some(&Value::String { val, .. }) if val == "symbols")
|
||||
);
|
||||
assert!(env.get(&"PWD".to_string()).is_some());
|
||||
assert_eq!(env.len(), 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
use nu_test_support::nu;
|
||||
|
||||
#[test]
|
||||
fn not_empty() {
|
||||
let result = nu!("keybindings list | is-not-empty");
|
||||
assert_eq!(result.out, "true");
|
||||
}
|
|
@ -1,2 +1 @@
|
|||
mod keybindings_list;
|
||||
mod nu_highlight;
|
||||
|
|
|
@ -32,6 +32,7 @@ fn completer() -> NuCompleter {
|
|||
fn completer_strings() -> NuCompleter {
|
||||
// Create a new engine
|
||||
let (dir, _, mut engine, mut stack) = new_engine();
|
||||
|
||||
// Add record value as example
|
||||
let record = r#"def animals [] { ["cat", "dog", "eel" ] }
|
||||
def my-command [animal: string@animals] { print $animal }"#;
|
||||
|
@ -89,12 +90,14 @@ fn subcommand_completer() -> NuCompleter {
|
|||
// Create a new engine
|
||||
let (dir, _, mut engine, mut stack) = new_engine();
|
||||
|
||||
// Use fuzzy matching, because subcommands are sorted by Levenshtein distance,
|
||||
// and that's not very useful with prefix matching
|
||||
let commands = r#"
|
||||
$env.config.completions.algorithm = "fuzzy"
|
||||
def foo [] {}
|
||||
def "foo bar" [] {}
|
||||
def "foo abaz" [] {}
|
||||
def "foo aabcrr" [] {}
|
||||
def "foo aabrr" [] {}
|
||||
def food [] {}
|
||||
"#;
|
||||
assert!(support::merge_input(commands.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||
|
@ -103,22 +106,6 @@ fn subcommand_completer() -> NuCompleter {
|
|||
NuCompleter::new(Arc::new(engine), Arc::new(stack))
|
||||
}
|
||||
|
||||
/// Use fuzzy completions but sort in alphabetical order
|
||||
#[fixture]
|
||||
fn fuzzy_alpha_sort_completer() -> NuCompleter {
|
||||
// Create a new engine
|
||||
let (dir, _, mut engine, mut stack) = new_engine();
|
||||
|
||||
let config = r#"
|
||||
$env.config.completions.algorithm = "fuzzy"
|
||||
$env.config.completions.sort = "alphabetical"
|
||||
"#;
|
||||
assert!(support::merge_input(config.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||
|
||||
// Instantiate a new completer
|
||||
NuCompleter::new(Arc::new(engine), Arc::new(stack))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn variables_dollar_sign_with_variablecompletion() {
|
||||
let (_, _, engine, stack) = new_engine();
|
||||
|
@ -136,28 +123,28 @@ fn variables_double_dash_argument_with_flagcompletion(mut completer: NuCompleter
|
|||
let suggestions = completer.complete("tst --", 6);
|
||||
let expected: Vec<String> = vec!["--help".into(), "--mod".into()];
|
||||
// dbg!(&expected, &suggestions);
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn variables_single_dash_argument_with_flagcompletion(mut completer: NuCompleter) {
|
||||
let suggestions = completer.complete("tst -", 5);
|
||||
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn variables_command_with_commandcompletion(mut completer_strings: NuCompleter) {
|
||||
let suggestions = completer_strings.complete("my-c ", 4);
|
||||
let expected: Vec<String> = vec!["my-command".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn variables_subcommands_with_customcompletion(mut completer_strings: NuCompleter) {
|
||||
let suggestions = completer_strings.complete("my-command ", 11);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
@ -166,7 +153,7 @@ fn variables_customcompletion_subcommands_with_customcompletion_2(
|
|||
) {
|
||||
let suggestions = completer_strings.complete("my-command ", 11);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -195,19 +182,19 @@ fn dotnu_completions() {
|
|||
let completion_str = "source-env ".to_string();
|
||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected.clone(), suggestions);
|
||||
|
||||
// Test use completion
|
||||
let completion_str = "use ".to_string();
|
||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected.clone(), suggestions);
|
||||
|
||||
// Test overlay use completion
|
||||
let completion_str = "overlay use ".to_string();
|
||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -271,22 +258,8 @@ fn file_completions() {
|
|||
folder(dir.join(".hidden_folder")),
|
||||
];
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let separator = '/';
|
||||
let target_dir = format!("cp {dir_str}{separator}");
|
||||
let slash_suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
let expected_slash_paths: Vec<String> = expected_paths
|
||||
.iter()
|
||||
.map(|s| s.replace('\\', "/"))
|
||||
.collect();
|
||||
|
||||
match_suggestions(&expected_slash_paths, &slash_suggestions);
|
||||
}
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completions for a file
|
||||
let target_dir = format!("cp {}", folder(dir.join("another")));
|
||||
|
@ -296,91 +269,17 @@ fn file_completions() {
|
|||
let expected_paths: Vec<String> = vec![file(dir.join("another").join("newfile"))];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completions for hidden files
|
||||
let target_dir = format!("ls {}{MAIN_SEPARATOR}.", folder(dir.join(".hidden_folder")));
|
||||
let target_dir = format!("ls {}/.", folder(dir.join(".hidden_folder")));
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
let expected_paths: Vec<String> =
|
||||
vec![file(dir.join(".hidden_folder").join(".hidden_subfile"))];
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let target_dir = format!("ls {}/.", folder(dir.join(".hidden_folder")));
|
||||
let slash_suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
let expected_slash: Vec<String> = expected_paths
|
||||
.iter()
|
||||
.map(|s| s.replace('\\', "/"))
|
||||
.collect();
|
||||
|
||||
match_suggestions(&expected_slash, &slash_suggestions);
|
||||
}
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn file_completions_with_mixed_separators() {
|
||||
// Create a new engine
|
||||
let (dir, dir_str, engine, stack) = new_dotnu_engine();
|
||||
|
||||
// Instantiate a new completer
|
||||
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
|
||||
|
||||
// Create Expected values
|
||||
let expected_paths: Vec<String> = vec![
|
||||
file(dir.join("lib-dir1").join("bar.nu")),
|
||||
file(dir.join("lib-dir1").join("baz.nu")),
|
||||
file(dir.join("lib-dir1").join("xyzzy.nu")),
|
||||
];
|
||||
let expecetd_slash_paths: Vec<String> = expected_paths
|
||||
.iter()
|
||||
.map(|s| s.replace(MAIN_SEPARATOR, "/"))
|
||||
.collect();
|
||||
|
||||
let target_dir = format!("ls {dir_str}/lib-dir1/");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expecetd_slash_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("cp {dir_str}\\lib-dir1/");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expecetd_slash_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("ls {dir_str}/lib-dir1\\/");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expecetd_slash_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("ls {dir_str}\\lib-dir1\\/");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expecetd_slash_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("ls {dir_str}\\lib-dir1\\");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("ls {dir_str}/lib-dir1\\");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("ls {dir_str}/lib-dir1/\\");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
|
||||
let target_dir = format!("ls {dir_str}\\lib-dir1/\\");
|
||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -404,7 +303,7 @@ fn partial_completions() {
|
|||
];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completions for the files whose name begin with "h"
|
||||
// and are present under directories whose names begin with "pa"
|
||||
|
@ -425,7 +324,7 @@ fn partial_completions() {
|
|||
];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completion for all files under directories whose names begin with "pa"
|
||||
let dir_str = folder(dir.join("pa"));
|
||||
|
@ -446,7 +345,7 @@ fn partial_completions() {
|
|||
];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completion for a single file
|
||||
let dir_str = file(dir.join("fi").join("so"));
|
||||
|
@ -457,7 +356,7 @@ fn partial_completions() {
|
|||
let expected_paths: Vec<String> = vec![file(dir.join("final_partial").join("somefile"))];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completion where there is a sneaky `..` in the path
|
||||
let dir_str = file(dir.join("par").join("..").join("fi").join("so"));
|
||||
|
@ -493,7 +392,7 @@ fn partial_completions() {
|
|||
];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completion for all files under directories whose names begin with "pa"
|
||||
let file_str = file(dir.join("partial-a").join("have"));
|
||||
|
@ -507,7 +406,7 @@ fn partial_completions() {
|
|||
];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
// Test completion for all files under directories whose names begin with "pa"
|
||||
let file_str = file(dir.join("partial-a").join("have_ext."));
|
||||
|
@ -521,7 +420,7 @@ fn partial_completions() {
|
|||
];
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -556,16 +455,15 @@ fn command_ls_with_filecompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
let target_dir = "ls custom_completion.";
|
||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||
|
||||
let expected_paths: Vec<String> = vec!["custom_completion.nu".to_string()];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn command_open_with_filecompletion() {
|
||||
let (_, _, engine, stack) = new_engine();
|
||||
|
@ -598,14 +496,14 @@ fn command_open_with_filecompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
let target_dir = "open custom_completion.";
|
||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||
|
||||
let expected_paths: Vec<String> = vec!["custom_completion.nu".to_string()];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -640,7 +538,7 @@ fn command_rm_with_globcompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -675,7 +573,7 @@ fn command_cp_with_globcompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -710,7 +608,7 @@ fn command_save_with_filecompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -745,7 +643,7 @@ fn command_touch_with_filecompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -780,7 +678,7 @@ fn command_watch_with_filecompletion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
@ -788,19 +686,19 @@ fn subcommand_completions(mut subcommand_completer: NuCompleter) {
|
|||
let prefix = "foo br";
|
||||
let suggestions = subcommand_completer.complete(prefix, prefix.len());
|
||||
match_suggestions(
|
||||
&vec!["foo bar".to_string(), "foo aabcrr".to_string()],
|
||||
&suggestions,
|
||||
vec!["foo bar".to_string(), "foo aabrr".to_string()],
|
||||
suggestions,
|
||||
);
|
||||
|
||||
let prefix = "foo b";
|
||||
let suggestions = subcommand_completer.complete(prefix, prefix.len());
|
||||
match_suggestions(
|
||||
&vec![
|
||||
vec![
|
||||
"foo bar".to_string(),
|
||||
"foo aabcrr".to_string(),
|
||||
"foo abaz".to_string(),
|
||||
"foo aabrr".to_string(),
|
||||
],
|
||||
&suggestions,
|
||||
suggestions,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -823,10 +721,10 @@ fn file_completion_quoted() {
|
|||
"`te#st.txt`".to_string(),
|
||||
"`te'st.txt`".to_string(),
|
||||
"`te(st).txt`".to_string(),
|
||||
format!("`{}`", folder("test dir")),
|
||||
format!("`{}`", folder("test dir".into())),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
|
||||
let dir: PathBuf = "test dir".into();
|
||||
let target_dir = format!("open '{}'", folder(dir.clone()));
|
||||
|
@ -837,7 +735,7 @@ fn file_completion_quoted() {
|
|||
format!("`{}`", file(dir.join("single quote"))),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -872,7 +770,7 @@ fn flag_completions() {
|
|||
];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -896,21 +794,8 @@ fn folder_with_directorycompletions() {
|
|||
folder(dir.join(".hidden_folder")),
|
||||
];
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let target_dir = format!("cd {dir_str}/");
|
||||
let slash_suggestions = completer.complete(&target_dir, target_dir.len());
|
||||
|
||||
let expected_slash_paths: Vec<String> = expected_paths
|
||||
.iter()
|
||||
.map(|s| s.replace('\\', "/"))
|
||||
.collect();
|
||||
|
||||
match_suggestions(&expected_slash_paths, &slash_suggestions);
|
||||
}
|
||||
|
||||
// Match the results
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -948,11 +833,11 @@ fn variables_completions() {
|
|||
"plugin-path".into(),
|
||||
"startup-time".into(),
|
||||
"temp-path".into(),
|
||||
"vendor-autoload-dirs".into(),
|
||||
"vendor-autoload-dir".into(),
|
||||
];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
// Test completions for $nu.h (filter)
|
||||
let suggestions = completer.complete("$nu.h", 5);
|
||||
|
@ -966,7 +851,7 @@ fn variables_completions() {
|
|||
];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
// Test completions for $nu.os-info
|
||||
let suggestions = completer.complete("$nu.os-info.", 12);
|
||||
|
@ -978,7 +863,7 @@ fn variables_completions() {
|
|||
"name".into(),
|
||||
];
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
// Test completions for custom var
|
||||
let suggestions = completer.complete("$actor.", 7);
|
||||
|
@ -988,7 +873,7 @@ fn variables_completions() {
|
|||
let expected: Vec<String> = vec!["age".into(), "name".into()];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
// Test completions for custom var (filtering)
|
||||
let suggestions = completer.complete("$actor.n", 8);
|
||||
|
@ -998,7 +883,7 @@ fn variables_completions() {
|
|||
let expected: Vec<String> = vec!["name".into()];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
// Test completions for $env
|
||||
let suggestions = completer.complete("$env.", 5);
|
||||
|
@ -1011,7 +896,7 @@ fn variables_completions() {
|
|||
let expected: Vec<String> = vec!["PATH".into(), "PWD".into(), "TEST".into()];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
// Test completions for $env
|
||||
let suggestions = completer.complete("$env.T", 6);
|
||||
|
@ -1021,12 +906,12 @@ fn variables_completions() {
|
|||
let expected: Vec<String> = vec!["TEST".into()];
|
||||
|
||||
// Match results
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
|
||||
let suggestions = completer.complete("$", 1);
|
||||
let expected: Vec<String> = vec!["$actor".into(), "$env".into(), "$in".into(), "$nu".into()];
|
||||
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1045,7 +930,7 @@ fn alias_of_command_and_flags() {
|
|||
#[cfg(not(windows))]
|
||||
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1064,7 +949,7 @@ fn alias_of_basic_command() {
|
|||
#[cfg(not(windows))]
|
||||
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1086,7 +971,7 @@ fn alias_of_another_alias() {
|
|||
#[cfg(not(windows))]
|
||||
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
fn run_external_completion(completer: &str, input: &str) -> Vec<Suggestion> {
|
||||
|
@ -1149,35 +1034,35 @@ fn unknown_command_completion() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions)
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn flagcompletion_triggers_after_cursor(mut completer: NuCompleter) {
|
||||
let suggestions = completer.complete("tst -h", 5);
|
||||
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn customcompletion_triggers_after_cursor(mut completer_strings: NuCompleter) {
|
||||
let suggestions = completer_strings.complete("my-command c", 11);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn customcompletion_triggers_after_cursor_piped(mut completer_strings: NuCompleter) {
|
||||
let suggestions = completer_strings.complete("my-command c | ls", 11);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn flagcompletion_triggers_after_cursor_piped(mut completer: NuCompleter) {
|
||||
let suggestions = completer.complete("tst -h | ls", 5);
|
||||
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1211,88 +1096,77 @@ fn filecompletions_triggers_after_cursor() {
|
|||
".hidden_folder/".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(&expected_paths, &suggestions);
|
||||
match_suggestions(expected_paths, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn extern_custom_completion_positional(mut extern_completer: NuCompleter) {
|
||||
let suggestions = extern_completer.complete("spam ", 5);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn extern_custom_completion_long_flag_1(mut extern_completer: NuCompleter) {
|
||||
let suggestions = extern_completer.complete("spam --foo=", 11);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn extern_custom_completion_long_flag_2(mut extern_completer: NuCompleter) {
|
||||
let suggestions = extern_completer.complete("spam --foo ", 11);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn extern_custom_completion_long_flag_short(mut extern_completer: NuCompleter) {
|
||||
let suggestions = extern_completer.complete("spam -f ", 8);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn extern_custom_completion_short_flag(mut extern_completer: NuCompleter) {
|
||||
let suggestions = extern_completer.complete("spam -b ", 8);
|
||||
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn extern_complete_flags(mut extern_completer: NuCompleter) {
|
||||
let suggestions = extern_completer.complete("spam -", 6);
|
||||
let expected: Vec<String> = vec!["--foo".into(), "-b".into(), "-f".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_before_word(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar", 8);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_on_word_left_boundary(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar", 8);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_next_to_word(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar", 11);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "bar".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_completer_triggers_cursor_after_word(mut custom_completer: NuCompleter) {
|
||||
let suggestions = custom_completer.complete("cmd foo bar ", 12);
|
||||
let expected: Vec<String> = vec!["cmd".into(), "foo".into(), "bar".into(), "".into()];
|
||||
match_suggestions(&expected, &suggestions);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn sort_fuzzy_completions_in_alphabetical_order(mut fuzzy_alpha_sort_completer: NuCompleter) {
|
||||
let suggestions = fuzzy_alpha_sort_completer.complete("ls nu", 5);
|
||||
// Even though "nushell" is a better match, it should come second because
|
||||
// the completions should be sorted in alphabetical order
|
||||
match_suggestions(
|
||||
&vec!["custom_completion.nu".into(), "nushell".into()],
|
||||
&suggestions,
|
||||
);
|
||||
match_suggestions(expected, suggestions);
|
||||
}
|
||||
|
||||
#[ignore = "was reverted, still needs fixing"]
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_path::{AbsolutePathBuf, PathBuf};
|
||||
use nu_protocol::{
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
|
@ -8,14 +7,14 @@ use nu_protocol::{
|
|||
};
|
||||
use nu_test_support::fs;
|
||||
use reedline::Suggestion;
|
||||
use std::path::MAIN_SEPARATOR;
|
||||
use std::path::{PathBuf, MAIN_SEPARATOR};
|
||||
|
||||
fn create_default_context() -> EngineState {
|
||||
nu_command::add_shell_command_context(nu_cmd_lang::create_default_context())
|
||||
}
|
||||
|
||||
// creates a new engine with the current path into the completions fixtures folder
|
||||
pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("completions");
|
||||
let dir_str = dir
|
||||
|
@ -70,7 +69,7 @@ pub fn new_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||
}
|
||||
|
||||
// creates a new engine with the current path into the completions fixtures folder
|
||||
pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
pub fn new_dotnu_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("dotnu_completions");
|
||||
let dir_str = dir
|
||||
|
@ -115,7 +114,7 @@ pub fn new_dotnu_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||
(dir, dir_str, engine_state, stack)
|
||||
}
|
||||
|
||||
pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("quoted_completions");
|
||||
let dir_str = dir
|
||||
|
@ -150,7 +149,7 @@ pub fn new_quote_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||
(dir, dir_str, engine_state, stack)
|
||||
}
|
||||
|
||||
pub fn new_partial_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
||||
pub fn new_partial_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("partial_completions");
|
||||
let dir_str = dir
|
||||
|
@ -186,7 +185,7 @@ pub fn new_partial_engine() -> (AbsolutePathBuf, String, EngineState, Stack) {
|
|||
}
|
||||
|
||||
// match a list of suggestions with the expected values
|
||||
pub fn match_suggestions(expected: &Vec<String>, suggestions: &Vec<Suggestion>) {
|
||||
pub fn match_suggestions(expected: Vec<String>, suggestions: Vec<Suggestion>) {
|
||||
let expected_len = expected.len();
|
||||
let suggestions_len = suggestions.len();
|
||||
if expected_len != suggestions_len {
|
||||
|
@ -196,25 +195,26 @@ pub fn match_suggestions(expected: &Vec<String>, suggestions: &Vec<Suggestion>)
|
|||
Expected: {expected:#?}\n"
|
||||
)
|
||||
}
|
||||
|
||||
let suggestoins_str = suggestions
|
||||
.iter()
|
||||
.map(|it| it.value.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(expected, &suggestoins_str);
|
||||
assert_eq!(
|
||||
expected,
|
||||
suggestions
|
||||
.into_iter()
|
||||
.map(|it| it.value)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
// append the separator to the converted path
|
||||
pub fn folder(path: impl Into<PathBuf>) -> String {
|
||||
pub fn folder(path: PathBuf) -> String {
|
||||
let mut converted_path = file(path);
|
||||
converted_path.push(MAIN_SEPARATOR);
|
||||
|
||||
converted_path
|
||||
}
|
||||
|
||||
// convert a given path to string
|
||||
pub fn file(path: impl Into<PathBuf>) -> String {
|
||||
path.into().into_os_string().into_string().unwrap()
|
||||
pub fn file(path: PathBuf) -> String {
|
||||
path.into_os_string().into_string().unwrap_or_default()
|
||||
}
|
||||
|
||||
// merge_input executes the given input into the engine
|
||||
|
@ -223,7 +223,7 @@ pub fn merge_input(
|
|||
input: &[u8],
|
||||
engine_state: &mut EngineState,
|
||||
stack: &mut Stack,
|
||||
dir: AbsolutePathBuf,
|
||||
dir: PathBuf,
|
||||
) -> Result<(), ShellError> {
|
||||
let (block, delta) = {
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
|
|
@ -5,15 +5,15 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-cmd-base"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.96.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.96.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.95.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.95.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
|
||||
|
||||
indexmap = { workspace = true }
|
||||
miette = { workspace = true }
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
Utilities used by the different `nu-command`/`nu-cmd-*` crates, should not contain any full `Command` implementations.
|
||||
|
||||
## Internal Nushell crate
|
||||
|
||||
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.
|
|
@ -1,4 +1,3 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
pub mod formats;
|
||||
pub mod hook;
|
||||
pub mod input_handler;
|
||||
|
|
|
@ -1,28 +1,21 @@
|
|||
use nu_path::AbsolutePathBuf;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Range, ShellError, Span, Value,
|
||||
};
|
||||
use std::ops::Bound;
|
||||
use std::{ops::Bound, path::PathBuf};
|
||||
|
||||
pub fn get_init_cwd() -> AbsolutePathBuf {
|
||||
std::env::current_dir()
|
||||
.ok()
|
||||
.and_then(|path| AbsolutePathBuf::try_from(path).ok())
|
||||
.or_else(|| {
|
||||
std::env::var("PWD")
|
||||
.ok()
|
||||
.and_then(|path| AbsolutePathBuf::try_from(path).ok())
|
||||
})
|
||||
.or_else(nu_path::home_dir)
|
||||
.expect("Failed to get current working directory")
|
||||
pub fn get_init_cwd() -> PathBuf {
|
||||
std::env::current_dir().unwrap_or_else(|_| {
|
||||
std::env::var("PWD")
|
||||
.map(Into::into)
|
||||
.unwrap_or_else(|_| nu_path::home_dir().unwrap_or_default())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_guaranteed_cwd(engine_state: &EngineState, stack: &Stack) -> AbsolutePathBuf {
|
||||
pub fn get_guaranteed_cwd(engine_state: &EngineState, stack: &Stack) -> PathBuf {
|
||||
engine_state
|
||||
.cwd(Some(stack))
|
||||
.ok()
|
||||
.unwrap_or_else(get_init_cwd)
|
||||
.unwrap_or(crate::util::get_init_cwd())
|
||||
}
|
||||
|
||||
type MakeRangeError = fn(&str, Span) -> ShellError;
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-cmd-extra"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -13,13 +13,13 @@ version = "0.96.2"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-json = { version = "0.96.2", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.96.2" }
|
||||
nu-pretty-hex = { version = "0.96.2", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.96.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.95.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-json = { version = "0.95.1", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.95.1" }
|
||||
nu-pretty-hex = { version = "0.95.1", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.95.1" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
heck = { workspace = true }
|
||||
|
@ -33,6 +33,6 @@ v_htmlescape = { workspace = true }
|
|||
itertools = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.96.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.95.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.95.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }
|
|
@ -239,7 +239,7 @@ fn to_html(
|
|||
let partial = call.has_flag(engine_state, stack, "partial")?;
|
||||
let list = call.has_flag(engine_state, stack, "list")?;
|
||||
let theme: Option<Spanned<String>> = call.get_flag(engine_state, stack, "theme")?;
|
||||
let config = &stack.get_config(engine_state);
|
||||
let config = engine_state.get_config();
|
||||
|
||||
let vec_of_values = input.into_iter().collect::<Vec<Value>>();
|
||||
let headers = merge_descriptors(&vec_of_values);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, Config, ListStream};
|
||||
use nu_protocol::{ast::PathMember, engine::StateWorkingSet, ListStream};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FormatPattern;
|
||||
|
@ -43,8 +43,6 @@ impl Command for FormatPattern {
|
|||
let it_id = working_set.add_variable(b"$it".to_vec(), call.head, Type::Any, false);
|
||||
stack.add_var(it_id, input_val.clone());
|
||||
|
||||
let config = stack.get_config(engine_state);
|
||||
|
||||
match specified_pattern {
|
||||
Err(e) => Err(e),
|
||||
Ok(pattern) => {
|
||||
|
@ -58,7 +56,7 @@ impl Command for FormatPattern {
|
|||
string_span.start + 1,
|
||||
)?;
|
||||
|
||||
format(input_val, &ops, engine_state, &config, call.head)
|
||||
format(input_val, &ops, engine_state, call.head)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,30 +181,33 @@ fn format(
|
|||
input_data: Value,
|
||||
format_operations: &[FormatOperation],
|
||||
engine_state: &EngineState,
|
||||
config: &Config,
|
||||
head_span: Span,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let data_as_value = input_data;
|
||||
|
||||
// We can only handle a Record or a List of Records
|
||||
match data_as_value {
|
||||
Value::Record { .. } => match format_record(format_operations, &data_as_value, config) {
|
||||
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
|
||||
Err(value) => Err(value),
|
||||
},
|
||||
Value::Record { .. } => {
|
||||
match format_record(format_operations, &data_as_value, engine_state) {
|
||||
Ok(value) => Ok(PipelineData::Value(Value::string(value, head_span), None)),
|
||||
Err(value) => Err(value),
|
||||
}
|
||||
}
|
||||
|
||||
Value::List { vals, .. } => {
|
||||
let mut list = vec![];
|
||||
for val in vals.iter() {
|
||||
match val {
|
||||
Value::Record { .. } => match format_record(format_operations, val, config) {
|
||||
Ok(value) => {
|
||||
list.push(Value::string(value, head_span));
|
||||
Value::Record { .. } => {
|
||||
match format_record(format_operations, val, engine_state) {
|
||||
Ok(value) => {
|
||||
list.push(Value::string(value, head_span));
|
||||
}
|
||||
Err(value) => {
|
||||
return Err(value);
|
||||
}
|
||||
}
|
||||
Err(value) => {
|
||||
return Err(value);
|
||||
}
|
||||
},
|
||||
}
|
||||
Value::Error { error, .. } => return Err(*error.clone()),
|
||||
_ => {
|
||||
return Err(ShellError::OnlySupportsThisInputType {
|
||||
|
@ -236,8 +237,9 @@ fn format(
|
|||
fn format_record(
|
||||
format_operations: &[FormatOperation],
|
||||
data_as_value: &Value,
|
||||
config: &Config,
|
||||
engine_state: &EngineState,
|
||||
) -> Result<String, ShellError> {
|
||||
let config = engine_state.get_config();
|
||||
let mut output = String::new();
|
||||
|
||||
for op in format_operations {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
mod example_test;
|
||||
pub mod extra;
|
||||
pub use extra::*;
|
||||
|
|
|
@ -6,22 +6,22 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.96.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.95.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.95.1" }
|
||||
|
||||
itertools = { workspace = true }
|
||||
shadow-rs = { version = "0.30", default-features = false }
|
||||
shadow-rs = { version = "0.29", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = { version = "0.30", default-features = false }
|
||||
shadow-rs = { version = "0.29", default-features = false }
|
||||
|
||||
[features]
|
||||
mimalloc = []
|
||||
|
|
|
@ -21,9 +21,7 @@ impl Command for Break {
|
|||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"This command is a parser keyword. For details, check:
|
||||
https://www.nushell.sh/book/thinking_in_nu.html
|
||||
|
||||
break can only be used in while, loop, and for loops. It can not be used with each or other filter commands"#
|
||||
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||
}
|
||||
|
||||
fn command_type(&self) -> CommandType {
|
||||
|
|
|
@ -46,9 +46,6 @@ impl Command for Const {
|
|||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let var_id = if let Some(id) = call.positional_nth(0).and_then(|pos| pos.as_var()) {
|
||||
id
|
||||
} else {
|
||||
|
|
|
@ -21,9 +21,7 @@ impl Command for Continue {
|
|||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"This command is a parser keyword. For details, check:
|
||||
https://www.nushell.sh/book/thinking_in_nu.html
|
||||
|
||||
continue can only be used in while, loop, and for loops. It can not be used with each or other filter commands"#
|
||||
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||
}
|
||||
|
||||
fn command_type(&self) -> CommandType {
|
||||
|
|
|
@ -81,10 +81,6 @@ impl Command for Do {
|
|||
|
||||
bind_args_to(&mut callee_stack, &block.signature, rest, head)?;
|
||||
let eval_block_with_early_return = get_eval_block_with_early_return(engine_state);
|
||||
|
||||
// Applies to all block evaluation once set true
|
||||
callee_stack.use_ir = caller_stack.has_env_var(engine_state, "NU_USE_IR");
|
||||
|
||||
let result = eval_block_with_early_return(engine_state, &mut callee_stack, block, input);
|
||||
|
||||
if has_env {
|
||||
|
|
|
@ -48,9 +48,6 @@ impl Command for For {
|
|||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let head = call.head;
|
||||
let var_id = call
|
||||
.positional_nth(0)
|
||||
|
|
|
@ -60,9 +60,6 @@ impl Command for If {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let cond = call.positional_nth(0).expect("checked through parser");
|
||||
let then_block = call
|
||||
.positional_nth(1)
|
||||
|
@ -102,9 +99,6 @@ impl Command for If {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let cond = call.positional_nth(0).expect("checked through parser");
|
||||
let then_block = call
|
||||
.positional_nth(1)
|
||||
|
|
|
@ -46,9 +46,6 @@ impl Command for Let {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let var_id = call
|
||||
.positional_nth(0)
|
||||
.expect("checked through parser")
|
||||
|
|
|
@ -37,9 +37,6 @@ impl Command for Loop {
|
|||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let head = call.head;
|
||||
let block_id = call
|
||||
.positional_nth(0)
|
||||
|
|
|
@ -43,9 +43,6 @@ impl Command for Match {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let value: Value = call.req(engine_state, stack, 0)?;
|
||||
let matches = call
|
||||
.positional_nth(1)
|
||||
|
|
|
@ -46,9 +46,6 @@ impl Command for Mut {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let var_id = call
|
||||
.positional_nth(0)
|
||||
.expect("checked through parser")
|
||||
|
|
|
@ -65,9 +65,9 @@ impl Command for OverlayUse {
|
|||
name_arg.item = trim_quotes_str(&name_arg.item).to_string();
|
||||
|
||||
let maybe_origin_module_id =
|
||||
if let Some(overlay_expr) = call.get_parser_info(caller_stack, "overlay_expr") {
|
||||
if let Some(overlay_expr) = call.get_parser_info("overlay_expr") {
|
||||
if let Expr::Overlay(module_id) = &overlay_expr.expr {
|
||||
*module_id
|
||||
module_id
|
||||
} else {
|
||||
return Err(ShellError::NushellFailedSpanned {
|
||||
msg: "Not an overlay".to_string(),
|
||||
|
@ -110,7 +110,7 @@ impl Command for OverlayUse {
|
|||
// a) adding a new overlay
|
||||
// b) refreshing an active overlay (the origin module changed)
|
||||
|
||||
let module = engine_state.get_module(module_id);
|
||||
let module = engine_state.get_module(*module_id);
|
||||
|
||||
// Evaluate the export-env block (if any) and keep its environment
|
||||
if let Some(block_id) = module.env_block {
|
||||
|
@ -118,7 +118,7 @@ impl Command for OverlayUse {
|
|||
&name_arg.item,
|
||||
engine_state,
|
||||
caller_stack,
|
||||
get_dirs_var_from_call(caller_stack, call),
|
||||
get_dirs_var_from_call(call),
|
||||
)?;
|
||||
|
||||
let block = engine_state.get_block(block_id);
|
||||
|
|
|
@ -47,9 +47,6 @@ impl Command for Try {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let try_block = call
|
||||
.positional_nth(0)
|
||||
.expect("checked through parser")
|
||||
|
|
|
@ -57,7 +57,7 @@ This command is a parser keyword. For details, check:
|
|||
let Some(Expression {
|
||||
expr: Expr::ImportPattern(import_pattern),
|
||||
..
|
||||
}) = call.get_parser_info(caller_stack, "import_pattern")
|
||||
}) = call.get_parser_info("import_pattern")
|
||||
else {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Unexpected import".into(),
|
||||
|
@ -68,9 +68,6 @@ This command is a parser keyword. For details, check:
|
|||
});
|
||||
};
|
||||
|
||||
// Necessary so that we can modify the stack.
|
||||
let import_pattern = import_pattern.clone();
|
||||
|
||||
if let Some(module_id) = import_pattern.head.id {
|
||||
// Add constants
|
||||
for var_id in &import_pattern.constants {
|
||||
|
@ -102,7 +99,7 @@ This command is a parser keyword. For details, check:
|
|||
&module_arg_str,
|
||||
engine_state,
|
||||
caller_stack,
|
||||
get_dirs_var_from_call(caller_stack, call),
|
||||
get_dirs_var_from_call(call),
|
||||
)?;
|
||||
let maybe_parent = maybe_file_path
|
||||
.as_ref()
|
||||
|
|
|
@ -46,9 +46,6 @@ impl Command for While {
|
|||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// This is compiled specially by the IR compiler. The code here is never used when
|
||||
// running in IR mode.
|
||||
let call = call.assert_ast_call()?;
|
||||
let head = call.head;
|
||||
let cond = call.positional_nth(0).expect("checked through parser");
|
||||
let block_id = call
|
||||
|
|
|
@ -4,7 +4,7 @@ use nu_protocol::{
|
|||
ast::Block,
|
||||
debugger::WithoutDebug,
|
||||
engine::{StateDelta, StateWorkingSet},
|
||||
report_error_new, Range,
|
||||
Range,
|
||||
};
|
||||
use std::{
|
||||
sync::Arc,
|
||||
|
@ -72,7 +72,7 @@ pub fn check_example_input_and_output_types_match_command_signature(
|
|||
witnessed_type_transformations
|
||||
}
|
||||
|
||||
pub fn eval_pipeline_without_terminal_expression(
|
||||
fn eval_pipeline_without_terminal_expression(
|
||||
src: &str,
|
||||
cwd: &std::path::Path,
|
||||
engine_state: &mut Box<EngineState>,
|
||||
|
@ -124,10 +124,7 @@ pub fn eval_block(
|
|||
|
||||
nu_engine::eval_block::<WithoutDebug>(engine_state, &mut stack, &block, input)
|
||||
.and_then(|data| data.into_value(Span::test_data()))
|
||||
.unwrap_or_else(|err| {
|
||||
report_error_new(engine_state, &err);
|
||||
panic!("test eval error in `{}`: {:?}", "TODO", err)
|
||||
})
|
||||
.unwrap_or_else(|err| panic!("test eval error in `{}`: {:?}", "TODO", err))
|
||||
}
|
||||
|
||||
pub fn check_example_evaluates_to_expected_output(
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
mod core_commands;
|
||||
mod default_context;
|
||||
pub mod example_support;
|
||||
|
|
|
@ -5,15 +5,15 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-cmd-plugin"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-plugin"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.96.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2", features = ["plugin"] }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.95.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1", features = ["plugin"] }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.95.1" }
|
||||
|
||||
itertools = { workspace = true }
|
||||
|
||||
|
|
|
@ -5,18 +5,18 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-color-config"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-json = { path = "../nu-json", version = "0.96.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.95.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }
|
|
@ -1,5 +0,0 @@
|
|||
Logic to resolve colors for syntax highlighting and output formatting
|
||||
|
||||
## Internal Nushell crate
|
||||
|
||||
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.
|
|
@ -1,4 +1,3 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
mod color_config;
|
||||
mod matching_brackets_style;
|
||||
mod nu_style;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{color_record_to_nustyle, lookup_ansi_color_style, text_style::Alignment, TextStyle};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_engine::ClosureEvalOnce;
|
||||
use nu_engine::{env::get_config, ClosureEvalOnce};
|
||||
use nu_protocol::{
|
||||
cli_error::CliError,
|
||||
engine::{Closure, EngineState, Stack, StateWorkingSet},
|
||||
|
@ -114,7 +114,7 @@ impl<'a> StyleComputer<'a> {
|
|||
|
||||
// The main constructor.
|
||||
pub fn from_config(engine_state: &'a EngineState, stack: &'a Stack) -> StyleComputer<'a> {
|
||||
let config = stack.get_config(engine_state);
|
||||
let config = get_config(engine_state, stack);
|
||||
|
||||
// Create the hashmap
|
||||
#[rustfmt::skip]
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-command"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
|
||||
version = "0.96.2"
|
||||
version = "0.95.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -13,21 +13,21 @@ version = "0.96.2"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.96.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.96.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.96.2" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.96.2" }
|
||||
nu-json = { path = "../nu-json", version = "0.96.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.96.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.96.2" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.96.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.2" }
|
||||
nu-system = { path = "../nu-system", version = "0.96.2" }
|
||||
nu-table = { path = "../nu-table", version = "0.96.2" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.96.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.96.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.95.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.95.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.95.1" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.95.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.95.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.95.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.95.1" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.95.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.95.1" }
|
||||
nu-system = { path = "../nu-system", version = "0.95.1" }
|
||||
nu-table = { path = "../nu-table", version = "0.95.1" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.95.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.95.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
nuon = { path = "../nuon", version = "0.96.2" }
|
||||
nuon = { path = "../nuon", version = "0.95.1" }
|
||||
|
||||
alphanumeric-sort = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
|
@ -137,10 +137,10 @@ sqlite = ["rusqlite"]
|
|||
trash-support = ["trash"]
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.96.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.95.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.95.1" }
|
||||
|
||||
dirs = { workspace = true }
|
||||
dirs-next = { workspace = true }
|
||||
mockito = { workspace = true, default-features = false }
|
||||
quickcheck = { workspace = true }
|
||||
quickcheck_macros = { workspace = true }
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
This crate contains the majority of our commands
|
||||
|
||||
We allow ourselves to move some of the commands in `nu-command` to `nu-cmd-*` crates as needed.
|
||||
|
||||
## Internal Nushell crate
|
||||
|
||||
This crate implements components of Nushell and is not designed to support plugin authors or other users directly.
|
|
@ -49,8 +49,10 @@ impl Command for BytesBuild {
|
|||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let mut output = vec![];
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
for val in call.rest_iter_flattened(engine_state, stack, eval_expression, 0)? {
|
||||
for val in call.rest_iter_flattened(0, |expr| {
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
eval_expression(engine_state, stack, expr)
|
||||
})? {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary { mut val, .. } => output.append(&mut val),
|
||||
|
|
|
@ -177,9 +177,11 @@ fn run_histogram(
|
|||
match v {
|
||||
// parse record, and fill valid value to actual input.
|
||||
Value::Record { val, .. } => {
|
||||
if let Some(v) = val.get(col_name) {
|
||||
if let Ok(v) = HashableValue::from_value(v.clone(), head_span) {
|
||||
inputs.push(v);
|
||||
for (c, v) in val.iter() {
|
||||
if c == col_name {
|
||||
if let Ok(v) = HashableValue::from_value(v.clone(), head_span) {
|
||||
inputs.push(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,9 +150,13 @@ fn fill(
|
|||
FillAlignment::Left
|
||||
};
|
||||
|
||||
let width = width_arg.unwrap_or(1);
|
||||
let width = if let Some(arg) = width_arg { arg } else { 1 };
|
||||
|
||||
let character = character_arg.unwrap_or_else(|| " ".to_string());
|
||||
let character = if let Some(arg) = character_arg {
|
||||
arg
|
||||
} else {
|
||||
" ".to_string()
|
||||
};
|
||||
|
||||
let arg = Arguments {
|
||||
width,
|
||||
|
|
|
@ -379,47 +379,42 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
|
|||
|
||||
// If input is not a timestamp, try parsing it as a string
|
||||
let span = input.span();
|
||||
|
||||
let parse_as_string = |val: &str| {
|
||||
match dateformat {
|
||||
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
|
||||
Ok(d) => Value::date ( d, head ),
|
||||
Err(reason) => {
|
||||
match NaiveDateTime::parse_from_str(val, &dt.0) {
|
||||
Ok(d) => Value::date (
|
||||
DateTime::from_naive_utc_and_offset(
|
||||
d,
|
||||
*Local::now().offset(),
|
||||
),
|
||||
head,
|
||||
),
|
||||
Err(_) => {
|
||||
Value::error (
|
||||
ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },
|
||||
match input {
|
||||
Value::String { val, .. } => {
|
||||
match dateformat {
|
||||
Some(dt) => match DateTime::parse_from_str(val, &dt.0) {
|
||||
Ok(d) => Value::date ( d, head ),
|
||||
Err(reason) => {
|
||||
match NaiveDateTime::parse_from_str(val, &dt.0) {
|
||||
Ok(d) => Value::date (
|
||||
DateTime::from_naive_utc_and_offset(
|
||||
d,
|
||||
*Local::now().offset(),
|
||||
),
|
||||
head,
|
||||
)
|
||||
),
|
||||
Err(_) => {
|
||||
Value::error (
|
||||
ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },
|
||||
head,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
// Tries to automatically parse the date
|
||||
// (i.e. without a format string)
|
||||
// and assumes the system's local timezone if none is specified
|
||||
None => match parse_date_from_string(val, span) {
|
||||
Ok(date) => Value::date (
|
||||
date,
|
||||
span,
|
||||
),
|
||||
Err(err) => err,
|
||||
},
|
||||
// Tries to automatically parse the date
|
||||
// (i.e. without a format string)
|
||||
// and assumes the system's local timezone if none is specified
|
||||
None => match parse_date_from_string(val, span) {
|
||||
Ok(date) => Value::date (
|
||||
date,
|
||||
span,
|
||||
),
|
||||
Err(err) => err,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match input {
|
||||
Value::String { val, .. } => parse_as_string(val),
|
||||
Value::Int { val, .. } => parse_as_string(&val.to_string()),
|
||||
|
||||
// Propagate errors by explicitly matching them before the final case.
|
||||
Value::Error { .. } => input.clone(),
|
||||
other => Value::error(
|
||||
|
@ -580,24 +575,6 @@ mod tests {
|
|||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn takes_int_with_formatstring() {
|
||||
let date_int = Value::test_int(1_614_434_140);
|
||||
let fmt_options = Some(DatetimeFormat("%s".to_string()));
|
||||
let args = Arguments {
|
||||
zone_options: None,
|
||||
format_options: fmt_options,
|
||||
cell_paths: None,
|
||||
};
|
||||
let actual = action(&date_int, &args, Span::test_data());
|
||||
let expected = Value::date(
|
||||
DateTime::parse_from_str("2021-02-27 21:55:40 +08:00", "%Y-%m-%d %H:%M:%S %z").unwrap(),
|
||||
Span::test_data(),
|
||||
);
|
||||
|
||||
assert_eq!(actual, expected)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn takes_timestamp() {
|
||||
let date_str = Value::test_string("1614434140000000000");
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{into_code, Config};
|
||||
|
@ -9,7 +7,7 @@ use num_format::ToFormattedString;
|
|||
struct Arguments {
|
||||
decimals_value: Option<i64>,
|
||||
cell_paths: Option<Vec<CellPath>>,
|
||||
config: Arc<Config>,
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl CmdArgument for Arguments {
|
||||
|
@ -176,7 +174,7 @@ fn string_helper(
|
|||
})
|
||||
}
|
||||
} else {
|
||||
let config = stack.get_config(engine_state);
|
||||
let config = engine_state.get_config().clone();
|
||||
let args = Arguments {
|
||||
decimals_value,
|
||||
cell_paths,
|
||||
|
|
|
@ -424,7 +424,11 @@ pub fn value_to_sql(value: Value) -> Result<Box<dyn rusqlite::ToSql>, ShellError
|
|||
Value::Filesize { val, .. } => Box::new(val),
|
||||
Value::Duration { val, .. } => Box::new(val),
|
||||
Value::Date { val, .. } => Box::new(val),
|
||||
Value::String { val, .. } => Box::new(val),
|
||||
Value::String { val, .. } => {
|
||||
// don't store ansi escape sequences in the database
|
||||
// escape single quotes
|
||||
Box::new(nu_utils::strip_ansi_unlikely(&val).into_owned())
|
||||
}
|
||||
Value::Binary { val, .. } => Box::new(val),
|
||||
Value::Nothing { .. } => Box::new(rusqlite::types::Null),
|
||||
val => {
|
||||
|
|
|
@ -33,7 +33,7 @@ impl Command for Debug {
|
|||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let config = stack.get_config(engine_state);
|
||||
let config = engine_state.get_config().clone();
|
||||
let raw = call.has_flag(engine_state, stack, "raw")?;
|
||||
|
||||
// Should PipelineData::Empty result in an error here?
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use nu_engine::{command_prelude::*, get_eval_expression};
|
||||
use nu_protocol::{
|
||||
ast::{self, Argument, Block, Expr, Expression},
|
||||
ast::{Argument, Block, Expr, Expression},
|
||||
engine::Closure,
|
||||
};
|
||||
|
||||
|
@ -106,7 +106,7 @@ pub fn get_pipeline_elements(
|
|||
fn get_arguments(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &ast::Call,
|
||||
call: &Call,
|
||||
eval_expression_fn: fn(&EngineState, &mut Stack, &Expression) -> Result<Value, ShellError>,
|
||||
) -> Vec<Value> {
|
||||
let mut arg_value = vec![];
|
||||
|
|
|
@ -28,10 +28,6 @@ impl Command for Metadata {
|
|||
.category(Category::Debug)
|
||||
}
|
||||
|
||||
fn requires_ast_for_arguments(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -39,7 +35,7 @@ impl Command for Metadata {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let arg = call.positional_nth(stack, 0);
|
||||
let arg = call.positional_nth(0);
|
||||
let head = call.head;
|
||||
|
||||
match arg {
|
||||
|
|
|
@ -42,32 +42,32 @@ impl Command for MetadataSet {
|
|||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
mut input: PipelineData,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let ds_fp: Option<String> = call.get_flag(engine_state, stack, "datasource-filepath")?;
|
||||
let ds_ls = call.has_flag(engine_state, stack, "datasource-ls")?;
|
||||
let content_type: Option<String> = call.get_flag(engine_state, stack, "content-type")?;
|
||||
|
||||
let mut metadata = match &mut input {
|
||||
PipelineData::Value(_, metadata)
|
||||
| PipelineData::ListStream(_, metadata)
|
||||
| PipelineData::ByteStream(_, metadata) => metadata.take().unwrap_or_default(),
|
||||
PipelineData::Empty => return Err(ShellError::PipelineEmpty { dst_span: head }),
|
||||
};
|
||||
|
||||
if let Some(content_type) = content_type {
|
||||
metadata.content_type = Some(content_type);
|
||||
}
|
||||
let signals = engine_state.signals().clone();
|
||||
let metadata = input
|
||||
.metadata()
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.with_content_type(content_type);
|
||||
|
||||
match (ds_fp, ds_ls) {
|
||||
(Some(path), false) => metadata.data_source = DataSource::FilePath(path.into()),
|
||||
(None, true) => metadata.data_source = DataSource::Ls,
|
||||
(Some(_), true) => (), // TODO: error here
|
||||
(None, false) => (),
|
||||
(Some(path), false) => Ok(input.into_pipeline_data_with_metadata(
|
||||
head,
|
||||
signals,
|
||||
metadata.with_data_source(DataSource::FilePath(path.into())),
|
||||
)),
|
||||
(None, true) => Ok(input.into_pipeline_data_with_metadata(
|
||||
head,
|
||||
signals,
|
||||
metadata.with_data_source(DataSource::Ls),
|
||||
)),
|
||||
_ => Ok(input.into_pipeline_data_with_metadata(head, signals, metadata)),
|
||||
}
|
||||
|
||||
Ok(input.set_metadata(Some(metadata)))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -85,9 +85,7 @@ impl Command for MetadataSet {
|
|||
Example {
|
||||
description: "Set the metadata of a file path",
|
||||
example: "'crates' | metadata set --content-type text/plain | metadata",
|
||||
result: Some(Value::test_record(record! {
|
||||
"content_type" => Value::test_string("text/plain"),
|
||||
})),
|
||||
result: Some(Value::record(record!("content_type" => Value::string("text/plain", Span::test_data())), Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ mod profile;
|
|||
mod timeit;
|
||||
mod view;
|
||||
mod view_files;
|
||||
mod view_ir;
|
||||
mod view_source;
|
||||
mod view_span;
|
||||
|
||||
|
@ -26,6 +25,5 @@ pub use profile::DebugProfile;
|
|||
pub use timeit::TimeIt;
|
||||
pub use view::View;
|
||||
pub use view_files::ViewFiles;
|
||||
pub use view_ir::ViewIr;
|
||||
pub use view_source::ViewSource;
|
||||
pub use view_span::ViewSpan;
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
use nu_engine::{command_prelude::*, ClosureEvalOnce};
|
||||
use nu_protocol::{
|
||||
debugger::{Profiler, ProfilerOptions},
|
||||
engine::Closure,
|
||||
};
|
||||
use nu_protocol::{debugger::Profiler, engine::Closure};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DebugProfile;
|
||||
|
@ -31,7 +28,6 @@ impl Command for DebugProfile {
|
|||
Some('v'),
|
||||
)
|
||||
.switch("expr", "Collect expression types", Some('x'))
|
||||
.switch("instructions", "Collect IR instructions", Some('i'))
|
||||
.switch("lines", "Collect line numbers", Some('l'))
|
||||
.named(
|
||||
"max-depth",
|
||||
|
@ -95,23 +91,19 @@ confusing the id/parent_id hierarchy. The --expr flag is helpful for investigati
|
|||
let collect_expanded_source = call.has_flag(engine_state, stack, "expanded-source")?;
|
||||
let collect_values = call.has_flag(engine_state, stack, "values")?;
|
||||
let collect_exprs = call.has_flag(engine_state, stack, "expr")?;
|
||||
let collect_instructions = call.has_flag(engine_state, stack, "instructions")?;
|
||||
let collect_lines = call.has_flag(engine_state, stack, "lines")?;
|
||||
let max_depth = call
|
||||
.get_flag(engine_state, stack, "max-depth")?
|
||||
.unwrap_or(2);
|
||||
|
||||
let profiler = Profiler::new(
|
||||
ProfilerOptions {
|
||||
max_depth,
|
||||
collect_spans,
|
||||
collect_source: true,
|
||||
collect_expanded_source,
|
||||
collect_values,
|
||||
collect_exprs,
|
||||
collect_instructions,
|
||||
collect_lines,
|
||||
},
|
||||
max_depth,
|
||||
collect_spans,
|
||||
true,
|
||||
collect_expanded_source,
|
||||
collect_values,
|
||||
collect_exprs,
|
||||
collect_lines,
|
||||
call.span(),
|
||||
);
|
||||
|
||||
|
|
|
@ -32,10 +32,6 @@ impl Command for TimeIt {
|
|||
vec!["timing", "timer", "benchmark", "measure"]
|
||||
}
|
||||
|
||||
fn requires_ast_for_arguments(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -43,14 +39,13 @@ impl Command for TimeIt {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
// reset outdest, so the command can write to stdout and stderr.
|
||||
let stack = &mut stack.push_redirection(None, None);
|
||||
|
||||
let command_to_run = call.positional_nth(stack, 0);
|
||||
let command_to_run = call.positional_nth(0);
|
||||
|
||||
// Get the start time after all other computation has been done.
|
||||
let start_time = Instant::now();
|
||||
|
||||
// reset outdest, so the command can write to stdout and stderr.
|
||||
let stack = &mut stack.push_redirection(None, None);
|
||||
if let Some(command_to_run) = command_to_run {
|
||||
if let Some(block_id) = command_to_run.as_block() {
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
@ -58,8 +53,7 @@ impl Command for TimeIt {
|
|||
eval_block(engine_state, stack, block, input)?
|
||||
} else {
|
||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
||||
let expression = &command_to_run.clone();
|
||||
eval_expression_with_input(engine_state, stack, expression, input)?.0
|
||||
eval_expression_with_input(engine_state, stack, command_to_run, input)?.0
|
||||
}
|
||||
} else {
|
||||
PipelineData::empty()
|
||||
|
|
|
@ -1,171 +0,0 @@
|
|||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ViewIr;
|
||||
|
||||
impl Command for ViewIr {
|
||||
fn name(&self) -> &str {
|
||||
"view ir"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.required(
|
||||
"target",
|
||||
SyntaxShape::Any,
|
||||
"The name or block to view compiled code for.",
|
||||
)
|
||||
.switch(
|
||||
"json",
|
||||
"Dump the raw block data as JSON (unstable).",
|
||||
Some('j'),
|
||||
)
|
||||
.switch(
|
||||
"decl-id",
|
||||
"Integer is a declaration ID rather than a block ID.",
|
||||
Some('d'),
|
||||
)
|
||||
.input_output_type(Type::Nothing, Type::String)
|
||||
.category(Category::Debug)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"View the compiled IR code for a block of code."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"
|
||||
The target can be a closure, the name of a custom command, or an internal block
|
||||
ID. Closure literals within IR dumps often reference the block by ID (e.g.
|
||||
`closure(3231)`), so this provides an easy way to read the IR of any embedded
|
||||
closures.
|
||||
|
||||
The --decl-id option is provided to use a declaration ID instead, which can be
|
||||
found on `call` instructions. This is sometimes better than using the name, as
|
||||
the declaration may not be in scope.
|
||||
"
|
||||
.trim()
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let target: Value = call.req(engine_state, stack, 0)?;
|
||||
let json = call.has_flag(engine_state, stack, "json")?;
|
||||
let is_decl_id = call.has_flag(engine_state, stack, "decl-id")?;
|
||||
|
||||
let block_id = match target {
|
||||
Value::Closure { ref val, .. } => val.block_id,
|
||||
// Decl by name
|
||||
Value::String { ref val, .. } => {
|
||||
if let Some(decl_id) = engine_state.find_decl(val.as_bytes(), &[]) {
|
||||
let decl = engine_state.get_decl(decl_id);
|
||||
decl.block_id().ok_or_else(|| ShellError::GenericError {
|
||||
error: format!("Can't view IR for `{val}`"),
|
||||
msg: "not a custom command".into(),
|
||||
span: Some(target.span()),
|
||||
help: Some("internal commands don't have Nushell source code".into()),
|
||||
inner: vec![],
|
||||
})?
|
||||
} else {
|
||||
return Err(ShellError::GenericError {
|
||||
error: format!("Can't view IR for `{val}`"),
|
||||
msg: "can't find a command with this name".into(),
|
||||
span: Some(target.span()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
}
|
||||
// Decl by ID - IR dump always shows name of decl, but sometimes it isn't in scope
|
||||
Value::Int { val, .. } if is_decl_id => {
|
||||
let decl_id = val
|
||||
.try_into()
|
||||
.ok()
|
||||
.filter(|id| *id < engine_state.num_decls())
|
||||
.ok_or_else(|| ShellError::IncorrectValue {
|
||||
msg: "not a valid decl id".into(),
|
||||
val_span: target.span(),
|
||||
call_span: call.head,
|
||||
})?;
|
||||
let decl = engine_state.get_decl(decl_id);
|
||||
decl.block_id().ok_or_else(|| ShellError::GenericError {
|
||||
error: format!("Can't view IR for `{}`", decl.name()),
|
||||
msg: "not a custom command".into(),
|
||||
span: Some(target.span()),
|
||||
help: Some("internal commands don't have Nushell source code".into()),
|
||||
inner: vec![],
|
||||
})?
|
||||
}
|
||||
// Block by ID - often shows up in IR
|
||||
Value::Int { val, .. } => val.try_into().map_err(|_| ShellError::IncorrectValue {
|
||||
msg: "not a valid block id".into(),
|
||||
val_span: target.span(),
|
||||
call_span: call.head,
|
||||
})?,
|
||||
// Pass through errors
|
||||
Value::Error { error, .. } => return Err(*error),
|
||||
_ => {
|
||||
return Err(ShellError::TypeMismatch {
|
||||
err_message: "expected closure, string, or int".into(),
|
||||
span: call.head,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let Some(block) = engine_state.try_get_block(block_id) else {
|
||||
return Err(ShellError::GenericError {
|
||||
error: format!("Unknown block ID: {block_id}"),
|
||||
msg: "ensure the block ID is correct and try again".into(),
|
||||
span: Some(target.span()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
};
|
||||
|
||||
let ir_block = block
|
||||
.ir_block
|
||||
.as_ref()
|
||||
.ok_or_else(|| ShellError::GenericError {
|
||||
error: "Can't view IR for this block".into(),
|
||||
msg: "block is missing compiled representation".into(),
|
||||
span: block.span,
|
||||
help: Some("the IrBlock is probably missing due to a compilation error".into()),
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
let formatted = if json {
|
||||
let formatted_instructions = ir_block
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|instruction| {
|
||||
instruction
|
||||
.display(engine_state, &ir_block.data)
|
||||
.to_string()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
serde_json::to_string_pretty(&serde_json::json!({
|
||||
"block_id": block_id,
|
||||
"span": block.span,
|
||||
"ir_block": ir_block,
|
||||
"formatted_instructions": formatted_instructions,
|
||||
}))
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "JSON serialization failed".into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
} else {
|
||||
format!("{}", ir_block.display(engine_state))
|
||||
};
|
||||
|
||||
Ok(Value::string(formatted, call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
|
@ -31,7 +31,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||
All,
|
||||
Any,
|
||||
Append,
|
||||
Chunks,
|
||||
Columns,
|
||||
Compact,
|
||||
Default,
|
||||
|
@ -155,7 +154,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||
TimeIt,
|
||||
View,
|
||||
ViewFiles,
|
||||
ViewIr,
|
||||
ViewSource,
|
||||
ViewSpan,
|
||||
};
|
||||
|
@ -291,6 +289,7 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||
ToText,
|
||||
ToToml,
|
||||
ToTsv,
|
||||
Touch,
|
||||
Upsert,
|
||||
Where,
|
||||
ToXml,
|
||||
|
@ -397,7 +396,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||
RandomFloat,
|
||||
RandomInt,
|
||||
RandomUuid,
|
||||
RandomBinary
|
||||
};
|
||||
|
||||
// Generators
|
||||
|
|
|
@ -60,13 +60,12 @@ impl Command for ConfigEnv {
|
|||
let (editor_name, editor_args) = get_editor(engine_state, stack, call.head)?;
|
||||
let paths = nu_engine::env::path_str(engine_state, stack, call.head)?;
|
||||
let cwd = engine_state.cwd(Some(stack))?;
|
||||
let editor_executable = crate::which(&editor_name, &paths, cwd.as_ref()).ok_or(
|
||||
ShellError::ExternalCommand {
|
||||
let editor_executable =
|
||||
crate::which(&editor_name, &paths, &cwd).ok_or(ShellError::ExternalCommand {
|
||||
label: format!("`{editor_name}` not found"),
|
||||
help: "Failed to find the editor executable".into(),
|
||||
span: call.head,
|
||||
},
|
||||
)?;
|
||||
})?;
|
||||
|
||||
let Some(env_path) = engine_state.get_config_path("env-path") else {
|
||||
return Err(ShellError::GenericError {
|
||||
|
|
|
@ -64,13 +64,12 @@ impl Command for ConfigNu {
|
|||
let (editor_name, editor_args) = get_editor(engine_state, stack, call.head)?;
|
||||
let paths = nu_engine::env::path_str(engine_state, stack, call.head)?;
|
||||
let cwd = engine_state.cwd(Some(stack))?;
|
||||
let editor_executable = crate::which(&editor_name, &paths, cwd.as_ref()).ok_or(
|
||||
ShellError::ExternalCommand {
|
||||
let editor_executable =
|
||||
crate::which(&editor_name, &paths, &cwd).ok_or(ShellError::ExternalCommand {
|
||||
label: format!("`{editor_name}` not found"),
|
||||
help: "Failed to find the editor executable".into(),
|
||||
span: call.head,
|
||||
},
|
||||
)?;
|
||||
})?;
|
||||
|
||||
let Some(config_path) = engine_state.get_config_path("config-path") else {
|
||||
return Err(ShellError::GenericError {
|
||||
|
|
6
crates/nu-command/src/env/export_env.rs
vendored
6
crates/nu-command/src/env/export_env.rs
vendored
|
@ -33,10 +33,6 @@ impl Command for ExportEnv {
|
|||
CommandType::Keyword
|
||||
}
|
||||
|
||||
fn requires_ast_for_arguments(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -45,7 +41,7 @@ impl Command for ExportEnv {
|
|||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let block_id = call
|
||||
.positional_nth(caller_stack, 0)
|
||||
.positional_nth(0)
|
||||
.expect("checked through parser")
|
||||
.as_block()
|
||||
.expect("internal error: missing block");
|
||||
|
|
2
crates/nu-command/src/env/source_env.rs
vendored
2
crates/nu-command/src/env/source_env.rs
vendored
|
@ -56,7 +56,7 @@ impl Command for SourceEnv {
|
|||
&source_filename.item,
|
||||
engine_state,
|
||||
caller_stack,
|
||||
get_dirs_var_from_call(caller_stack, call),
|
||||
get_dirs_var_from_call(call),
|
||||
)? {
|
||||
PathBuf::from(&path)
|
||||
} else {
|
||||
|
|
|
@ -31,7 +31,7 @@ mod test_examples {
|
|||
check_example_evaluates_to_expected_output,
|
||||
check_example_input_and_output_types_match_command_signature,
|
||||
};
|
||||
use nu_cmd_lang::{Break, Describe, Echo, If, Let, Mut};
|
||||
use nu_cmd_lang::{Break, Echo, If, Let, Mut};
|
||||
use nu_protocol::{
|
||||
engine::{Command, EngineState, StateWorkingSet},
|
||||
Type,
|
||||
|
@ -81,7 +81,6 @@ mod test_examples {
|
|||
working_set.add_decl(Box::new(Break));
|
||||
working_set.add_decl(Box::new(Date));
|
||||
working_set.add_decl(Box::new(Default));
|
||||
working_set.add_decl(Box::new(Describe));
|
||||
working_set.add_decl(Box::new(Each));
|
||||
working_set.add_decl(Box::new(Echo));
|
||||
working_set.add_decl(Box::new(Enumerate));
|
||||
|
|
|
@ -43,10 +43,7 @@ impl Command for Cd {
|
|||
|
||||
// If getting PWD failed, default to the initial directory. This way, the
|
||||
// user can use `cd` to recover PWD to a good state.
|
||||
let cwd = engine_state
|
||||
.cwd(Some(stack))
|
||||
.ok()
|
||||
.unwrap_or_else(get_init_cwd);
|
||||
let cwd = engine_state.cwd(Some(stack)).unwrap_or(get_init_cwd());
|
||||
|
||||
let path_val = {
|
||||
if let Some(path) = path_val {
|
||||
|
@ -65,7 +62,7 @@ impl Command for Cd {
|
|||
if let Some(oldpwd) = stack.get_env_var(engine_state, "OLDPWD") {
|
||||
oldpwd.to_path()?
|
||||
} else {
|
||||
cwd.into()
|
||||
cwd
|
||||
}
|
||||
} else {
|
||||
// Trim whitespace from the end of path.
|
||||
|
@ -134,7 +131,7 @@ impl Command for Cd {
|
|||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: r#"Change to the previous working directory (same as "cd $env.OLDPWD")"#,
|
||||
description: "Change to the previous working directory ($OLDPWD)",
|
||||
example: r#"cd -"#,
|
||||
result: None,
|
||||
},
|
||||
|
@ -143,16 +140,6 @@ impl Command for Cd {
|
|||
example: r#"def --env gohome [] { cd ~ }"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Move two directories up in the tree (the parent directory's parent). Additional dots can be added for additional levels.",
|
||||
example: r#"cd ..."#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "The cd command itself is often optional. Simply entering a path to a directory will cd to it.",
|
||||
example: r#"/home"#,
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ impl Command for Du {
|
|||
let current_dir = current_dir(engine_state, stack)?;
|
||||
|
||||
let paths = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
|
||||
let paths = if !call.has_positional_args(stack, 0) {
|
||||
let paths = if call.rest_iter(0).count() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(paths)
|
||||
|
|
|
@ -108,7 +108,7 @@ impl Command for Ls {
|
|||
};
|
||||
|
||||
let pattern_arg = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
|
||||
let input_pattern_arg = if !call.has_positional_args(stack, 0) {
|
||||
let input_pattern_arg = if call.rest_iter(0).count() == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(pattern_arg)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::util::get_rest_for_glob_pattern;
|
||||
#[allow(deprecated)]
|
||||
use nu_engine::{command_prelude::*, current_dir, get_eval_block};
|
||||
use nu_protocol::{ast, ByteStream, DataSource, NuGlob, PipelineMetadata};
|
||||
use nu_protocol::{ByteStream, DataSource, NuGlob, PipelineMetadata};
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
|
@ -56,7 +56,7 @@ impl Command for Open {
|
|||
let mut paths = get_rest_for_glob_pattern(engine_state, stack, call, 0)?;
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
if paths.is_empty() && !call.has_positional_args(stack, 0) {
|
||||
if paths.is_empty() && call.rest_iter(0).next().is_none() {
|
||||
// try to use path from pipeline input if there were no positional or spread args
|
||||
let (filename, span) = match input {
|
||||
PipelineData::Value(val, ..) => {
|
||||
|
@ -180,8 +180,7 @@ impl Command for Open {
|
|||
let block = engine_state.get_block(block_id);
|
||||
eval_block(engine_state, stack, block, stream)
|
||||
} else {
|
||||
let call = ast::Call::new(call_span);
|
||||
decl.run(engine_state, stack, &(&call).into(), stream)
|
||||
decl.run(engine_state, stack, &Call::new(call_span), stream)
|
||||
};
|
||||
output.push(command_output.map_err(|inner| {
|
||||
ShellError::GenericError{
|
||||
|
|
|
@ -135,9 +135,12 @@ fn rm(
|
|||
let home: Option<String> = nu_path::home_dir().map(|path| {
|
||||
{
|
||||
if path.exists() {
|
||||
nu_path::canonicalize_with(&path, ¤tdir_path).unwrap_or(path.into())
|
||||
match nu_path::canonicalize_with(&path, ¤tdir_path) {
|
||||
Ok(canon_path) => canon_path,
|
||||
Err(_) => path,
|
||||
}
|
||||
} else {
|
||||
path.into()
|
||||
path
|
||||
}
|
||||
}
|
||||
.to_string_lossy()
|
||||
|
@ -167,7 +170,7 @@ fn rm(
|
|||
}
|
||||
|
||||
let span = call.head;
|
||||
let rm_always_trash = stack.get_config(engine_state).rm_always_trash;
|
||||
let rm_always_trash = engine_state.get_config().rm_always_trash;
|
||||
|
||||
if !TRASH_SUPPORTED {
|
||||
if rm_always_trash {
|
||||
|
|
|
@ -4,8 +4,10 @@ use nu_engine::get_eval_block;
|
|||
use nu_engine::{command_prelude::*, current_dir};
|
||||
use nu_path::expand_path_with;
|
||||
use nu_protocol::{
|
||||
ast, byte_stream::copy_with_signals, process::ChildPipe, ByteStreamSource, DataSource, OutDest,
|
||||
PipelineMetadata, Signals,
|
||||
ast::{Expr, Expression},
|
||||
byte_stream::copy_with_signals,
|
||||
process::ChildPipe,
|
||||
ByteStreamSource, DataSource, OutDest, PipelineMetadata, Signals,
|
||||
};
|
||||
use std::{
|
||||
fs::File,
|
||||
|
@ -67,6 +69,24 @@ impl Command for Save {
|
|||
let append = call.has_flag(engine_state, stack, "append")?;
|
||||
let force = call.has_flag(engine_state, stack, "force")?;
|
||||
let progress = call.has_flag(engine_state, stack, "progress")?;
|
||||
let out_append = if let Some(Expression {
|
||||
expr: Expr::Bool(out_append),
|
||||
..
|
||||
}) = call.get_parser_info("out-append")
|
||||
{
|
||||
*out_append
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let err_append = if let Some(Expression {
|
||||
expr: Expr::Bool(err_append),
|
||||
..
|
||||
}) = call.get_parser_info("err-append")
|
||||
{
|
||||
*err_append
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let span = call.head;
|
||||
#[allow(deprecated)]
|
||||
|
@ -89,7 +109,14 @@ impl Command for Save {
|
|||
PipelineData::ByteStream(stream, metadata) => {
|
||||
check_saving_to_source_file(metadata.as_ref(), &path, stderr_path.as_ref())?;
|
||||
|
||||
let (file, stderr_file) = get_files(&path, stderr_path.as_ref(), append, force)?;
|
||||
let (file, stderr_file) = get_files(
|
||||
&path,
|
||||
stderr_path.as_ref(),
|
||||
append,
|
||||
out_append,
|
||||
err_append,
|
||||
force,
|
||||
)?;
|
||||
|
||||
let size = stream.known_size();
|
||||
let signals = engine_state.signals();
|
||||
|
@ -121,11 +148,9 @@ impl Command for Save {
|
|||
} else {
|
||||
match stderr {
|
||||
ChildPipe::Pipe(mut pipe) => {
|
||||
io::copy(&mut pipe, &mut io::stderr())
|
||||
}
|
||||
ChildPipe::Tee(mut tee) => {
|
||||
io::copy(&mut tee, &mut io::stderr())
|
||||
io::copy(&mut pipe, &mut io::sink())
|
||||
}
|
||||
ChildPipe::Tee(mut tee) => io::copy(&mut tee, &mut io::sink()),
|
||||
}
|
||||
.err_span(span)?;
|
||||
}
|
||||
|
@ -196,7 +221,14 @@ impl Command for Save {
|
|||
stderr_path.as_ref(),
|
||||
)?;
|
||||
|
||||
let (mut file, _) = get_files(&path, stderr_path.as_ref(), append, force)?;
|
||||
let (mut file, _) = get_files(
|
||||
&path,
|
||||
stderr_path.as_ref(),
|
||||
append,
|
||||
out_append,
|
||||
err_append,
|
||||
force,
|
||||
)?;
|
||||
for val in ls {
|
||||
file.write_all(&value_to_bytes(val)?)
|
||||
.map_err(|err| ShellError::IOError {
|
||||
|
@ -226,7 +258,14 @@ impl Command for Save {
|
|||
input_to_bytes(input, Path::new(&path.item), raw, engine_state, stack, span)?;
|
||||
|
||||
// Only open file after successful conversion
|
||||
let (mut file, _) = get_files(&path, stderr_path.as_ref(), append, force)?;
|
||||
let (mut file, _) = get_files(
|
||||
&path,
|
||||
stderr_path.as_ref(),
|
||||
append,
|
||||
out_append,
|
||||
err_append,
|
||||
force,
|
||||
)?;
|
||||
|
||||
file.write_all(&bytes).map_err(|err| ShellError::IOError {
|
||||
msg: err.to_string(),
|
||||
|
@ -358,8 +397,7 @@ fn convert_to_extension(
|
|||
let eval_block = get_eval_block(engine_state);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else {
|
||||
let call = ast::Call::new(span);
|
||||
decl.run(engine_state, stack, &(&call).into(), input)
|
||||
decl.run(engine_state, stack, &Call::new(span), input)
|
||||
}
|
||||
} else {
|
||||
Ok(input)
|
||||
|
@ -435,17 +473,19 @@ fn get_files(
|
|||
path: &Spanned<PathBuf>,
|
||||
stderr_path: Option<&Spanned<PathBuf>>,
|
||||
append: bool,
|
||||
out_append: bool,
|
||||
err_append: bool,
|
||||
force: bool,
|
||||
) -> Result<(File, Option<File>), ShellError> {
|
||||
// First check both paths
|
||||
let (path, path_span) = prepare_path(path, append, force)?;
|
||||
let (path, path_span) = prepare_path(path, append || out_append, force)?;
|
||||
let stderr_path_and_span = stderr_path
|
||||
.as_ref()
|
||||
.map(|stderr_path| prepare_path(stderr_path, append, force))
|
||||
.map(|stderr_path| prepare_path(stderr_path, append || err_append, force))
|
||||
.transpose()?;
|
||||
|
||||
// Only if both files can be used open and possibly truncate them
|
||||
let file = open_file(path, path_span, append)?;
|
||||
let file = open_file(path, path_span, append || out_append)?;
|
||||
|
||||
let stderr_file = stderr_path_and_span
|
||||
.map(|(stderr_path, stderr_path_span)| {
|
||||
|
@ -458,7 +498,7 @@ fn get_files(
|
|||
inner: vec![],
|
||||
})
|
||||
} else {
|
||||
open_file(stderr_path, stderr_path_span, append)
|
||||
open_file(stderr_path, stderr_path_span, append || err_append)
|
||||
}
|
||||
})
|
||||
.transpose()?;
|
||||
|
|
|
@ -86,22 +86,17 @@ impl Command for UCp {
|
|||
},
|
||||
Example {
|
||||
description: "Copy only if source file is newer than target file",
|
||||
example: "cp -u myfile newfile",
|
||||
example: "cp -u a b",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Copy file preserving mode and timestamps attributes",
|
||||
example: "cp --preserve [ mode timestamps ] myfile newfile",
|
||||
example: "cp --preserve [ mode timestamps ] a b",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Copy file erasing all attributes",
|
||||
example: "cp --preserve [] myfile newfile",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Copy file to a directory three levels above its current location",
|
||||
example: "cp myfile ....",
|
||||
example: "cp --preserve [] a b",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
|
@ -240,7 +235,7 @@ impl Command for UCp {
|
|||
for (sources, need_expand_tilde) in sources.iter_mut() {
|
||||
for src in sources.iter_mut() {
|
||||
if !src.is_absolute() {
|
||||
*src = nu_path::expand_path_with(&*src, &cwd, *need_expand_tilde);
|
||||
*src = nu_path::expand_path_with(&src, &cwd, *need_expand_tilde);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,21 +30,11 @@ impl Command for UMv {
|
|||
example: "mv test.txt my/subdirectory",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Move only if source file is newer than target file",
|
||||
example: "mv -u new/test.txt old/",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Move many files into a directory",
|
||||
example: "mv *.txt my/subdirectory",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: r#"Move a file into the "my" directory two levels up in the directory tree"#,
|
||||
example: "mv test.txt .../my/",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -59,11 +49,6 @@ impl Command for UMv {
|
|||
.switch("verbose", "explain what is being done.", Some('v'))
|
||||
.switch("progress", "display a progress bar", Some('p'))
|
||||
.switch("interactive", "prompt before overwriting", Some('i'))
|
||||
.switch(
|
||||
"update",
|
||||
"move and overwrite only when the SOURCE file is newer than the destination file or when the destination file is missing",
|
||||
Some('u')
|
||||
)
|
||||
.switch("no-clobber", "do not overwrite an existing file", Some('n'))
|
||||
.rest(
|
||||
"paths",
|
||||
|
@ -92,11 +77,6 @@ impl Command for UMv {
|
|||
} else {
|
||||
uu_mv::OverwriteMode::Force
|
||||
};
|
||||
let update = if call.has_flag(engine_state, stack, "update")? {
|
||||
UpdateMode::ReplaceIfOlder
|
||||
} else {
|
||||
UpdateMode::ReplaceAll
|
||||
};
|
||||
|
||||
#[allow(deprecated)]
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
|
@ -161,7 +141,7 @@ impl Command for UMv {
|
|||
for (files, need_expand_tilde) in files.iter_mut() {
|
||||
for src in files.iter_mut() {
|
||||
if !src.is_absolute() {
|
||||
*src = nu_path::expand_path_with(&*src, &cwd, *need_expand_tilde);
|
||||
*src = nu_path::expand_path_with(&src, &cwd, *need_expand_tilde);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +164,7 @@ impl Command for UMv {
|
|||
verbose,
|
||||
suffix: String::from("~"),
|
||||
backup: BackupMode::NoBackup,
|
||||
update,
|
||||
update: UpdateMode::ReplaceAll,
|
||||
target_dir: None,
|
||||
no_target_dir: false,
|
||||
strip_slashes: false,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use dialoguer::Input;
|
||||
use nu_engine::{command_prelude::*, get_eval_expression};
|
||||
use nu_protocol::{FromValue, NuGlob};
|
||||
use nu_protocol::{ast::Expr, FromValue, NuGlob};
|
||||
use std::{
|
||||
error::Error,
|
||||
path::{Path, PathBuf},
|
||||
|
@ -92,19 +92,42 @@ pub fn is_older(src: &Path, dst: &Path) -> Option<bool> {
|
|||
|
||||
/// Get rest arguments from given `call`, starts with `starting_pos`.
|
||||
///
|
||||
/// It's similar to `call.rest`, except that it always returns NuGlob.
|
||||
/// It's similar to `call.rest`, except that it always returns NuGlob. And if input argument has
|
||||
/// Type::Glob, the NuGlob is unquoted, which means it's required to expand.
|
||||
pub fn get_rest_for_glob_pattern(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
starting_pos: usize,
|
||||
) -> Result<Vec<Spanned<NuGlob>>, ShellError> {
|
||||
let mut output = vec![];
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
|
||||
call.rest_iter_flattened(engine_state, stack, eval_expression, starting_pos)?
|
||||
.into_iter()
|
||||
// This used to be much more complex, but I think `FromValue` should be able to handle the
|
||||
// nuance here.
|
||||
.map(FromValue::from_value)
|
||||
.collect()
|
||||
for result in call.rest_iter_flattened(starting_pos, |expr| {
|
||||
let result = eval_expression(engine_state, stack, expr);
|
||||
match result {
|
||||
Err(e) => Err(e),
|
||||
Ok(result) => {
|
||||
let span = result.span();
|
||||
// convert from string to quoted string if expr is a variable
|
||||
// or string interpolation
|
||||
match result {
|
||||
Value::String { val, .. }
|
||||
if matches!(
|
||||
&expr.expr,
|
||||
Expr::FullCellPath(_) | Expr::StringInterpolation(_)
|
||||
) =>
|
||||
{
|
||||
// should not expand if given input type is not glob.
|
||||
Ok(Value::glob(val, expr.ty != Type::Glob, span))
|
||||
}
|
||||
other => Ok(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
})? {
|
||||
output.push(FromValue::from_value(result)?);
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user