mirror of
https://github.com/nushell/nushell.git
synced 2025-07-02 07:31:39 +02:00
Compare commits
90 Commits
Author | SHA1 | Date | |
---|---|---|---|
e76b3d61de | |||
1adebefc3e | |||
d1e1d0ac3e | |||
b398448cd9 | |||
02f92fa527 | |||
773d167449 | |||
aa92141ad7 | |||
80624267fd | |||
2030e25ddc | |||
247fff424d | |||
c902d8bc0c | |||
b0e5723a68 | |||
9273bb3f72 | |||
f7d3ccfc70 | |||
d86350af80 | |||
14512988ba | |||
33e1120add | |||
3278d290be | |||
daec3fc3d3 | |||
a6ba58ec41 | |||
65327e0e7e | |||
3ed3712fdc | |||
f46962d236 | |||
aa4778ff07 | |||
e81689f2c0 | |||
4656310a1c | |||
34e58bc5d6 | |||
fbe9d6f529 | |||
e266590813 | |||
b27148d14b | |||
4858a9a817 | |||
3ec53e544c | |||
c52d45cb97 | |||
11531b7630 | |||
a098a27837 | |||
2591bd8c63 | |||
a03fb946d9 | |||
9c58f2a522 | |||
3cb9147f22 | |||
f1d72e2670 | |||
f1e7a01b2e | |||
b88ace4cde | |||
34d7c17e78 | |||
3f1824111d | |||
fbae137442 | |||
9850424251 | |||
918ec9daa8 | |||
7b502a4c7f | |||
7b07e976b8 | |||
e45b169cba | |||
5ebfa10495 | |||
3f93dc2f1d | |||
a43514deb2 | |||
ab77bf3289 | |||
0afe1e4e67 | |||
ef26d539a7 | |||
fce8581321 | |||
ba6abd77c9 | |||
a7295c8f1b | |||
2a310ef187 | |||
530e250573 | |||
6fbc76bc0f | |||
884382bac4 | |||
d97975e9fa | |||
839b264261 | |||
7ef4e5f940 | |||
646aace05b | |||
772ad896c8 | |||
9c4bbe3c63 | |||
c5ca839294 | |||
5337a6dffa | |||
56ce10347e | |||
37bc90c62a | |||
ad7522bba0 | |||
bbcf374886 | |||
99c42582fe | |||
5a56d47f25 | |||
529c98085a | |||
2b955f82b7 | |||
1843fdc060 | |||
ec4e3a6d5c | |||
4ab468e65f | |||
1d18f6947e | |||
df3b6d9d26 | |||
4bbdb73668 | |||
62d3497bbb | |||
e614970c08 | |||
d931331b57 | |||
f18da2609a | |||
2ef9cc118e |
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -82,11 +82,9 @@ jobs:
|
|||||||
# toolchain: ${{ matrix.rust }}
|
# toolchain: ${{ matrix.rust }}
|
||||||
# override: true
|
# override: true
|
||||||
|
|
||||||
# Temporarily disabled; the cache was getting huge (2.6GB compressed) on Windows and causing issues.
|
- uses: Swatinem/rust-cache@v1
|
||||||
# TODO: investigate why the cache was so big
|
with:
|
||||||
# - uses: Swatinem/rust-cache@v1
|
key: ${{ matrix.style }}v3 # increment this to bust the cache if needed
|
||||||
# with:
|
|
||||||
# key: ${{ matrix.style }}v3 # increment this to bust the cache if needed
|
|
||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
41
.github/workflows/manual.yml
vendored
Normal file
41
.github/workflows/manual.yml
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# This is a basic workflow that is manually triggered
|
||||||
|
# Don't run it unless you know what you are doing
|
||||||
|
|
||||||
|
name: Manual Workflow for Winget Submission
|
||||||
|
|
||||||
|
# Controls when the action will run. Workflow runs when manually triggered using the UI
|
||||||
|
# or API.
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
# Inputs the workflow accepts.
|
||||||
|
inputs:
|
||||||
|
ver:
|
||||||
|
# Friendly description to be shown in the UI instead of 'ver'
|
||||||
|
description: 'The nushell version to release'
|
||||||
|
# Default value if no value is explicitly provided
|
||||||
|
default: '0.66.0'
|
||||||
|
# Input has to be provided for the workflow to run
|
||||||
|
required: true
|
||||||
|
uri:
|
||||||
|
# Friendly description to be shown in the UI instead of 'uri'
|
||||||
|
description: 'The nushell windows .msi package URI to publish'
|
||||||
|
# Default value if no value is explicitly provided
|
||||||
|
default: 'https://github.com/nushell/nushell/releases/download/0.66.0/nu-0.66.0-x86_64-pc-windows-msvc.msi'
|
||||||
|
# Input has to be provided for the workflow to run
|
||||||
|
required: true
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
# This workflow contains a single job
|
||||||
|
rls-winget-pkg:
|
||||||
|
name: Publish winget package manually
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
# Runs commands using the runners shell
|
||||||
|
- name: Submit package to Windows Package Manager Community Repository Manually
|
||||||
|
run: |
|
||||||
|
iwr https://github.com/microsoft/winget-create/releases/download/v1.0.4.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||||
|
.\wingetcreate.exe update Nushell.Nushell -s -v ${{ github.event.inputs.ver }} -u ${{ github.event.inputs.uri }} -t ${{ secrets.NUSHELL_PAT }}
|
14
.github/workflows/release-pkg.nu
vendored
14
.github/workflows/release-pkg.nu
vendored
@ -41,7 +41,7 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
|||||||
} else {
|
} else {
|
||||||
# musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?'
|
# musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?'
|
||||||
# Actually just for x86_64-unknown-linux-musl target
|
# Actually just for x86_64-unknown-linux-musl target
|
||||||
sudo apt install musl-tools -y
|
if $os == 'ubuntu-latest' { sudo apt install musl-tools -y }
|
||||||
cargo-build-nu $flags
|
cargo-build-nu $flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
|||||||
# Build for Windows without static-link-openssl feature
|
# Build for Windows without static-link-openssl feature
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
if $os in ['windows-latest'] {
|
if $os in ['windows-latest'] {
|
||||||
if ($flags | str trim | empty?) {
|
if ($flags | str trim | is-empty) {
|
||||||
cargo build --release --all --target $target --features=extra
|
cargo build --release --all --target $target --features=extra
|
||||||
} else {
|
} else {
|
||||||
cargo build --release --all --target $target --features=extra $flags
|
cargo build --release --all --target $target --features=extra $flags
|
||||||
@ -80,7 +80,7 @@ let ver = if $os == 'windows-latest' {
|
|||||||
} else {
|
} else {
|
||||||
(do -i { ./output/nu -c 'version' }) | str collect
|
(do -i { ./output/nu -c 'version' }) | str collect
|
||||||
}
|
}
|
||||||
if ($ver | str trim | empty?) {
|
if ($ver | str trim | is-empty) {
|
||||||
$'(ansi r)Incompatible nu binary...(ansi reset)'
|
$'(ansi r)Incompatible nu binary...(ansi reset)'
|
||||||
} else { $ver }
|
} else { $ver }
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
|||||||
cd $src; hr-line
|
cd $src; hr-line
|
||||||
# Wix need the binaries be stored in target/release/
|
# Wix need the binaries be stored in target/release/
|
||||||
cp -r $'($dist)/*' target/release/
|
cp -r $'($dist)/*' target/release/
|
||||||
cargo install cargo-wix --version 0.3.2
|
cargo install cargo-wix --version 0.3.3
|
||||||
cargo wix --no-build --nocapture --package nu --output $wixRelease
|
cargo wix --no-build --nocapture --package nu --output $wixRelease
|
||||||
echo $'::set-output name=archive::($wixRelease)'
|
echo $'::set-output name=archive::($wixRelease)'
|
||||||
|
|
||||||
@ -124,14 +124,14 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
|||||||
7z a $archive *
|
7z a $archive *
|
||||||
print $'archive: ---> ($archive)';
|
print $'archive: ---> ($archive)';
|
||||||
let pkg = (ls -f $archive | get name)
|
let pkg = (ls -f $archive | get name)
|
||||||
if not ($pkg | empty?) {
|
if not ($pkg | is-empty) {
|
||||||
echo $'::set-output name=archive::($pkg | get 0)'
|
echo $'::set-output name=archive::($pkg | get 0)'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def 'cargo-build-nu' [ options: string ] {
|
def 'cargo-build-nu' [ options: string ] {
|
||||||
if ($options | str trim | empty?) {
|
if ($options | str trim | is-empty) {
|
||||||
cargo build --release --all --target $target --features=extra,static-link-openssl
|
cargo build --release --all --target $target --features=extra,static-link-openssl
|
||||||
} else {
|
} else {
|
||||||
cargo build --release --all --target $target --features=extra,static-link-openssl $options
|
cargo build --release --all --target $target --features=extra,static-link-openssl $options
|
||||||
@ -143,7 +143,7 @@ def 'hr-line' [
|
|||||||
--blank-line(-b): bool
|
--blank-line(-b): bool
|
||||||
] {
|
] {
|
||||||
print $'(ansi g)---------------------------------------------------------------------------->(ansi reset)'
|
print $'(ansi g)---------------------------------------------------------------------------->(ansi reset)'
|
||||||
if $blank-line { char nl }
|
if $blank_line { char nl }
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get the specified env key's value or ''
|
# Get the specified env key's value or ''
|
||||||
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@ -70,9 +70,9 @@ jobs:
|
|||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Setup Nushell
|
- name: Setup Nushell
|
||||||
uses: hustcer/setup-nu@v1
|
uses: hustcer/setup-nu@v2.1
|
||||||
with:
|
with:
|
||||||
version: 0.63.0
|
version: 0.68.0
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
2
.github/workflows/winget-submission.yml
vendored
2
.github/workflows/winget-submission.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Submit package to Windows Package Manager Community Repository
|
- name: Submit package to Windows Package Manager Community Repository
|
||||||
run: |
|
run: |
|
||||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
iwr https://github.com/microsoft/winget-create/releases/download/v1.0.4.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||||
$github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json
|
$github = Get-Content '${{ github.event_path }}' | ConvertFrom-Json
|
||||||
$installerUrl = $github.release.assets | Where-Object -Property name -match 'windows-msvc.msi' | Select -ExpandProperty browser_download_url -First 1
|
$installerUrl = $github.release.assets | Where-Object -Property name -match 'windows-msvc.msi' | Select -ExpandProperty browser_download_url -First 1
|
||||||
.\wingetcreate.exe update Nushell.Nushell -s -v $github.release.tag_name -u $installerUrl -t ${{ secrets.NUSHELL_PAT }}
|
.\wingetcreate.exe update Nushell.Nushell -s -v $github.release.tag_name -u $installerUrl -t ${{ secrets.NUSHELL_PAT }}
|
||||||
|
@ -70,5 +70,5 @@ cargo build
|
|||||||
- To redirect trace logs to a file, enable the `--log-target file` switch.
|
- To redirect trace logs to a file, enable the `--log-target file` switch.
|
||||||
```shell
|
```shell
|
||||||
cargo run --release --features=extra -- --log-level trace --log-target file
|
cargo run --release --features=extra -- --log-level trace --log-target file
|
||||||
[($nu.temp-path) nu-($nu.pid).log] | path join | open
|
open $"($nu.temp-path)/nu-($nu.pid).log"
|
||||||
```
|
```
|
||||||
|
318
Cargo.lock
generated
318
Cargo.lock
generated
@ -70,9 +70,9 @@ checksum = "77e9c9abb82613923ec78d7a461595d52491ba7240f3c64c0bbe0e6d98e0fce0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7ed72e1635e121ca3e79420540282af22da58be50de153d36f81ddc6b83aa9e"
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@ -419,6 +419,12 @@ version = "3.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-order"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b021a13e4bf34a5679ada4609a01337ae82f2c4c97493b9d8cbf8aa9af9bd0f4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byte-slice-cast"
|
name = "byte-slice-cast"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -494,10 +500,10 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "capnp"
|
name = "cast"
|
||||||
version = "0.14.8"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "82efa3b0ab5e7e32b786334b052560ec0094135f906975d7481651b9ecf31a6a"
|
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
@ -588,6 +594,17 @@ dependencies = [
|
|||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "2.34.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"textwrap 0.11.0",
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codepage"
|
name = "codepage"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -702,6 +719,42 @@ dependencies = [
|
|||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"cast",
|
||||||
|
"clap",
|
||||||
|
"criterion-plot",
|
||||||
|
"csv",
|
||||||
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
|
"num-traits",
|
||||||
|
"oorandom",
|
||||||
|
"plotters",
|
||||||
|
"rayon",
|
||||||
|
"regex",
|
||||||
|
"serde",
|
||||||
|
"serde_cbor",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"tinytemplate",
|
||||||
|
"walkdir",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "criterion-plot"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
|
||||||
|
dependencies = [
|
||||||
|
"cast",
|
||||||
|
"itertools",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "critical-section"
|
name = "critical-section"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
@ -1530,6 +1583,12 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "1.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hamcrest2"
|
name = "hamcrest2"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -1710,13 +1769,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.44"
|
version = "0.1.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "808cf7d67cf4a22adc5be66e75ebdf769b3f2ea032041437a7061f97a63dad4b"
|
checksum = "4c495f162af0bf17656d0014a0eded5f3cd2f365fdd204548c2869db89359dc7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android_system_properties",
|
"android_system_properties",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
@ -2145,9 +2205,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lz4-sys"
|
name = "lz4-sys"
|
||||||
version = "1.9.3"
|
version = "1.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7be8908e2ed6f31c02db8a9fa962f03e36c53fbfde437363eae3306b85d7e17"
|
checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
@ -2159,6 +2219,15 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach2"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
@ -2258,7 +2327,7 @@ dependencies = [
|
|||||||
"supports-hyperlinks",
|
"supports-hyperlinks",
|
||||||
"supports-unicode",
|
"supports-unicode",
|
||||||
"terminal_size 0.1.17",
|
"terminal_size 0.1.17",
|
||||||
"textwrap",
|
"textwrap 0.15.0",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
@ -2440,6 +2509,7 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
|
"memoffset",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2506,7 +2576,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu"
|
name = "nu"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2558,8 +2628,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atty",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm 0.24.0",
|
"crossterm 0.24.0",
|
||||||
"fancy-regex",
|
"fancy-regex",
|
||||||
@ -2586,7 +2657,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-color-config"
|
name = "nu-color-config"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-json",
|
"nu-json",
|
||||||
@ -2597,7 +2668,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-command"
|
name = "nu-command"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"Inflector",
|
"Inflector",
|
||||||
"alphanumeric-sort",
|
"alphanumeric-sort",
|
||||||
@ -2653,6 +2724,7 @@ dependencies = [
|
|||||||
"pathdiff",
|
"pathdiff",
|
||||||
"polars",
|
"polars",
|
||||||
"powierza-coefficient",
|
"powierza-coefficient",
|
||||||
|
"proptest",
|
||||||
"quick-xml 0.23.0",
|
"quick-xml 0.23.0",
|
||||||
"quickcheck",
|
"quickcheck",
|
||||||
"quickcheck_macros",
|
"quickcheck_macros",
|
||||||
@ -2690,19 +2762,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-engine"
|
name = "nu-engine"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"nu-glob",
|
"nu-glob",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
"nu-utils",
|
"nu-utils",
|
||||||
|
"strip-ansi-escapes",
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-glob"
|
name = "nu-glob"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"doc-comment",
|
"doc-comment",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
@ -2710,7 +2783,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-json"
|
name = "nu-json"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fancy-regex",
|
"fancy-regex",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
@ -2723,7 +2796,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-parser"
|
name = "nu-parser"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"itertools",
|
"itertools",
|
||||||
@ -2739,7 +2812,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-path"
|
name = "nu-path"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"dunce",
|
"dunce",
|
||||||
@ -2748,19 +2821,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-plugin"
|
name = "nu-plugin"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode",
|
"bincode",
|
||||||
"capnp",
|
"byte-order",
|
||||||
|
"criterion",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
|
"rmp",
|
||||||
|
"rmp-serde",
|
||||||
|
"rmpv",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-pretty-hex"
|
name = "nu-pretty-hex"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heapless",
|
"heapless",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
@ -2769,7 +2846,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-protocol"
|
name = "nu-protocol"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
"chrono",
|
"chrono",
|
||||||
@ -2790,12 +2867,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-system"
|
name = "nu-system"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atty",
|
||||||
"chrono",
|
"chrono",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"libproc",
|
"libproc",
|
||||||
|
"mach2",
|
||||||
|
"nix",
|
||||||
"ntapi",
|
"ntapi",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"procfs",
|
"procfs",
|
||||||
@ -2804,7 +2884,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-table"
|
name = "nu-table"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
@ -2815,7 +2895,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-term-grid"
|
name = "nu-term-grid"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
@ -2823,7 +2903,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-test-support"
|
name = "nu-test-support"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getset",
|
"getset",
|
||||||
"hamcrest2",
|
"hamcrest2",
|
||||||
@ -2838,7 +2918,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-utils"
|
name = "nu-utils"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
"lscolors",
|
"lscolors",
|
||||||
@ -2858,7 +2938,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_example"
|
name = "nu_plugin_example"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2866,7 +2946,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_gstat"
|
name = "nu_plugin_gstat"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"git2",
|
"git2",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -2876,7 +2956,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_inc"
|
name = "nu_plugin_inc"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-plugin",
|
"nu-plugin",
|
||||||
"nu-protocol",
|
"nu-protocol",
|
||||||
@ -2885,7 +2965,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_query"
|
name = "nu_plugin_query"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gjson",
|
"gjson",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -3070,9 +3150,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.13.0"
|
version = "1.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
checksum = "074864da206b4973b84eb91683020dbefd6a8c3f0f38e054d93954e891935e4e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oorandom"
|
||||||
|
version = "11.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opaque-debug"
|
name = "opaque-debug"
|
||||||
@ -3230,6 +3316,12 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9423e2b32f7a043629287a536f21951e8c6a82482d0acb1eeebfc90bc2225b22"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathdiff"
|
name = "pathdiff"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -3421,6 +3513,34 @@ dependencies = [
|
|||||||
"array-init-cursor",
|
"array-init-cursor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "716b4eeb6c4a1d3ecc956f75b43ec2e8e8ba80026413e70a3f41fd3313d3492b"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"plotters-backend",
|
||||||
|
"plotters-svg",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-backend"
|
||||||
|
version = "0.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plotters-svg"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
|
||||||
|
dependencies = [
|
||||||
|
"plotters-backend",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polars"
|
name = "polars"
|
||||||
version = "0.23.2"
|
version = "0.23.2"
|
||||||
@ -3677,6 +3797,26 @@ dependencies = [
|
|||||||
"rustix",
|
"rustix",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proptest"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set",
|
||||||
|
"bitflags",
|
||||||
|
"byteorder",
|
||||||
|
"lazy_static",
|
||||||
|
"num-traits",
|
||||||
|
"quick-error 2.0.1",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"rand_chacha 0.3.1",
|
||||||
|
"rand_xorshift",
|
||||||
|
"regex-syntax",
|
||||||
|
"rusty-fork",
|
||||||
|
"tempfile",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pure-rust-locales"
|
name = "pure-rust-locales"
|
||||||
version = "0.5.6"
|
version = "0.5.6"
|
||||||
@ -3699,6 +3839,12 @@ version = "1.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.19.0"
|
version = "0.19.0"
|
||||||
@ -3868,6 +4014,15 @@ dependencies = [
|
|||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_xorshift"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.6.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.5.3"
|
version = "1.5.3"
|
||||||
@ -3923,9 +4078,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reedline"
|
name = "reedline"
|
||||||
version = "0.10.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d84e8704e9eb141e73ac426c72af95eb195d4c3221a11ea92d5709f4a025adb5"
|
checksum = "5559b5ab4817b0da0c6fc6814edfae537209e01d955a2f3e7595606e3d039691"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm 0.24.0",
|
"crossterm 0.24.0",
|
||||||
@ -4040,6 +4195,38 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rmp"
|
||||||
|
version = "0.8.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rmp-serde"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25786b0d276110195fa3d6f3f31299900cf71dfbd6c28450f3f58a0e7f7a347e"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"rmp",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rmpv"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de8813b3a2f95c5138fe5925bfb8784175d88d6bff059ba8ce090aa891319754"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"rmp",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roxmltree"
|
name = "roxmltree"
|
||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
@ -4180,6 +4367,18 @@ version = "1.0.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8"
|
checksum = "24c8ad4f0c00e1eb5bc7614d236a7f1300e3dbd76b68cac8e06fb00b015ad8d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusty-fork"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"quick-error 1.2.3",
|
||||||
|
"tempfile",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
@ -4311,18 +4510,28 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.140"
|
version = "1.0.144"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03"
|
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_cbor"
|
||||||
version = "1.0.140"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da"
|
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||||
|
dependencies = [
|
||||||
|
"half",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.144"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -4725,7 +4934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "36e39da5d30887b5690e29de4c5ebb8ddff64ebd9933f98a01daaa4fd11b36ea"
|
checksum = "36e39da5d30887b5690e29de4c5ebb8ddff64ebd9933f98a01daaa4fd11b36ea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"peresil",
|
"peresil",
|
||||||
"quick-error",
|
"quick-error 1.2.3",
|
||||||
"sxd-document",
|
"sxd-document",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4865,6 +5074,15 @@ version = "0.2.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
@ -4940,6 +5158,16 @@ version = "0.2.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinytemplate"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
@ -5462,13 +5690,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
version = "4.2.5"
|
version = "4.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
|
checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"lazy_static",
|
|
||||||
"libc",
|
"libc",
|
||||||
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
35
Cargo.toml
35
Cargo.toml
@ -11,7 +11,7 @@ name = "nu"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/nushell/nushell"
|
repository = "https://github.com/nushell/nushell"
|
||||||
rust-version = "1.60"
|
rust-version = "1.60"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@ -39,21 +39,21 @@ ctrlc = "3.2.1"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
miette = "5.1.0"
|
miette = "5.1.0"
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-cli = { path="./crates/nu-cli", version = "0.67.0" }
|
nu-cli = { path="./crates/nu-cli", version = "0.68.1" }
|
||||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.67.0" }
|
nu-color-config = { path = "./crates/nu-color-config", version = "0.68.1" }
|
||||||
nu-command = { path="./crates/nu-command", version = "0.67.0" }
|
nu-command = { path="./crates/nu-command", version = "0.68.1" }
|
||||||
nu-engine = { path="./crates/nu-engine", version = "0.67.0" }
|
nu-engine = { path="./crates/nu-engine", version = "0.68.1" }
|
||||||
nu-json = { path="./crates/nu-json", version = "0.67.0" }
|
nu-json = { path="./crates/nu-json", version = "0.68.1" }
|
||||||
nu-parser = { path="./crates/nu-parser", version = "0.67.0" }
|
nu-parser = { path="./crates/nu-parser", version = "0.68.1" }
|
||||||
nu-path = { path="./crates/nu-path", version = "0.67.0" }
|
nu-path = { path="./crates/nu-path", version = "0.68.1" }
|
||||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.67.0" }
|
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.68.1" }
|
||||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.67.0" }
|
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.68.1" }
|
||||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.67.0" }
|
nu-protocol = { path = "./crates/nu-protocol", version = "0.68.1" }
|
||||||
nu-system = { path = "./crates/nu-system", version = "0.67.0" }
|
nu-system = { path = "./crates/nu-system", version = "0.68.1" }
|
||||||
nu-table = { path = "./crates/nu-table", version = "0.67.0" }
|
nu-table = { path = "./crates/nu-table", version = "0.68.1" }
|
||||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.67.0" }
|
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.68.1" }
|
||||||
nu-utils = { path = "./crates/nu-utils", version = "0.67.0" }
|
nu-utils = { path = "./crates/nu-utils", version = "0.68.1" }
|
||||||
reedline = { version = "0.10.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.11.0", features = ["bashisms", "sqlite"]}
|
||||||
rayon = "1.5.1"
|
rayon = "1.5.1"
|
||||||
is_executable = "1.0.1"
|
is_executable = "1.0.1"
|
||||||
simplelog = "0.12.0"
|
simplelog = "0.12.0"
|
||||||
@ -65,7 +65,7 @@ openssl = { version = "0.10.38", features = ["vendored"], optional = true }
|
|||||||
signal-hook = { version = "0.3.14", default-features = false }
|
signal-hook = { version = "0.3.14", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path="./crates/nu-test-support", version = "0.67.0" }
|
nu-test-support = { path="./crates/nu-test-support", version = "0.68.1" }
|
||||||
tempfile = "3.2.0"
|
tempfile = "3.2.0"
|
||||||
assert_cmd = "2.0.2"
|
assert_cmd = "2.0.2"
|
||||||
pretty_assertions = "1.0.0"
|
pretty_assertions = "1.0.0"
|
||||||
@ -121,3 +121,4 @@ debug = false
|
|||||||
[[bin]]
|
[[bin]]
|
||||||
name = "nu"
|
name = "nu"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
@ -5,23 +5,24 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-cli"
|
name = "nu-cli"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
nu-test-support = { path="../nu-test-support", version = "0.67.0" }
|
nu-test-support = { path="../nu-test-support", version = "0.68.1" }
|
||||||
nu-command = { path = "../nu-command", version = "0.67.0" }
|
nu-command = { path = "../nu-command", version = "0.68.1" }
|
||||||
rstest = {version = "0.15.0", default-features = false}
|
rstest = {version = "0.15.0", default-features = false}
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-engine = { path = "../nu-engine", version = "0.67.0" }
|
nu-engine = { path = "../nu-engine", version = "0.68.1" }
|
||||||
nu-path = { path = "../nu-path", version = "0.67.0" }
|
nu-path = { path = "../nu-path", version = "0.68.1" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.67.0" }
|
nu-parser = { path = "../nu-parser", version = "0.68.1" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.67.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.68.1" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.67.0" }
|
nu-utils = { path = "../nu-utils", version = "0.68.1" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.67.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.68.1" }
|
||||||
reedline = { version = "0.10.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.11.0", features = ["bashisms", "sqlite"]}
|
||||||
|
|
||||||
|
atty = "0.2.14"
|
||||||
chrono = "0.4.21"
|
chrono = "0.4.21"
|
||||||
crossterm = "0.24.0"
|
crossterm = "0.24.0"
|
||||||
fancy-regex = "0.10.0"
|
fancy-regex = "0.10.0"
|
||||||
|
@ -11,6 +11,7 @@ pub struct CommandCompletion {
|
|||||||
engine_state: Arc<EngineState>,
|
engine_state: Arc<EngineState>,
|
||||||
flattened: Vec<(Span, FlatShape)>,
|
flattened: Vec<(Span, FlatShape)>,
|
||||||
flat_shape: FlatShape,
|
flat_shape: FlatShape,
|
||||||
|
force_completion_after_space: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandCompletion {
|
impl CommandCompletion {
|
||||||
@ -19,11 +20,13 @@ impl CommandCompletion {
|
|||||||
_: &StateWorkingSet,
|
_: &StateWorkingSet,
|
||||||
flattened: Vec<(Span, FlatShape)>,
|
flattened: Vec<(Span, FlatShape)>,
|
||||||
flat_shape: FlatShape,
|
flat_shape: FlatShape,
|
||||||
|
force_completion_after_space: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine_state,
|
engine_state,
|
||||||
flattened,
|
flattened,
|
||||||
flat_shape,
|
flat_shape,
|
||||||
|
force_completion_after_space,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +209,10 @@ impl Completer for CommandCompletion {
|
|||||||
|| ((span.end - span.start) == 0)
|
|| ((span.end - span.start) == 0)
|
||||||
{
|
{
|
||||||
// we're in a gap or at a command
|
// we're in a gap or at a command
|
||||||
|
if working_set.get_span_contents(span).is_empty() && !self.force_completion_after_space
|
||||||
|
{
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
self.complete_commands(
|
self.complete_commands(
|
||||||
working_set,
|
working_set,
|
||||||
span,
|
span,
|
||||||
|
@ -2,10 +2,11 @@ use crate::completions::{
|
|||||||
CommandCompletion, Completer, CompletionOptions, CustomCompletion, DirectoryCompletion,
|
CommandCompletion, Completer, CompletionOptions, CustomCompletion, DirectoryCompletion,
|
||||||
DotNuCompletion, FileCompletion, FlagCompletion, MatchAlgorithm, VariableCompletion,
|
DotNuCompletion, FileCompletion, FlagCompletion, MatchAlgorithm, VariableCompletion,
|
||||||
};
|
};
|
||||||
|
use nu_engine::eval_block;
|
||||||
use nu_parser::{flatten_expression, parse, FlatShape};
|
use nu_parser::{flatten_expression, parse, FlatShape};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
Span,
|
BlockId, PipelineData, Span, Value,
|
||||||
};
|
};
|
||||||
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
use reedline::{Completer as ReedlineCompleter, Suggestion};
|
||||||
use std::str;
|
use std::str;
|
||||||
@ -56,6 +57,67 @@ impl NuCompleter {
|
|||||||
suggestions
|
suggestions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn external_completion(
|
||||||
|
&self,
|
||||||
|
block_id: BlockId,
|
||||||
|
spans: Vec<String>,
|
||||||
|
offset: usize,
|
||||||
|
span: Span,
|
||||||
|
) -> Vec<Suggestion> {
|
||||||
|
let stack = self.stack.clone();
|
||||||
|
let block = self.engine_state.get_block(block_id);
|
||||||
|
let mut callee_stack = stack.gather_captures(&block.captures);
|
||||||
|
|
||||||
|
// Line
|
||||||
|
if let Some(pos_arg) = block.signature.required_positional.get(0) {
|
||||||
|
if let Some(var_id) = pos_arg.var_id {
|
||||||
|
callee_stack.add_var(
|
||||||
|
var_id,
|
||||||
|
Value::List {
|
||||||
|
vals: spans
|
||||||
|
.into_iter()
|
||||||
|
.map(|it| Value::String {
|
||||||
|
val: it,
|
||||||
|
span: Span::unknown(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
span: Span::unknown(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = eval_block(
|
||||||
|
&self.engine_state,
|
||||||
|
&mut callee_stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(span),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(pd) => {
|
||||||
|
let value = pd.into_value(span);
|
||||||
|
if let Value::List { vals, span: _ } = value {
|
||||||
|
let result = map_value_completions(
|
||||||
|
vals.iter(),
|
||||||
|
Span {
|
||||||
|
start: span.start,
|
||||||
|
end: span.end,
|
||||||
|
},
|
||||||
|
offset,
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => println!("failed to eval completer block: {}", err),
|
||||||
|
}
|
||||||
|
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
fn completion_helper(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
|
fn completion_helper(&mut self, line: &str, pos: usize) -> Vec<Suggestion> {
|
||||||
let mut working_set = StateWorkingSet::new(&self.engine_state);
|
let mut working_set = StateWorkingSet::new(&self.engine_state);
|
||||||
let offset = working_set.next_span_start();
|
let offset = working_set.next_span_start();
|
||||||
@ -63,14 +125,32 @@ impl NuCompleter {
|
|||||||
let initial_line = line.to_string();
|
let initial_line = line.to_string();
|
||||||
new_line.push(b'a');
|
new_line.push(b'a');
|
||||||
let pos = offset + pos;
|
let pos = offset + pos;
|
||||||
|
let config = self.engine_state.get_config();
|
||||||
|
|
||||||
let (output, _err) = parse(&mut working_set, Some("completer"), &new_line, false, &[]);
|
let (output, _err) = parse(&mut working_set, Some("completer"), &new_line, false, &[]);
|
||||||
|
|
||||||
for pipeline in output.pipelines.into_iter() {
|
for pipeline in output.pipelines.into_iter() {
|
||||||
for expr in pipeline.expressions {
|
for expr in pipeline.expressions {
|
||||||
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
||||||
let span_offset: usize = alias_offset.iter().sum();
|
let span_offset: usize = alias_offset.iter().sum();
|
||||||
|
let mut spans: Vec<String> = vec![];
|
||||||
|
|
||||||
for (flat_idx, flat) in flattened.iter().enumerate() {
|
for (flat_idx, flat) in flattened.iter().enumerate() {
|
||||||
|
// Read the current spam to string
|
||||||
|
let current_span = working_set.get_span_contents(flat.0).to_vec();
|
||||||
|
let current_span_str = String::from_utf8_lossy(¤t_span);
|
||||||
|
|
||||||
|
// Skip the last 'a' as span item
|
||||||
|
if flat_idx == flattened.len() - 1 {
|
||||||
|
let mut chars = current_span_str.chars();
|
||||||
|
chars.next_back();
|
||||||
|
let current_span_str = chars.as_str().to_owned();
|
||||||
|
spans.push(current_span_str.to_string());
|
||||||
|
} else {
|
||||||
|
spans.push(current_span_str.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete based on the last span
|
||||||
if pos + span_offset >= flat.0.start && pos + span_offset < flat.0.end {
|
if pos + span_offset >= flat.0.start && pos + span_offset < flat.0.end {
|
||||||
// Context variables
|
// Context variables
|
||||||
let most_left_var =
|
let most_left_var =
|
||||||
@ -113,8 +193,38 @@ impl NuCompleter {
|
|||||||
|
|
||||||
// Flags completion
|
// Flags completion
|
||||||
if prefix.starts_with(b"-") {
|
if prefix.starts_with(b"-") {
|
||||||
let mut completer = FlagCompletion::new(expr);
|
// Try to complete flag internally
|
||||||
|
let mut completer = FlagCompletion::new(expr.clone());
|
||||||
|
let result = self.process_completion(
|
||||||
|
&mut completer,
|
||||||
|
&working_set,
|
||||||
|
prefix.clone(),
|
||||||
|
new_span,
|
||||||
|
offset,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !result.is_empty() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We got no results for internal completion
|
||||||
|
// now we can check if external completer is set and use it
|
||||||
|
if let Some(block_id) = config.external_completer {
|
||||||
|
return self.external_completion(block_id, spans, offset, new_span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// specially check if it is currently empty - always complete commands
|
||||||
|
if flat_idx == 0 && working_set.get_span_contents(new_span).is_empty() {
|
||||||
|
let mut completer = CommandCompletion::new(
|
||||||
|
self.engine_state.clone(),
|
||||||
|
&working_set,
|
||||||
|
flattened.clone(),
|
||||||
|
// flat_idx,
|
||||||
|
FlatShape::String,
|
||||||
|
true,
|
||||||
|
);
|
||||||
return self.process_completion(
|
return self.process_completion(
|
||||||
&mut completer,
|
&mut completer,
|
||||||
&working_set,
|
&working_set,
|
||||||
@ -125,7 +235,7 @@ impl NuCompleter {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Completions that depends on the previous expression (e.g: use, source)
|
// Completions that depends on the previous expression (e.g: use, source-env)
|
||||||
if flat_idx > 0 {
|
if flat_idx > 0 {
|
||||||
if let Some(previous_expr) = flattened.get(flat_idx - 1) {
|
if let Some(previous_expr) = flattened.get(flat_idx - 1) {
|
||||||
// Read the content for the previous expression
|
// Read the content for the previous expression
|
||||||
@ -133,7 +243,7 @@ impl NuCompleter {
|
|||||||
working_set.get_span_contents(previous_expr.0).to_vec();
|
working_set.get_span_contents(previous_expr.0).to_vec();
|
||||||
|
|
||||||
// Completion for .nu files
|
// Completion for .nu files
|
||||||
if prev_expr_str == b"use" || prev_expr_str == b"source" {
|
if prev_expr_str == b"use" || prev_expr_str == b"source-env" {
|
||||||
let mut completer =
|
let mut completer =
|
||||||
DotNuCompletion::new(self.engine_state.clone());
|
DotNuCompletion::new(self.engine_state.clone());
|
||||||
|
|
||||||
@ -212,9 +322,10 @@ impl NuCompleter {
|
|||||||
flattened.clone(),
|
flattened.clone(),
|
||||||
// flat_idx,
|
// flat_idx,
|
||||||
flat_shape.clone(),
|
flat_shape.clone(),
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let out: Vec<_> = self.process_completion(
|
let mut out: Vec<_> = self.process_completion(
|
||||||
&mut completer,
|
&mut completer,
|
||||||
&working_set,
|
&working_set,
|
||||||
prefix.clone(),
|
prefix.clone(),
|
||||||
@ -223,21 +334,30 @@ impl NuCompleter {
|
|||||||
pos,
|
pos,
|
||||||
);
|
);
|
||||||
|
|
||||||
if out.is_empty() {
|
if !out.is_empty() {
|
||||||
let mut completer =
|
return out;
|
||||||
FileCompletion::new(self.engine_state.clone());
|
|
||||||
|
|
||||||
return self.process_completion(
|
|
||||||
&mut completer,
|
|
||||||
&working_set,
|
|
||||||
prefix,
|
|
||||||
new_span,
|
|
||||||
offset,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
// Check for file completion
|
||||||
|
let mut completer = FileCompletion::new(self.engine_state.clone());
|
||||||
|
out = self.process_completion(
|
||||||
|
&mut completer,
|
||||||
|
&working_set,
|
||||||
|
prefix,
|
||||||
|
new_span,
|
||||||
|
offset,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !out.is_empty() {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to complete using an exnternal compelter (if set)
|
||||||
|
if let Some(block_id) = config.external_completer {
|
||||||
|
return self
|
||||||
|
.external_completion(block_id, spans, offset, new_span);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -383,3 +503,65 @@ fn most_left_variable(
|
|||||||
|
|
||||||
Some((var, sublevels))
|
Some((var, sublevels))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_value_completions<'a>(
|
||||||
|
list: impl Iterator<Item = &'a Value>,
|
||||||
|
span: Span,
|
||||||
|
offset: usize,
|
||||||
|
) -> Vec<Suggestion> {
|
||||||
|
list.filter_map(move |x| {
|
||||||
|
// Match for string values
|
||||||
|
if let Ok(s) = x.as_string() {
|
||||||
|
return Some(Suggestion {
|
||||||
|
value: s,
|
||||||
|
description: None,
|
||||||
|
extra: None,
|
||||||
|
span: reedline::Span {
|
||||||
|
start: span.start - offset,
|
||||||
|
end: span.end - offset,
|
||||||
|
},
|
||||||
|
append_whitespace: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match for record values
|
||||||
|
if let Ok((cols, vals)) = x.as_record() {
|
||||||
|
let mut suggestion = Suggestion {
|
||||||
|
value: String::from(""), // Initialize with empty string
|
||||||
|
description: None,
|
||||||
|
extra: None,
|
||||||
|
span: reedline::Span {
|
||||||
|
start: span.start - offset,
|
||||||
|
end: span.end - offset,
|
||||||
|
},
|
||||||
|
append_whitespace: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iterate the cols looking for `value` and `description`
|
||||||
|
cols.iter().zip(vals).for_each(|it| {
|
||||||
|
// Match `value` column
|
||||||
|
if it.0 == "value" {
|
||||||
|
// Convert the value to string
|
||||||
|
if let Ok(val_str) = it.1.as_string() {
|
||||||
|
// Update the suggestion value
|
||||||
|
suggestion.value = val_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match `description` column
|
||||||
|
if it.0 == "description" {
|
||||||
|
// Convert the value to string
|
||||||
|
if let Ok(desc_str) = it.1.as_string() {
|
||||||
|
// Update the suggestion value
|
||||||
|
suggestion.description = Some(desc_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Some(suggestion);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
@ -8,6 +8,8 @@ use nu_protocol::{
|
|||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use super::completer::map_value_completions;
|
||||||
|
|
||||||
pub struct CustomCompletion {
|
pub struct CustomCompletion {
|
||||||
engine_state: Arc<EngineState>,
|
engine_state: Arc<EngineState>,
|
||||||
stack: Stack,
|
stack: Stack,
|
||||||
@ -26,69 +28,6 @@ impl CustomCompletion {
|
|||||||
sort_by: SortBy::None,
|
sort_by: SortBy::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map_completions<'a>(
|
|
||||||
&self,
|
|
||||||
list: impl Iterator<Item = &'a Value>,
|
|
||||||
span: Span,
|
|
||||||
offset: usize,
|
|
||||||
) -> Vec<Suggestion> {
|
|
||||||
list.filter_map(move |x| {
|
|
||||||
// Match for string values
|
|
||||||
if let Ok(s) = x.as_string() {
|
|
||||||
return Some(Suggestion {
|
|
||||||
value: s,
|
|
||||||
description: None,
|
|
||||||
extra: None,
|
|
||||||
span: reedline::Span {
|
|
||||||
start: span.start - offset,
|
|
||||||
end: span.end - offset,
|
|
||||||
},
|
|
||||||
append_whitespace: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match for record values
|
|
||||||
if let Ok((cols, vals)) = x.as_record() {
|
|
||||||
let mut suggestion = Suggestion {
|
|
||||||
value: String::from(""), // Initialize with empty string
|
|
||||||
description: None,
|
|
||||||
extra: None,
|
|
||||||
span: reedline::Span {
|
|
||||||
start: span.start - offset,
|
|
||||||
end: span.end - offset,
|
|
||||||
},
|
|
||||||
append_whitespace: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Iterate the cols looking for `value` and `description`
|
|
||||||
cols.iter().zip(vals).for_each(|it| {
|
|
||||||
// Match `value` column
|
|
||||||
if it.0 == "value" {
|
|
||||||
// Convert the value to string
|
|
||||||
if let Ok(val_str) = it.1.as_string() {
|
|
||||||
// Update the suggestion value
|
|
||||||
suggestion.value = val_str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match `description` column
|
|
||||||
if it.0 == "description" {
|
|
||||||
// Convert the value to string
|
|
||||||
if let Ok(desc_str) = it.1.as_string() {
|
|
||||||
// Update the suggestion value
|
|
||||||
suggestion.description = Some(desc_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return Some(suggestion);
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Completer for CustomCompletion {
|
impl Completer for CustomCompletion {
|
||||||
@ -144,7 +83,7 @@ impl Completer for CustomCompletion {
|
|||||||
.and_then(|val| {
|
.and_then(|val| {
|
||||||
val.as_list()
|
val.as_list()
|
||||||
.ok()
|
.ok()
|
||||||
.map(|it| self.map_completions(it.iter(), span, offset))
|
.map(|it| map_value_completions(it.iter(), span, offset))
|
||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let options = value.get_data_by_key("options");
|
let options = value.get_data_by_key("options");
|
||||||
@ -189,7 +128,7 @@ impl Completer for CustomCompletion {
|
|||||||
|
|
||||||
completions
|
completions
|
||||||
}
|
}
|
||||||
Value::List { vals, .. } => self.map_completions(vals.iter(), span, offset),
|
Value::List { vals, .. } => map_value_completions(vals.iter(), span, offset),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use nu_protocol::{
|
|||||||
ast::PathMember,
|
ast::PathMember,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
format_duration, BlockId, HistoryFileFormat, PipelineData, PositionalArg, ShellError, Span,
|
format_duration, BlockId, HistoryFileFormat, PipelineData, PositionalArg, ShellError, Span,
|
||||||
Type, Value, VarId,
|
Spanned, Type, Value, VarId,
|
||||||
};
|
};
|
||||||
use reedline::{DefaultHinter, Emacs, SqliteBackedHistory, Vi};
|
use reedline::{DefaultHinter, Emacs, SqliteBackedHistory, Vi};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
@ -39,9 +39,20 @@ pub fn evaluate_repl(
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
nushell_path: &str,
|
nushell_path: &str,
|
||||||
is_perf_true: bool,
|
is_perf_true: bool,
|
||||||
|
prerun_command: Option<Spanned<String>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
use reedline::{FileBackedHistory, Reedline, Signal};
|
use reedline::{FileBackedHistory, Reedline, Signal};
|
||||||
|
|
||||||
|
// Guard against invocation without a connected terminal.
|
||||||
|
// reedline / crossterm event polling will fail without a connected tty
|
||||||
|
if !atty::is(atty::Stream::Stdin) {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::NotFound,
|
||||||
|
"Nushell launched as interactive REPL but STDIN is not a TTY, either launch in a valid terminal or provide arguments to invoke a script!",
|
||||||
|
))
|
||||||
|
.into_diagnostic();
|
||||||
|
}
|
||||||
|
|
||||||
let mut entry_num = 0;
|
let mut entry_num = 0;
|
||||||
|
|
||||||
let mut nu_prompt = NushellPrompt::new();
|
let mut nu_prompt = NushellPrompt::new();
|
||||||
@ -140,6 +151,17 @@ pub fn evaluate_repl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(s) = prerun_command {
|
||||||
|
eval_source(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
s.item.as_bytes(),
|
||||||
|
&format!("entry #{}", entry_num),
|
||||||
|
PipelineData::new(Span::new(0, 0)),
|
||||||
|
);
|
||||||
|
engine_state.merge_env(stack, get_guaranteed_cwd(engine_state, stack))?;
|
||||||
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if is_perf_true {
|
if is_perf_true {
|
||||||
info!(
|
info!(
|
||||||
@ -312,7 +334,8 @@ pub fn evaluate_repl(
|
|||||||
Ok(Signal::Success(s)) => {
|
Ok(Signal::Success(s)) => {
|
||||||
let history_supports_meta =
|
let history_supports_meta =
|
||||||
matches!(config.history_file_format, HistoryFileFormat::Sqlite);
|
matches!(config.history_file_format, HistoryFileFormat::Sqlite);
|
||||||
if history_supports_meta && !s.is_empty() {
|
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
|
||||||
|
{
|
||||||
line_editor
|
line_editor
|
||||||
.update_last_command_context(&|mut c| {
|
.update_last_command_context(&|mut c| {
|
||||||
c.start_timestamp = Some(chrono::Utc::now());
|
c.start_timestamp = Some(chrono::Utc::now());
|
||||||
@ -433,7 +456,8 @@ pub fn evaluate_repl(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if history_supports_meta && !s.is_empty() {
|
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
|
||||||
|
{
|
||||||
line_editor
|
line_editor
|
||||||
.update_last_command_context(&|mut c| {
|
.update_last_command_context(&|mut c| {
|
||||||
c.duration = Some(cmd_duration);
|
c.duration = Some(cmd_duration);
|
||||||
@ -484,6 +508,10 @@ pub fn evaluate_repl(
|
|||||||
let message = err.to_string();
|
let message = err.to_string();
|
||||||
if !message.contains("duration") {
|
if !message.contains("duration") {
|
||||||
println!("Error: {:?}", err);
|
println!("Error: {:?}", err);
|
||||||
|
// TODO: Identify possible error cases where a hard failure is preferable
|
||||||
|
// Ignoring and reporting could hide bigger problems
|
||||||
|
// e.g. https://github.com/nushell/nushell/issues/6452
|
||||||
|
// Alternatively only allow that expected failures let the REPL loop
|
||||||
}
|
}
|
||||||
if shell_integration {
|
if shell_integration {
|
||||||
run_ansi_sequence(&get_command_finished_marker(stack, engine_state))?;
|
run_ansi_sequence(&get_command_finished_marker(stack, engine_state))?;
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use support::{match_suggestions, new_engine};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_of_command_and_flags() {
|
|
||||||
let (dir, _, mut engine, mut stack) = new_engine();
|
|
||||||
|
|
||||||
// Create an alias
|
|
||||||
let alias = r#"alias ll = ls -l"#;
|
|
||||||
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let suggestions = completer.complete("ll t", 4);
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_of_basic_command() {
|
|
||||||
let (dir, _, mut engine, mut stack) = new_engine();
|
|
||||||
|
|
||||||
// Create an alias
|
|
||||||
let alias = r#"alias ll = ls "#;
|
|
||||||
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let suggestions = completer.complete("ll t", 4);
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn alias_of_another_alias() {
|
|
||||||
let (dir, _, mut engine, mut stack) = new_engine();
|
|
||||||
|
|
||||||
// Create an alias
|
|
||||||
let alias = r#"alias ll = ls -la"#;
|
|
||||||
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir.clone()).is_ok());
|
|
||||||
// Create the second alias
|
|
||||||
let alias = r#"alias lf = ll -f"#;
|
|
||||||
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let suggestions = completer.complete("lf t", 4);
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
660
crates/nu-cli/tests/completions.rs
Normal file
660
crates/nu-cli/tests/completions.rs
Normal file
@ -0,0 +1,660 @@
|
|||||||
|
pub mod support;
|
||||||
|
|
||||||
|
use nu_cli::NuCompleter;
|
||||||
|
use nu_parser::parse;
|
||||||
|
use nu_protocol::engine::StateWorkingSet;
|
||||||
|
use reedline::{Completer, Suggestion};
|
||||||
|
use rstest::{fixture, rstest};
|
||||||
|
use support::{file, folder, match_suggestions, new_engine};
|
||||||
|
|
||||||
|
#[fixture]
|
||||||
|
fn completer() -> NuCompleter {
|
||||||
|
// Create a new engine
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Add record value as example
|
||||||
|
let record = "def tst [--mod -s] {}";
|
||||||
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
// Instantiate a new completer
|
||||||
|
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[fixture]
|
||||||
|
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 }"#;
|
||||||
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
// Instantiate a new completer
|
||||||
|
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn variables_completions_double_dash_argument(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn variables_completions_single_dash_argument(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn variables_completions_command(mut completer_strings: NuCompleter) {
|
||||||
|
let suggestions = completer_strings.complete("my-command ", 9);
|
||||||
|
let expected: Vec<String> = vec!["my-command".into()];
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn variables_completions_subcommands(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn variables_completions_subcommands_2(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dotnu_completions() {
|
||||||
|
// Create a new engine
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
// Instatiate a new completer
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
// Test source completion
|
||||||
|
let completion_str = "source-env ".to_string();
|
||||||
|
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||||
|
|
||||||
|
assert_eq!(1, suggestions.len());
|
||||||
|
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
||||||
|
|
||||||
|
// Test use completion
|
||||||
|
let completion_str = "use ".to_string();
|
||||||
|
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||||
|
|
||||||
|
assert_eq!(1, suggestions.len());
|
||||||
|
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn external_completer_trailing_space() {
|
||||||
|
// https://github.com/nushell/nushell/issues/6378
|
||||||
|
let block = "let external_completer = {|spans| $spans}";
|
||||||
|
let input = "gh alias ".to_string();
|
||||||
|
|
||||||
|
let suggestions = run_external_completion(&block, &input);
|
||||||
|
assert_eq!(3, suggestions.len());
|
||||||
|
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
||||||
|
assert_eq!("alias", suggestions.get(1).unwrap().value);
|
||||||
|
assert_eq!("", suggestions.get(2).unwrap().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn external_completer_no_trailing_space() {
|
||||||
|
let block = "let external_completer = {|spans| $spans}";
|
||||||
|
let input = "gh alias".to_string();
|
||||||
|
|
||||||
|
let suggestions = run_external_completion(&block, &input);
|
||||||
|
assert_eq!(2, suggestions.len());
|
||||||
|
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
||||||
|
assert_eq!("alias", suggestions.get(1).unwrap().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn external_completer_pass_flags() {
|
||||||
|
let block = "let external_completer = {|spans| $spans}";
|
||||||
|
let input = "gh api --".to_string();
|
||||||
|
|
||||||
|
let suggestions = run_external_completion(&block, &input);
|
||||||
|
assert_eq!(3, suggestions.len());
|
||||||
|
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
||||||
|
assert_eq!("api", suggestions.get(1).unwrap().value);
|
||||||
|
assert_eq!("--", suggestions.get(2).unwrap().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn file_completions() {
|
||||||
|
// Create a new engine
|
||||||
|
let (dir, dir_str, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
// Instatiate a new completer
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
// Test completions for the current folder
|
||||||
|
let target_dir = format!("cp {}", dir_str);
|
||||||
|
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||||
|
|
||||||
|
// Create the expected values
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
file(dir.join("nushell")),
|
||||||
|
folder(dir.join("test_a")),
|
||||||
|
folder(dir.join("test_b")),
|
||||||
|
folder(dir.join("another")),
|
||||||
|
file(dir.join("custom_completion.nu")),
|
||||||
|
file(dir.join(".hidden_file")),
|
||||||
|
folder(dir.join(".hidden_folder")),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Match the results
|
||||||
|
match_suggestions(expected_paths, suggestions);
|
||||||
|
|
||||||
|
// Test completions for a file
|
||||||
|
let target_dir = format!("cp {}", folder(dir.join("another")));
|
||||||
|
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||||
|
|
||||||
|
// Create the expected values
|
||||||
|
let expected_paths: Vec<String> = vec![file(dir.join("another").join("newfile"))];
|
||||||
|
|
||||||
|
// Match the results
|
||||||
|
match_suggestions(expected_paths, suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_ls_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "ls ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn command_open_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "open ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_rm_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "rm ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_cp_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "cp ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_save_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "save ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_touch_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "touch ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_watch_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "watch ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn flag_completions() {
|
||||||
|
// Create a new engine
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
// Instatiate a new completer
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
// Test completions for the 'ls' flags
|
||||||
|
let suggestions = completer.complete("ls -", 4);
|
||||||
|
|
||||||
|
assert_eq!(14, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec![
|
||||||
|
"--all".into(),
|
||||||
|
"--directory".into(),
|
||||||
|
"--du".into(),
|
||||||
|
"--full-paths".into(),
|
||||||
|
"--help".into(),
|
||||||
|
"--long".into(),
|
||||||
|
"--short-names".into(),
|
||||||
|
"-D".into(),
|
||||||
|
"-a".into(),
|
||||||
|
"-d".into(),
|
||||||
|
"-f".into(),
|
||||||
|
"-h".into(),
|
||||||
|
"-l".into(),
|
||||||
|
"-s".into(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn folder_completions() {
|
||||||
|
// Create a new engine
|
||||||
|
let (dir, dir_str, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
// Instatiate a new completer
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
// Test completions for the current folder
|
||||||
|
let target_dir = format!("cd {}", dir_str);
|
||||||
|
let suggestions = completer.complete(&target_dir, target_dir.len());
|
||||||
|
|
||||||
|
// Create the expected values
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
folder(dir.join("test_a")),
|
||||||
|
folder(dir.join("test_b")),
|
||||||
|
folder(dir.join("another")),
|
||||||
|
folder(dir.join(".hidden_folder")),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Match the results
|
||||||
|
match_suggestions(expected_paths, suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn variables_completions() {
|
||||||
|
// Create a new engine
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Add record value as example
|
||||||
|
let record = "let actor = { name: 'Tom Hardy', age: 44 }";
|
||||||
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
// Instatiate a new completer
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
// Test completions for $nu
|
||||||
|
let suggestions = completer.complete("$nu.", 4);
|
||||||
|
|
||||||
|
assert_eq!(9, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec![
|
||||||
|
"config-path".into(),
|
||||||
|
"env-path".into(),
|
||||||
|
"history-path".into(),
|
||||||
|
"home-path".into(),
|
||||||
|
"loginshell-path".into(),
|
||||||
|
"os-info".into(),
|
||||||
|
"pid".into(),
|
||||||
|
"scope".into(),
|
||||||
|
"temp-path".into(),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
|
||||||
|
// Test completions for $nu.h (filter)
|
||||||
|
let suggestions = completer.complete("$nu.h", 5);
|
||||||
|
|
||||||
|
assert_eq!(2, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec!["history-path".into(), "home-path".into()];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
|
||||||
|
// Test completions for custom var
|
||||||
|
let suggestions = completer.complete("$actor.", 7);
|
||||||
|
|
||||||
|
assert_eq!(2, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec!["age".into(), "name".into()];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
|
||||||
|
// Test completions for custom var (filtering)
|
||||||
|
let suggestions = completer.complete("$actor.n", 8);
|
||||||
|
|
||||||
|
assert_eq!(1, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec!["name".into()];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
|
||||||
|
// Test completions for $env
|
||||||
|
let suggestions = completer.complete("$env.", 5);
|
||||||
|
|
||||||
|
assert_eq!(2, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec!["PWD".into(), "TEST".into()];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
|
||||||
|
// Test completions for $env
|
||||||
|
let suggestions = completer.complete("$env.T", 6);
|
||||||
|
|
||||||
|
assert_eq!(1, suggestions.len());
|
||||||
|
|
||||||
|
let expected: Vec<String> = vec!["TEST".into()];
|
||||||
|
|
||||||
|
// Match results
|
||||||
|
match_suggestions(expected, suggestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_of_command_and_flags() {
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Create an alias
|
||||||
|
let alias = r#"alias ll = ls -l"#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let suggestions = completer.complete("ll t", 4);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_of_basic_command() {
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Create an alias
|
||||||
|
let alias = r#"alias ll = ls "#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let suggestions = completer.complete("ll t", 4);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_of_another_alias() {
|
||||||
|
let (dir, _, mut engine, mut stack) = new_engine();
|
||||||
|
|
||||||
|
// Create an alias
|
||||||
|
let alias = r#"alias ll = ls -la"#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir.clone()).is_ok());
|
||||||
|
// Create the second alias
|
||||||
|
let alias = r#"alias lf = ll -f"#;
|
||||||
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let suggestions = completer.complete("lf t", 4);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
|
||||||
|
// Create a new engine
|
||||||
|
let (dir, _, mut engine_state, mut stack) = new_engine();
|
||||||
|
let (_, delta) = {
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
let (block, err) = parse(&mut working_set, None, block.as_bytes(), false, &[]);
|
||||||
|
assert!(err.is_none());
|
||||||
|
|
||||||
|
(block, working_set.render())
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(engine_state.merge_delta(delta).is_ok());
|
||||||
|
|
||||||
|
// Merge environment into the permanent state
|
||||||
|
assert!(engine_state.merge_env(&mut stack, &dir).is_ok());
|
||||||
|
|
||||||
|
let latest_block_id = engine_state.num_blocks() - 1;
|
||||||
|
|
||||||
|
// Change config adding the external completer
|
||||||
|
let mut config = engine_state.get_config().clone();
|
||||||
|
config.external_completer = Some(latest_block_id);
|
||||||
|
engine_state.set_config(&config);
|
||||||
|
|
||||||
|
// Instatiate a new completer
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine_state), stack);
|
||||||
|
|
||||||
|
completer.complete(&input, input.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unknown_command_completion() {
|
||||||
|
let (_, _, engine, stack) = new_engine();
|
||||||
|
|
||||||
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||||
|
|
||||||
|
let target_dir = "thiscommanddoesnotexist ";
|
||||||
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a\\".to_string(),
|
||||||
|
"test_b\\".to_string(),
|
||||||
|
"another\\".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder\\".to_string(),
|
||||||
|
];
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
let expected_paths: Vec<String> = vec![
|
||||||
|
"nushell".to_string(),
|
||||||
|
"test_a/".to_string(),
|
||||||
|
"test_b/".to_string(),
|
||||||
|
"another/".to_string(),
|
||||||
|
"custom_completion.nu".to_string(),
|
||||||
|
".hidden_file".to_string(),
|
||||||
|
".hidden_folder/".to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
match_suggestions(expected_paths, suggestions)
|
||||||
|
}
|
@ -1,69 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use rstest::{fixture, rstest};
|
|
||||||
use support::{match_suggestions, new_engine};
|
|
||||||
|
|
||||||
#[fixture]
|
|
||||||
fn completer() -> NuCompleter {
|
|
||||||
// Create a new engine
|
|
||||||
let (dir, _, mut engine, mut stack) = new_engine();
|
|
||||||
|
|
||||||
// Add record value as example
|
|
||||||
let record = "def tst [--mod -s] {}";
|
|
||||||
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
||||||
|
|
||||||
// Instantiate a new completer
|
|
||||||
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[fixture]
|
|
||||||
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 }"#;
|
|
||||||
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
||||||
|
|
||||||
// Instantiate a new completer
|
|
||||||
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn variables_completions_double_dash_argument(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn variables_completions_single_dash_argument(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn variables_completions_command(mut completer_strings: NuCompleter) {
|
|
||||||
let suggestions = completer_strings.complete("my-command ", 9);
|
|
||||||
let expected: Vec<String> = vec!["my-command".into()];
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn variables_completions_subcommands(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn variables_completions_subcommands_2(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);
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use support::new_engine;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dotnu_completions() {
|
|
||||||
// Create a new engine
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
// Instatiate a new completer
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
// Test source completion
|
|
||||||
let completion_str = "source ".to_string();
|
|
||||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
|
||||||
|
|
||||||
assert_eq!(1, suggestions.len());
|
|
||||||
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
|
||||||
|
|
||||||
// Test use completion
|
|
||||||
let completion_str = "use ".to_string();
|
|
||||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
|
||||||
|
|
||||||
assert_eq!(1, suggestions.len());
|
|
||||||
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
|
||||||
}
|
|
@ -1,272 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use support::{file, folder, match_suggestions, new_engine};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn file_completions() {
|
|
||||||
// Create a new engine
|
|
||||||
let (dir, dir_str, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
// Instatiate a new completer
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
// Test completions for the current folder
|
|
||||||
let target_dir = format!("cp {}", dir_str);
|
|
||||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
|
||||||
|
|
||||||
// Create the expected values
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
file(dir.join("nushell")),
|
|
||||||
folder(dir.join("test_a")),
|
|
||||||
folder(dir.join("test_b")),
|
|
||||||
folder(dir.join("another")),
|
|
||||||
file(dir.join("custom_completion.nu")),
|
|
||||||
file(dir.join(".hidden_file")),
|
|
||||||
folder(dir.join(".hidden_folder")),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Match the results
|
|
||||||
match_suggestions(expected_paths, suggestions);
|
|
||||||
|
|
||||||
// Test completions for a file
|
|
||||||
let target_dir = format!("cp {}", folder(dir.join("another")));
|
|
||||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
|
||||||
|
|
||||||
// Create the expected values
|
|
||||||
let expected_paths: Vec<String> = vec![file(dir.join("another").join("newfile"))];
|
|
||||||
|
|
||||||
// Match the results
|
|
||||||
match_suggestions(expected_paths, suggestions);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command_ls_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "ls ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
#[test]
|
|
||||||
fn command_open_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "open ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command_rm_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "rm ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command_cp_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "cp ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command_save_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "save ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command_touch_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "touch ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn command_watch_completion() {
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
let target_dir = "watch ";
|
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a\\".to_string(),
|
|
||||||
"test_b\\".to_string(),
|
|
||||||
"another\\".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder\\".to_string(),
|
|
||||||
];
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
"nushell".to_string(),
|
|
||||||
"test_a/".to_string(),
|
|
||||||
"test_b/".to_string(),
|
|
||||||
"another/".to_string(),
|
|
||||||
"custom_completion.nu".to_string(),
|
|
||||||
".hidden_file".to_string(),
|
|
||||||
".hidden_folder/".to_string(),
|
|
||||||
];
|
|
||||||
|
|
||||||
match_suggestions(expected_paths, suggestions)
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use support::{match_suggestions, new_engine};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn flag_completions() {
|
|
||||||
// Create a new engine
|
|
||||||
let (_, _, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
// Instatiate a new completer
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
// Test completions for the 'ls' flags
|
|
||||||
let suggestions = completer.complete("ls -", 4);
|
|
||||||
|
|
||||||
assert_eq!(14, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec![
|
|
||||||
"--all".into(),
|
|
||||||
"--directory".into(),
|
|
||||||
"--du".into(),
|
|
||||||
"--full-paths".into(),
|
|
||||||
"--help".into(),
|
|
||||||
"--long".into(),
|
|
||||||
"--short-names".into(),
|
|
||||||
"-D".into(),
|
|
||||||
"-a".into(),
|
|
||||||
"-d".into(),
|
|
||||||
"-f".into(),
|
|
||||||
"-h".into(),
|
|
||||||
"-l".into(),
|
|
||||||
"-s".into(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use support::{folder, match_suggestions, new_engine};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn folder_completions() {
|
|
||||||
// Create a new engine
|
|
||||||
let (dir, dir_str, engine, stack) = new_engine();
|
|
||||||
|
|
||||||
// Instatiate a new completer
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
// Test completions for the current folder
|
|
||||||
let target_dir = format!("cd {}", dir_str);
|
|
||||||
let suggestions = completer.complete(&target_dir, target_dir.len());
|
|
||||||
|
|
||||||
// Create the expected values
|
|
||||||
let expected_paths: Vec<String> = vec![
|
|
||||||
folder(dir.join("test_a")),
|
|
||||||
folder(dir.join("test_b")),
|
|
||||||
folder(dir.join("another")),
|
|
||||||
folder(dir.join(".hidden_folder")),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Match the results
|
|
||||||
match_suggestions(expected_paths, suggestions);
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
pub mod support;
|
|
||||||
|
|
||||||
use nu_cli::NuCompleter;
|
|
||||||
use reedline::Completer;
|
|
||||||
use support::{match_suggestions, new_engine};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn variables_completions() {
|
|
||||||
// Create a new engine
|
|
||||||
let (dir, _, mut engine, mut stack) = new_engine();
|
|
||||||
|
|
||||||
// Add record value as example
|
|
||||||
let record = "let actor = { name: 'Tom Hardy', age: 44 }";
|
|
||||||
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
||||||
|
|
||||||
// Instatiate a new completer
|
|
||||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
||||||
|
|
||||||
// Test completions for $nu
|
|
||||||
let suggestions = completer.complete("$nu.", 4);
|
|
||||||
|
|
||||||
assert_eq!(9, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec![
|
|
||||||
"config-path".into(),
|
|
||||||
"env-path".into(),
|
|
||||||
"history-path".into(),
|
|
||||||
"home-path".into(),
|
|
||||||
"loginshell-path".into(),
|
|
||||||
"os-info".into(),
|
|
||||||
"pid".into(),
|
|
||||||
"scope".into(),
|
|
||||||
"temp-path".into(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
|
|
||||||
// Test completions for $nu.h (filter)
|
|
||||||
let suggestions = completer.complete("$nu.h", 5);
|
|
||||||
|
|
||||||
assert_eq!(2, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec!["history-path".into(), "home-path".into()];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
|
|
||||||
// Test completions for custom var
|
|
||||||
let suggestions = completer.complete("$actor.", 7);
|
|
||||||
|
|
||||||
assert_eq!(2, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec!["age".into(), "name".into()];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
|
|
||||||
// Test completions for custom var (filtering)
|
|
||||||
let suggestions = completer.complete("$actor.n", 8);
|
|
||||||
|
|
||||||
assert_eq!(1, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec!["name".into()];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
|
|
||||||
// Test completions for $env
|
|
||||||
let suggestions = completer.complete("$env.", 5);
|
|
||||||
|
|
||||||
assert_eq!(2, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec!["PWD".into(), "TEST".into()];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
|
|
||||||
// Test completions for $env
|
|
||||||
let suggestions = completer.complete("$env.T", 6);
|
|
||||||
|
|
||||||
assert_eq!(1, suggestions.len());
|
|
||||||
|
|
||||||
let expected: Vec<String> = vec!["TEST".into()];
|
|
||||||
|
|
||||||
// Match results
|
|
||||||
match_suggestions(expected, suggestions);
|
|
||||||
}
|
|
@ -5,11 +5,11 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-color-config"
|
name = "nu-color-config"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.67.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.68.1" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
nu-json = { path = "../nu-json", version = "0.67.0" }
|
nu-json = { path = "../nu-json", version = "0.68.1" }
|
||||||
nu-table = { path = "../nu-table", version = "0.67.0" }
|
nu-table = { path = "../nu-table", version = "0.68.1" }
|
||||||
serde = { version="1.0.123", features=["derive"] }
|
serde = { version="1.0.123", features=["derive"] }
|
||||||
|
@ -5,25 +5,25 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
name = "nu-command"
|
name = "nu-command"
|
||||||
version = "0.67.0"
|
version = "0.68.1"
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nu-color-config = { path = "../nu-color-config", version = "0.67.0" }
|
nu-color-config = { path = "../nu-color-config", version = "0.68.1" }
|
||||||
nu-engine = { path = "../nu-engine", version = "0.67.0" }
|
nu-engine = { path = "../nu-engine", version = "0.68.1" }
|
||||||
nu-glob = { path = "../nu-glob", version = "0.67.0" }
|
nu-glob = { path = "../nu-glob", version = "0.68.1" }
|
||||||
nu-json = { path = "../nu-json", version = "0.67.0" }
|
nu-json = { path = "../nu-json", version = "0.68.1" }
|
||||||
nu-parser = { path = "../nu-parser", version = "0.67.0" }
|
nu-parser = { path = "../nu-parser", version = "0.68.1" }
|
||||||
nu-path = { path = "../nu-path", version = "0.67.0" }
|
nu-path = { path = "../nu-path", version = "0.68.1" }
|
||||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.67.0" }
|
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.68.1" }
|
||||||
nu-protocol = { path = "../nu-protocol", version = "0.67.0" }
|
nu-protocol = { path = "../nu-protocol", version = "0.68.1" }
|
||||||
nu-system = { path = "../nu-system", version = "0.67.0" }
|
nu-system = { path = "../nu-system", version = "0.68.1" }
|
||||||
nu-table = { path = "../nu-table", version = "0.67.0" }
|
nu-table = { path = "../nu-table", version = "0.68.1" }
|
||||||
nu-term-grid = { path = "../nu-term-grid", version = "0.67.0" }
|
nu-term-grid = { path = "../nu-term-grid", version = "0.68.1" }
|
||||||
nu-test-support = { path = "../nu-test-support", version = "0.67.0" }
|
nu-test-support = { path = "../nu-test-support", version = "0.68.1" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.67.0" }
|
nu-utils = { path = "../nu-utils", version = "0.68.1" }
|
||||||
nu-ansi-term = "0.46.0"
|
nu-ansi-term = "0.46.0"
|
||||||
num-format = { version = "0.4.0" }
|
num-format = { version = "0.4.0" }
|
||||||
|
|
||||||
@ -86,8 +86,8 @@ toml = "0.5.8"
|
|||||||
unicode-segmentation = "1.8.0"
|
unicode-segmentation = "1.8.0"
|
||||||
url = "2.2.1"
|
url = "2.2.1"
|
||||||
uuid = { version = "1.1.2", features = ["v4"] }
|
uuid = { version = "1.1.2", features = ["v4"] }
|
||||||
which = { version = "4.2.2", optional = true }
|
which = { version = "4.3.0", optional = true }
|
||||||
reedline = { version = "0.10.0", features = ["bashisms", "sqlite"]}
|
reedline = { version = "0.11.0", features = ["bashisms", "sqlite"]}
|
||||||
wax = { version = "0.5.0", features = ["diagnostics"] }
|
wax = { version = "0.5.0", features = ["diagnostics"] }
|
||||||
rusqlite = { version = "0.28.0", features = ["bundled"], optional = true }
|
rusqlite = { version = "0.28.0", features = ["bundled"], optional = true }
|
||||||
sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
sqlparser = { version = "0.16.0", features = ["serde"], optional = true }
|
||||||
@ -152,6 +152,7 @@ shadow-rs = { version = "0.16.1", default-features = false }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hamcrest2 = "0.3.0"
|
hamcrest2 = "0.3.0"
|
||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
|
proptest = "1.0.0"
|
||||||
quickcheck = "1.0.3"
|
quickcheck = "1.0.3"
|
||||||
quickcheck_macros = "1.0.0"
|
quickcheck_macros = "1.0.0"
|
||||||
rstest = {version = "0.15.0", default-features = false}
|
rstest = {version = "0.15.0", default-features = false}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
# Seeds for failure cases proptest has generated in the past. It is
|
||||||
|
# automatically read and these particular cases re-run before any
|
||||||
|
# novel cases are generated.
|
||||||
|
#
|
||||||
|
# It is recommended to check this file in to source control so that
|
||||||
|
# everyone who runs the test benefits from these saved cases.
|
||||||
|
cc 96a80ecd19729fb43a7b7bb2766b37d6083ba73b16abb97075875e3cfcdc763f # shrinks to c = '"'
|
||||||
|
cc 4146602559ea717a02bcef3c6d73cdf613c30d0c3f92c48e26c79b9a1544e027 # shrinks to c = '\\'
|
||||||
|
cc 80532a0ee73df456a719b9e3cce1ae5f3d26009dde819cbaf16f8e0cb6709705 # shrinks to c = ':'
|
||||||
|
cc cdb88505686eea3c74c36f282fd29b2b68bc118ded4ebfc36f9838d174bd7653 # shrinks to c = '`'
|
||||||
|
cc 0f534d55f9771e8810b9c4252a4168abfaec1a35e1b0cac12dbaf726d295a08c # shrinks to c = '\0'
|
||||||
|
cc 5d31bcbab722acd1f4e23ca3a4f95ff309a636b45a73ca8ae9f820d93ff57acc # shrinks to c = '{'
|
||||||
|
cc 5afec063bc96160d681d77f90041b67ef5cfdea4dcbd12d984fd828fbeb4b421 # shrinks to c = '#'
|
||||||
|
cc f919beb3ee5c70e756a15635d65ded7d44f3ae58b5e86b6c09e814d5d8cdd506 # shrinks to c = ';'
|
||||||
|
cc ec00f39b8d45dfd8808947a56af5e50ba5a0ef7c951723b45377815a02e515b1 # shrinks to c = '('
|
||||||
|
cc 25b773cdf4c24179151fa86244c7de4136e05df9e94e6ee77a336ebfd8764444 # shrinks to c = '|'
|
||||||
|
cc 94dc0d54b97d59e1c0f4cb11bdccb3823a1bb908cbc3fd643ee8f067169fad72 # shrinks to c = '0'
|
||||||
|
cc c9d0051fb1e5a8bdc1d4f5a3dceac1b4b465827d1dff4fc3a3755baae6a7bb48 # shrinks to c = '$'
|
||||||
|
cc 14ec40d2eb5bd2663e9b11bb49fb2120852f9ea71678c69d732161412b55a3ec # shrinks to s = ""
|
||||||
|
cc d4afccc51ed9d421bdb7e1723e273dfb6e77c3a449489671a496db234e87c5ed # shrinks to c = '\r'
|
||||||
|
cc 515a56d73eb1b69290ef4c714b629421989879aebd57991bd2c2bf11294353b1 # shrinks to s = "\\\\𐊀{"
|
||||||
|
cc 111566990fffa432acd2dbc845141b0e7870f97125c7621e3ddf142204568246 # shrinks to s = "'\":`"
|
||||||
|
cc 0424c33000d9188be96b3049046eb052770b2158bf5ebb0c98656d7145e8aca9 # shrinks to s = "0"
|
@ -49,7 +49,7 @@ impl Command for BytesIndexOf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["pattern", "match", "find", "search", "index"]
|
vec!["pattern", "match", "find", "search"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -39,7 +39,7 @@ impl Command for BytesLen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["len", "size", "count"]
|
vec!["size", "count"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -29,7 +29,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["convert", "binary", "bytes", "bin"]
|
vec!["convert", "bytes"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -103,7 +103,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["convert", "date", "time", "timezone", "UTC"]
|
vec!["convert", "timezone", "UTC"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -3,7 +3,8 @@ use nu_parser::parse_duration_bytes;
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath, Expr},
|
ast::{Call, CellPath, Expr},
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Unit, Value,
|
Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Unit,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -16,6 +17,12 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("into duration")
|
Signature::build("into duration")
|
||||||
|
.named(
|
||||||
|
"convert",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"convert duration into another duration",
|
||||||
|
Some('c'),
|
||||||
|
)
|
||||||
.rest(
|
.rest(
|
||||||
"rest",
|
"rest",
|
||||||
SyntaxShape::CellPath,
|
SyntaxShape::CellPath,
|
||||||
@ -106,6 +113,15 @@ impl Command for SubCommand {
|
|||||||
span,
|
span,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description: "Convert string to a named duration",
|
||||||
|
example: "'7min' | into duration --convert sec",
|
||||||
|
result: Some(Value::String {
|
||||||
|
val: "420 sec".to_string(),
|
||||||
|
span,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,17 +133,21 @@ fn into_duration(
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
|
let convert_to_unit: Option<Spanned<String>> = call.get_flag(engine_state, stack, "convert")?;
|
||||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||||
|
|
||||||
input.map(
|
input.map(
|
||||||
move |v| {
|
move |v| {
|
||||||
if column_paths.is_empty() {
|
if column_paths.is_empty() {
|
||||||
action(&v, head)
|
action(&v, &convert_to_unit, head)
|
||||||
} else {
|
} else {
|
||||||
let mut ret = v;
|
let mut ret = v;
|
||||||
for path in &column_paths {
|
for path in &column_paths {
|
||||||
let r =
|
let d = convert_to_unit.clone();
|
||||||
ret.update_cell_path(&path.members, Box::new(move |old| action(old, head)));
|
let r = ret.update_cell_path(
|
||||||
|
&path.members,
|
||||||
|
Box::new(move |old| action(old, &d, head)),
|
||||||
|
);
|
||||||
if let Err(error) = r {
|
if let Err(error) = r {
|
||||||
return Value::Error { error };
|
return Value::Error { error };
|
||||||
}
|
}
|
||||||
@ -140,6 +160,148 @@ fn into_duration(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_str_from_unit_to_unit(
|
||||||
|
val: i64,
|
||||||
|
from_unit: &str,
|
||||||
|
to_unit: &str,
|
||||||
|
span: Span,
|
||||||
|
value_span: Span,
|
||||||
|
) -> Result<i64, ShellError> {
|
||||||
|
match (from_unit, to_unit) {
|
||||||
|
("ns", "ns") => Ok(val),
|
||||||
|
("ns", "us") => Ok(val / 1000),
|
||||||
|
("ns", "ms") => Ok(val / 1000 / 1000),
|
||||||
|
("ns", "sec") => Ok(val / 1000 / 1000 / 1000),
|
||||||
|
("ns", "min") => Ok(val / 1000 / 1000 / 1000 / 60),
|
||||||
|
("ns", "hr") => Ok(val / 1000 / 1000 / 1000 / 60 / 60),
|
||||||
|
("ns", "day") => Ok(val / 1000 / 1000 / 1000 / 60 / 60 / 24),
|
||||||
|
("ns", "wk") => Ok(val / 1000 / 1000 / 1000 / 60 / 60 / 24 / 7),
|
||||||
|
("ns", "month") => Ok(val / 1000 / 1000 / 1000 / 60 / 60 / 24 / 30),
|
||||||
|
("ns", "yr") => Ok(val / 1000 / 1000 / 1000 / 60 / 60 / 24 / 365),
|
||||||
|
("ns", "dec") => Ok(val / 10 / 1000 / 1000 / 1000 / 60 / 60 / 24 / 365),
|
||||||
|
|
||||||
|
("us", "ns") => Ok(val * 1000),
|
||||||
|
("us", "us") => Ok(val),
|
||||||
|
("us", "ms") => Ok(val / 1000),
|
||||||
|
("us", "sec") => Ok(val / 1000 / 1000),
|
||||||
|
("us", "min") => Ok(val / 1000 / 1000 / 60),
|
||||||
|
("us", "hr") => Ok(val / 1000 / 1000 / 60 / 60),
|
||||||
|
("us", "day") => Ok(val / 1000 / 1000 / 60 / 60 / 24),
|
||||||
|
("us", "wk") => Ok(val / 1000 / 1000 / 60 / 60 / 24 / 7),
|
||||||
|
("us", "month") => Ok(val / 1000 / 1000 / 60 / 60 / 24 / 30),
|
||||||
|
("us", "yr") => Ok(val / 1000 / 1000 / 60 / 60 / 24 / 365),
|
||||||
|
("us", "dec") => Ok(val / 10 / 1000 / 1000 / 60 / 60 / 24 / 365),
|
||||||
|
|
||||||
|
("ms", "ns") => Ok(val * 1000 * 1000),
|
||||||
|
("ms", "us") => Ok(val * 1000),
|
||||||
|
("ms", "ms") => Ok(val),
|
||||||
|
("ms", "sec") => Ok(val / 1000),
|
||||||
|
("ms", "min") => Ok(val / 1000 / 60),
|
||||||
|
("ms", "hr") => Ok(val / 1000 / 60 / 60),
|
||||||
|
("ms", "day") => Ok(val / 1000 / 60 / 60 / 24),
|
||||||
|
("ms", "wk") => Ok(val / 1000 / 60 / 60 / 24 / 7),
|
||||||
|
("ms", "month") => Ok(val / 1000 / 60 / 60 / 24 / 30),
|
||||||
|
("ms", "yr") => Ok(val / 1000 / 60 / 60 / 24 / 365),
|
||||||
|
("ms", "dec") => Ok(val / 10 / 1000 / 60 / 60 / 24 / 365),
|
||||||
|
|
||||||
|
("sec", "ns") => Ok(val * 1000 * 1000 * 1000),
|
||||||
|
("sec", "us") => Ok(val * 1000 * 1000),
|
||||||
|
("sec", "ms") => Ok(val * 1000),
|
||||||
|
("sec", "sec") => Ok(val),
|
||||||
|
("sec", "min") => Ok(val / 60),
|
||||||
|
("sec", "hr") => Ok(val / 60 / 60),
|
||||||
|
("sec", "day") => Ok(val / 60 / 60 / 24),
|
||||||
|
("sec", "wk") => Ok(val / 60 / 60 / 24 / 7),
|
||||||
|
("sec", "month") => Ok(val / 60 / 60 / 24 / 30),
|
||||||
|
("sec", "yr") => Ok(val / 60 / 60 / 24 / 365),
|
||||||
|
("sec", "dec") => Ok(val / 10 / 60 / 60 / 24 / 365),
|
||||||
|
|
||||||
|
("min", "ns") => Ok(val * 1000 * 1000 * 1000 * 60),
|
||||||
|
("min", "us") => Ok(val * 1000 * 1000 * 60),
|
||||||
|
("min", "ms") => Ok(val * 1000 * 60),
|
||||||
|
("min", "sec") => Ok(val * 60),
|
||||||
|
("min", "min") => Ok(val),
|
||||||
|
("min", "hr") => Ok(val / 60),
|
||||||
|
("min", "day") => Ok(val / 60 / 24),
|
||||||
|
("min", "wk") => Ok(val / 60 / 24 / 7),
|
||||||
|
("min", "month") => Ok(val / 60 / 24 / 30),
|
||||||
|
("min", "yr") => Ok(val / 60 / 24 / 365),
|
||||||
|
("min", "dec") => Ok(val / 10 / 60 / 24 / 365),
|
||||||
|
|
||||||
|
("hr", "ns") => Ok(val * 1000 * 1000 * 1000 * 60 * 60),
|
||||||
|
("hr", "us") => Ok(val * 1000 * 1000 * 60 * 60),
|
||||||
|
("hr", "ms") => Ok(val * 1000 * 60 * 60),
|
||||||
|
("hr", "sec") => Ok(val * 60 * 60),
|
||||||
|
("hr", "min") => Ok(val * 60),
|
||||||
|
("hr", "hr") => Ok(val),
|
||||||
|
("hr", "day") => Ok(val / 24),
|
||||||
|
("hr", "wk") => Ok(val / 24 / 7),
|
||||||
|
("hr", "month") => Ok(val / 24 / 30),
|
||||||
|
("hr", "yr") => Ok(val / 24 / 365),
|
||||||
|
("hr", "dec") => Ok(val / 10 / 24 / 365),
|
||||||
|
|
||||||
|
("day", "ns") => Ok(val * 1000 * 1000 * 1000 * 60 * 60 * 24),
|
||||||
|
("day", "us") => Ok(val * 1000 * 1000 * 60 * 60 * 24),
|
||||||
|
("day", "ms") => Ok(val * 1000 * 60 * 60 * 24),
|
||||||
|
("day", "sec") => Ok(val * 60 * 60 * 24),
|
||||||
|
("day", "min") => Ok(val * 60 * 24),
|
||||||
|
("day", "hr") => Ok(val * 24),
|
||||||
|
("day", "day") => Ok(val),
|
||||||
|
("day", "wk") => Ok(val / 7),
|
||||||
|
("day", "month") => Ok(val / 30),
|
||||||
|
("day", "yr") => Ok(val / 365),
|
||||||
|
("day", "dec") => Ok(val / 10 / 365),
|
||||||
|
|
||||||
|
("wk", "ns") => Ok(val * 1000 * 1000 * 1000 * 60 * 60 * 24 * 7),
|
||||||
|
("wk", "us") => Ok(val * 1000 * 1000 * 60 * 60 * 24 * 7),
|
||||||
|
("wk", "ms") => Ok(val * 1000 * 60 * 60 * 24 * 7),
|
||||||
|
("wk", "sec") => Ok(val * 60 * 60 * 24 * 7),
|
||||||
|
("wk", "min") => Ok(val * 60 * 24 * 7),
|
||||||
|
("wk", "hr") => Ok(val * 24 * 7),
|
||||||
|
("wk", "day") => Ok(val * 7),
|
||||||
|
("wk", "wk") => Ok(val),
|
||||||
|
("wk", "month") => Ok(val / 4),
|
||||||
|
("wk", "yr") => Ok(val / 52),
|
||||||
|
("wk", "dec") => Ok(val / 10 / 52),
|
||||||
|
|
||||||
|
("month", "ns") => Ok(val * 1000 * 1000 * 1000 * 60 * 60 * 24 * 30),
|
||||||
|
("month", "us") => Ok(val * 1000 * 1000 * 60 * 60 * 24 * 30),
|
||||||
|
("month", "ms") => Ok(val * 1000 * 60 * 60 * 24 * 30),
|
||||||
|
("month", "sec") => Ok(val * 60 * 60 * 24 * 30),
|
||||||
|
("month", "min") => Ok(val * 60 * 24 * 30),
|
||||||
|
("month", "hr") => Ok(val * 24 * 30),
|
||||||
|
("month", "day") => Ok(val * 30),
|
||||||
|
("month", "wk") => Ok(val * 4),
|
||||||
|
("month", "month") => Ok(val),
|
||||||
|
("month", "yr") => Ok(val / 12),
|
||||||
|
("month", "dec") => Ok(val / 10 / 12),
|
||||||
|
|
||||||
|
("yr", "ns") => Ok(val * 1000 * 1000 * 1000 * 60 * 60 * 24 * 365),
|
||||||
|
("yr", "us") => Ok(val * 1000 * 1000 * 60 * 60 * 24 * 365),
|
||||||
|
("yr", "ms") => Ok(val * 1000 * 60 * 60 * 24 * 365),
|
||||||
|
("yr", "sec") => Ok(val * 60 * 60 * 24 * 365),
|
||||||
|
("yr", "min") => Ok(val * 60 * 24 * 365),
|
||||||
|
("yr", "hr") => Ok(val * 24 * 365),
|
||||||
|
("yr", "day") => Ok(val * 365),
|
||||||
|
("yr", "wk") => Ok(val * 52),
|
||||||
|
("yr", "month") => Ok(val * 12),
|
||||||
|
("yr", "yr") => Ok(val),
|
||||||
|
("yr", "dec") => Ok(val / 10),
|
||||||
|
|
||||||
|
_ => Err(ShellError::CantConvertWithValue(
|
||||||
|
"string duration".to_string(),
|
||||||
|
"string duration".to_string(),
|
||||||
|
to_unit.to_string(),
|
||||||
|
span,
|
||||||
|
value_span,
|
||||||
|
Some(
|
||||||
|
"supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec"
|
||||||
|
.to_string(),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, ShellError> {
|
fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, ShellError> {
|
||||||
if let Some(expression) = parse_duration_bytes(s.as_bytes(), span) {
|
if let Some(expression) = parse_duration_bytes(s.as_bytes(), span) {
|
||||||
if let Expr::ValueWithUnit(value, unit) = expression.expr {
|
if let Expr::ValueWithUnit(value, unit) = expression.expr {
|
||||||
@ -168,20 +330,105 @@ fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, Shel
|
|||||||
s.to_string(),
|
s.to_string(),
|
||||||
span,
|
span,
|
||||||
value_span,
|
value_span,
|
||||||
Some("supported units are ns, us, ms, sec, min, hr, day, and wk".to_string()),
|
Some(
|
||||||
|
"supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec".to_string(),
|
||||||
|
),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action(input: &Value, span: Span) -> Value {
|
fn string_to_unit_duration(
|
||||||
|
s: &str,
|
||||||
|
span: Span,
|
||||||
|
value_span: Span,
|
||||||
|
) -> Result<(&str, i64), ShellError> {
|
||||||
|
if let Some(expression) = parse_duration_bytes(s.as_bytes(), span) {
|
||||||
|
if let Expr::ValueWithUnit(value, unit) = expression.expr {
|
||||||
|
if let Expr::Int(x) = value.expr {
|
||||||
|
match unit.item {
|
||||||
|
Unit::Nanosecond => return Ok(("ns", x)),
|
||||||
|
Unit::Microsecond => return Ok(("us", x)),
|
||||||
|
Unit::Millisecond => return Ok(("ms", x)),
|
||||||
|
Unit::Second => return Ok(("sec", x)),
|
||||||
|
Unit::Minute => return Ok(("min", x)),
|
||||||
|
Unit::Hour => return Ok(("hr", x)),
|
||||||
|
Unit::Day => return Ok(("day", x)),
|
||||||
|
Unit::Week => return Ok(("wk", x)),
|
||||||
|
Unit::Month => return Ok(("month", x)), //30 days to a month
|
||||||
|
Unit::Year => return Ok(("yr", x)), //365 days to a year
|
||||||
|
Unit::Decade => return Ok(("dec", x)), //365 days to a year
|
||||||
|
|
||||||
|
_ => return Ok(("ns", 0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(ShellError::CantConvertWithValue(
|
||||||
|
"duration".to_string(),
|
||||||
|
"string".to_string(),
|
||||||
|
s.to_string(),
|
||||||
|
span,
|
||||||
|
value_span,
|
||||||
|
Some(
|
||||||
|
"supported units are ns, us, ms, sec, min, hr, day, wk, month, yr and dec".to_string(),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn action(input: &Value, convert_to_unit: &Option<Spanned<String>>, span: Span) -> Value {
|
||||||
match input {
|
match input {
|
||||||
Value::Duration { .. } => input.clone(),
|
Value::Duration {
|
||||||
|
val: _val_num,
|
||||||
|
span: _value_span,
|
||||||
|
} => {
|
||||||
|
if let Some(_to_unit) = convert_to_unit {
|
||||||
|
Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
"Cannot convert from a Value::Duration right now. Try making it a string."
|
||||||
|
.into(),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
Value::String {
|
Value::String {
|
||||||
val,
|
val,
|
||||||
span: value_span,
|
span: value_span,
|
||||||
} => match string_to_duration(val, span, *value_span) {
|
} => {
|
||||||
Ok(val) => Value::Duration { val, span },
|
if let Some(to_unit) = convert_to_unit {
|
||||||
Err(error) => Value::Error { error },
|
if let Ok(dur) = string_to_unit_duration(val, span, *value_span) {
|
||||||
},
|
let from_unit = dur.0;
|
||||||
|
let duration = dur.1;
|
||||||
|
match convert_str_from_unit_to_unit(
|
||||||
|
duration,
|
||||||
|
from_unit,
|
||||||
|
&to_unit.item,
|
||||||
|
span,
|
||||||
|
*value_span,
|
||||||
|
) {
|
||||||
|
Ok(d) => Value::String {
|
||||||
|
val: format!("{} {}", d, &to_unit.item),
|
||||||
|
span: *value_span,
|
||||||
|
},
|
||||||
|
Err(e) => Value::Error { error: e },
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Value::Error {
|
||||||
|
error: ShellError::UnsupportedInput(
|
||||||
|
"'into duration' does not support this string input".into(),
|
||||||
|
span,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match string_to_duration(val, span, *value_span) {
|
||||||
|
Ok(val) => Value::Duration { val, span },
|
||||||
|
Err(error) => Value::Error { error },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => Value::Error {
|
_ => Value::Error {
|
||||||
error: ShellError::UnsupportedInput(
|
error: ShellError::UnsupportedInput(
|
||||||
"'into duration' does not support this input".into(),
|
"'into duration' does not support this input".into(),
|
||||||
@ -207,8 +454,9 @@ mod test {
|
|||||||
let span = Span::test_data();
|
let span = Span::test_data();
|
||||||
let word = Value::test_string("3ns");
|
let word = Value::test_string("3ns");
|
||||||
let expected = Value::Duration { val: 3, span };
|
let expected = Value::Duration { val: 3, span };
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,8 +468,9 @@ mod test {
|
|||||||
val: 4 * 1000,
|
val: 4 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,8 +482,9 @@ mod test {
|
|||||||
val: 5 * 1000 * 1000,
|
val: 5 * 1000 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,8 +496,9 @@ mod test {
|
|||||||
val: 1000 * 1000 * 1000,
|
val: 1000 * 1000 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,8 +510,9 @@ mod test {
|
|||||||
val: 7 * 60 * 1000 * 1000 * 1000,
|
val: 7 * 60 * 1000 * 1000 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,8 +524,9 @@ mod test {
|
|||||||
val: 42 * 60 * 60 * 1000 * 1000 * 1000,
|
val: 42 * 60 * 60 * 1000 * 1000 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,8 +538,9 @@ mod test {
|
|||||||
val: 123 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
val: 123 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,8 +552,9 @@ mod test {
|
|||||||
val: 3 * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
val: 3 * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
||||||
span,
|
span,
|
||||||
};
|
};
|
||||||
|
let convert_duration = None;
|
||||||
|
|
||||||
let actual = action(&word, span);
|
let actual = action(&word, &convert_duration, span);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["convert", "number", "size", "bytes"]
|
vec!["convert", "number", "bytes"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -38,7 +38,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["convert", "str", "text"]
|
vec!["convert", "text"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -27,7 +27,7 @@ impl Command for Alias {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
77
crates/nu-command/src/core_commands/ast.rs
Normal file
77
crates/nu-command/src/core_commands/ast.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use nu_engine::CallExt;
|
||||||
|
use nu_parser::parse;
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{Command, EngineState, Stack, StateWorkingSet},
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Ast;
|
||||||
|
|
||||||
|
impl Command for Ast {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"ast"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Print the abstract syntax tree (ast) for a pipeline."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("ast")
|
||||||
|
.required(
|
||||||
|
"pipeline",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"the pipeline to print the ast for",
|
||||||
|
)
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
_input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let head = call.head;
|
||||||
|
let pipeline: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||||
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
|
let (output, err) = parse(&mut working_set, None, pipeline.item.as_bytes(), false, &[]);
|
||||||
|
eprintln!("output: {:#?}\nerror: {:#?}", output, err);
|
||||||
|
|
||||||
|
Ok(PipelineData::new(head))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Print the ast of a string",
|
||||||
|
example: "ast 'hello'",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Print the ast of a pipeline",
|
||||||
|
example: "ast 'ls | where name =~ README'",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Print the ast of a pipeline with an error",
|
||||||
|
example: "ast 'for x in 1..10 { echo $x '",
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use super::Ast;
|
||||||
|
use crate::test_examples;
|
||||||
|
test_examples(Ast {})
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,7 @@ impl Command for Def {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -28,7 +28,7 @@ impl Command for DefEnv {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html
|
https://www.nushell.sh/book/thinking_in_nu.html
|
||||||
|
|
||||||
=== EXTRA NOTE ===
|
=== EXTRA NOTE ===
|
||||||
All blocks are scoped, including variable definition and environment variable changes.
|
All blocks are scoped, including variable definition and environment variable changes.
|
||||||
|
@ -29,7 +29,7 @@ impl Command for ErrorMake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["err", "panic", "crash", "throw"]
|
vec!["panic", "crash", "throw"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -23,7 +23,7 @@ impl Command for ExportCommand {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -27,7 +27,7 @@ impl Command for ExportAlias {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -28,7 +28,7 @@ impl Command for ExportDef {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -28,7 +28,7 @@ impl Command for ExportDefEnv {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html
|
https://www.nushell.sh/book/thinking_in_nu.html
|
||||||
|
|
||||||
=== EXTRA NOTE ===
|
=== EXTRA NOTE ===
|
||||||
All blocks are scoped, including variable definition and environment variable changes.
|
All blocks are scoped, including variable definition and environment variable changes.
|
||||||
|
@ -3,9 +3,9 @@ use nu_protocol::engine::{Command, EngineState, Stack};
|
|||||||
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
use nu_protocol::{Category, Example, PipelineData, Signature, Span, SyntaxShape, Value};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ExportEnv;
|
pub struct ExportEnvModule;
|
||||||
|
|
||||||
impl Command for ExportEnv {
|
impl Command for ExportEnvModule {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"export env"
|
"export env"
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ impl Command for ExportEnv {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -23,7 +23,7 @@ impl Command for ExportExtern {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -22,7 +22,7 @@ impl Command for ExportUse {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -23,7 +23,7 @@ impl Command for Extern {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -46,7 +46,7 @@ impl Command for For {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -26,7 +26,7 @@ impl Command for Hide {
|
|||||||
r#"Definitions are hidden by priority: First aliases, then custom commands.
|
r#"Definitions are hidden by priority: First aliases, then custom commands.
|
||||||
|
|
||||||
This command is a parser keyword. For details, check:
|
This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -35,7 +35,7 @@ impl Command for If {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -28,7 +28,7 @@ impl Command for Let {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
mod alias;
|
mod alias;
|
||||||
|
mod ast;
|
||||||
mod debug;
|
mod debug;
|
||||||
mod def;
|
mod def;
|
||||||
mod def_env;
|
mod def_env;
|
||||||
@ -24,11 +25,11 @@ mod let_;
|
|||||||
mod metadata;
|
mod metadata;
|
||||||
mod module;
|
mod module;
|
||||||
pub(crate) mod overlay;
|
pub(crate) mod overlay;
|
||||||
mod source;
|
|
||||||
mod use_;
|
mod use_;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
pub use alias::Alias;
|
pub use alias::Alias;
|
||||||
|
pub use ast::Ast;
|
||||||
pub use debug::Debug;
|
pub use debug::Debug;
|
||||||
pub use def::Def;
|
pub use def::Def;
|
||||||
pub use def_env::DefEnv;
|
pub use def_env::DefEnv;
|
||||||
@ -40,7 +41,7 @@ pub use export::ExportCommand;
|
|||||||
pub use export_alias::ExportAlias;
|
pub use export_alias::ExportAlias;
|
||||||
pub use export_def::ExportDef;
|
pub use export_def::ExportDef;
|
||||||
pub use export_def_env::ExportDefEnv;
|
pub use export_def_env::ExportDefEnv;
|
||||||
pub use export_env::ExportEnv;
|
pub use export_env::ExportEnvModule;
|
||||||
pub use export_extern::ExportExtern;
|
pub use export_extern::ExportExtern;
|
||||||
pub use export_use::ExportUse;
|
pub use export_use::ExportUse;
|
||||||
pub use extern_::Extern;
|
pub use extern_::Extern;
|
||||||
@ -54,7 +55,6 @@ pub use let_::Let;
|
|||||||
pub use metadata::Metadata;
|
pub use metadata::Metadata;
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use overlay::*;
|
pub use overlay::*;
|
||||||
pub use source::Source;
|
|
||||||
pub use use_::Use;
|
pub use use_::Use;
|
||||||
pub use version::Version;
|
pub use version::Version;
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
|
@ -27,7 +27,7 @@ impl Command for Module {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -1,180 +0,0 @@
|
|||||||
use nu_engine::{eval_block, CallExt};
|
|
||||||
use nu_protocol::ast::Call;
|
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
|
||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape};
|
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OverlayAdd;
|
|
||||||
|
|
||||||
impl Command for OverlayAdd {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"overlay add"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Add definitions from a module as an overlay"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
|
||||||
Signature::build("overlay add")
|
|
||||||
.required(
|
|
||||||
"name",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"Module name to create overlay for",
|
|
||||||
)
|
|
||||||
.optional(
|
|
||||||
"as",
|
|
||||||
SyntaxShape::Keyword(b"as".to_vec(), Box::new(SyntaxShape::String)),
|
|
||||||
"as keyword followed by a new name",
|
|
||||||
)
|
|
||||||
.switch(
|
|
||||||
"prefix",
|
|
||||||
"Prepend module name to the imported commands and aliases",
|
|
||||||
Some('p'),
|
|
||||||
)
|
|
||||||
.category(Category::Core)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
|
||||||
r#"This command is a parser keyword. For details, check:
|
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let name_arg: Spanned<String> = call.req(engine_state, stack, 0)?;
|
|
||||||
|
|
||||||
let (overlay_name, overlay_name_span) = if let Some(kw_expression) = call.positional_nth(1)
|
|
||||||
{
|
|
||||||
// If renamed via the 'as' keyword, use the new name as the overlay name
|
|
||||||
if let Some(new_name_expression) = kw_expression.as_keyword() {
|
|
||||||
if let Some(new_name) = new_name_expression.as_string() {
|
|
||||||
(new_name, new_name_expression.span)
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::NushellFailedSpanned(
|
|
||||||
"Wrong keyword type".to_string(),
|
|
||||||
"keyword argument not a string".to_string(),
|
|
||||||
new_name_expression.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::NushellFailedSpanned(
|
|
||||||
"Wrong keyword type".to_string(),
|
|
||||||
"keyword argument not a keyword".to_string(),
|
|
||||||
kw_expression.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else if engine_state
|
|
||||||
.find_overlay(name_arg.item.as_bytes())
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
(name_arg.item, name_arg.span)
|
|
||||||
} else if let Some(os_str) = Path::new(&name_arg.item).file_stem() {
|
|
||||||
if let Some(name) = os_str.to_str() {
|
|
||||||
(name.to_string(), name_arg.span)
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::NonUtf8(name_arg.span));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::OverlayNotFoundAtRuntime(
|
|
||||||
name_arg.item,
|
|
||||||
name_arg.span,
|
|
||||||
));
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(overlay_id) = engine_state.find_overlay(overlay_name.as_bytes()) {
|
|
||||||
let old_module_id = engine_state.get_overlay(overlay_id).origin;
|
|
||||||
|
|
||||||
stack.add_overlay(overlay_name.clone());
|
|
||||||
|
|
||||||
if let Some(new_module_id) = engine_state.find_module(overlay_name.as_bytes(), &[]) {
|
|
||||||
if !stack.has_env_overlay(&overlay_name, engine_state)
|
|
||||||
|| (old_module_id != new_module_id)
|
|
||||||
{
|
|
||||||
// Add environment variables only if:
|
|
||||||
// a) adding a new overlay
|
|
||||||
// b) refreshing an active overlay (the origin module changed)
|
|
||||||
let module = engine_state.get_module(new_module_id);
|
|
||||||
|
|
||||||
for (name, block_id) in module.env_vars() {
|
|
||||||
let name = if let Ok(s) = String::from_utf8(name.clone()) {
|
|
||||||
s
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::NonUtf8(call.head));
|
|
||||||
};
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
|
|
||||||
let val = eval_block(
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
block,
|
|
||||||
PipelineData::new(call.head),
|
|
||||||
false,
|
|
||||||
true,
|
|
||||||
)?
|
|
||||||
.into_value(call.head);
|
|
||||||
|
|
||||||
stack.add_env_var(name, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::OverlayNotFoundAtRuntime(
|
|
||||||
overlay_name,
|
|
||||||
overlay_name_span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(PipelineData::new(call.head))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Create an overlay from a module",
|
|
||||||
example: r#"module spam { export def foo [] { "foo" } }
|
|
||||||
overlay add spam
|
|
||||||
foo"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Create an overlay with a prefix",
|
|
||||||
example: r#"echo 'export def foo { "foo" }'
|
|
||||||
overlay add --prefix spam
|
|
||||||
spam foo"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Create an overlay from a file",
|
|
||||||
example: r#"echo 'export env FOO { "foo" }' | save spam.nu
|
|
||||||
overlay add spam.nu
|
|
||||||
$env.FOO"#,
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_examples() {
|
|
||||||
use crate::test_examples;
|
|
||||||
|
|
||||||
test_examples(OverlayAdd {})
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,7 +23,7 @@ impl Command for Overlay {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -4,20 +4,20 @@ use nu_protocol::engine::{Command, EngineState, Stack};
|
|||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape};
|
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OverlayRemove;
|
pub struct OverlayHide;
|
||||||
|
|
||||||
impl Command for OverlayRemove {
|
impl Command for OverlayHide {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"overlay remove"
|
"overlay hide"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
fn usage(&self) -> &str {
|
||||||
"Remove an active overlay"
|
"Hide an active overlay"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
Signature::build("overlay remove")
|
Signature::build("overlay hide")
|
||||||
.optional("name", SyntaxShape::String, "Overlay to remove")
|
.optional("name", SyntaxShape::String, "Overlay to hide")
|
||||||
.switch(
|
.switch(
|
||||||
"keep-custom",
|
"keep-custom",
|
||||||
"Keep all newly added symbols within the next activated overlay",
|
"Keep all newly added symbols within the next activated overlay",
|
||||||
@ -26,7 +26,7 @@ impl Command for OverlayRemove {
|
|||||||
.named(
|
.named(
|
||||||
"keep-env",
|
"keep-env",
|
||||||
SyntaxShape::List(Box::new(SyntaxShape::String)),
|
SyntaxShape::List(Box::new(SyntaxShape::String)),
|
||||||
"List of environment variables to keep from the removed overlay",
|
"List of environment variables to keep from the hidden overlay",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
)
|
)
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
@ -34,7 +34,7 @@ impl Command for OverlayRemove {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
@ -110,31 +110,31 @@ impl Command for OverlayRemove {
|
|||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Remove an overlay created from a module",
|
description: "Hide an overlay created from a module",
|
||||||
example: r#"module spam { export def foo [] { "foo" } }
|
example: r#"module spam { export def foo [] { "foo" } }
|
||||||
overlay add spam
|
overlay use spam
|
||||||
overlay remove spam"#,
|
overlay hide spam"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Remove an overlay created from a file",
|
description: "Hide an overlay created from a file",
|
||||||
example: r#"echo 'export alias f = "foo"' | save spam.nu
|
example: r#"echo 'export alias f = "foo"' | save spam.nu
|
||||||
overlay add spam.nu
|
overlay use spam.nu
|
||||||
overlay remove spam"#,
|
overlay hide spam"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Remove the last activated overlay",
|
description: "Hide the last activated overlay",
|
||||||
example: r#"module spam { export env FOO { "foo" } }
|
example: r#"module spam { export env FOO { "foo" } }
|
||||||
overlay add spam
|
overlay use spam
|
||||||
overlay remove"#,
|
overlay hide"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Keep the current working directory when removing an overlay",
|
description: "Keep the current working directory when removing an overlay",
|
||||||
example: r#"overlay new spam
|
example: r#"overlay new spam
|
||||||
cd some-dir
|
cd some-dir
|
||||||
overlay remove --keep-env [ PWD ] spam"#,
|
overlay hide --keep-env [ PWD ] spam"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
@ -4,8 +4,6 @@ use nu_protocol::{
|
|||||||
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
|
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::trace;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct OverlayList;
|
pub struct OverlayList;
|
||||||
|
|
||||||
@ -28,41 +26,17 @@ impl Command for OverlayList {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let active_overlays_parser: Vec<Value> = engine_state
|
|
||||||
.active_overlay_names(&[])
|
|
||||||
.iter()
|
|
||||||
.map(|s| Value::string(String::from_utf8_lossy(s), call.head))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let active_overlays_engine: Vec<Value> = stack
|
let active_overlays_engine: Vec<Value> = stack
|
||||||
.active_overlays
|
.active_overlays
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| Value::string(s, call.head))
|
.map(|s| Value::string(s, call.head))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Check if the overlays in the engine match the overlays in the parser
|
|
||||||
if (active_overlays_parser.len() != active_overlays_engine.len())
|
|
||||||
|| active_overlays_parser
|
|
||||||
.iter()
|
|
||||||
.zip(active_overlays_engine.iter())
|
|
||||||
.any(|(op, oe)| op != oe)
|
|
||||||
{
|
|
||||||
trace!("parser overlays: {:?}", active_overlays_parser);
|
|
||||||
trace!("engine overlays: {:?}", active_overlays_engine);
|
|
||||||
|
|
||||||
return Err(ShellError::NushellFailedSpannedHelp(
|
|
||||||
"Overlay mismatch".into(),
|
|
||||||
"Active overlays do not match between the engine and the parser.".into(),
|
|
||||||
call.head,
|
|
||||||
"Run Nushell with --log-level=trace to see what went wrong.".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::List {
|
Ok(Value::List {
|
||||||
vals: active_overlays_engine,
|
vals: active_overlays_engine,
|
||||||
span: call.head,
|
span: call.head,
|
||||||
@ -74,7 +48,7 @@ impl Command for OverlayList {
|
|||||||
vec![Example {
|
vec![Example {
|
||||||
description: "Get the last activated overlay",
|
description: "Get the last activated overlay",
|
||||||
example: r#"module spam { export def foo [] { "foo" } }
|
example: r#"module spam { export def foo [] { "foo" } }
|
||||||
overlay add spam
|
overlay use spam
|
||||||
overlay list | last"#,
|
overlay list | last"#,
|
||||||
result: Some(Value::String {
|
result: Some(Value::String {
|
||||||
val: "spam".to_string(),
|
val: "spam".to_string(),
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
mod add;
|
|
||||||
mod command;
|
mod command;
|
||||||
|
mod hide;
|
||||||
mod list;
|
mod list;
|
||||||
mod new;
|
mod new;
|
||||||
mod remove;
|
mod use_;
|
||||||
|
|
||||||
pub use add::OverlayAdd;
|
|
||||||
pub use command::Overlay;
|
pub use command::Overlay;
|
||||||
|
pub use hide::OverlayHide;
|
||||||
pub use list::OverlayList;
|
pub use list::OverlayList;
|
||||||
pub use new::OverlayNew;
|
pub use new::OverlayNew;
|
||||||
pub use remove::OverlayRemove;
|
pub use use_::OverlayUse;
|
||||||
|
@ -31,7 +31,7 @@ impl Command for OverlayNew {
|
|||||||
r#"The command will first create an empty module, then add it as an overlay.
|
r#"The command will first create an empty module, then add it as an overlay.
|
||||||
|
|
||||||
This command is a parser keyword. For details, check:
|
This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
225
crates/nu-command/src/core_commands/overlay/use_.rs
Normal file
225
crates/nu-command/src/core_commands/overlay/use_.rs
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
use nu_engine::{eval_block, find_in_dirs_env, redirect_env, CallExt};
|
||||||
|
use nu_protocol::ast::{Call, Expr};
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct OverlayUse;
|
||||||
|
|
||||||
|
impl Command for OverlayUse {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"overlay use"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Use definitions from a module as an overlay"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
Signature::build("overlay use")
|
||||||
|
.required(
|
||||||
|
"name",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"Module name to use overlay for",
|
||||||
|
)
|
||||||
|
.optional(
|
||||||
|
"as",
|
||||||
|
SyntaxShape::Keyword(b"as".to_vec(), Box::new(SyntaxShape::String)),
|
||||||
|
"as keyword followed by a new name",
|
||||||
|
)
|
||||||
|
.switch(
|
||||||
|
"prefix",
|
||||||
|
"Prepend module name to the imported commands and aliases",
|
||||||
|
Some('p'),
|
||||||
|
)
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extra_usage(&self) -> &str {
|
||||||
|
r#"This command is a parser keyword. For details, check:
|
||||||
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
caller_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
||||||
|
|
||||||
|
let origin_module_id = if let Some(overlay_expr) = call.positional_nth(0) {
|
||||||
|
if let Expr::Overlay(module_id) = overlay_expr.expr {
|
||||||
|
module_id
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NushellFailedSpanned(
|
||||||
|
"Not an overlay".to_string(),
|
||||||
|
"requires an overlay (path or a string)".to_string(),
|
||||||
|
overlay_expr.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NushellFailedSpanned(
|
||||||
|
"Missing positional".to_string(),
|
||||||
|
"missing required overlay".to_string(),
|
||||||
|
call.head,
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
let overlay_name = if let Some(kw_expression) = call.positional_nth(1) {
|
||||||
|
// If renamed via the 'as' keyword, use the new name as the overlay name
|
||||||
|
if let Some(new_name_expression) = kw_expression.as_keyword() {
|
||||||
|
if let Some(new_name) = new_name_expression.as_string() {
|
||||||
|
new_name
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NushellFailedSpanned(
|
||||||
|
"Wrong keyword type".to_string(),
|
||||||
|
"keyword argument not a string".to_string(),
|
||||||
|
new_name_expression.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NushellFailedSpanned(
|
||||||
|
"Wrong keyword type".to_string(),
|
||||||
|
"keyword argument not a keyword".to_string(),
|
||||||
|
kw_expression.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if engine_state
|
||||||
|
.find_overlay(name_arg.item.as_bytes())
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
name_arg.item.clone()
|
||||||
|
} else if let Some(os_str) = Path::new(&name_arg.item).file_stem() {
|
||||||
|
if let Some(name) = os_str.to_str() {
|
||||||
|
name.to_string()
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NonUtf8(name_arg.span));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::OverlayNotFoundAtRuntime(
|
||||||
|
name_arg.item,
|
||||||
|
name_arg.span,
|
||||||
|
));
|
||||||
|
};
|
||||||
|
|
||||||
|
caller_stack.add_overlay(overlay_name);
|
||||||
|
|
||||||
|
if let Some(module_id) = origin_module_id {
|
||||||
|
// Add environment variables only if:
|
||||||
|
// a) adding a new overlay
|
||||||
|
// b) refreshing an active overlay (the origin module changed)
|
||||||
|
|
||||||
|
let module = engine_state.get_module(module_id);
|
||||||
|
|
||||||
|
for (name, block_id) in module.env_vars() {
|
||||||
|
let name = if let Ok(s) = String::from_utf8(name.clone()) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::NonUtf8(call.head));
|
||||||
|
};
|
||||||
|
|
||||||
|
let block = engine_state.get_block(block_id);
|
||||||
|
|
||||||
|
let val = eval_block(
|
||||||
|
engine_state,
|
||||||
|
caller_stack,
|
||||||
|
block,
|
||||||
|
PipelineData::new(call.head),
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?
|
||||||
|
.into_value(call.head);
|
||||||
|
|
||||||
|
caller_stack.add_env_var(name, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate the export-env block (if any) and keep its environment
|
||||||
|
if let Some(block_id) = module.env_block {
|
||||||
|
let maybe_path = find_in_dirs_env(&name_arg.item, engine_state, caller_stack)?;
|
||||||
|
|
||||||
|
if let Some(path) = &maybe_path {
|
||||||
|
// Set the currently evaluated directory, if the argument is a valid path
|
||||||
|
let mut parent = path.clone();
|
||||||
|
parent.pop();
|
||||||
|
|
||||||
|
let file_pwd = Value::String {
|
||||||
|
val: parent.to_string_lossy().to_string(),
|
||||||
|
span: call.head,
|
||||||
|
};
|
||||||
|
|
||||||
|
caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||||
|
}
|
||||||
|
|
||||||
|
let block = engine_state.get_block(block_id);
|
||||||
|
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
||||||
|
|
||||||
|
let _ = eval_block(
|
||||||
|
engine_state,
|
||||||
|
&mut callee_stack,
|
||||||
|
block,
|
||||||
|
input,
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Merge the block's environment to the current stack
|
||||||
|
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||||
|
|
||||||
|
if maybe_path.is_some() {
|
||||||
|
// Remove the file-relative PWD, if the argument is a valid path
|
||||||
|
caller_stack.remove_env_var(engine_state, "FILE_PWD");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(PipelineData::new(call.head))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![
|
||||||
|
Example {
|
||||||
|
description: "Create an overlay from a module",
|
||||||
|
example: r#"module spam { export def foo [] { "foo" } }
|
||||||
|
overlay use spam
|
||||||
|
foo"#,
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Create an overlay with a prefix",
|
||||||
|
example: r#"echo 'export def foo { "foo" }'
|
||||||
|
overlay use --prefix spam
|
||||||
|
spam foo"#,
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Create an overlay from a file",
|
||||||
|
example: r#"echo 'export env FOO { "foo" }' | save spam.nu
|
||||||
|
overlay use spam.nu
|
||||||
|
$env.FOO"#,
|
||||||
|
result: None,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(OverlayUse {})
|
||||||
|
}
|
||||||
|
}
|
@ -21,12 +21,6 @@ impl Command for Register {
|
|||||||
SyntaxShape::Filepath,
|
SyntaxShape::Filepath,
|
||||||
"path of executable for plugin",
|
"path of executable for plugin",
|
||||||
)
|
)
|
||||||
.required_named(
|
|
||||||
"encoding",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"Encoding used to communicate with plugin. Options: [capnp, json]",
|
|
||||||
Some('e'),
|
|
||||||
)
|
|
||||||
.optional(
|
.optional(
|
||||||
"signature",
|
"signature",
|
||||||
SyntaxShape::Any,
|
SyntaxShape::Any,
|
||||||
@ -43,7 +37,7 @@ impl Command for Register {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
@ -64,12 +58,12 @@ impl Command for Register {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Register `nu_plugin_query` plugin from ~/.cargo/bin/ dir",
|
description: "Register `nu_plugin_query` plugin from ~/.cargo/bin/ dir",
|
||||||
example: r#"register -e json ~/.cargo/bin/nu_plugin_query"#,
|
example: r#"register ~/.cargo/bin/nu_plugin_query"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Register `nu_plugin_query` plugin from `nu -c`(plugin will be available in that nu session only)",
|
description: "Register `nu_plugin_query` plugin from `nu -c`(plugin will be available in that nu session only)",
|
||||||
example: r#"let plugin = ((which nu).path.0 | path dirname | path join 'nu_plugin_query'); nu -c $'register -e json ($plugin); version'"#,
|
example: r#"let plugin = ((which nu).path.0 | path dirname | path join 'nu_plugin_query'); nu -c $'register ($plugin); version'"#,
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -25,7 +25,7 @@ impl Command for Use {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
||||||
|
@ -34,7 +34,7 @@ impl Command for CollectDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "collect"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -47,7 +47,7 @@ impl Command for DescribeDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "SQLite", "describe"]
|
vec!["database", "SQLite"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -41,7 +41,7 @@ impl Command for FromDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "from"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -49,7 +49,7 @@ impl Command for IntoSqliteDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["convert", "sqlite", "database"]
|
vec!["convert", "database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -47,7 +47,7 @@ impl Command for JoinDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "join"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -34,7 +34,7 @@ impl Command for LimitDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "limit"]
|
vec!["database", "head", "tail"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -29,7 +29,7 @@ impl Command for OpenDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "open"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -37,7 +37,7 @@ impl Command for OrderByDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "order-by"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -34,7 +34,7 @@ impl Command for SchemaDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "info", "SQLite", "schema"]
|
vec!["database", "info", "SQLite"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -33,7 +33,7 @@ impl Command for ProjectionDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "select"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -30,7 +30,7 @@ impl Command for ToDataBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "into", "db"]
|
vec!["database", "convert"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -31,7 +31,7 @@ impl Command for WhereDb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "where"]
|
vec!["database"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -30,7 +30,7 @@ impl Command for AndExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "and", "expression"]
|
vec!["database", "expression"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -30,7 +30,7 @@ impl Command for OrExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "or", "expression"]
|
vec!["database", "expression"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -92,7 +92,7 @@ impl Command for OverExpr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["database", "over", "expression"]
|
vec!["database", "expression"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -23,7 +23,6 @@ impl Command for Date {
|
|||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec![
|
vec![
|
||||||
"date",
|
|
||||||
"time",
|
"time",
|
||||||
"now",
|
"now",
|
||||||
"today",
|
"today",
|
||||||
|
@ -35,7 +35,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["date", "format", "strftime"]
|
vec!["fmt", "strftime"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -22,8 +22,6 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec![
|
vec![
|
||||||
"date",
|
|
||||||
"humanize",
|
|
||||||
"relative",
|
"relative",
|
||||||
"now",
|
"now",
|
||||||
"today",
|
"today",
|
||||||
|
@ -22,7 +22,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["UTC", "GMT", "timezone", "list", "list-timezone"]
|
vec!["UTC", "GMT", "tz"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -19,7 +19,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["date", "now", "present", "current-time"]
|
vec!["present", "current-time"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -23,7 +23,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["date", "to", "record", "structured", "table"]
|
vec!["structured", "table"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -23,7 +23,7 @@ impl Command for SubCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["date", "to", "record", "structured", "table"]
|
vec!["structured"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -34,9 +34,7 @@ impl Command for SubCommand {
|
|||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec![
|
vec![
|
||||||
"date",
|
"tz",
|
||||||
"to",
|
|
||||||
"timezone",
|
|
||||||
"transform",
|
"transform",
|
||||||
"convert",
|
"convert",
|
||||||
"UTC",
|
"UTC",
|
||||||
@ -128,7 +126,7 @@ fn _to_timezone(dt: DateTime<FixedOffset>, timezone: &Spanned<String>, span: Spa
|
|||||||
match datetime_in_timezone(&dt, timezone.item.as_str()) {
|
match datetime_in_timezone(&dt, timezone.item.as_str()) {
|
||||||
Ok(dt) => Value::Date { val: dt, span },
|
Ok(dt) => Value::Date { val: dt, span },
|
||||||
Err(_) => Value::Error {
|
Err(_) => Value::Error {
|
||||||
error: ShellError::UnsupportedInput(String::from("invalid time zone"), span),
|
error: ShellError::UnsupportedInput(String::from("invalid time zone"), timezone.span),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ pub fn create_default_context() -> EngineState {
|
|||||||
// Core
|
// Core
|
||||||
bind_command! {
|
bind_command! {
|
||||||
Alias,
|
Alias,
|
||||||
|
Ast,
|
||||||
Debug,
|
Debug,
|
||||||
Def,
|
Def,
|
||||||
DefEnv,
|
DefEnv,
|
||||||
@ -40,7 +41,7 @@ pub fn create_default_context() -> EngineState {
|
|||||||
ExportCommand,
|
ExportCommand,
|
||||||
ExportDef,
|
ExportDef,
|
||||||
ExportDefEnv,
|
ExportDefEnv,
|
||||||
ExportEnv,
|
ExportEnvModule,
|
||||||
ExportExtern,
|
ExportExtern,
|
||||||
ExportUse,
|
ExportUse,
|
||||||
Extern,
|
Extern,
|
||||||
@ -51,14 +52,13 @@ pub fn create_default_context() -> EngineState {
|
|||||||
If,
|
If,
|
||||||
Ignore,
|
Ignore,
|
||||||
Overlay,
|
Overlay,
|
||||||
OverlayAdd,
|
OverlayUse,
|
||||||
OverlayList,
|
OverlayList,
|
||||||
OverlayNew,
|
OverlayNew,
|
||||||
OverlayRemove,
|
OverlayHide,
|
||||||
Let,
|
Let,
|
||||||
Metadata,
|
Metadata,
|
||||||
Module,
|
Module,
|
||||||
Source,
|
|
||||||
Use,
|
Use,
|
||||||
Version,
|
Version,
|
||||||
};
|
};
|
||||||
@ -160,10 +160,17 @@ pub fn create_default_context() -> EngineState {
|
|||||||
Exec,
|
Exec,
|
||||||
External,
|
External,
|
||||||
NuCheck,
|
NuCheck,
|
||||||
Ps,
|
|
||||||
Sys,
|
Sys,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
target_os = "android",
|
||||||
|
target_os = "linux",
|
||||||
|
target_os = "macos",
|
||||||
|
target_os = "windows"
|
||||||
|
))]
|
||||||
|
bind_command! { Ps };
|
||||||
|
|
||||||
#[cfg(feature = "which-support")]
|
#[cfg(feature = "which-support")]
|
||||||
bind_command! { Which };
|
bind_command! { Which };
|
||||||
|
|
||||||
@ -184,11 +191,13 @@ pub fn create_default_context() -> EngineState {
|
|||||||
SplitChars,
|
SplitChars,
|
||||||
SplitColumn,
|
SplitColumn,
|
||||||
SplitRow,
|
SplitRow,
|
||||||
|
SplitWords,
|
||||||
Str,
|
Str,
|
||||||
StrCamelCase,
|
StrCamelCase,
|
||||||
StrCapitalize,
|
StrCapitalize,
|
||||||
StrCollect,
|
StrCollect,
|
||||||
StrContains,
|
StrContains,
|
||||||
|
StrDistance,
|
||||||
StrDowncase,
|
StrDowncase,
|
||||||
StrEndswith,
|
StrEndswith,
|
||||||
StrReplace,
|
StrReplace,
|
||||||
@ -352,8 +361,10 @@ pub fn create_default_context() -> EngineState {
|
|||||||
// Env
|
// Env
|
||||||
bind_command! {
|
bind_command! {
|
||||||
Env,
|
Env,
|
||||||
|
ExportEnv,
|
||||||
LetEnv,
|
LetEnv,
|
||||||
LoadEnv,
|
LoadEnv,
|
||||||
|
SourceEnv,
|
||||||
WithEnv,
|
WithEnv,
|
||||||
ConfigNu,
|
ConfigNu,
|
||||||
ConfigEnv,
|
ConfigEnv,
|
||||||
@ -428,6 +439,7 @@ pub fn create_default_context() -> EngineState {
|
|||||||
// Deprecated
|
// Deprecated
|
||||||
bind_command! {
|
bind_command! {
|
||||||
HashBase64,
|
HashBase64,
|
||||||
|
Source,
|
||||||
StrDatetimeDeprecated,
|
StrDatetimeDeprecated,
|
||||||
StrDecimalDeprecated,
|
StrDecimalDeprecated,
|
||||||
StrIntDeprecated,
|
StrIntDeprecated,
|
||||||
|
@ -5,11 +5,14 @@ use std::collections::HashMap;
|
|||||||
/// subcommands like `foo bar` where `foo` is still a valid command.
|
/// subcommands like `foo bar` where `foo` is still a valid command.
|
||||||
/// For those, it's currently easiest to have a "stub" command that just returns an error.
|
/// For those, it's currently easiest to have a "stub" command that just returns an error.
|
||||||
pub fn deprecated_commands() -> HashMap<String, String> {
|
pub fn deprecated_commands() -> HashMap<String, String> {
|
||||||
let mut commands = HashMap::new();
|
HashMap::from([
|
||||||
commands.insert("keep".to_string(), "take".to_string());
|
("keep".to_string(), "take".to_string()),
|
||||||
commands.insert("match".to_string(), "find".to_string());
|
("match".to_string(), "find".to_string()),
|
||||||
commands.insert("nth".to_string(), "select".to_string());
|
("nth".to_string(), "select".to_string()),
|
||||||
commands.insert("pivot".to_string(), "transpose".to_string());
|
("pivot".to_string(), "transpose".to_string()),
|
||||||
commands.insert("unalias".to_string(), "hide".to_string());
|
("unalias".to_string(), "hide".to_string()),
|
||||||
commands
|
("all?".to_string(), "all".to_string()),
|
||||||
|
("any?".to_string(), "any".to_string()),
|
||||||
|
("empty?".to_string(), "is-empty".to_string()),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
mod deprecated_commands;
|
mod deprecated_commands;
|
||||||
mod hash_base64;
|
mod hash_base64;
|
||||||
|
mod source;
|
||||||
mod str_datetime;
|
mod str_datetime;
|
||||||
mod str_decimal;
|
mod str_decimal;
|
||||||
mod str_find_replace;
|
mod str_find_replace;
|
||||||
@ -7,6 +8,7 @@ mod str_int;
|
|||||||
|
|
||||||
pub use deprecated_commands::*;
|
pub use deprecated_commands::*;
|
||||||
pub use hash_base64::HashBase64;
|
pub use hash_base64::HashBase64;
|
||||||
|
pub use source::Source;
|
||||||
pub use str_datetime::StrDatetimeDeprecated;
|
pub use str_datetime::StrDatetimeDeprecated;
|
||||||
pub use str_decimal::StrDecimalDeprecated;
|
pub use str_decimal::StrDecimalDeprecated;
|
||||||
pub use str_find_replace::StrFindReplaceDeprecated;
|
pub use str_find_replace::StrFindReplaceDeprecated;
|
||||||
|
@ -28,7 +28,7 @@ impl Command for Source {
|
|||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"This command is a parser keyword. For details, check:
|
r#"This command is a parser keyword. For details, check:
|
||||||
https://www.nushell.sh/book/thinking_in_nushell.html"#
|
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_parser_keyword(&self) -> bool {
|
fn is_parser_keyword(&self) -> bool {
|
@ -58,7 +58,7 @@ impl Command for ConfigEnv {
|
|||||||
nu_config.push("env.nu");
|
nu_config.push("env.nu");
|
||||||
|
|
||||||
let name = Spanned {
|
let name = Spanned {
|
||||||
item: get_editor(engine_state, stack),
|
item: get_editor(engine_state, stack)?,
|
||||||
span: Span { start: 0, end: 0 },
|
span: Span { start: 0, end: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,6 +70,7 @@ impl Command for ConfigEnv {
|
|||||||
let command = ExternalCommand {
|
let command = ExternalCommand {
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
|
arg_keep_raw: vec![false],
|
||||||
redirect_stdout: false,
|
redirect_stdout: false,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
env_vars: env_vars_str,
|
env_vars: env_vars_str,
|
||||||
|
@ -58,7 +58,7 @@ impl Command for ConfigNu {
|
|||||||
nu_config.push("config.nu");
|
nu_config.push("config.nu");
|
||||||
|
|
||||||
let name = Spanned {
|
let name = Spanned {
|
||||||
item: get_editor(engine_state, stack),
|
item: get_editor(engine_state, stack)?,
|
||||||
span: Span { start: 0, end: 0 },
|
span: Span { start: 0, end: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,6 +70,7 @@ impl Command for ConfigNu {
|
|||||||
let command = ExternalCommand {
|
let command = ExternalCommand {
|
||||||
name,
|
name,
|
||||||
args,
|
args,
|
||||||
|
arg_keep_raw: vec![false],
|
||||||
redirect_stdout: false,
|
redirect_stdout: false,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
env_vars: env_vars_str,
|
env_vars: env_vars_str,
|
||||||
|
15
crates/nu-command/src/env/config/utils.rs
vendored
15
crates/nu-command/src/env/config/utils.rs
vendored
@ -1,17 +1,20 @@
|
|||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
|
|
||||||
pub(crate) fn get_editor(engine_state: &EngineState, stack: &mut Stack) -> String {
|
pub(crate) fn get_editor(
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
) -> Result<String, nu_protocol::ShellError> {
|
||||||
let config = engine_state.get_config();
|
let config = engine_state.get_config();
|
||||||
let env_vars = stack.get_env_vars(engine_state);
|
let env_vars = stack.get_env_vars(engine_state);
|
||||||
if !config.buffer_editor.is_empty() {
|
if !config.buffer_editor.is_empty() {
|
||||||
config.buffer_editor.clone()
|
Ok(config.buffer_editor.clone())
|
||||||
} else if let Some(value) = env_vars.get("EDITOR") {
|
} else if let Some(value) = env_vars.get("EDITOR") {
|
||||||
value.as_string().expect("Unknown type")
|
value.as_string()
|
||||||
} else if let Some(value) = env_vars.get("VISUAL") {
|
} else if let Some(value) = env_vars.get("VISUAL") {
|
||||||
value.as_string().expect("Unknown type")
|
value.as_string()
|
||||||
} else if cfg!(target_os = "windows") {
|
} else if cfg!(target_os = "windows") {
|
||||||
"notepad".to_string()
|
Ok("notepad".to_string())
|
||||||
} else {
|
} else {
|
||||||
"nano".to_string()
|
Ok("nano".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
crates/nu-command/src/env/env_command.rs
vendored
2
crates/nu-command/src/env/env_command.rs
vendored
@ -75,7 +75,7 @@ impl Command for Env {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Check whether the env variable `MY_ENV_ABC` exists",
|
description: "Check whether the env variable `MY_ENV_ABC` exists",
|
||||||
example: r#"env | any? name == MY_ENV_ABC"#,
|
example: r#"env | any name == MY_ENV_ABC"#,
|
||||||
result: Some(Value::test_bool(false)),
|
result: Some(Value::test_bool(false)),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
|
74
crates/nu-command/src/env/export_env.rs
vendored
Normal file
74
crates/nu-command/src/env/export_env.rs
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
use nu_engine::{eval_block, redirect_env, CallExt};
|
||||||
|
use nu_protocol::{
|
||||||
|
ast::Call,
|
||||||
|
engine::{CaptureBlock, Command, EngineState, Stack},
|
||||||
|
Category, Example, PipelineData, Signature, Span, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ExportEnv;
|
||||||
|
|
||||||
|
impl Command for ExportEnv {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"export-env"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("export-env")
|
||||||
|
.required(
|
||||||
|
"block",
|
||||||
|
SyntaxShape::Block(Some(vec![])),
|
||||||
|
"the block to run to set the environment",
|
||||||
|
)
|
||||||
|
.category(Category::Env)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Run a block and preserve its environment in a current scope."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
caller_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
|
let capture_block: CaptureBlock = call.req(engine_state, caller_stack, 0)?;
|
||||||
|
let block = engine_state.get_block(capture_block.block_id);
|
||||||
|
let mut callee_stack = caller_stack.captures_to_stack(&capture_block.captures);
|
||||||
|
|
||||||
|
let _ = eval_block(
|
||||||
|
engine_state,
|
||||||
|
&mut callee_stack,
|
||||||
|
block,
|
||||||
|
input,
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
|
);
|
||||||
|
|
||||||
|
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||||
|
|
||||||
|
Ok(PipelineData::new(call.head))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Set an environment",
|
||||||
|
example: r#"export-env { let-env SPAM = 'eggs' }; $env.SPAM"#,
|
||||||
|
result: Some(Value::string("eggs", Span::test_data())),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_examples() {
|
||||||
|
use crate::test_examples;
|
||||||
|
|
||||||
|
test_examples(ExportEnv {})
|
||||||
|
}
|
||||||
|
}
|
19
crates/nu-command/src/env/let_env.rs
vendored
19
crates/nu-command/src/env/let_env.rs
vendored
@ -1,7 +1,9 @@
|
|||||||
use nu_engine::{current_dir, eval_expression_with_input, CallExt};
|
use nu_engine::{current_dir, eval_expression_with_input, CallExt};
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Value};
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LetEnv;
|
pub struct LetEnv;
|
||||||
@ -34,7 +36,7 @@ impl Command for LetEnv {
|
|||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
// TODO: find and require the crossplatform restrictions on environment names
|
// TODO: find and require the crossplatform restrictions on environment names
|
||||||
let env_var = call.req(engine_state, stack, 0)?;
|
let env_var: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let keyword_expr = call
|
let keyword_expr = call
|
||||||
.positional_nth(1)
|
.positional_nth(1)
|
||||||
@ -47,19 +49,26 @@ impl Command for LetEnv {
|
|||||||
.0
|
.0
|
||||||
.into_value(call.head);
|
.into_value(call.head);
|
||||||
|
|
||||||
if env_var == "PWD" {
|
if env_var.item == "FILE_PWD" {
|
||||||
|
return Err(ShellError::AutomaticEnvVarSetManually(
|
||||||
|
env_var.item,
|
||||||
|
env_var.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if env_var.item == "PWD" {
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let rhs = rhs.as_string()?;
|
let rhs = rhs.as_string()?;
|
||||||
let rhs = nu_path::expand_path_with(rhs, cwd);
|
let rhs = nu_path::expand_path_with(rhs, cwd);
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
env_var,
|
env_var.item,
|
||||||
Value::String {
|
Value::String {
|
||||||
val: rhs.to_string_lossy().to_string(),
|
val: rhs.to_string_lossy().to_string(),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
stack.add_env_var(env_var, rhs);
|
stack.add_env_var(env_var.item, rhs);
|
||||||
}
|
}
|
||||||
Ok(PipelineData::new(call.head))
|
Ok(PipelineData::new(call.head))
|
||||||
}
|
}
|
||||||
|
8
crates/nu-command/src/env/load_env.rs
vendored
8
crates/nu-command/src/env/load_env.rs
vendored
@ -38,6 +38,10 @@ impl Command for LoadEnv {
|
|||||||
match arg {
|
match arg {
|
||||||
Some((cols, vals)) => {
|
Some((cols, vals)) => {
|
||||||
for (env_var, rhs) in cols.into_iter().zip(vals) {
|
for (env_var, rhs) in cols.into_iter().zip(vals) {
|
||||||
|
if env_var == "FILE_PWD" {
|
||||||
|
return Err(ShellError::AutomaticEnvVarSetManually(env_var, call.head));
|
||||||
|
}
|
||||||
|
|
||||||
if env_var == "PWD" {
|
if env_var == "PWD" {
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let rhs = rhs.as_string()?;
|
let rhs = rhs.as_string()?;
|
||||||
@ -58,6 +62,10 @@ impl Command for LoadEnv {
|
|||||||
None => match input {
|
None => match input {
|
||||||
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
|
PipelineData::Value(Value::Record { cols, vals, .. }, ..) => {
|
||||||
for (env_var, rhs) in cols.into_iter().zip(vals) {
|
for (env_var, rhs) in cols.into_iter().zip(vals) {
|
||||||
|
if env_var == "FILE_PWD" {
|
||||||
|
return Err(ShellError::AutomaticEnvVarSetManually(env_var, call.head));
|
||||||
|
}
|
||||||
|
|
||||||
if env_var == "PWD" {
|
if env_var == "PWD" {
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let rhs = rhs.as_string()?;
|
let rhs = rhs.as_string()?;
|
||||||
|
4
crates/nu-command/src/env/mod.rs
vendored
4
crates/nu-command/src/env/mod.rs
vendored
@ -1,7 +1,9 @@
|
|||||||
mod config;
|
mod config;
|
||||||
mod env_command;
|
mod env_command;
|
||||||
|
mod export_env;
|
||||||
mod let_env;
|
mod let_env;
|
||||||
mod load_env;
|
mod load_env;
|
||||||
|
mod source_env;
|
||||||
mod with_env;
|
mod with_env;
|
||||||
|
|
||||||
pub use config::ConfigEnv;
|
pub use config::ConfigEnv;
|
||||||
@ -9,6 +11,8 @@ pub use config::ConfigMeta;
|
|||||||
pub use config::ConfigNu;
|
pub use config::ConfigNu;
|
||||||
pub use config::ConfigReset;
|
pub use config::ConfigReset;
|
||||||
pub use env_command::Env;
|
pub use env_command::Env;
|
||||||
|
pub use export_env::ExportEnv;
|
||||||
pub use let_env::LetEnv;
|
pub use let_env::LetEnv;
|
||||||
pub use load_env::LoadEnv;
|
pub use load_env::LoadEnv;
|
||||||
|
pub use source_env::SourceEnv;
|
||||||
pub use with_env::WithEnv;
|
pub use with_env::WithEnv;
|
||||||
|
92
crates/nu-command/src/env/source_env.rs
vendored
Normal file
92
crates/nu-command/src/env/source_env.rs
vendored
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use nu_engine::{eval_block, find_in_dirs_env, redirect_env, CallExt};
|
||||||
|
use nu_protocol::ast::Call;
|
||||||
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::{
|
||||||
|
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Source a file for environment variables.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SourceEnv;
|
||||||
|
|
||||||
|
impl Command for SourceEnv {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"source-env"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("source-env")
|
||||||
|
.required(
|
||||||
|
"filename",
|
||||||
|
SyntaxShape::String, // type is string to avoid automatically canonicalizing the path
|
||||||
|
"the filepath to the script file to source the environment from",
|
||||||
|
)
|
||||||
|
.category(Category::Core)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Source the environment from a source file into the current environment."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
caller_stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let source_filename: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
|
||||||
|
|
||||||
|
// Note: this hidden positional is the block_id that corresponded to the 0th position
|
||||||
|
// it is put here by the parser
|
||||||
|
let block_id: i64 = call.req(engine_state, caller_stack, 1)?;
|
||||||
|
|
||||||
|
// Set the currently evaluated directory (file-relative PWD)
|
||||||
|
let mut parent = if let Some(path) =
|
||||||
|
find_in_dirs_env(&source_filename.item, engine_state, caller_stack)?
|
||||||
|
{
|
||||||
|
PathBuf::from(&path)
|
||||||
|
} else {
|
||||||
|
return Err(ShellError::FileNotFound(source_filename.span));
|
||||||
|
};
|
||||||
|
parent.pop();
|
||||||
|
|
||||||
|
let file_pwd = Value::String {
|
||||||
|
val: parent.to_string_lossy().to_string(),
|
||||||
|
span: call.head,
|
||||||
|
};
|
||||||
|
|
||||||
|
caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||||
|
|
||||||
|
// Evaluate the block
|
||||||
|
let block = engine_state.get_block(block_id as usize).clone();
|
||||||
|
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
||||||
|
|
||||||
|
let result = eval_block(
|
||||||
|
engine_state,
|
||||||
|
&mut callee_stack,
|
||||||
|
&block,
|
||||||
|
input,
|
||||||
|
call.redirect_stdout,
|
||||||
|
call.redirect_stderr,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Merge the block's environment to the current stack
|
||||||
|
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||||
|
|
||||||
|
// Remove the file-relative PWD
|
||||||
|
caller_stack.remove_env_var(engine_state, "FILE_PWD");
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
vec![Example {
|
||||||
|
description: "Sources the environment from foo.nu in the current context",
|
||||||
|
example: r#"source-env foo.nu"#,
|
||||||
|
result: None,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
@ -13,8 +13,8 @@ use crate::To;
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use super::{
|
use super::{
|
||||||
Ansi, Date, From, If, Into, Math, Path, Random, Split, SplitColumn, SplitRow, Str, StrCollect,
|
Ansi, Date, From, If, Into, LetEnv, Math, Path, Random, Split, SplitColumn, SplitRow, Str,
|
||||||
StrLength, StrReplace, Url, Wrap,
|
StrCollect, StrLength, StrReplace, Url, Wrap,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -47,6 +47,7 @@ pub fn test_examples(cmd: impl Command + 'static) {
|
|||||||
working_set.add_decl(Box::new(Url));
|
working_set.add_decl(Box::new(Url));
|
||||||
working_set.add_decl(Box::new(Ansi));
|
working_set.add_decl(Box::new(Ansi));
|
||||||
working_set.add_decl(Box::new(Wrap));
|
working_set.add_decl(Box::new(Wrap));
|
||||||
|
working_set.add_decl(Box::new(LetEnv));
|
||||||
|
|
||||||
use super::Echo;
|
use super::Echo;
|
||||||
working_set.add_decl(Box::new(Echo));
|
working_set.add_decl(Box::new(Echo));
|
||||||
|
@ -20,7 +20,7 @@ impl Command for IsAdmin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["root", "admin", "administrator", "superuser", "supervisor"]
|
vec!["root", "administrator", "superuser", "supervisor"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
@ -20,7 +20,7 @@ impl Command for Cd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["cd", "change", "directory", "dir", "folder", "switch"]
|
vec!["change", "directory", "dir", "folder", "switch"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> nu_protocol::Signature {
|
fn signature(&self) -> nu_protocol::Signature {
|
||||||
|
@ -36,7 +36,7 @@ impl Command for Cp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["cp", "copy", "file", "files"]
|
vec!["copy", "file", "files"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
@ -50,7 +50,7 @@ impl Command for Cp {
|
|||||||
)
|
)
|
||||||
.switch(
|
.switch(
|
||||||
"verbose",
|
"verbose",
|
||||||
"do copy in verbose mode (default:false)",
|
"show successful copies in addition to failed copies (default:false)",
|
||||||
Some('v'),
|
Some('v'),
|
||||||
)
|
)
|
||||||
// TODO: add back in additional features
|
// TODO: add back in additional features
|
||||||
@ -285,7 +285,11 @@ impl Command for Cp {
|
|||||||
if verbose {
|
if verbose {
|
||||||
Ok(result.into_iter().into_pipeline_data(ctrlc))
|
Ok(result.into_iter().into_pipeline_data(ctrlc))
|
||||||
} else {
|
} else {
|
||||||
Ok(PipelineData::new(span))
|
// filter to only errors
|
||||||
|
Ok(result
|
||||||
|
.into_iter()
|
||||||
|
.filter(|v| matches!(v, Value::Error { .. }))
|
||||||
|
.into_pipeline_data(ctrlc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,9 +352,22 @@ fn copy_file(src: PathBuf, dst: PathBuf, span: Span) -> Value {
|
|||||||
let msg = format!("copied {:} to {:}", src.display(), dst.display());
|
let msg = format!("copied {:} to {:}", src.display(), dst.display());
|
||||||
Value::String { val: msg, span }
|
Value::String { val: msg, span }
|
||||||
}
|
}
|
||||||
Err(e) => Value::Error {
|
Err(e) => {
|
||||||
error: ShellError::FileNotFoundCustom(format!("copy file {src:?} failed: {e}"), span),
|
let message = format!("copy file {src:?} failed: {e}");
|
||||||
},
|
|
||||||
|
use std::io::ErrorKind;
|
||||||
|
let shell_error = match e.kind() {
|
||||||
|
ErrorKind::NotFound => ShellError::FileNotFoundCustom(message, span),
|
||||||
|
ErrorKind::PermissionDenied => ShellError::PermissionDeniedError(message, span),
|
||||||
|
ErrorKind::Interrupted => ShellError::IOInterrupted(message, span),
|
||||||
|
ErrorKind::OutOfMemory => ShellError::OutOfMemoryError(message, span),
|
||||||
|
// TODO: handle ExecutableFileBusy etc. when io_error_more is stabilized
|
||||||
|
// https://github.com/rust-lang/rust/issues/86442
|
||||||
|
_ => ShellError::IOErrorSpanned(message, span),
|
||||||
|
};
|
||||||
|
|
||||||
|
Value::Error { error: shell_error }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ impl Command for Glob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
vec!["glob", "files", "folders", "list", "ls"]
|
vec!["pattern", "files", "folders", "list", "ls"]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user