forked from extern/nushell
Compare commits
1 Commits
main
...
revert-113
Author | SHA1 | Date | |
---|---|---|---|
|
286a6b021c |
1
.github/.typos.toml
vendored
1
.github/.typos.toml
vendored
@ -12,4 +12,3 @@ IIF = "IIF"
|
|||||||
numer = "numer"
|
numer = "numer"
|
||||||
ratatui = "ratatui"
|
ratatui = "ratatui"
|
||||||
doas = "doas"
|
doas = "doas"
|
||||||
wheres = "wheres"
|
|
||||||
|
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@ -92,17 +92,6 @@ jobs:
|
|||||||
- name: Tests
|
- name: Tests
|
||||||
run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
|
run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
|
||||||
|
|
||||||
- name: Check for clean repo
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
|
||||||
echo "there are changes";
|
|
||||||
git status --porcelain
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "no changes in working directory";
|
|
||||||
fi
|
|
||||||
|
|
||||||
std-lib-and-python-virtualenv:
|
std-lib-and-python-virtualenv:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
@ -140,17 +129,6 @@ jobs:
|
|||||||
run: nu scripts/test_virtualenv.nu
|
run: nu scripts/test_virtualenv.nu
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Check for clean repo
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
|
||||||
echo "there are changes";
|
|
||||||
git status --porcelain
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "no changes in working directory";
|
|
||||||
fi
|
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
@ -172,14 +150,3 @@ jobs:
|
|||||||
|
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: cargo test --profile ci --package nu_plugin_*
|
run: cargo test --profile ci --package nu_plugin_*
|
||||||
|
|
||||||
- name: Check for clean repo
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
if [ -n "$(git status --porcelain)" ]; then
|
|
||||||
echo "there are changes";
|
|
||||||
git status --porcelain
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "no changes in working directory";
|
|
||||||
fi
|
|
||||||
|
2
.github/workflows/nightly-build.yml
vendored
2
.github/workflows/nightly-build.yml
vendored
@ -119,7 +119,7 @@ jobs:
|
|||||||
os: ubuntu-20.04
|
os: ubuntu-20.04
|
||||||
target_rustflags: ''
|
target_rustflags: ''
|
||||||
- target: riscv64gc-unknown-linux-gnu
|
- target: riscv64gc-unknown-linux-gnu
|
||||||
os: ubuntu-latest
|
os: ubuntu-20.04
|
||||||
target_rustflags: ''
|
target_rustflags: ''
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
8
.github/workflows/release-pkg.nu
vendored
8
.github/workflows/release-pkg.nu
vendored
@ -82,8 +82,8 @@ print $'Start building ($bin)...'; hr-line
|
|||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
# Build for Ubuntu and macOS
|
# Build for Ubuntu and macOS
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
if $os in [$USE_UBUNTU, 'macos-latest', 'ubuntu-latest'] {
|
if $os in [$USE_UBUNTU, 'macos-latest'] {
|
||||||
if $os starts-with ubuntu {
|
if $os == $USE_UBUNTU {
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt-get install libxcb-composite0-dev -y
|
sudo apt-get install libxcb-composite0-dev -y
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ if $os in [$USE_UBUNTU, 'macos-latest', 'ubuntu-latest'] {
|
|||||||
_ => {
|
_ => {
|
||||||
# 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
|
||||||
if $os starts-with ubuntu { sudo apt install musl-tools -y }
|
if $os == $USE_UBUNTU { sudo apt install musl-tools -y }
|
||||||
cargo-build-nu $flags
|
cargo-build-nu $flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -153,7 +153,7 @@ if ($ver | str trim | is-empty) {
|
|||||||
# Create a release archive and send it to output for the following steps
|
# Create a release archive and send it to output for the following steps
|
||||||
# ----------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------
|
||||||
cd $dist; print $'(char nl)Creating release archive...'; hr-line
|
cd $dist; print $'(char nl)Creating release archive...'; hr-line
|
||||||
if $os in [$USE_UBUNTU, 'macos-latest', 'ubuntu-latest'] {
|
if $os in [$USE_UBUNTU, 'macos-latest'] {
|
||||||
|
|
||||||
let files = (ls | get name)
|
let files = (ls | get name)
|
||||||
let dest = if $env.RELEASE_TYPE == 'full' { $'($bin)-($version)-($FULL_NAME)' } else { $'($bin)-($version)-($target)' }
|
let dest = if $env.RELEASE_TYPE == 'full' { $'($bin)-($version)-($FULL_NAME)' } else { $'($bin)-($version)-($target)' }
|
||||||
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -66,7 +66,7 @@ jobs:
|
|||||||
os: ubuntu-20.04
|
os: ubuntu-20.04
|
||||||
target_rustflags: ''
|
target_rustflags: ''
|
||||||
- target: riscv64gc-unknown-linux-gnu
|
- target: riscv64gc-unknown-linux-gnu
|
||||||
os: ubuntu-latest
|
os: ubuntu-20.04
|
||||||
target_rustflags: ''
|
target_rustflags: ''
|
||||||
|
|
||||||
runs-on: ${{matrix.os}}
|
runs-on: ${{matrix.os}}
|
||||||
|
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
@ -10,6 +10,6 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Check spelling
|
- name: Check spelling
|
||||||
uses: crate-ci/typos@v1.17.0
|
uses: crate-ci/typos@v1.16.24
|
||||||
with:
|
with:
|
||||||
config: ./.github/.typos.toml
|
config: ./.github/.typos.toml
|
||||||
|
179
Cargo.lock
generated
179
Cargo.lock
generated
@ -1252,6 +1252,16 @@ version = "0.1.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fancy-regex"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fancy-regex"
|
name = "fancy-regex"
|
||||||
version = "0.12.0"
|
version = "0.12.0"
|
||||||
@ -1281,7 +1291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5"
|
checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1788,7 +1798,7 @@ dependencies = [
|
|||||||
"iana-time-zone-haiku",
|
"iana-time-zone-haiku",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-core 0.51.1",
|
"windows-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1802,9 +1812,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ical"
|
name = "ical"
|
||||||
version = "0.9.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26393c372d4c4d51616084afe36c0b44e4467febaa6f91f11f789094b4863bf9"
|
checksum = "356d82bd58997815d55ea6f9081bd4cac149e50ca943f7a4f7c050fec7271c1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
@ -1884,6 +1894,17 @@ version = "0.3.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0508c56cfe9bfd5dfeb0c22ab9a6abfda2f27bdca422132e494266351ed8d83c"
|
checksum = "0508c56cfe9bfd5dfeb0c22ab9a6abfda2f27bdca422132e494266351ed8d83c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-docker"
|
name = "is-docker"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1900,7 +1921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1953,15 +1974,6 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itertools"
|
|
||||||
version = "0.12.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
|
||||||
dependencies = [
|
|
||||||
"either",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
@ -2222,6 +2234,12 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.12"
|
version = "0.4.12"
|
||||||
@ -2255,9 +2273,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lscolors"
|
name = "lscolors"
|
||||||
version = "0.16.0"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab0b209ec3976527806024406fe765474b9a1750a0ed4b8f0372364741f50e7b"
|
checksum = "bf7015a04103ad78abb77e4b79ed151e767922d1cfde5f62640471c629a2320d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
]
|
]
|
||||||
@ -2276,9 +2294,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lsp-types"
|
name = "lsp-types"
|
||||||
version = "0.95.0"
|
version = "0.94.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984"
|
checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"serde",
|
"serde",
|
||||||
@ -2659,7 +2677,7 @@ version = "0.88.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"fancy-regex",
|
"fancy-regex 0.11.0",
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"is_executable",
|
"is_executable",
|
||||||
"log",
|
"log",
|
||||||
@ -2680,7 +2698,7 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"reedline",
|
"reedline",
|
||||||
"rstest",
|
"rstest",
|
||||||
"sysinfo 0.30.4",
|
"sysinfo",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"uuid",
|
"uuid",
|
||||||
"which 5.0.0",
|
"which 5.0.0",
|
||||||
@ -2708,7 +2726,7 @@ version = "0.88.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-tz",
|
"chrono-tz",
|
||||||
"fancy-regex",
|
"fancy-regex 0.12.0",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"nu-cmd-lang",
|
"nu-cmd-lang",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -2730,7 +2748,7 @@ name = "nu-cmd-extra"
|
|||||||
version = "0.88.2"
|
version = "0.88.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"fancy-regex",
|
"fancy-regex 0.11.0",
|
||||||
"heck",
|
"heck",
|
||||||
"htmlescape",
|
"htmlescape",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
@ -2754,8 +2772,8 @@ dependencies = [
|
|||||||
name = "nu-cmd-lang"
|
name = "nu-cmd-lang"
|
||||||
version = "0.88.2"
|
version = "0.88.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fancy-regex",
|
"fancy-regex 0.11.0",
|
||||||
"itertools 0.12.0",
|
"itertools 0.11.0",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
"nu-parser",
|
"nu-parser",
|
||||||
@ -2798,7 +2816,7 @@ dependencies = [
|
|||||||
"dirs-next",
|
"dirs-next",
|
||||||
"dtparse",
|
"dtparse",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"fancy-regex",
|
"fancy-regex 0.11.0",
|
||||||
"filesize",
|
"filesize",
|
||||||
"filetime",
|
"filetime",
|
||||||
"fs_extra",
|
"fs_extra",
|
||||||
@ -2806,7 +2824,7 @@ dependencies = [
|
|||||||
"human-date-parser",
|
"human-date-parser",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"itertools 0.12.0",
|
"itertools 0.11.0",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"lscolors",
|
"lscolors",
|
||||||
@ -2859,7 +2877,7 @@ dependencies = [
|
|||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"sha2",
|
"sha2",
|
||||||
"sysinfo 0.30.4",
|
"sysinfo",
|
||||||
"tabled",
|
"tabled",
|
||||||
"terminal_size 0.3.0",
|
"terminal_size 0.3.0",
|
||||||
"titlecase",
|
"titlecase",
|
||||||
@ -2876,7 +2894,7 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
"wax",
|
"wax",
|
||||||
"which 5.0.0",
|
"which 5.0.0",
|
||||||
"windows 0.52.0",
|
"windows 0.48.0",
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2907,7 +2925,7 @@ dependencies = [
|
|||||||
"nu-utils",
|
"nu-utils",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"strip-ansi-escapes",
|
"strip-ansi-escapes",
|
||||||
"terminal_size 0.3.0",
|
"terminal_size 0.2.6",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2955,7 +2973,7 @@ version = "0.88.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytesize",
|
"bytesize",
|
||||||
"chrono",
|
"chrono",
|
||||||
"itertools 0.12.0",
|
"itertools 0.11.0",
|
||||||
"log",
|
"log",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
"nu-path",
|
"nu-path",
|
||||||
@ -3002,7 +3020,7 @@ dependencies = [
|
|||||||
"byte-unit",
|
"byte-unit",
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-humanize",
|
"chrono-humanize",
|
||||||
"fancy-regex",
|
"fancy-regex 0.11.0",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lru",
|
"lru",
|
||||||
"miette",
|
"miette",
|
||||||
@ -3043,15 +3061,15 @@ dependencies = [
|
|||||||
"ntapi",
|
"ntapi",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"procfs",
|
"procfs",
|
||||||
"sysinfo 0.30.4",
|
"sysinfo",
|
||||||
"windows 0.52.0",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-table"
|
name = "nu-table"
|
||||||
version = "0.88.2"
|
version = "0.88.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fancy-regex",
|
"fancy-regex 0.11.0",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"nu-color-config",
|
"nu-color-config",
|
||||||
"nu-engine",
|
"nu-engine",
|
||||||
@ -3396,9 +3414,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-src"
|
name = "openssl-src"
|
||||||
version = "300.1.6+3.1.4"
|
version = "300.2.1+3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085"
|
checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
@ -4072,7 +4090,7 @@ dependencies = [
|
|||||||
"polars-error",
|
"polars-error",
|
||||||
"rayon",
|
"rayon",
|
||||||
"smartstring",
|
"smartstring",
|
||||||
"sysinfo 0.29.11",
|
"sysinfo",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4177,7 +4195,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"procfs-core",
|
"procfs-core",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4374,13 +4392,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reedline"
|
name = "reedline"
|
||||||
version = "0.27.1"
|
version = "0.27.0"
|
||||||
source = "git+https://github.com/nushell/reedline.git?branch=main#b68ce33c750b700bb4f8adccbc2e160d1b7c8742"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147452ce32c2cba4900b410f1d18b9ca29b67301a8eed76676e42e720d71cc39"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"fd-lock",
|
"fd-lock",
|
||||||
"itertools 0.12.0",
|
"itertools 0.10.5",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"serde",
|
"serde",
|
||||||
@ -4627,6 +4646,20 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys 0.3.8",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.28"
|
version = "0.38.28"
|
||||||
@ -4636,7 +4669,7 @@ dependencies = [
|
|||||||
"bitflags 2.4.1",
|
"bitflags 2.4.1",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys 0.4.12",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4868,9 +4901,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shadow-rs"
|
name = "shadow-rs"
|
||||||
version = "0.26.0"
|
version = "0.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "878cb1e3162d98ee1016b832efbb683ad6302b462a2894c54f488dc0bd96f11c"
|
checksum = "f9198caff1c94f1a5df6664bddbc379896b51b98a55b0b3fedcb23078fe00c77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_format",
|
"const_format",
|
||||||
"is_debug",
|
"is_debug",
|
||||||
@ -5243,20 +5276,6 @@ name = "sysinfo"
|
|||||||
version = "0.29.11"
|
version = "0.29.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
|
checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666"
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
"ntapi",
|
|
||||||
"once_cell",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sysinfo"
|
|
||||||
version = "0.30.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "717570a2533606f81f8cfac02a1915a620e725ffb78f6fc5e259769a4d747407"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
@ -5264,7 +5283,7 @@ dependencies = [
|
|||||||
"ntapi",
|
"ntapi",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rayon",
|
"rayon",
|
||||||
"windows 0.52.0",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5294,7 +5313,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5328,13 +5347,23 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal_size"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237"
|
||||||
|
dependencies = [
|
||||||
|
"rustix 0.37.27",
|
||||||
|
"windows-sys 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "terminal_size"
|
name = "terminal_size"
|
||||||
version = "0.3.0"
|
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 = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5718,9 +5747,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unsafe-libyaml"
|
name = "unsafe-libyaml"
|
||||||
version = "0.2.10"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
|
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ureq"
|
name = "ureq"
|
||||||
@ -6042,7 +6071,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"home",
|
"home",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6054,7 +6083,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"home",
|
"home",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -6109,12 +6138,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.52.0"
|
version = "0.48.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core 0.52.0",
|
"windows-targets 0.48.5",
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6126,15 +6154,6 @@ dependencies = [
|
|||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-core"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
@ -6369,8 +6388,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995"
|
checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys 0.4.12",
|
||||||
"rustix",
|
"rustix 0.38.28",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -33,11 +33,7 @@ members = [
|
|||||||
"crates/nu-cmd-lang",
|
"crates/nu-cmd-lang",
|
||||||
"crates/nu-cmd-dataframe",
|
"crates/nu-cmd-dataframe",
|
||||||
"crates/nu-command",
|
"crates/nu-command",
|
||||||
"crates/nu-color-config",
|
|
||||||
"crates/nu-explore",
|
|
||||||
"crates/nu-json",
|
|
||||||
"crates/nu-lsp",
|
"crates/nu-lsp",
|
||||||
"crates/nu-pretty-hex",
|
|
||||||
"crates/nu-protocol",
|
"crates/nu-protocol",
|
||||||
"crates/nu-plugin",
|
"crates/nu-plugin",
|
||||||
"crates/nu_plugin_inc",
|
"crates/nu_plugin_inc",
|
||||||
@ -47,8 +43,6 @@ members = [
|
|||||||
"crates/nu_plugin_custom_values",
|
"crates/nu_plugin_custom_values",
|
||||||
"crates/nu_plugin_formats",
|
"crates/nu_plugin_formats",
|
||||||
"crates/nu-std",
|
"crates/nu-std",
|
||||||
"crates/nu-table",
|
|
||||||
"crates/nu-term-grid",
|
|
||||||
"crates/nu-utils",
|
"crates/nu-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -74,7 +68,6 @@ nu-table = { path = "./crates/nu-table", version = "0.88.2" }
|
|||||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.88.2" }
|
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.88.2" }
|
||||||
nu-std = { path = "./crates/nu-std", version = "0.88.2" }
|
nu-std = { path = "./crates/nu-std", version = "0.88.2" }
|
||||||
nu-utils = { path = "./crates/nu-utils", version = "0.88.2" }
|
nu-utils = { path = "./crates/nu-utils", version = "0.88.2" }
|
||||||
|
|
||||||
nu-ansi-term = "0.49.0"
|
nu-ansi-term = "0.49.0"
|
||||||
reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
|
reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
|
||||||
|
|
||||||
@ -173,7 +166,7 @@ bench = false
|
|||||||
# To use a development version of a dependency please use a global override here
|
# To use a development version of a dependency please use a global override here
|
||||||
# changing versions in each sub-crate of the workspace is tedious
|
# changing versions in each sub-crate of the workspace is tedious
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
reedline = { git = "https://github.com/nushell/reedline.git", branch = "main" }
|
# reedline = { git = "https://github.com/nushell/reedline.git", branch = "main" }
|
||||||
# nu-ansi-term = {git = "https://github.com/nushell/nu-ansi-term.git", branch = "main"}
|
# nu-ansi-term = {git = "https://github.com/nushell/nu-ansi-term.git", branch = "main"}
|
||||||
# uu_cp = { git = "https://github.com/uutils/coreutils.git", branch = "main" }
|
# uu_cp = { git = "https://github.com/uutils/coreutils.git", branch = "main" }
|
||||||
|
|
||||||
|
@ -24,9 +24,13 @@ fn canonicalize_path(engine_state: &EngineState, path: &Path) -> PathBuf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_home_path(engine_state: &EngineState) -> PathBuf {
|
fn get_home_path(engine_state: &EngineState) -> PathBuf {
|
||||||
nu_path::home_dir()
|
let home_path = if let Some(path) = nu_path::home_dir() {
|
||||||
.map(|path| canonicalize_path(engine_state, &path))
|
let canon_home_path = canonicalize_path(engine_state, &path);
|
||||||
.unwrap_or_default()
|
canon_home_path
|
||||||
|
} else {
|
||||||
|
std::path::PathBuf::new()
|
||||||
|
};
|
||||||
|
home_path
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: All benchmarks live in this 1 file to speed up build times when benchmarking.
|
// FIXME: All benchmarks live in this 1 file to speed up build times when benchmarking.
|
||||||
|
@ -29,7 +29,7 @@ reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
|
|||||||
|
|
||||||
chrono = { default-features = false, features = ["std"], version = "0.4" }
|
chrono = { default-features = false, features = ["std"], version = "0.4" }
|
||||||
crossterm = "0.27"
|
crossterm = "0.27"
|
||||||
fancy-regex = "0.12"
|
fancy-regex = "0.11"
|
||||||
fuzzy-matcher = "0.3"
|
fuzzy-matcher = "0.3"
|
||||||
is_executable = "1.0"
|
is_executable = "1.0"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
@ -37,7 +37,7 @@ miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
|||||||
once_cell = "1.18"
|
once_cell = "1.18"
|
||||||
percent-encoding = "2"
|
percent-encoding = "2"
|
||||||
pathdiff = "0.2"
|
pathdiff = "0.2"
|
||||||
sysinfo = "0.30"
|
sysinfo = "0.29"
|
||||||
unicode-segmentation = "1.10"
|
unicode-segmentation = "1.10"
|
||||||
uuid = { version = "1.6.0", features = ["v4"] }
|
uuid = { version = "1.6.0", features = ["v4"] }
|
||||||
which = "5.0.0"
|
which = "5.0.0"
|
||||||
|
@ -250,9 +250,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"
|
if prev_expr_str == b"use" || prev_expr_str == b"source-env"
|
||||||
|| prev_expr_str == b"overlay 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());
|
||||||
@ -354,9 +352,11 @@ impl NuCompleter {
|
|||||||
if let Some(external_result) = self.external_completion(
|
if let Some(external_result) = self.external_completion(
|
||||||
block_id, &spans, offset, new_span,
|
block_id, &spans, offset, new_span,
|
||||||
) {
|
) {
|
||||||
|
if !external_result.is_empty() {
|
||||||
return external_result;
|
return external_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for file completion
|
// Check for file completion
|
||||||
let mut completer =
|
let mut completer =
|
||||||
|
@ -22,10 +22,7 @@ fn complete_rec(
|
|||||||
Some(base) if matches(base, &entry_name, options) => {
|
Some(base) if matches(base, &entry_name, options) => {
|
||||||
let partial = &partial[1..];
|
let partial = &partial[1..];
|
||||||
if !partial.is_empty() || isdir {
|
if !partial.is_empty() || isdir {
|
||||||
completions.extend(complete_rec(partial, &path, options, dir, isdir));
|
completions.extend(complete_rec(partial, &path, options, dir, isdir))
|
||||||
if entry_name.eq(base) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
completions.push(path)
|
completions.push(path)
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use nu_protocol::{
|
|||||||
};
|
};
|
||||||
use reedline::Suggestion;
|
use reedline::Suggestion;
|
||||||
use std::{
|
use std::{
|
||||||
path::{is_separator, Path, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR},
|
path::{is_separator, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -91,22 +91,17 @@ impl Completer for DotNuCompletion {
|
|||||||
// and transform them into suggestions
|
// and transform them into suggestions
|
||||||
let output: Vec<Suggestion> = search_dirs
|
let output: Vec<Suggestion> = search_dirs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|search_dir| {
|
.flat_map(|it| {
|
||||||
let completions = file_path_completion(span, &partial, &search_dir, options);
|
file_path_completion(span, &partial, &it, options)
|
||||||
completions
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(move |it| {
|
.filter(|it| {
|
||||||
// Different base dir, so we list the .nu files or folders
|
// Different base dir, so we list the .nu files or folders
|
||||||
if !is_current_folder {
|
if !is_current_folder {
|
||||||
it.1.ends_with(".nu") || it.1.ends_with(SEP)
|
it.1.ends_with(".nu") || it.1.ends_with(SEP)
|
||||||
} else {
|
} else {
|
||||||
// Lib dirs, so we filter only the .nu files or directory modules
|
// Lib dirs, so we filter only the .nu files
|
||||||
if it.1.ends_with(SEP) {
|
|
||||||
Path::new(&search_dir).join(&it.1).join("mod.nu").exists()
|
|
||||||
} else {
|
|
||||||
it.1.ends_with(".nu")
|
it.1.ends_with(".nu")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.map(move |x| Suggestion {
|
.map(move |x| Suggestion {
|
||||||
value: x.1,
|
value: x.1,
|
||||||
|
@ -35,10 +35,6 @@ pub fn evaluate_commands(
|
|||||||
let mut working_set = StateWorkingSet::new(engine_state);
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
let output = parse(&mut working_set, None, commands.item.as_bytes(), false);
|
let output = parse(&mut working_set, None, commands.item.as_bytes(), false);
|
||||||
if let Some(warning) = working_set.parse_warnings.first() {
|
|
||||||
report_error(&working_set, warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(err) = working_set.parse_errors.first() {
|
if let Some(err) = working_set.parse_errors.first() {
|
||||||
report_error(&working_set, err);
|
report_error(&working_set, err);
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use crate::prompt_update::{POST_PROMPT_MARKER, PRE_PROMPT_MARKER};
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use nu_utils::enable_vt_processing;
|
use nu_utils::enable_vt_processing;
|
||||||
use reedline::DefaultPrompt;
|
use reedline::DefaultPrompt;
|
||||||
@ -12,7 +11,6 @@ use {
|
|||||||
/// Nushell prompt definition
|
/// Nushell prompt definition
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct NushellPrompt {
|
pub struct NushellPrompt {
|
||||||
shell_integration: bool,
|
|
||||||
left_prompt_string: Option<String>,
|
left_prompt_string: Option<String>,
|
||||||
right_prompt_string: Option<String>,
|
right_prompt_string: Option<String>,
|
||||||
default_prompt_indicator: Option<String>,
|
default_prompt_indicator: Option<String>,
|
||||||
@ -22,10 +20,15 @@ pub struct NushellPrompt {
|
|||||||
render_right_prompt_on_last_line: bool,
|
render_right_prompt_on_last_line: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for NushellPrompt {
|
||||||
|
fn default() -> Self {
|
||||||
|
NushellPrompt::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl NushellPrompt {
|
impl NushellPrompt {
|
||||||
pub fn new(shell_integration: bool) -> NushellPrompt {
|
pub fn new() -> NushellPrompt {
|
||||||
NushellPrompt {
|
NushellPrompt {
|
||||||
shell_integration,
|
|
||||||
left_prompt_string: None,
|
left_prompt_string: None,
|
||||||
right_prompt_string: None,
|
right_prompt_string: None,
|
||||||
default_prompt_indicator: None,
|
default_prompt_indicator: None,
|
||||||
@ -108,13 +111,9 @@ impl Prompt for NushellPrompt {
|
|||||||
.to_string()
|
.to_string()
|
||||||
.replace('\n', "\r\n");
|
.replace('\n', "\r\n");
|
||||||
|
|
||||||
if self.shell_integration {
|
|
||||||
format!("{PRE_PROMPT_MARKER}{prompt}{POST_PROMPT_MARKER}").into()
|
|
||||||
} else {
|
|
||||||
prompt.into()
|
prompt.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn render_prompt_right(&self) -> Cow<str> {
|
fn render_prompt_right(&self) -> Cow<str> {
|
||||||
if let Some(prompt_string) = &self.right_prompt_string {
|
if let Some(prompt_string) = &self.right_prompt_string {
|
||||||
|
@ -7,6 +7,8 @@ use nu_protocol::{
|
|||||||
Config, PipelineData, Value,
|
Config, PipelineData, Value,
|
||||||
};
|
};
|
||||||
use reedline::Prompt;
|
use reedline::Prompt;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Name of environment variable where the prompt could be stored
|
// Name of environment variable where the prompt could be stored
|
||||||
pub(crate) const PROMPT_COMMAND: &str = "PROMPT_COMMAND";
|
pub(crate) const PROMPT_COMMAND: &str = "PROMPT_COMMAND";
|
||||||
@ -26,8 +28,8 @@ pub(crate) const TRANSIENT_PROMPT_MULTILINE_INDICATOR: &str =
|
|||||||
"TRANSIENT_PROMPT_MULTILINE_INDICATOR";
|
"TRANSIENT_PROMPT_MULTILINE_INDICATOR";
|
||||||
// According to Daniel Imms @Tyriar, we need to do these this way:
|
// According to Daniel Imms @Tyriar, we need to do these this way:
|
||||||
// <133 A><prompt><133 B><command><133 C><command output>
|
// <133 A><prompt><133 B><command><133 C><command output>
|
||||||
pub(crate) const PRE_PROMPT_MARKER: &str = "\x1b]133;A\x1b\\";
|
const PRE_PROMPT_MARKER: &str = "\x1b]133;A\x1b\\";
|
||||||
pub(crate) const POST_PROMPT_MARKER: &str = "\x1b]133;B\x1b\\";
|
const POST_PROMPT_MARKER: &str = "\x1b]133;B\x1b\\";
|
||||||
|
|
||||||
fn get_prompt_string(
|
fn get_prompt_string(
|
||||||
prompt: &str,
|
prompt: &str,
|
||||||
@ -96,12 +98,12 @@ fn get_prompt_string(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_prompt(
|
pub(crate) fn update_prompt<'prompt>(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &Stack,
|
stack: &Stack,
|
||||||
nu_prompt: &mut NushellPrompt,
|
nu_prompt: &'prompt mut NushellPrompt,
|
||||||
) {
|
) -> &'prompt dyn Prompt {
|
||||||
let mut stack = stack.clone();
|
let mut stack = stack.clone();
|
||||||
|
|
||||||
let left_prompt_string = get_prompt_string(PROMPT_COMMAND, config, engine_state, &mut stack);
|
let left_prompt_string = get_prompt_string(PROMPT_COMMAND, config, engine_state, &mut stack);
|
||||||
@ -144,55 +146,125 @@ pub(crate) fn update_prompt(
|
|||||||
(prompt_vi_insert_string, prompt_vi_normal_string),
|
(prompt_vi_insert_string, prompt_vi_normal_string),
|
||||||
config.render_right_prompt_on_last_line,
|
config.render_right_prompt_on_last_line,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let ret_val = nu_prompt as &dyn Prompt;
|
||||||
trace!("update_prompt {}:{}:{}", file!(), line!(), column!());
|
trace!("update_prompt {}:{}:{}", file!(), line!(), column!());
|
||||||
|
|
||||||
|
ret_val
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct the transient prompt based on the normal nu_prompt
|
struct TransientPrompt {
|
||||||
pub(crate) fn make_transient_prompt(
|
engine_state: Arc<EngineState>,
|
||||||
|
stack: Stack,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try getting `$env.TRANSIENT_PROMPT_<X>`, and get `$env.PROMPT_<X>` if that fails
|
||||||
|
fn get_transient_prompt_string(
|
||||||
|
transient_prompt: &str,
|
||||||
|
prompt: &str,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
nu_prompt: &NushellPrompt,
|
) -> Option<String> {
|
||||||
) -> Box<dyn Prompt> {
|
get_prompt_string(transient_prompt, config, engine_state, stack)
|
||||||
let mut nu_prompt = nu_prompt.clone();
|
.or_else(|| get_prompt_string(prompt, config, engine_state, stack))
|
||||||
|
|
||||||
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND, config, engine_state, stack) {
|
|
||||||
nu_prompt.update_prompt_left(Some(s))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND_RIGHT, config, engine_state, stack)
|
impl Prompt for TransientPrompt {
|
||||||
{
|
fn render_prompt_left(&self) -> Cow<str> {
|
||||||
nu_prompt.update_prompt_right(Some(s), config.render_right_prompt_on_last_line)
|
let mut nu_prompt = NushellPrompt::new();
|
||||||
|
let config = &self.engine_state.get_config().clone();
|
||||||
|
let mut stack = self.stack.clone();
|
||||||
|
nu_prompt.update_prompt_left(get_transient_prompt_string(
|
||||||
|
TRANSIENT_PROMPT_COMMAND,
|
||||||
|
PROMPT_COMMAND,
|
||||||
|
config,
|
||||||
|
&self.engine_state,
|
||||||
|
&mut stack,
|
||||||
|
));
|
||||||
|
nu_prompt.render_prompt_left().to_string().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_INDICATOR, config, engine_state, stack) {
|
fn render_prompt_right(&self) -> Cow<str> {
|
||||||
nu_prompt.update_prompt_indicator(Some(s))
|
let mut nu_prompt = NushellPrompt::new();
|
||||||
|
let config = &self.engine_state.get_config().clone();
|
||||||
|
let mut stack = self.stack.clone();
|
||||||
|
nu_prompt.update_prompt_right(
|
||||||
|
get_transient_prompt_string(
|
||||||
|
TRANSIENT_PROMPT_COMMAND_RIGHT,
|
||||||
|
PROMPT_COMMAND_RIGHT,
|
||||||
|
config,
|
||||||
|
&self.engine_state,
|
||||||
|
&mut stack,
|
||||||
|
),
|
||||||
|
config.render_right_prompt_on_last_line,
|
||||||
|
);
|
||||||
|
nu_prompt.render_prompt_right().to_string().into()
|
||||||
}
|
}
|
||||||
if let Some(s) = get_prompt_string(
|
|
||||||
|
fn render_prompt_indicator(&self, prompt_mode: reedline::PromptEditMode) -> Cow<str> {
|
||||||
|
let mut nu_prompt = NushellPrompt::new();
|
||||||
|
let config = &self.engine_state.get_config().clone();
|
||||||
|
let mut stack = self.stack.clone();
|
||||||
|
nu_prompt.update_prompt_indicator(get_transient_prompt_string(
|
||||||
|
TRANSIENT_PROMPT_INDICATOR,
|
||||||
|
PROMPT_INDICATOR,
|
||||||
|
config,
|
||||||
|
&self.engine_state,
|
||||||
|
&mut stack,
|
||||||
|
));
|
||||||
|
nu_prompt.update_prompt_vi_insert(get_transient_prompt_string(
|
||||||
TRANSIENT_PROMPT_INDICATOR_VI_INSERT,
|
TRANSIENT_PROMPT_INDICATOR_VI_INSERT,
|
||||||
|
PROMPT_INDICATOR_VI_INSERT,
|
||||||
config,
|
config,
|
||||||
engine_state,
|
&self.engine_state,
|
||||||
stack,
|
&mut stack,
|
||||||
) {
|
));
|
||||||
nu_prompt.update_prompt_vi_insert(Some(s))
|
nu_prompt.update_prompt_vi_normal(get_transient_prompt_string(
|
||||||
}
|
|
||||||
if let Some(s) = get_prompt_string(
|
|
||||||
TRANSIENT_PROMPT_INDICATOR_VI_NORMAL,
|
TRANSIENT_PROMPT_INDICATOR_VI_NORMAL,
|
||||||
|
PROMPT_INDICATOR_VI_NORMAL,
|
||||||
config,
|
config,
|
||||||
engine_state,
|
&self.engine_state,
|
||||||
stack,
|
&mut stack,
|
||||||
) {
|
));
|
||||||
nu_prompt.update_prompt_vi_normal(Some(s))
|
nu_prompt
|
||||||
|
.render_prompt_indicator(prompt_mode)
|
||||||
|
.to_string()
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = get_prompt_string(
|
fn render_prompt_multiline_indicator(&self) -> Cow<str> {
|
||||||
|
let mut nu_prompt = NushellPrompt::new();
|
||||||
|
let config = &self.engine_state.get_config().clone();
|
||||||
|
let mut stack = self.stack.clone();
|
||||||
|
nu_prompt.update_prompt_multiline(get_transient_prompt_string(
|
||||||
TRANSIENT_PROMPT_MULTILINE_INDICATOR,
|
TRANSIENT_PROMPT_MULTILINE_INDICATOR,
|
||||||
|
PROMPT_MULTILINE_INDICATOR,
|
||||||
config,
|
config,
|
||||||
engine_state,
|
&self.engine_state,
|
||||||
stack,
|
&mut stack,
|
||||||
) {
|
));
|
||||||
nu_prompt.update_prompt_multiline(Some(s))
|
nu_prompt
|
||||||
|
.render_prompt_multiline_indicator()
|
||||||
|
.to_string()
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
Box::new(nu_prompt)
|
fn render_prompt_history_search_indicator(
|
||||||
|
&self,
|
||||||
|
history_search: reedline::PromptHistorySearch,
|
||||||
|
) -> Cow<str> {
|
||||||
|
NushellPrompt::new()
|
||||||
|
.render_prompt_history_search_indicator(history_search)
|
||||||
|
.to_string()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct the transient prompt
|
||||||
|
pub(crate) fn transient_prompt(engine_state: Arc<EngineState>, stack: &Stack) -> Box<dyn Prompt> {
|
||||||
|
Box::new(TransientPrompt {
|
||||||
|
engine_state,
|
||||||
|
stack: stack.clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ use std::{
|
|||||||
sync::atomic::Ordering,
|
sync::atomic::Ordering,
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
use sysinfo::System;
|
use sysinfo::SystemExt;
|
||||||
|
|
||||||
// According to Daniel Imms @Tyriar, we need to do these this way:
|
// According to Daniel Imms @Tyriar, we need to do these this way:
|
||||||
// <133 A><prompt><133 B><command><133 C><command output>
|
// <133 A><prompt><133 B><command><133 C><command output>
|
||||||
@ -54,8 +54,7 @@ pub fn evaluate_repl(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
use nu_cmd_base::hook;
|
use nu_cmd_base::hook;
|
||||||
use reedline::Signal;
|
use reedline::Signal;
|
||||||
let config = engine_state.get_config();
|
let use_color = engine_state.get_config().use_ansi_coloring;
|
||||||
let use_color = config.use_ansi_coloring;
|
|
||||||
|
|
||||||
// Guard against invocation without a connected terminal.
|
// Guard against invocation without a connected terminal.
|
||||||
// reedline / crossterm event polling will fail without a connected tty
|
// reedline / crossterm event polling will fail without a connected tty
|
||||||
@ -69,7 +68,7 @@ pub fn evaluate_repl(
|
|||||||
|
|
||||||
let mut entry_num = 0;
|
let mut entry_num = 0;
|
||||||
|
|
||||||
let mut nu_prompt = NushellPrompt::new(config.shell_integration);
|
let mut nu_prompt = NushellPrompt::new();
|
||||||
|
|
||||||
let start_time = std::time::Instant::now();
|
let start_time = std::time::Instant::now();
|
||||||
// Translate environment variables from Strings to Values
|
// Translate environment variables from Strings to Values
|
||||||
@ -135,6 +134,17 @@ pub fn evaluate_repl(
|
|||||||
use_color,
|
use_color,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
start_time = std::time::Instant::now();
|
||||||
|
let sys = sysinfo::System::new();
|
||||||
|
perf(
|
||||||
|
"get sysinfo",
|
||||||
|
start_time,
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!(),
|
||||||
|
use_color,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(s) = prerun_command {
|
if let Some(s) = prerun_command {
|
||||||
eval_source(
|
eval_source(
|
||||||
engine_state,
|
engine_state,
|
||||||
@ -202,6 +212,20 @@ pub fn evaluate_repl(
|
|||||||
use_color,
|
use_color,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
start_time = std::time::Instant::now();
|
||||||
|
// Reset the SIGQUIT handler
|
||||||
|
if let Some(sig_quit) = engine_state.get_sig_quit() {
|
||||||
|
sig_quit.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
perf(
|
||||||
|
"reset sig_quit",
|
||||||
|
start_time,
|
||||||
|
file!(),
|
||||||
|
line!(),
|
||||||
|
column!(),
|
||||||
|
use_color,
|
||||||
|
);
|
||||||
|
|
||||||
start_time = std::time::Instant::now();
|
start_time = std::time::Instant::now();
|
||||||
let config = engine_state.get_config();
|
let config = engine_state.get_config();
|
||||||
|
|
||||||
@ -243,7 +267,11 @@ pub fn evaluate_repl(
|
|||||||
.with_quick_completions(config.quick_completions)
|
.with_quick_completions(config.quick_completions)
|
||||||
.with_partial_completions(config.partial_completions)
|
.with_partial_completions(config.partial_completions)
|
||||||
.with_ansi_colors(config.use_ansi_coloring)
|
.with_ansi_colors(config.use_ansi_coloring)
|
||||||
.with_cursor_config(cursor_config);
|
.with_cursor_config(cursor_config)
|
||||||
|
.with_transient_prompt(prompt_update::transient_prompt(
|
||||||
|
engine_reference.clone(),
|
||||||
|
stack,
|
||||||
|
));
|
||||||
perf(
|
perf(
|
||||||
"reedline builder",
|
"reedline builder",
|
||||||
start_time,
|
start_time,
|
||||||
@ -396,9 +424,7 @@ pub fn evaluate_repl(
|
|||||||
|
|
||||||
start_time = std::time::Instant::now();
|
start_time = std::time::Instant::now();
|
||||||
let config = &engine_state.get_config().clone();
|
let config = &engine_state.get_config().clone();
|
||||||
prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt);
|
let prompt = prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt);
|
||||||
let transient_prompt =
|
|
||||||
prompt_update::make_transient_prompt(config, engine_state, stack, &nu_prompt);
|
|
||||||
perf(
|
perf(
|
||||||
"update_prompt",
|
"update_prompt",
|
||||||
start_time,
|
start_time,
|
||||||
@ -411,13 +437,12 @@ pub fn evaluate_repl(
|
|||||||
entry_num += 1;
|
entry_num += 1;
|
||||||
|
|
||||||
start_time = std::time::Instant::now();
|
start_time = std::time::Instant::now();
|
||||||
line_editor = line_editor.with_transient_prompt(transient_prompt);
|
let input = line_editor.read_line(prompt);
|
||||||
let input = line_editor.read_line(&nu_prompt);
|
|
||||||
let shell_integration = config.shell_integration;
|
let shell_integration = config.shell_integration;
|
||||||
|
|
||||||
match input {
|
match input {
|
||||||
Ok(Signal::Success(s)) => {
|
Ok(Signal::Success(s)) => {
|
||||||
let hostname = System::host_name();
|
let hostname = sys.host_name();
|
||||||
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() && line_editor.has_last_command_context()
|
if history_supports_meta && !s.is_empty() && line_editor.has_last_command_context()
|
||||||
@ -739,7 +764,7 @@ fn map_nucursorshape_to_cursorshape(shape: NuCursorShape) -> Option<SetCursorSty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
|
pub fn get_command_finished_marker(stack: &Stack, engine_state: &EngineState) -> String {
|
||||||
let exit_code = stack
|
let exit_code = stack
|
||||||
.get_env_var(engine_state, "LAST_EXIT_CODE")
|
.get_env_var(engine_state, "LAST_EXIT_CODE")
|
||||||
.and_then(|e| e.as_i64().ok());
|
.and_then(|e| e.as_i64().ok());
|
||||||
|
@ -329,6 +329,7 @@ fn find_matching_block_end_in_expr(
|
|||||||
Expr::ImportPattern(_) => None,
|
Expr::ImportPattern(_) => None,
|
||||||
Expr::Overlay(_) => None,
|
Expr::Overlay(_) => None,
|
||||||
Expr::Signature(_) => None,
|
Expr::Signature(_) => None,
|
||||||
|
Expr::MatchPattern(_) => None,
|
||||||
Expr::MatchBlock(_) => None,
|
Expr::MatchBlock(_) => None,
|
||||||
Expr::Nothing => None,
|
Expr::Nothing => None,
|
||||||
Expr::Garbage => None,
|
Expr::Garbage => None,
|
||||||
@ -385,7 +386,6 @@ fn find_matching_block_end_in_expr(
|
|||||||
Argument::Named((_, _, opt_expr)) => opt_expr.as_ref(),
|
Argument::Named((_, _, opt_expr)) => opt_expr.as_ref(),
|
||||||
Argument::Positional(inner_expr) => Some(inner_expr),
|
Argument::Positional(inner_expr) => Some(inner_expr),
|
||||||
Argument::Unknown(inner_expr) => Some(inner_expr),
|
Argument::Unknown(inner_expr) => Some(inner_expr),
|
||||||
Argument::Spread(inner_expr) => Some(inner_expr),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(inner_expr) = opt_expr {
|
if let Some(inner_expr) = opt_expr {
|
||||||
|
@ -220,10 +220,6 @@ pub fn eval_source(
|
|||||||
source,
|
source,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
if let Some(warning) = working_set.parse_warnings.first() {
|
|
||||||
report_error(&working_set, warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(err) = working_set.parse_errors.first() {
|
if let Some(err) = working_set.parse_errors.first() {
|
||||||
set_last_exit_code(stack, 1);
|
set_last_exit_code(stack, 1);
|
||||||
report_error(&working_set, err);
|
report_error(&working_set, err);
|
||||||
|
@ -91,7 +91,7 @@ fn variables_dollar_sign_with_varialblecompletion() {
|
|||||||
let target_dir = "$ ";
|
let target_dir = "$ ";
|
||||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||||
|
|
||||||
assert_eq!(8, suggestions.len());
|
assert_eq!(7, suggestions.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@ -144,34 +144,15 @@ fn dotnu_completions() {
|
|||||||
let completion_str = "source-env ".to_string();
|
let completion_str = "source-env ".to_string();
|
||||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||||
|
|
||||||
assert_eq!(2, suggestions.len());
|
assert_eq!(1, suggestions.len());
|
||||||
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
||||||
#[cfg(windows)]
|
|
||||||
assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value);
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
assert_eq!("directory_completion/", suggestions.get(1).unwrap().value);
|
|
||||||
|
|
||||||
// Test use completion
|
// Test use completion
|
||||||
let completion_str = "use ".to_string();
|
let completion_str = "use ".to_string();
|
||||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
let suggestions = completer.complete(&completion_str, completion_str.len());
|
||||||
|
|
||||||
assert_eq!(2, suggestions.len());
|
assert_eq!(1, suggestions.len());
|
||||||
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
||||||
#[cfg(windows)]
|
|
||||||
assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value);
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
assert_eq!("directory_completion/", suggestions.get(1).unwrap().value);
|
|
||||||
|
|
||||||
// Test overlay use completion
|
|
||||||
let completion_str = "overlay use ".to_string();
|
|
||||||
let suggestions = completer.complete(&completion_str, completion_str.len());
|
|
||||||
|
|
||||||
assert_eq!(2, suggestions.len());
|
|
||||||
assert_eq!("custom_completion.nu", suggestions.first().unwrap().value);
|
|
||||||
#[cfg(windows)]
|
|
||||||
assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value);
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
assert_eq!("directory_completion/", suggestions.get(1).unwrap().value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -227,7 +208,6 @@ fn file_completions() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
folder(dir.join("another")),
|
folder(dir.join("another")),
|
||||||
file(dir.join("custom_completion.nu")),
|
file(dir.join("custom_completion.nu")),
|
||||||
folder(dir.join("directory_completion")),
|
|
||||||
file(dir.join("nushell")),
|
file(dir.join("nushell")),
|
||||||
folder(dir.join("test_a")),
|
folder(dir.join("test_a")),
|
||||||
folder(dir.join("test_b")),
|
folder(dir.join("test_b")),
|
||||||
@ -343,7 +323,6 @@ fn command_ls_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -354,7 +333,6 @@ fn command_ls_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -377,7 +355,6 @@ fn command_open_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -388,7 +365,6 @@ fn command_open_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -412,7 +388,6 @@ fn command_rm_with_globcompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -423,7 +398,6 @@ fn command_rm_with_globcompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -447,7 +421,6 @@ fn command_cp_with_globcompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -458,7 +431,6 @@ fn command_cp_with_globcompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -482,7 +454,6 @@ fn command_save_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -493,7 +464,6 @@ fn command_save_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -517,7 +487,6 @@ fn command_touch_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -528,7 +497,6 @@ fn command_touch_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -552,7 +520,6 @@ fn command_watch_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -563,7 +530,6 @@ fn command_watch_with_filecompletion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -659,7 +625,6 @@ fn folder_with_directorycompletions() {
|
|||||||
// Create the expected values
|
// Create the expected values
|
||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
folder(dir.join("another")),
|
folder(dir.join("another")),
|
||||||
folder(dir.join("directory_completion")),
|
|
||||||
folder(dir.join("test_a")),
|
folder(dir.join("test_a")),
|
||||||
folder(dir.join("test_b")),
|
folder(dir.join("test_b")),
|
||||||
folder(dir.join(".hidden_folder")),
|
folder(dir.join(".hidden_folder")),
|
||||||
@ -874,7 +839,6 @@ fn unknown_command_completion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -885,7 +849,6 @@ fn unknown_command_completion() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
@ -936,7 +899,6 @@ fn filecompletions_triggers_after_cursor() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another\\".to_string(),
|
"another\\".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion\\".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a\\".to_string(),
|
"test_a\\".to_string(),
|
||||||
"test_b\\".to_string(),
|
"test_b\\".to_string(),
|
||||||
@ -947,7 +909,6 @@ fn filecompletions_triggers_after_cursor() {
|
|||||||
let expected_paths: Vec<String> = vec![
|
let expected_paths: Vec<String> = vec![
|
||||||
"another/".to_string(),
|
"another/".to_string(),
|
||||||
"custom_completion.nu".to_string(),
|
"custom_completion.nu".to_string(),
|
||||||
"directory_completion/".to_string(),
|
|
||||||
"nushell".to_string(),
|
"nushell".to_string(),
|
||||||
"test_a/".to_string(),
|
"test_a/".to_string(),
|
||||||
"test_b/".to_string(),
|
"test_b/".to_string(),
|
||||||
|
@ -26,9 +26,9 @@ num = { version = "0.4", optional = true }
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
sqlparser = { version = "0.39", optional = true }
|
sqlparser = { version = "0.39", optional = true }
|
||||||
polars-io = { version = "0.35", features = ["avro"], optional = true }
|
polars-io = { version = "0.35", features = ["avro"], optional = true }
|
||||||
polars-arrow = { version = "0.35", optional = true }
|
polars-arrow = "0.35"
|
||||||
polars-ops = { version = "0.35", optional = true }
|
polars-ops = "0.35"
|
||||||
polars-plan = { version = "0.35", optional = true }
|
polars-plan = "0.35"
|
||||||
|
|
||||||
[dependencies.polars]
|
[dependencies.polars]
|
||||||
features = [
|
features = [
|
||||||
@ -65,7 +65,7 @@ optional = true
|
|||||||
version = "0.35"
|
version = "0.35"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
dataframe = ["num", "polars", "polars-io", "polars-arrow", "polars-ops", "polars-plan", "sqlparser"]
|
dataframe = ["num", "polars", "polars-io", "sqlparser"]
|
||||||
default = []
|
default = []
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -874,7 +874,7 @@ fn series_to_values(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|field| field.name.to_string())
|
.map(|field| field.name.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
let record = Record::from_raw_cols_vals(cols, vals?);
|
let record = Record { cols, vals: vals? };
|
||||||
Ok(Value::record(record, span))
|
Ok(Value::record(record, span))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
@ -982,7 +982,10 @@ fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result<Value, ShellEr
|
|||||||
.map(|f| f.name().to_string())
|
.map(|f| f.name().to_string())
|
||||||
.collect();
|
.collect();
|
||||||
Ok(Value::Record {
|
Ok(Value::Record {
|
||||||
val: Record::from_raw_cols_vals(fields, values?),
|
val: Record {
|
||||||
|
cols: fields,
|
||||||
|
vals: values?,
|
||||||
|
},
|
||||||
internal_span: span,
|
internal_span: span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1056,7 +1059,6 @@ fn time_from_midnight(nanos: i64, span: Span) -> Result<Value, ShellError> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use indexmap::indexmap;
|
use indexmap::indexmap;
|
||||||
use nu_protocol::record;
|
|
||||||
use polars::export::arrow::array::{BooleanArray, PrimitiveArray};
|
use polars::export::arrow::array::{BooleanArray, PrimitiveArray};
|
||||||
use polars::prelude::Field;
|
use polars::prelude::Field;
|
||||||
use polars_io::prelude::StructArray;
|
use polars_io::prelude::StructArray;
|
||||||
@ -1247,10 +1249,13 @@ mod tests {
|
|||||||
Field::new(field_name_1, DataType::Boolean),
|
Field::new(field_name_1, DataType::Boolean),
|
||||||
];
|
];
|
||||||
let test_owned_struct = AnyValue::StructOwned(Box::new((values, fields.clone())));
|
let test_owned_struct = AnyValue::StructOwned(Box::new((values, fields.clone())));
|
||||||
let comparison_owned_record = Value::test_record(record!(
|
let comparison_owned_record = Value::record(
|
||||||
field_name_0 => Value::int(1, span),
|
Record {
|
||||||
field_name_1 => Value::bool(true, span),
|
cols: vec![field_name_0.to_owned(), field_name_1.to_owned()],
|
||||||
));
|
vals: vec![Value::int(1, span), Value::bool(true, span)],
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
any_value_to_value(&test_owned_struct, span)?,
|
any_value_to_value(&test_owned_struct, span)?,
|
||||||
comparison_owned_record.clone()
|
comparison_owned_record.clone()
|
||||||
|
@ -158,10 +158,7 @@ impl NuDataFrame {
|
|||||||
.map(|i| format!("{i}"))
|
.map(|i| format!("{i}"))
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
conversion::insert_record(
|
conversion::insert_record(&mut column_values, Record { cols, vals })?
|
||||||
&mut column_values,
|
|
||||||
Record::from_raw_cols_vals(cols, vals),
|
|
||||||
)?
|
|
||||||
}
|
}
|
||||||
Value::Record { val: record, .. } => {
|
Value::Record { val: record, .. } => {
|
||||||
conversion::insert_record(&mut column_values, record)?
|
conversion::insert_record(&mut column_values, record)?
|
||||||
|
@ -24,7 +24,7 @@ heck = "0.4.1"
|
|||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
ahash = "0.8.3"
|
ahash = "0.8.3"
|
||||||
nu-ansi-term = "0.49.0"
|
nu-ansi-term = "0.49.0"
|
||||||
fancy-regex = "0.12.0"
|
fancy-regex = "0.11.0"
|
||||||
rust-embed = "8.0.0"
|
rust-embed = "8.0.0"
|
||||||
serde = "1.0.164"
|
serde = "1.0.164"
|
||||||
nu-pretty-hex = { version = "0.88.2", path = "../nu-pretty-hex" }
|
nu-pretty-hex = { version = "0.88.2", path = "../nu-pretty-hex" }
|
||||||
|
@ -65,7 +65,7 @@ pub fn add_extra_command_context(mut engine_state: EngineState) -> EngineState {
|
|||||||
bind_command!(platform::ansi::Gradient);
|
bind_command!(platform::ansi::Gradient);
|
||||||
|
|
||||||
bind_command!(
|
bind_command!(
|
||||||
strings::format::FormatPattern,
|
strings::format::Format,
|
||||||
strings::encode_decode::EncodeHex,
|
strings::encode_decode::EncodeHex,
|
||||||
strings::encode_decode::DecodeHex,
|
strings::encode_decode::DecodeHex,
|
||||||
strings::str_::case::Str,
|
strings::str_::case::Str,
|
||||||
|
@ -10,15 +10,15 @@ use nu_protocol::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FormatPattern;
|
pub struct Format;
|
||||||
|
|
||||||
impl Command for FormatPattern {
|
impl Command for Format {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"format pattern"
|
"format"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
fn signature(&self) -> Signature {
|
||||||
Signature::build("format pattern")
|
Signature::build("format")
|
||||||
.input_output_types(vec![
|
.input_output_types(vec![
|
||||||
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
||||||
(Type::Record(vec![]), Type::Any),
|
(Type::Record(vec![]), Type::Any),
|
||||||
@ -80,12 +80,12 @@ impl Command for FormatPattern {
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Print filenames with their sizes",
|
description: "Print filenames with their sizes",
|
||||||
example: "ls | format pattern '{name}: {size}'",
|
example: "ls | format '{name}: {size}'",
|
||||||
result: None,
|
result: None,
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Print elements from some columns of a table",
|
description: "Print elements from some columns of a table",
|
||||||
example: "[[col1, col2]; [v1, v2] [v3, v4]] | format pattern '{col2}'",
|
example: "[[col1, col2]; [v1, v2] [v3, v4]] | format '{col2}'",
|
||||||
result: Some(Value::list(
|
result: Some(Value::list(
|
||||||
vec![Value::test_string("v2"), Value::test_string("v4")],
|
vec![Value::test_string("v2"), Value::test_string("v4")],
|
||||||
Span::test_data(),
|
Span::test_data(),
|
||||||
@ -318,8 +318,8 @@ fn format_record(
|
|||||||
mod test {
|
mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_examples() {
|
fn test_examples() {
|
||||||
use super::FormatPattern;
|
use super::Format;
|
||||||
use crate::test_examples;
|
use crate::test_examples;
|
||||||
test_examples(FormatPattern {})
|
test_examples(Format {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
mod command;
|
mod command;
|
||||||
|
|
||||||
pub(crate) use command::FormatPattern;
|
pub(crate) use command::Format;
|
||||||
|
@ -18,12 +18,12 @@ nu-protocol = { path = "../nu-protocol", version = "0.88.2" }
|
|||||||
nu-utils = { path = "../nu-utils", version = "0.88.2" }
|
nu-utils = { path = "../nu-utils", version = "0.88.2" }
|
||||||
nu-ansi-term = "0.49.0"
|
nu-ansi-term = "0.49.0"
|
||||||
|
|
||||||
fancy-regex = "0.12"
|
fancy-regex = "0.11"
|
||||||
itertools = "0.12"
|
itertools = "0.11"
|
||||||
shadow-rs = { version = "0.26", default-features = false }
|
shadow-rs = { version = "0.24", default-features = false }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
shadow-rs = { version = "0.26", default-features = false }
|
shadow-rs = { version = "0.24", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
mimalloc = []
|
mimalloc = []
|
||||||
|
@ -290,6 +290,7 @@ fn describe_value(
|
|||||||
| Value::Date { .. }
|
| Value::Date { .. }
|
||||||
| Value::Range { .. }
|
| Value::Range { .. }
|
||||||
| Value::String { .. }
|
| Value::String { .. }
|
||||||
|
| Value::MatchPattern { .. }
|
||||||
| Value::Nothing { .. } => Value::record(
|
| Value::Nothing { .. } => Value::record(
|
||||||
record!(
|
record!(
|
||||||
"type" => Value::string(value.get_type().to_string(), head),
|
"type" => Value::string(value.get_type().to_string(), head),
|
||||||
|
@ -278,6 +278,9 @@ impl<'a> std::fmt::Debug for DebuggableValue<'a> {
|
|||||||
let rec = val.collect().map_err(|_| std::fmt::Error)?;
|
let rec = val.collect().map_err(|_| std::fmt::Error)?;
|
||||||
write!(f, "LazyRecord({:?})", DebuggableValue(&rec))
|
write!(f, "LazyRecord({:?})", DebuggableValue(&rec))
|
||||||
}
|
}
|
||||||
|
Value::MatchPattern { val, .. } => {
|
||||||
|
write!(f, "MatchPattern({:?})", val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ fn color_string_to_nustyle(color_string: String) -> Style {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use nu_ansi_term::{Color, Style};
|
use nu_ansi_term::{Color, Style};
|
||||||
use nu_protocol::{record, Span, Value};
|
use nu_protocol::{Span, Value};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_color_string_to_nustyle_empty_string() {
|
fn test_color_string_to_nustyle_empty_string() {
|
||||||
@ -120,10 +120,13 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_get_style_from_value() {
|
fn test_get_style_from_value() {
|
||||||
// Test case 1: all values are valid
|
// Test case 1: all values are valid
|
||||||
let record = record! {
|
let record = Record {
|
||||||
"bg" => Value::test_string("red"),
|
cols: vec!["bg".to_string(), "fg".to_string(), "attr".to_string()],
|
||||||
"fg" => Value::test_string("blue"),
|
vals: vec![
|
||||||
"attr" => Value::test_string("bold"),
|
Value::string("red", Span::unknown()),
|
||||||
|
Value::string("blue", Span::unknown()),
|
||||||
|
Value::string("bold", Span::unknown()),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
let expected_style = NuStyle {
|
let expected_style = NuStyle {
|
||||||
bg: Some("red".to_string()),
|
bg: Some("red".to_string()),
|
||||||
@ -133,15 +136,19 @@ mod tests {
|
|||||||
assert_eq!(get_style_from_value(&record), Some(expected_style));
|
assert_eq!(get_style_from_value(&record), Some(expected_style));
|
||||||
|
|
||||||
// Test case 2: no values are valid
|
// Test case 2: no values are valid
|
||||||
let record = record! {
|
let record = Record {
|
||||||
"invalid" => Value::nothing(Span::test_data()),
|
cols: vec!["invalid".to_string()],
|
||||||
|
vals: vec![Value::nothing(Span::unknown())],
|
||||||
};
|
};
|
||||||
assert_eq!(get_style_from_value(&record), None);
|
assert_eq!(get_style_from_value(&record), None);
|
||||||
|
|
||||||
// Test case 3: some values are valid
|
// Test case 3: some values are valid
|
||||||
let record = record! {
|
let record = Record {
|
||||||
"bg" => Value::test_string("green"),
|
cols: vec!["bg".to_string(), "invalid".to_string()],
|
||||||
"invalid" => Value::nothing(Span::unknown()),
|
vals: vec![
|
||||||
|
Value::string("green", Span::unknown()),
|
||||||
|
Value::nothing(Span::unknown()),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
let expected_style = NuStyle {
|
let expected_style = NuStyle {
|
||||||
bg: Some("green".to_string()),
|
bg: Some("green".to_string()),
|
||||||
|
@ -131,7 +131,8 @@ impl<'a> StyleComputer<'a> {
|
|||||||
Value::Closure { .. }
|
Value::Closure { .. }
|
||||||
| Value::CustomValue { .. }
|
| Value::CustomValue { .. }
|
||||||
| Value::Error { .. }
|
| Value::Error { .. }
|
||||||
| Value::LazyRecord { .. } => TextStyle::basic_left(),
|
| Value::LazyRecord { .. }
|
||||||
|
| Value::MatchPattern { .. } => TextStyle::basic_left(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ dialoguer = { default-features = false, features = ["fuzzy-select"], version = "
|
|||||||
digest = { default-features = false, version = "0.10" }
|
digest = { default-features = false, version = "0.10" }
|
||||||
dtparse = "2.0"
|
dtparse = "2.0"
|
||||||
encoding_rs = "0.8"
|
encoding_rs = "0.8"
|
||||||
fancy-regex = "0.12"
|
fancy-regex = "0.11"
|
||||||
filesize = "0.2"
|
filesize = "0.2"
|
||||||
filetime = "0.2"
|
filetime = "0.2"
|
||||||
fs_extra = "1.3"
|
fs_extra = "1.3"
|
||||||
@ -50,9 +50,9 @@ htmlescape = "0.3"
|
|||||||
human-date-parser = "0.1.1"
|
human-date-parser = "0.1.1"
|
||||||
indexmap = "2.1"
|
indexmap = "2.1"
|
||||||
indicatif = "0.17"
|
indicatif = "0.17"
|
||||||
itertools = "0.12"
|
itertools = "0.11"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
lscolors = { version = "0.16", default-features = false, features = ["nu-ansi-term"] }
|
lscolors = { version = "0.15", default-features = false, features = ["nu-ansi-term"] }
|
||||||
md5 = { package = "md-5", version = "0.10" }
|
md5 = { package = "md-5", version = "0.10" }
|
||||||
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
@ -80,7 +80,7 @@ serde_json = "1.0"
|
|||||||
serde_urlencoded = "0.7"
|
serde_urlencoded = "0.7"
|
||||||
serde_yaml = "0.9"
|
serde_yaml = "0.9"
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
sysinfo = "0.30"
|
sysinfo = "0.29"
|
||||||
tabled = { version = "0.14.0", features = ["color"], default-features = false }
|
tabled = { version = "0.14.0", features = ["color"], default-features = false }
|
||||||
terminal_size = "0.3"
|
terminal_size = "0.3"
|
||||||
titlecase = "2.0"
|
titlecase = "2.0"
|
||||||
@ -104,9 +104,9 @@ winreg = "0.52"
|
|||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
umask = "2.1"
|
umask = "2.1"
|
||||||
nix = { version = "0.27", default-features = false, features = ["user", "resource"] }
|
nix = { version = "0.27", default-features = false, features = ["user"] }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
|
[target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "android"), not(target_os = "ios")))'.dependencies]
|
||||||
procfs = "0.16.0"
|
procfs = "0.16.0"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
||||||
@ -122,7 +122,7 @@ features = [
|
|||||||
"Win32_Security",
|
"Win32_Security",
|
||||||
"Win32_System_Threading",
|
"Win32_System_Threading",
|
||||||
]
|
]
|
||||||
version = "0.52"
|
version = "0.48"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
plugin = ["nu-parser/plugin"]
|
plugin = ["nu-parser/plugin"]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{eval_expression, CallExt};
|
use nu_engine::eval_expression;
|
||||||
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::{
|
use nu_protocol::{
|
||||||
@ -48,7 +48,8 @@ impl Command for BytesBuild {
|
|||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
for val in call.rest_iter_flattened(0, |expr| eval_expression(engine_state, stack, expr))? {
|
for expr in call.positional_iter() {
|
||||||
|
let val = eval_expression(engine_state, stack, expr)?;
|
||||||
match val {
|
match val {
|
||||||
Value::Binary { mut val, .. } => output.append(&mut val),
|
Value::Binary { mut val, .. } => output.append(&mut val),
|
||||||
// Explicitly propagate errors instead of dropping them.
|
// Explicitly propagate errors instead of dropping them.
|
||||||
|
@ -105,13 +105,6 @@ impl Command for BytesRemove {
|
|||||||
vec![0x10, 0xAA, 0x10, 0xBB, 0xCC, 0xAA],
|
vec![0x10, 0xAA, 0x10, 0xBB, 0xCC, 0xAA],
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Example {
|
|
||||||
description: "Remove find binary from end not found",
|
|
||||||
example: "0x[10 AA 10 BB CC AA 10] | bytes remove --end 0x[11]",
|
|
||||||
result: Some(Value::test_binary (
|
|
||||||
vec![0x10, 0xAA, 0x10, 0xBB, 0xCC, 0xAA, 0x10],
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
Example {
|
Example {
|
||||||
description: "Remove all occurrences of find binary in table",
|
description: "Remove all occurrences of find binary in table",
|
||||||
example: "[[ColA ColB ColC]; [0x[11 12 13] 0x[14 15 16] 0x[17 18 19]]] | bytes remove 0x[11] ColA ColC",
|
example: "[[ColA ColB ColC]; [0x[11 12 13] 0x[14 15 16] 0x[17 18 19]]] | bytes remove 0x[11] ColA ColC",
|
||||||
@ -166,11 +159,8 @@ fn remove_impl(input: &[u8], arg: &Arguments, span: Span) -> Value {
|
|||||||
}
|
}
|
||||||
// append the remaining thing to result, this can be happening when
|
// append the remaining thing to result, this can be happening when
|
||||||
// we have something to remove and remove_all is False.
|
// we have something to remove and remove_all is False.
|
||||||
// check if the left is positive, if it is not, we don't need to append anything.
|
|
||||||
if left > 0 {
|
|
||||||
let mut remain = input[..left as usize].iter().copied().rev().collect();
|
let mut remain = input[..left as usize].iter().copied().rev().collect();
|
||||||
result.append(&mut remain);
|
result.append(&mut remain);
|
||||||
}
|
|
||||||
result = result.into_iter().rev().collect();
|
result = result.into_iter().rev().collect();
|
||||||
Value::binary(result, span)
|
Value::binary(result, span)
|
||||||
} else {
|
} else {
|
||||||
|
@ -258,16 +258,16 @@ fn histogram_impl(
|
|||||||
result.push((
|
result.push((
|
||||||
count, // attach count first for easily sorting.
|
count, // attach count first for easily sorting.
|
||||||
Value::record(
|
Value::record(
|
||||||
Record::from_raw_cols_vals(
|
Record {
|
||||||
result_cols.clone(),
|
cols: result_cols.clone(),
|
||||||
vec![
|
vals: vec![
|
||||||
val.into_value(),
|
val.into_value(),
|
||||||
Value::int(count, span),
|
Value::int(count, span),
|
||||||
Value::float(quantile, span),
|
Value::float(quantile, span),
|
||||||
Value::string(percentage, span),
|
Value::string(percentage, span),
|
||||||
Value::string(freq, span),
|
Value::string(freq, span),
|
||||||
],
|
],
|
||||||
),
|
},
|
||||||
span,
|
span,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
@ -260,6 +260,7 @@ fn nu_value_to_string(value: Value, separator: &str) -> String {
|
|||||||
Value::Binary { val, .. } => format!("{val:?}"),
|
Value::Binary { val, .. } => format!("{val:?}"),
|
||||||
Value::CellPath { val, .. } => val.to_string(),
|
Value::CellPath { val, .. } => val.to_string(),
|
||||||
Value::CustomValue { val, .. } => val.value_string(),
|
Value::CustomValue { val, .. } => val.value_string(),
|
||||||
|
Value::MatchPattern { val, .. } => format!("{:?}", val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +499,13 @@ pub fn convert_sqlite_row_to_nu_value(row: &Row, span: Span, column_names: Vec<S
|
|||||||
vals.push(val);
|
vals.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::record(Record::from_raw_cols_vals(column_names, vals), span)
|
Value::record(
|
||||||
|
Record {
|
||||||
|
cols: column_names,
|
||||||
|
vals,
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
|
pub fn convert_sqlite_value_to_nu_value(value: ValueRef, span: Span) -> Value {
|
||||||
|
@ -191,24 +191,6 @@ fn get_arguments(engine_state: &EngineState, stack: &mut Stack, call: Call) -> V
|
|||||||
let arg_value_name_span_start = evaled_span.start as i64;
|
let arg_value_name_span_start = evaled_span.start as i64;
|
||||||
let arg_value_name_span_end = evaled_span.end as i64;
|
let arg_value_name_span_end = evaled_span.end as i64;
|
||||||
|
|
||||||
let record = record! {
|
|
||||||
"arg_type" => Value::string(arg_type, span),
|
|
||||||
"name" => Value::string(arg_value_name, inner_expr.span),
|
|
||||||
"type" => Value::string(arg_value_type, span),
|
|
||||||
"span_start" => Value::int(arg_value_name_span_start, span),
|
|
||||||
"span_end" => Value::int(arg_value_name_span_end, span),
|
|
||||||
};
|
|
||||||
arg_value.push(Value::record(record, inner_expr.span));
|
|
||||||
}
|
|
||||||
Argument::Spread(inner_expr) => {
|
|
||||||
let arg_type = "spread";
|
|
||||||
let evaluated_expression = get_expression_as_value(engine_state, stack, inner_expr);
|
|
||||||
let arg_value_name = debug_string_without_formatting(&evaluated_expression);
|
|
||||||
let arg_value_type = &evaluated_expression.get_type().to_string();
|
|
||||||
let evaled_span = evaluated_expression.span();
|
|
||||||
let arg_value_name_span_start = evaled_span.start as i64;
|
|
||||||
let arg_value_name_span_end = evaled_span.end as i64;
|
|
||||||
|
|
||||||
let record = record! {
|
let record = record! {
|
||||||
"arg_type" => Value::string(arg_type, span),
|
"arg_type" => Value::string(arg_type, span),
|
||||||
"name" => Value::string(arg_value_name, inner_expr.span),
|
"name" => Value::string(arg_value_name, inner_expr.span),
|
||||||
@ -277,5 +259,6 @@ pub fn debug_string_without_formatting(value: &Value) -> String {
|
|||||||
Value::Binary { val, .. } => format!("{val:?}"),
|
Value::Binary { val, .. } => format!("{val:?}"),
|
||||||
Value::CellPath { val, .. } => val.to_string(),
|
Value::CellPath { val, .. } => val.to_string(),
|
||||||
Value::CustomValue { val, .. } => val.value_string(),
|
Value::CustomValue { val, .. } => val.value_string(),
|
||||||
|
Value::MatchPattern { val, .. } => format!("{:?}", val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use nu_protocol::{
|
|||||||
record, Category, Example, IntoPipelineData, LazyRecord, PipelineData, Record, ShellError,
|
record, Category, Example, IntoPipelineData, LazyRecord, PipelineData, Record, ShellError,
|
||||||
Signature, Span, Type, Value,
|
Signature, Span, Type, Value,
|
||||||
};
|
};
|
||||||
use sysinfo::{MemoryRefreshKind, Pid, ProcessRefreshKind, RefreshKind, System};
|
use sysinfo::{Pid, PidExt, ProcessExt, ProcessRefreshKind, RefreshKind, System, SystemExt};
|
||||||
const ENV_PATH_SEPARATOR_CHAR: char = {
|
const ENV_PATH_SEPARATOR_CHAR: char = {
|
||||||
#[cfg(target_family = "windows")]
|
#[cfg(target_family = "windows")]
|
||||||
{
|
{
|
||||||
@ -98,9 +98,8 @@ impl LazySystemInfoRecord {
|
|||||||
}
|
}
|
||||||
"system" => {
|
"system" => {
|
||||||
// only get information requested
|
// only get information requested
|
||||||
let system_opt = SystemOpt::from((system_option, || {
|
let system_opt =
|
||||||
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
|
SystemOpt::from((system_option, || RefreshKind::new().with_memory()));
|
||||||
}));
|
|
||||||
|
|
||||||
let system = system_opt.get_system();
|
let system = system_opt.get_system();
|
||||||
|
|
||||||
@ -136,26 +135,14 @@ impl LazySystemInfoRecord {
|
|||||||
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, self.span),
|
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, self.span),
|
||||||
"status" => Value::string(p.status().to_string(), self.span),
|
"status" => Value::string(p.status().to_string(), self.span),
|
||||||
"root" => {
|
"root" => {
|
||||||
if let Some(path) = p.exe().and_then(|p| p.parent()) {
|
if let Some(filename) = p.exe().parent() {
|
||||||
Value::string(path.to_string_lossy().to_string(), self.span)
|
Value::string(filename.to_string_lossy().to_string(), self.span)
|
||||||
} else {
|
|
||||||
Value::nothing(self.span)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cwd" => {
|
|
||||||
if let Some(path) = p.cwd() {
|
|
||||||
Value::string(path.to_string_lossy().to_string(), self.span)
|
|
||||||
}else{
|
|
||||||
Value::nothing(self.span)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exe_path" => {
|
|
||||||
if let Some(path)= p.exe() {
|
|
||||||
Value::string(path.to_string_lossy().to_string(), self.span)
|
|
||||||
} else {
|
} else {
|
||||||
Value::nothing(self.span)
|
Value::nothing(self.span)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cwd" => Value::string(p.cwd().to_string_lossy().to_string(), self.span),
|
||||||
|
"exe_path" => Value::string(p.exe().to_string_lossy().to_string(), self.span),
|
||||||
"command" => Value::string(p.cmd().join(" "), self.span),
|
"command" => Value::string(p.cmd().join(" "), self.span),
|
||||||
"name" => Value::string(p.name().to_string(), self.span),
|
"name" => Value::string(p.name().to_string(), self.span),
|
||||||
"environment" => {
|
"environment" => {
|
||||||
@ -193,9 +180,8 @@ impl LazySystemInfoRecord {
|
|||||||
} else {
|
} else {
|
||||||
// If we can't get the process information, just return the system information
|
// If we can't get the process information, just return the system information
|
||||||
// only get information requested
|
// only get information requested
|
||||||
let system_opt = SystemOpt::from((system_option, || {
|
let system_opt =
|
||||||
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
|
SystemOpt::from((system_option, || RefreshKind::new().with_memory()));
|
||||||
}));
|
|
||||||
let system = system_opt.get_system();
|
let system = system_opt.get_system();
|
||||||
|
|
||||||
Ok(Value::record(
|
Ok(Value::record(
|
||||||
@ -242,7 +228,7 @@ impl<'a> LazyRecord<'a> for LazySystemInfoRecord {
|
|||||||
.without_disk_usage()
|
.without_disk_usage()
|
||||||
.without_user(),
|
.without_user(),
|
||||||
)
|
)
|
||||||
.with_memory(MemoryRefreshKind::everything());
|
.with_memory();
|
||||||
// only get information requested
|
// only get information requested
|
||||||
let system = System::new_with_specifics(rk);
|
let system = System::new_with_specifics(rk);
|
||||||
|
|
||||||
|
@ -86,12 +86,6 @@ impl Command for Metadata {
|
|||||||
PipelineMetadata {
|
PipelineMetadata {
|
||||||
data_source: DataSource::HtmlThemes,
|
data_source: DataSource::HtmlThemes,
|
||||||
} => record.push("source", Value::string("into html --list", head)),
|
} => record.push("source", Value::string("into html --list", head)),
|
||||||
PipelineMetadata {
|
|
||||||
data_source: DataSource::FilePath(path),
|
|
||||||
} => record.push(
|
|
||||||
"source",
|
|
||||||
Value::string(path.to_string_lossy().to_string(), head),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,12 +133,6 @@ fn build_metadata_record(arg: &Value, metadata: Option<&PipelineMetadata>, head:
|
|||||||
PipelineMetadata {
|
PipelineMetadata {
|
||||||
data_source: DataSource::HtmlThemes,
|
data_source: DataSource::HtmlThemes,
|
||||||
} => record.push("source", Value::string("into html --list", head)),
|
} => record.push("source", Value::string("into html --list", head)),
|
||||||
PipelineMetadata {
|
|
||||||
data_source: DataSource::FilePath(path),
|
|
||||||
} => record.push(
|
|
||||||
"source",
|
|
||||||
Value::string(path.to_string_lossy().to_string(), head),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +191,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||||||
StrSubstring,
|
StrSubstring,
|
||||||
StrTrim,
|
StrTrim,
|
||||||
StrUpcase,
|
StrUpcase,
|
||||||
Format,
|
|
||||||
FormatDate,
|
FormatDate,
|
||||||
FormatDuration,
|
FormatDuration,
|
||||||
FormatFilesize,
|
FormatFilesize,
|
||||||
@ -233,9 +232,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
|||||||
Whoami,
|
Whoami,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
bind_command! { ULimit };
|
|
||||||
|
|
||||||
// Date
|
// Date
|
||||||
bind_command! {
|
bind_command! {
|
||||||
Date,
|
Date,
|
||||||
|
@ -66,17 +66,16 @@ fn is_root_impl() -> bool {
|
|||||||
System::Threading::{GetCurrentProcess, OpenProcessToken},
|
System::Threading::{GetCurrentProcess, OpenProcessToken},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut handle = HANDLE::default();
|
||||||
let mut elevated = false;
|
let mut elevated = false;
|
||||||
|
|
||||||
// Checks whether the access token associated with the current process has elevated privileges.
|
// Checks whether the access token associated with the current process has elevated privileges.
|
||||||
// SAFETY: `elevated` only touched by safe code.
|
// SAFETY: `elevated` only touched by safe code.
|
||||||
// `handle` lives long enough, initialized, mutated, used and closed with validity check.
|
// `handle` lives long enough, initialized, mutated as out param, used, closed with validity check.
|
||||||
// `elevation` only read on success and passed with correct `size`.
|
// `elevation` only read on success and passed with correct `size`.
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut handle = HANDLE::default();
|
|
||||||
|
|
||||||
// Opens the access token associated with the current process.
|
// Opens the access token associated with the current process.
|
||||||
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle).is_ok() {
|
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle).as_bool() {
|
||||||
let mut elevation = TOKEN_ELEVATION::default();
|
let mut elevation = TOKEN_ELEVATION::default();
|
||||||
let mut size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
let mut size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||||
|
|
||||||
@ -90,7 +89,7 @@ fn is_root_impl() -> bool {
|
|||||||
size,
|
size,
|
||||||
&mut size,
|
&mut size,
|
||||||
)
|
)
|
||||||
.is_ok()
|
.as_bool()
|
||||||
{
|
{
|
||||||
// Whether the token has elevated privileges.
|
// Whether the token has elevated privileges.
|
||||||
// Safe to read as `GetTokenInformation` will not write outside `elevation` and it succeeded
|
// Safe to read as `GetTokenInformation` will not write outside `elevation` and it succeeded
|
||||||
@ -101,7 +100,7 @@ fn is_root_impl() -> bool {
|
|||||||
|
|
||||||
if !handle.is_invalid() {
|
if !handle.is_invalid() {
|
||||||
// Closes the object handle.
|
// Closes the object handle.
|
||||||
let _ = CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,16 +229,7 @@ fn have_permission(dir: impl AsRef<Path>) -> PermissionResult<'static> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(unix)]
|
||||||
fn any_group(_current_user_gid: gid_t, owner_group: u32) -> bool {
|
|
||||||
use crate::filesystem::util::users;
|
|
||||||
let Some(user_groups) = users::current_user_groups() else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
user_groups.iter().any(|gid| gid.as_raw() == owner_group)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(any(target_os = "linux", target_os = "android"))))]
|
|
||||||
fn any_group(current_user_gid: gid_t, owner_group: u32) -> bool {
|
fn any_group(current_user_gid: gid_t, owner_group: u32) -> bool {
|
||||||
use crate::filesystem::util::users;
|
use crate::filesystem::util::users;
|
||||||
|
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
use nu_engine::{current_dir, eval_block, CallExt};
|
use nu_engine::{current_dir, eval_block, CallExt};
|
||||||
use nu_path::expand_to_real_path;
|
|
||||||
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::util::BufferedReader;
|
use nu_protocol::util::BufferedReader;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, DataSource, Example, IntoInterruptiblePipelineData, PipelineData, PipelineMetadata,
|
Category, Example, IntoInterruptiblePipelineData, PipelineData, RawStream, ShellError,
|
||||||
RawStream, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Signature, Spanned, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
use std::io::BufReader;
|
use std::io::BufReader;
|
||||||
|
|
||||||
@ -158,7 +157,6 @@ impl Command for Open {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let buf_reader = BufReader::new(file);
|
let buf_reader = BufReader::new(file);
|
||||||
let real_path = expand_to_real_path(path);
|
|
||||||
|
|
||||||
let file_contents = PipelineData::ExternalStream {
|
let file_contents = PipelineData::ExternalStream {
|
||||||
stdout: Some(RawStream::new(
|
stdout: Some(RawStream::new(
|
||||||
@ -170,9 +168,7 @@ impl Command for Open {
|
|||||||
stderr: None,
|
stderr: None,
|
||||||
exit_code: None,
|
exit_code: None,
|
||||||
span: call_span,
|
span: call_span,
|
||||||
metadata: Some(PipelineMetadata {
|
metadata: None,
|
||||||
data_source: DataSource::FilePath(real_path),
|
|
||||||
}),
|
|
||||||
trim_end_newline: false,
|
trim_end_newline: false,
|
||||||
};
|
};
|
||||||
let exts_opt: Option<Vec<String>> = if raw {
|
let exts_opt: Option<Vec<String>> = if raw {
|
||||||
|
@ -381,23 +381,11 @@ fn rm(
|
|||||||
{
|
{
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
} else if metadata.is_symlink() {
|
} else if metadata.is_file()
|
||||||
// In Windows, symlink pointing to a directory can be removed using
|
|| is_socket
|
||||||
// std::fs::remove_dir instead of std::fs::remove_file.
|
|| is_fifo
|
||||||
#[cfg(windows)]
|
|| metadata.file_type().is_symlink()
|
||||||
{
|
{
|
||||||
f.metadata().and_then(|metadata| {
|
|
||||||
if metadata.is_dir() {
|
|
||||||
std::fs::remove_dir(&f)
|
|
||||||
} else {
|
|
||||||
std::fs::remove_file(&f)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
std::fs::remove_file(&f)
|
|
||||||
} else if metadata.is_file() || is_socket || is_fifo {
|
|
||||||
std::fs::remove_file(&f)
|
std::fs::remove_file(&f)
|
||||||
} else {
|
} else {
|
||||||
std::fs::remove_dir_all(&f)
|
std::fs::remove_dir_all(&f)
|
||||||
|
@ -4,8 +4,8 @@ use nu_path::expand_path_with;
|
|||||||
use nu_protocol::ast::{Call, Expr, Expression};
|
use nu_protocol::ast::{Call, Expr, Expression};
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, DataSource, Example, PipelineData, PipelineMetadata, RawStream, ShellError,
|
Category, Example, PipelineData, RawStream, ShellError, Signature, Span, Spanned, SyntaxShape,
|
||||||
Signature, Span, Spanned, SyntaxShape, Type, Value,
|
Type, Value,
|
||||||
};
|
};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
@ -149,42 +149,9 @@ impl Command for Save {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PipelineData::ListStream(ls, pipeline_metadata)
|
PipelineData::ListStream(ls, _)
|
||||||
if raw || prepare_path(&path, append, force)?.0.extension().is_none() =>
|
if raw || prepare_path(&path, append, force)?.0.extension().is_none() =>
|
||||||
{
|
{
|
||||||
if let Some(PipelineMetadata {
|
|
||||||
data_source: DataSource::FilePath(input_path),
|
|
||||||
}) = pipeline_metadata
|
|
||||||
{
|
|
||||||
if path.item == input_path {
|
|
||||||
return Err(ShellError::GenericError {
|
|
||||||
error: "pipeline input and output are same file".into(),
|
|
||||||
msg: format!(
|
|
||||||
"can't save output to '{}' while it's being reading",
|
|
||||||
path.item.display()
|
|
||||||
),
|
|
||||||
span: Some(path.span),
|
|
||||||
help: Some("you should change output path".into()),
|
|
||||||
inner: vec![],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ref err_path) = stderr_path {
|
|
||||||
if err_path.item == input_path {
|
|
||||||
return Err(ShellError::GenericError {
|
|
||||||
error: "pipeline input and stderr are same file".into(),
|
|
||||||
msg: format!(
|
|
||||||
"can't save stderr to '{}' while it's being reading",
|
|
||||||
err_path.item.display()
|
|
||||||
),
|
|
||||||
span: Some(err_path.span),
|
|
||||||
help: Some("you should change stderr path".into()),
|
|
||||||
inner: vec![],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (mut file, _) = get_files(
|
let (mut file, _) = get_files(
|
||||||
&path,
|
&path,
|
||||||
stderr_path.as_ref(),
|
stderr_path.as_ref(),
|
||||||
@ -373,7 +340,10 @@ fn prepare_path(
|
|||||||
|
|
||||||
fn open_file(path: &Path, span: Span, append: bool) -> Result<File, ShellError> {
|
fn open_file(path: &Path, span: Span, append: bool) -> Result<File, ShellError> {
|
||||||
let file = match (append, path.exists()) {
|
let file = match (append, path.exists()) {
|
||||||
(true, true) => std::fs::OpenOptions::new().append(true).open(path),
|
(true, true) => std::fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.append(true)
|
||||||
|
.open(path),
|
||||||
_ => std::fs::File::create(path),
|
_ => std::fs::File::create(path),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,8 +165,9 @@ pub fn is_older(src: &Path, dst: &Path) -> Option<bool> {
|
|||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub mod users {
|
pub mod users {
|
||||||
use libc::{gid_t, uid_t};
|
use libc::{c_int, gid_t, uid_t};
|
||||||
use nix::unistd::{Gid, Group, Uid, User};
|
use nix::unistd::{Gid, Group, Uid, User};
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
pub fn get_user_by_uid(uid: uid_t) -> Option<User> {
|
pub fn get_user_by_uid(uid: uid_t) -> Option<User> {
|
||||||
User::from_uid(Uid::from_raw(uid)).ok().flatten()
|
User::from_uid(Uid::from_raw(uid)).ok().flatten()
|
||||||
@ -184,7 +185,6 @@ pub mod users {
|
|||||||
Gid::current().as_raw()
|
Gid::current().as_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
|
||||||
pub fn get_current_username() -> Option<String> {
|
pub fn get_current_username() -> Option<String> {
|
||||||
User::from_uid(Uid::current())
|
User::from_uid(Uid::current())
|
||||||
.ok()
|
.ok()
|
||||||
@ -192,30 +192,6 @@ pub mod users {
|
|||||||
.map(|user| user.name)
|
.map(|user| user.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
pub fn current_user_groups() -> Option<Vec<Gid>> {
|
|
||||||
// SAFETY:
|
|
||||||
// if first arg is 0 then it ignores second argument and returns number of groups present for given user.
|
|
||||||
let ngroups = unsafe { libc::getgroups(0, core::ptr::null::<gid_t> as *mut _) };
|
|
||||||
let mut buff: Vec<gid_t> = vec![0; ngroups as usize];
|
|
||||||
|
|
||||||
// SAFETY:
|
|
||||||
// buff is the size of ngroups and getgroups reads max ngroups elements into buff
|
|
||||||
let found = unsafe { libc::getgroups(ngroups, buff.as_mut_ptr()) };
|
|
||||||
|
|
||||||
if found < 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
buff.truncate(found as usize);
|
|
||||||
buff.sort_unstable();
|
|
||||||
buff.dedup();
|
|
||||||
buff.into_iter()
|
|
||||||
.filter_map(|i| get_group_by_gid(i as gid_t))
|
|
||||||
.map(|group| group.gid)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Returns groups for a provided user name and primary group id.
|
/// Returns groups for a provided user name and primary group id.
|
||||||
///
|
///
|
||||||
/// # libc functions used
|
/// # libc functions used
|
||||||
@ -231,9 +207,7 @@ pub mod users {
|
|||||||
/// println!("User is a member of group #{group}");
|
/// println!("User is a member of group #{group}");
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
|
||||||
pub fn get_user_groups(username: &str, gid: gid_t) -> Option<Vec<Gid>> {
|
pub fn get_user_groups(username: &str, gid: gid_t) -> Option<Vec<Gid>> {
|
||||||
use std::ffi::CString;
|
|
||||||
// MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons
|
// MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
let mut buff: Vec<i32> = vec![0; 1024];
|
let mut buff: Vec<i32> = vec![0; 1024];
|
||||||
@ -244,7 +218,7 @@ pub mod users {
|
|||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut count = buff.len() as libc::c_int;
|
let mut count = buff.len() as c_int;
|
||||||
|
|
||||||
// MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons
|
// MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
|
@ -516,6 +516,7 @@ fn value_should_be_printed(
|
|||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
},
|
},
|
||||||
Value::Binary { .. } => false,
|
Value::Binary { .. } => false,
|
||||||
|
Value::MatchPattern { .. } => false,
|
||||||
});
|
});
|
||||||
if invert {
|
if invert {
|
||||||
match_found = !match_found;
|
match_found = !match_found;
|
||||||
|
@ -174,7 +174,7 @@ pub fn group_by(
|
|||||||
Value::CellPath { val, .. } => group_cell_path(val, values)?,
|
Value::CellPath { val, .. } => group_cell_path(val, values)?,
|
||||||
Value::Block { .. } | Value::Closure { .. } => {
|
Value::Block { .. } | Value::Closure { .. } => {
|
||||||
let block: Option<Closure> = call.opt(engine_state, stack, 0)?;
|
let block: Option<Closure> = call.opt(engine_state, stack, 0)?;
|
||||||
group_closure(values, span, block, stack, engine_state, call)?
|
group_closure(&values, span, block, stack, engine_state, call)?
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
@ -231,8 +231,9 @@ pub fn group_no_grouper(values: Vec<Value>) -> Result<IndexMap<String, Vec<Value
|
|||||||
Ok(groups)
|
Ok(groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor this, it's a bit of a mess
|
||||||
fn group_closure(
|
fn group_closure(
|
||||||
values: Vec<Value>,
|
values: &[Value],
|
||||||
span: Span,
|
span: Span,
|
||||||
block: Option<Closure>,
|
block: Option<Closure>,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
@ -240,13 +241,13 @@ fn group_closure(
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||||
let error_key = "error";
|
let error_key = "error";
|
||||||
let mut groups: IndexMap<String, Vec<Value>> = IndexMap::new();
|
let mut keys: Vec<Result<String, ShellError>> = vec![];
|
||||||
|
let value_list = Value::list(values.to_vec(), span);
|
||||||
if let Some(capture_block) = &block {
|
|
||||||
let block = engine_state.get_block(capture_block.block_id);
|
|
||||||
|
|
||||||
for value in values {
|
for value in values {
|
||||||
|
if let Some(capture_block) = &block {
|
||||||
let mut stack = stack.captures_to_stack(capture_block.captures.clone());
|
let mut stack = stack.captures_to_stack(capture_block.captures.clone());
|
||||||
|
let block = engine_state.get_block(capture_block.block_id);
|
||||||
let pipeline = eval_block(
|
let pipeline = eval_block(
|
||||||
engine_state,
|
engine_state,
|
||||||
&mut stack,
|
&mut stack,
|
||||||
@ -256,16 +257,11 @@ fn group_closure(
|
|||||||
call.redirect_stderr,
|
call.redirect_stderr,
|
||||||
);
|
);
|
||||||
|
|
||||||
let group_key = match pipeline {
|
match pipeline {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let mut s = s.into_iter();
|
let collection: Vec<Value> = s.into_iter().collect();
|
||||||
|
|
||||||
let key = match s.next() {
|
if collection.len() > 1 {
|
||||||
Some(Value::Error { .. }) | None => error_key.into(),
|
|
||||||
Some(return_value) => return_value.as_string()?,
|
|
||||||
};
|
|
||||||
|
|
||||||
if s.next().is_some() {
|
|
||||||
return Err(ShellError::GenericError {
|
return Err(ShellError::GenericError {
|
||||||
error: "expected one value from the block".into(),
|
error: "expected one value from the block".into(),
|
||||||
msg: "requires a table with one value for grouping".into(),
|
msg: "requires a table with one value for grouping".into(),
|
||||||
@ -275,13 +271,38 @@ fn group_closure(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
key
|
let value = match collection.first() {
|
||||||
}
|
Some(Value::Error { .. }) | None => Value::string(error_key, span),
|
||||||
Err(_) => error_key.into(),
|
Some(return_value) => return_value.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
groups.entry(group_key).or_default().push(value);
|
keys.push(value.as_string());
|
||||||
}
|
}
|
||||||
|
Err(_) => {
|
||||||
|
keys.push(Ok(error_key.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let map = keys;
|
||||||
|
let block = Box::new(move |idx: usize, row: &Value| match map.get(idx) {
|
||||||
|
Some(Ok(key)) => Ok(key.clone()),
|
||||||
|
Some(Err(reason)) => Err(reason.clone()),
|
||||||
|
None => row.as_string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let grouper = &Some(block);
|
||||||
|
let mut groups: IndexMap<String, Vec<Value>> = IndexMap::new();
|
||||||
|
|
||||||
|
for (idx, value) in value_list.into_pipeline_data().into_iter().enumerate() {
|
||||||
|
let group_key = if let Some(ref grouper) = grouper {
|
||||||
|
grouper(idx, &value)
|
||||||
|
} else {
|
||||||
|
value.as_string()
|
||||||
|
};
|
||||||
|
|
||||||
|
let group = groups.entry(group_key?).or_default();
|
||||||
|
group.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(groups)
|
Ok(groups)
|
||||||
|
@ -55,7 +55,10 @@ fn from_delimited_string_to_value(
|
|||||||
.collect::<Vec<Value>>();
|
.collect::<Vec<Value>>();
|
||||||
|
|
||||||
rows.push(Value::record(
|
rows.push(Value::record(
|
||||||
Record::from_raw_cols_vals(headers.clone(), output_row),
|
Record {
|
||||||
|
cols: headers.clone(),
|
||||||
|
vals: output_row,
|
||||||
|
},
|
||||||
span,
|
span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -242,6 +242,12 @@ fn convert_to_value(
|
|||||||
msg: "extra tokens in input file".into(),
|
msg: "extra tokens in input file".into(),
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
}),
|
}),
|
||||||
|
Expr::MatchPattern(..) => Err(ShellError::OutsideSpannedLabeledError {
|
||||||
|
src: original_text.to_string(),
|
||||||
|
error: "Error when loading".into(),
|
||||||
|
msg: "extra tokens in input file".into(),
|
||||||
|
span: expr.span,
|
||||||
|
}),
|
||||||
Expr::GlobPattern(val) => Ok(Value::string(val, span)),
|
Expr::GlobPattern(val) => Ok(Value::string(val, span)),
|
||||||
Expr::ImportPattern(..) => Err(ShellError::OutsideSpannedLabeledError {
|
Expr::ImportPattern(..) => Err(ShellError::OutsideSpannedLabeledError {
|
||||||
src: original_text.to_string(),
|
src: original_text.to_string(),
|
||||||
@ -403,7 +409,13 @@ fn convert_to_value(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for row in cells {
|
for row in cells {
|
||||||
if cols.len() != row.len() {
|
let mut vals = vec![];
|
||||||
|
|
||||||
|
for cell in row {
|
||||||
|
vals.push(convert_to_value(cell, span, original_text)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
if cols.len() != vals.len() {
|
||||||
return Err(ShellError::OutsideSpannedLabeledError {
|
return Err(ShellError::OutsideSpannedLabeledError {
|
||||||
src: original_text.to_string(),
|
src: original_text.to_string(),
|
||||||
error: "Error when loading".into(),
|
error: "Error when loading".into(),
|
||||||
@ -411,13 +423,12 @@ fn convert_to_value(
|
|||||||
span: expr.span,
|
span: expr.span,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let vals: Vec<Value> = row
|
|
||||||
.into_iter()
|
|
||||||
.map(|cell| convert_to_value(cell, span, original_text))
|
|
||||||
.collect::<Result<_, _>>()?;
|
|
||||||
|
|
||||||
output.push(Value::record(
|
output.push(Value::record(
|
||||||
Record::from_raw_cols_vals(cols.clone(), vals),
|
Record {
|
||||||
|
cols: cols.clone(),
|
||||||
|
vals,
|
||||||
|
},
|
||||||
span,
|
span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,10 @@ pub fn value_to_json_value(v: &Value) -> Result<nu_json::Value, ShellError> {
|
|||||||
|
|
||||||
Value::List { vals, .. } => nu_json::Value::Array(json_list(vals)?),
|
Value::List { vals, .. } => nu_json::Value::Array(json_list(vals)?),
|
||||||
Value::Error { error, .. } => return Err(*error.clone()),
|
Value::Error { error, .. } => return Err(*error.clone()),
|
||||||
Value::Closure { .. } | Value::Block { .. } | Value::Range { .. } => nu_json::Value::Null,
|
Value::Closure { .. }
|
||||||
|
| Value::Block { .. }
|
||||||
|
| Value::Range { .. }
|
||||||
|
| Value::MatchPattern { .. } => nu_json::Value::Null,
|
||||||
Value::Binary { val, .. } => {
|
Value::Binary { val, .. } => {
|
||||||
nu_json::Value::Array(val.iter().map(|x| nu_json::Value::U64(*x as u64)).collect())
|
nu_json::Value::Array(val.iter().map(|x| nu_json::Value::U64(*x as u64)).collect())
|
||||||
}
|
}
|
||||||
|
@ -241,6 +241,12 @@ pub fn value_to_string(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Value::MatchPattern { .. } => Err(ShellError::UnsupportedInput {
|
||||||
|
msg: "match patterns are currently not nuon-compatible".to_string(),
|
||||||
|
input: "value originates from here".into(),
|
||||||
|
msg_span: span,
|
||||||
|
input_span: v.span(),
|
||||||
|
}),
|
||||||
Value::Nothing { .. } => Ok("null".to_string()),
|
Value::Nothing { .. } => Ok("null".to_string()),
|
||||||
Value::Range { val, .. } => Ok(format!(
|
Value::Range { val, .. } => Ok(format!(
|
||||||
"{}..{}{}",
|
"{}..{}{}",
|
||||||
|
@ -148,6 +148,7 @@ fn local_into_string(value: Value, separator: &str, config: &Config) -> String {
|
|||||||
Value::Binary { val, .. } => format!("{val:?}"),
|
Value::Binary { val, .. } => format!("{val:?}"),
|
||||||
Value::CellPath { val, .. } => val.to_string(),
|
Value::CellPath { val, .. } => val.to_string(),
|
||||||
Value::CustomValue { val, .. } => val.value_string(),
|
Value::CustomValue { val, .. } => val.value_string(),
|
||||||
|
Value::MatchPattern { val, .. } => format!("{:?}", val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ fn helper(engine_state: &EngineState, v: &Value) -> Result<toml::Value, ShellErr
|
|||||||
.collect::<Result<Vec<toml::Value>, ShellError>>()?,
|
.collect::<Result<Vec<toml::Value>, ShellError>>()?,
|
||||||
),
|
),
|
||||||
Value::CustomValue { .. } => toml::Value::String("<Custom Value>".to_string()),
|
Value::CustomValue { .. } => toml::Value::String("<Custom Value>".to_string()),
|
||||||
|
Value::MatchPattern { .. } => toml::Value::String("<Match Pattern>".to_string()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,10 +34,10 @@ impl Command for ToXml {
|
|||||||
fn extra_usage(&self) -> &str {
|
fn extra_usage(&self) -> &str {
|
||||||
r#"Every XML entry is represented via a record with tag, attribute and content fields.
|
r#"Every XML entry is represented via a record with tag, attribute and content fields.
|
||||||
To represent different types of entries different values must be written to this fields:
|
To represent different types of entries different values must be written to this fields:
|
||||||
1. Tag entry: `{tag: <tag name> attributes: {<attr name>: "<string value>" ...} content: [<entries>]}`
|
1. Tag entry: `{tag: <tag name> attrs: {<attr name>: "<string value>" ...} content: [<entries>]}`
|
||||||
2. Comment entry: `{tag: '!' attributes: null content: "<comment string>"}`
|
2. Comment entry: `{tag: '!' attrs: null content: "<comment string>"}`
|
||||||
3. Processing instruction (PI): `{tag: '?<pi name>' attributes: null content: "<pi content string>"}`
|
3. Processing instruction (PI): `{tag: '?<pi name>' attrs: null content: "<pi content string>"}`
|
||||||
4. Text: `{tag: null attributes: null content: "<text>"}`. Or as plain `<text>` instead of record.
|
4. Text: `{tag: null attrs: null content: "<text>"}`. Or as plain `<text>` instead of record.
|
||||||
|
|
||||||
Additionally any field which is: empty record, empty list or null, can be omitted."#
|
Additionally any field which is: empty record, empty list or null, can be omitted."#
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ Additionally any field which is: empty record, empty list or null, can be omitte
|
|||||||
vec![
|
vec![
|
||||||
Example {
|
Example {
|
||||||
description: "Outputs an XML string representing the contents of this table",
|
description: "Outputs an XML string representing the contents of this table",
|
||||||
example: r#"{tag: note attributes: {} content : [{tag: remember attributes: {} content : [{tag: null attributes: null content : Event}]}]} | to xml"#,
|
example: r#"{tag: note attributes: {} content : [{tag: remember attributes: {} content : [{tag: null attrs: null content : Event}]}]} | to xml"#,
|
||||||
result: Some(Value::test_string(
|
result: Some(Value::test_string(
|
||||||
"<note><remember>Event</remember></note>",
|
"<note><remember>Event</remember></note>",
|
||||||
)),
|
)),
|
||||||
@ -110,17 +110,6 @@ fn to_xml_entry<W: Write>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Value::Record { val: record, .. } = &entry {
|
if let Value::Record { val: record, .. } = &entry {
|
||||||
if let Some(bad_column) = find_invalid_column(record) {
|
|
||||||
return Err(ShellError::CantConvert {
|
|
||||||
to_type: "XML".into(),
|
|
||||||
from_type: "record".into(),
|
|
||||||
span: entry_span,
|
|
||||||
help: Some(format!(
|
|
||||||
"Invalid column \"{}\" in xml entry. Only \"{}\", \"{}\" and \"{}\" are permitted",
|
|
||||||
bad_column, COLUMN_TAG_NAME, COLUMN_ATTRS_NAME, COLUMN_CONTENT_NAME
|
|
||||||
)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// If key is not found it is assumed to be nothing. This way
|
// If key is not found it is assumed to be nothing. This way
|
||||||
// user can write a tag like {tag: a content: [...]} instead
|
// user can write a tag like {tag: a content: [...]} instead
|
||||||
// of longer {tag: a attributes: {} content: [...]}
|
// of longer {tag: a attributes: {} content: [...]}
|
||||||
@ -155,12 +144,7 @@ fn to_xml_entry<W: Write>(
|
|||||||
(Value::String { val: tag_name, .. }, attrs, children) => to_tag_like(
|
(Value::String { val: tag_name, .. }, attrs, children) => to_tag_like(
|
||||||
entry_span, tag_name, tag_span, attrs, children, top_level, writer,
|
entry_span, tag_name, tag_span, attrs, children, top_level, writer,
|
||||||
),
|
),
|
||||||
_ => Err(ShellError::CantConvert {
|
_ => Ok(()),
|
||||||
to_type: "XML".into(),
|
|
||||||
from_type: "record".into(),
|
|
||||||
span: entry_span,
|
|
||||||
help: Some("Tag missing or is not a string".into()),
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::CantConvert {
|
Err(ShellError::CantConvert {
|
||||||
@ -172,14 +156,6 @@ fn to_xml_entry<W: Write>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_invalid_column(record: &Record) -> Option<&String> {
|
|
||||||
const VALID_COLS: [&str; 3] = [COLUMN_TAG_NAME, COLUMN_ATTRS_NAME, COLUMN_CONTENT_NAME];
|
|
||||||
record
|
|
||||||
.cols
|
|
||||||
.iter()
|
|
||||||
.find(|col| !VALID_COLS.contains(&col.as_str()))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert record to tag-like entry: tag, PI, comment.
|
/// Convert record to tag-like entry: tag, PI, comment.
|
||||||
fn to_tag_like<W: Write>(
|
fn to_tag_like<W: Write>(
|
||||||
entry_span: Span,
|
entry_span: Span,
|
||||||
|
@ -97,6 +97,7 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
|
|||||||
.collect::<Result<Vec<serde_yaml::Value>, ShellError>>()?,
|
.collect::<Result<Vec<serde_yaml::Value>, ShellError>>()?,
|
||||||
),
|
),
|
||||||
Value::CustomValue { .. } => serde_yaml::Value::Null,
|
Value::CustomValue { .. } => serde_yaml::Value::Null,
|
||||||
|
Value::MatchPattern { .. } => serde_yaml::Value::Null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ mod random;
|
|||||||
mod removed;
|
mod removed;
|
||||||
mod shells;
|
mod shells;
|
||||||
mod sort_utils;
|
mod sort_utils;
|
||||||
#[cfg(feature = "sqlite")]
|
|
||||||
mod stor;
|
mod stor;
|
||||||
mod strings;
|
mod strings;
|
||||||
mod system;
|
mod system;
|
||||||
|
@ -5,8 +5,7 @@ use base64::{alphabet, Engine};
|
|||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{EngineState, Stack};
|
use nu_protocol::engine::{EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
record, BufferedReader, IntoPipelineData, PipelineData, RawStream, ShellError, Span, Spanned,
|
record, BufferedReader, IntoPipelineData, PipelineData, RawStream, ShellError, Span, Value,
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
use ureq::{Error, ErrorKind, Request, Response};
|
use ureq::{Error, ErrorKind, Request, Response};
|
||||||
|
|
||||||
@ -27,45 +26,29 @@ pub enum BodyType {
|
|||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
// Only panics if the user agent is invalid but we define it statically so either
|
||||||
pub enum RedirectMode {
|
// it always or never fails
|
||||||
Follow,
|
|
||||||
Error,
|
|
||||||
Manual,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn http_client(
|
pub fn http_client(
|
||||||
allow_insecure: bool,
|
allow_insecure: bool,
|
||||||
redirect_mode: RedirectMode,
|
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
) -> Result<ureq::Agent, ShellError> {
|
) -> ureq::Agent {
|
||||||
let tls = native_tls::TlsConnector::builder()
|
let tls = native_tls::TlsConnector::builder()
|
||||||
.danger_accept_invalid_certs(allow_insecure)
|
.danger_accept_invalid_certs(allow_insecure)
|
||||||
.build()
|
.build()
|
||||||
.map_err(|e| ShellError::GenericError {
|
.expect("Failed to build network tls");
|
||||||
error: format!("Failed to build network tls: {}", e),
|
|
||||||
msg: String::new(),
|
|
||||||
span: None,
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut agent_builder = ureq::builder()
|
let mut agent_builder = ureq::builder()
|
||||||
.user_agent("nushell")
|
.user_agent("nushell")
|
||||||
.tls_connector(std::sync::Arc::new(tls));
|
.tls_connector(std::sync::Arc::new(tls));
|
||||||
|
|
||||||
if let RedirectMode::Manual | RedirectMode::Error = redirect_mode {
|
|
||||||
agent_builder = agent_builder.redirects(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(http_proxy) = retrieve_http_proxy_from_env(engine_state, stack) {
|
if let Some(http_proxy) = retrieve_http_proxy_from_env(engine_state, stack) {
|
||||||
if let Ok(proxy) = ureq::Proxy::new(http_proxy) {
|
if let Ok(proxy) = ureq::Proxy::new(http_proxy) {
|
||||||
agent_builder = agent_builder.proxy(proxy);
|
agent_builder = agent_builder.proxy(proxy);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(agent_builder.build())
|
agent_builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn http_parse_url(
|
pub fn http_parse_url(
|
||||||
@ -85,18 +68,6 @@ pub fn http_parse_url(
|
|||||||
Ok((requested_url, url))
|
Ok((requested_url, url))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn http_parse_redirect_mode(mode: Option<Spanned<String>>) -> Result<RedirectMode, ShellError> {
|
|
||||||
mode.map_or(Ok(RedirectMode::Follow), |v| match &v.item[..] {
|
|
||||||
"follow" | "f" => Ok(RedirectMode::Follow),
|
|
||||||
"error" | "e" => Ok(RedirectMode::Error),
|
|
||||||
"manual" | "m" => Ok(RedirectMode::Manual),
|
|
||||||
_ => Err(ShellError::TypeMismatch {
|
|
||||||
err_message: "Invalid redirect handling mode".to_string(),
|
|
||||||
span: v.span,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn response_to_buffer(
|
pub fn response_to_buffer(
|
||||||
response: Response,
|
response: Response,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -481,26 +452,6 @@ fn transform_response_using_content_type(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_response_redirection(
|
|
||||||
redirect_mode: RedirectMode,
|
|
||||||
span: Span,
|
|
||||||
response: &Result<Response, ShellErrorOrRequestError>,
|
|
||||||
) -> Result<(), ShellError> {
|
|
||||||
if let Ok(resp) = response {
|
|
||||||
if RedirectMode::Error == redirect_mode && (300..400).contains(&resp.status()) {
|
|
||||||
return Err(ShellError::NetworkFailure {
|
|
||||||
msg: format!(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' ({} {})",
|
|
||||||
resp.status(),
|
|
||||||
resp.status_text()
|
|
||||||
),
|
|
||||||
span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn request_handle_response_content(
|
fn request_handle_response_content(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
|
@ -2,13 +2,12 @@ use nu_engine::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::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::network::http::client::{
|
use crate::network::http::client::{
|
||||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
request_handle_response, request_set_timeout, send_request,
|
||||||
request_set_timeout, send_request,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::client::RequestFlags;
|
use super::client::RequestFlags;
|
||||||
@ -80,11 +79,6 @@ impl Command for SubCommand {
|
|||||||
"allow-errors",
|
"allow-errors",
|
||||||
"do not fail if the server returns an error code",
|
"do not fail if the server returns an error code",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
).named(
|
|
||||||
"redirect-mode",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
|
|
||||||
Some('R')
|
|
||||||
)
|
)
|
||||||
.filter()
|
.filter()
|
||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
@ -156,7 +150,6 @@ struct Arguments {
|
|||||||
timeout: Option<Value>,
|
timeout: Option<Value>,
|
||||||
full: bool,
|
full: bool,
|
||||||
allow_errors: bool,
|
allow_errors: bool,
|
||||||
redirect: Option<Spanned<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_delete(
|
fn run_delete(
|
||||||
@ -177,7 +170,6 @@ fn run_delete(
|
|||||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||||
full: call.has_flag("full"),
|
full: call.has_flag("full"),
|
||||||
allow_errors: call.has_flag("allow-errors"),
|
allow_errors: call.has_flag("allow-errors"),
|
||||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
helper(engine_state, stack, call, args)
|
helper(engine_state, stack, call, args)
|
||||||
@ -194,9 +186,8 @@ fn helper(
|
|||||||
let span = args.url.span();
|
let span = args.url.span();
|
||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
let redirect_mode = http_parse_redirect_mode(args.redirect)?;
|
|
||||||
|
|
||||||
let client = http_client(args.insecure, redirect_mode, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.delete(&requested_url);
|
let mut request = client.delete(&requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
@ -211,7 +202,6 @@ fn helper(
|
|||||||
allow_errors: args.allow_errors,
|
allow_errors: args.allow_errors,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_response_redirection(redirect_mode, span, &response)?;
|
|
||||||
request_handle_response(
|
request_handle_response(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
|
@ -2,15 +2,16 @@ use nu_engine::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::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::network::http::client::{
|
use crate::network::http::client::{
|
||||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
request_handle_response, request_set_timeout, send_request,
|
||||||
request_set_timeout, send_request, RequestFlags,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::client::RequestFlags;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
|
|
||||||
@ -72,12 +73,6 @@ impl Command for SubCommand {
|
|||||||
"do not fail if the server returns an error code",
|
"do not fail if the server returns an error code",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
)
|
)
|
||||||
.named(
|
|
||||||
"redirect-mode",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
|
|
||||||
Some('R')
|
|
||||||
)
|
|
||||||
.filter()
|
.filter()
|
||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
}
|
}
|
||||||
@ -142,7 +137,6 @@ struct Arguments {
|
|||||||
timeout: Option<Value>,
|
timeout: Option<Value>,
|
||||||
full: bool,
|
full: bool,
|
||||||
allow_errors: bool,
|
allow_errors: bool,
|
||||||
redirect: Option<Spanned<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_get(
|
fn run_get(
|
||||||
@ -161,7 +155,6 @@ fn run_get(
|
|||||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||||
full: call.has_flag("full"),
|
full: call.has_flag("full"),
|
||||||
allow_errors: call.has_flag("allow-errors"),
|
allow_errors: call.has_flag("allow-errors"),
|
||||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
|
||||||
};
|
};
|
||||||
helper(engine_state, stack, call, args)
|
helper(engine_state, stack, call, args)
|
||||||
}
|
}
|
||||||
@ -177,9 +170,8 @@ fn helper(
|
|||||||
let span = args.url.span();
|
let span = args.url.span();
|
||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
let redirect_mode = http_parse_redirect_mode(args.redirect)?;
|
|
||||||
|
|
||||||
let client = http_client(args.insecure, redirect_mode, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.get(&requested_url);
|
let mut request = client.get(&requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
@ -194,7 +186,6 @@ fn helper(
|
|||||||
allow_errors: args.allow_errors,
|
allow_errors: args.allow_errors,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_response_redirection(redirect_mode, span, &response)?;
|
|
||||||
request_handle_response(
|
request_handle_response(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
|
@ -5,13 +5,12 @@ use nu_engine::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::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::network::http::client::{
|
use crate::network::http::client::{
|
||||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||||
request_add_authorization_header, request_add_custom_headers, request_handle_response_headers,
|
request_handle_response_headers, request_set_timeout, send_request,
|
||||||
request_set_timeout, send_request,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -59,11 +58,6 @@ impl Command for SubCommand {
|
|||||||
"insecure",
|
"insecure",
|
||||||
"allow insecure server connections when using SSL",
|
"allow insecure server connections when using SSL",
|
||||||
Some('k'),
|
Some('k'),
|
||||||
).named(
|
|
||||||
"redirect-mode",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
|
|
||||||
Some('R')
|
|
||||||
)
|
)
|
||||||
.filter()
|
.filter()
|
||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
@ -120,7 +114,6 @@ struct Arguments {
|
|||||||
user: Option<String>,
|
user: Option<String>,
|
||||||
password: Option<String>,
|
password: Option<String>,
|
||||||
timeout: Option<Value>,
|
timeout: Option<Value>,
|
||||||
redirect: Option<Spanned<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_head(
|
fn run_head(
|
||||||
@ -136,7 +129,6 @@ fn run_head(
|
|||||||
user: call.get_flag(engine_state, stack, "user")?,
|
user: call.get_flag(engine_state, stack, "user")?,
|
||||||
password: call.get_flag(engine_state, stack, "password")?,
|
password: call.get_flag(engine_state, stack, "password")?,
|
||||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
|
||||||
};
|
};
|
||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
|
|
||||||
@ -154,9 +146,8 @@ fn helper(
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = args.url.span();
|
let span = args.url.span();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
let redirect_mode = http_parse_redirect_mode(args.redirect)?;
|
|
||||||
|
|
||||||
let client = http_client(args.insecure, redirect_mode, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.head(&requested_url);
|
let mut request = client.head(&requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
@ -164,7 +155,6 @@ fn helper(
|
|||||||
request = request_add_custom_headers(args.headers, request)?;
|
request = request_add_custom_headers(args.headers, request)?;
|
||||||
|
|
||||||
let response = send_request(request, None, None, ctrlc);
|
let response = send_request(request, None, None, ctrlc);
|
||||||
check_response_redirection(redirect_mode, span, &response)?;
|
|
||||||
request_handle_response_headers(span, response)
|
request_handle_response_headers(span, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ use crate::network::http::client::{
|
|||||||
request_handle_response, request_set_timeout, send_request,
|
request_handle_response, request_set_timeout, send_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::client::{RedirectMode, RequestFlags};
|
use super::client::RequestFlags;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SubCommand;
|
pub struct SubCommand;
|
||||||
@ -160,7 +160,7 @@ fn helper(
|
|||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
|
|
||||||
let client = http_client(args.insecure, RedirectMode::Follow, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.request("OPTIONS", &requested_url);
|
let mut request = client.request("OPTIONS", &requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
|
@ -2,13 +2,12 @@ use nu_engine::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::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::network::http::client::{
|
use crate::network::http::client::{
|
||||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
request_handle_response, request_set_timeout, send_request,
|
||||||
request_set_timeout, send_request,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::client::RequestFlags;
|
use super::client::RequestFlags;
|
||||||
@ -76,11 +75,6 @@ impl Command for SubCommand {
|
|||||||
"allow-errors",
|
"allow-errors",
|
||||||
"do not fail if the server returns an error code",
|
"do not fail if the server returns an error code",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
).named(
|
|
||||||
"redirect-mode",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
|
|
||||||
Some('R')
|
|
||||||
)
|
)
|
||||||
.filter()
|
.filter()
|
||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
@ -148,7 +142,6 @@ struct Arguments {
|
|||||||
timeout: Option<Value>,
|
timeout: Option<Value>,
|
||||||
full: bool,
|
full: bool,
|
||||||
allow_errors: bool,
|
allow_errors: bool,
|
||||||
redirect: Option<Spanned<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_patch(
|
fn run_patch(
|
||||||
@ -169,7 +162,6 @@ fn run_patch(
|
|||||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||||
full: call.has_flag("full"),
|
full: call.has_flag("full"),
|
||||||
allow_errors: call.has_flag("allow-errors"),
|
allow_errors: call.has_flag("allow-errors"),
|
||||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
helper(engine_state, stack, call, args)
|
helper(engine_state, stack, call, args)
|
||||||
@ -186,9 +178,8 @@ fn helper(
|
|||||||
let span = args.url.span();
|
let span = args.url.span();
|
||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
let redirect_mode = http_parse_redirect_mode(args.redirect)?;
|
|
||||||
|
|
||||||
let client = http_client(args.insecure, redirect_mode, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.patch(&requested_url);
|
let mut request = client.patch(&requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
@ -203,7 +194,6 @@ fn helper(
|
|||||||
allow_errors: args.allow_errors,
|
allow_errors: args.allow_errors,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_response_redirection(redirect_mode, span, &response)?;
|
|
||||||
request_handle_response(
|
request_handle_response(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
|
@ -2,13 +2,12 @@ use nu_engine::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::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::network::http::client::{
|
use crate::network::http::client::{
|
||||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
request_handle_response, request_set_timeout, send_request,
|
||||||
request_set_timeout, send_request,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::client::RequestFlags;
|
use super::client::RequestFlags;
|
||||||
@ -76,11 +75,6 @@ impl Command for SubCommand {
|
|||||||
"allow-errors",
|
"allow-errors",
|
||||||
"do not fail if the server returns an error code",
|
"do not fail if the server returns an error code",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
).named(
|
|
||||||
"redirect-mode",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
|
|
||||||
Some('R')
|
|
||||||
)
|
)
|
||||||
.filter()
|
.filter()
|
||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
@ -146,7 +140,6 @@ struct Arguments {
|
|||||||
timeout: Option<Value>,
|
timeout: Option<Value>,
|
||||||
full: bool,
|
full: bool,
|
||||||
allow_errors: bool,
|
allow_errors: bool,
|
||||||
redirect: Option<Spanned<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_post(
|
fn run_post(
|
||||||
@ -167,7 +160,6 @@ fn run_post(
|
|||||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||||
full: call.has_flag("full"),
|
full: call.has_flag("full"),
|
||||||
allow_errors: call.has_flag("allow-errors"),
|
allow_errors: call.has_flag("allow-errors"),
|
||||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
helper(engine_state, stack, call, args)
|
helper(engine_state, stack, call, args)
|
||||||
@ -184,9 +176,8 @@ fn helper(
|
|||||||
let span = args.url.span();
|
let span = args.url.span();
|
||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
let redirect_mode = http_parse_redirect_mode(args.redirect)?;
|
|
||||||
|
|
||||||
let client = http_client(args.insecure, redirect_mode, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.post(&requested_url);
|
let mut request = client.post(&requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
@ -201,7 +192,6 @@ fn helper(
|
|||||||
allow_errors: args.allow_errors,
|
allow_errors: args.allow_errors,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_response_redirection(redirect_mode, span, &response)?;
|
|
||||||
request_handle_response(
|
request_handle_response(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
|
@ -2,13 +2,12 @@ use nu_engine::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::{
|
use nu_protocol::{
|
||||||
Category, Example, PipelineData, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::network::http::client::{
|
use crate::network::http::client::{
|
||||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
request_handle_response, request_set_timeout, send_request,
|
||||||
request_set_timeout, send_request,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::client::RequestFlags;
|
use super::client::RequestFlags;
|
||||||
@ -76,11 +75,6 @@ impl Command for SubCommand {
|
|||||||
"allow-errors",
|
"allow-errors",
|
||||||
"do not fail if the server returns an error code",
|
"do not fail if the server returns an error code",
|
||||||
Some('e'),
|
Some('e'),
|
||||||
).named(
|
|
||||||
"redirect-mode",
|
|
||||||
SyntaxShape::String,
|
|
||||||
"What to do when encountering redirects. Default: 'follow'. Valid options: 'follow' ('f'), 'manual' ('m'), 'error' ('e').",
|
|
||||||
Some('R')
|
|
||||||
)
|
)
|
||||||
.filter()
|
.filter()
|
||||||
.category(Category::Network)
|
.category(Category::Network)
|
||||||
@ -146,7 +140,6 @@ struct Arguments {
|
|||||||
timeout: Option<Value>,
|
timeout: Option<Value>,
|
||||||
full: bool,
|
full: bool,
|
||||||
allow_errors: bool,
|
allow_errors: bool,
|
||||||
redirect: Option<Spanned<String>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_put(
|
fn run_put(
|
||||||
@ -167,7 +160,6 @@ fn run_put(
|
|||||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||||
full: call.has_flag("full"),
|
full: call.has_flag("full"),
|
||||||
allow_errors: call.has_flag("allow-errors"),
|
allow_errors: call.has_flag("allow-errors"),
|
||||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
helper(engine_state, stack, call, args)
|
helper(engine_state, stack, call, args)
|
||||||
@ -184,9 +176,8 @@ fn helper(
|
|||||||
let span = args.url.span();
|
let span = args.url.span();
|
||||||
let ctrl_c = engine_state.ctrlc.clone();
|
let ctrl_c = engine_state.ctrlc.clone();
|
||||||
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
let (requested_url, _) = http_parse_url(call, span, args.url)?;
|
||||||
let redirect_mode = http_parse_redirect_mode(args.redirect)?;
|
|
||||||
|
|
||||||
let client = http_client(args.insecure, redirect_mode, engine_state, stack)?;
|
let client = http_client(args.insecure, engine_state, stack);
|
||||||
let mut request = client.put(&requested_url);
|
let mut request = client.put(&requested_url);
|
||||||
|
|
||||||
request = request_set_timeout(args.timeout, request)?;
|
request = request_set_timeout(args.timeout, request)?;
|
||||||
@ -201,7 +192,6 @@ fn helper(
|
|||||||
allow_errors: args.allow_errors,
|
allow_errors: args.allow_errors,
|
||||||
};
|
};
|
||||||
|
|
||||||
check_response_redirection(redirect_mode, span, &response)?;
|
|
||||||
request_handle_response(
|
request_handle_response(
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
|
@ -7,8 +7,6 @@ mod is_terminal;
|
|||||||
mod kill;
|
mod kill;
|
||||||
mod sleep;
|
mod sleep;
|
||||||
mod term_size;
|
mod term_size;
|
||||||
#[cfg(unix)]
|
|
||||||
mod ulimit;
|
|
||||||
mod whoami;
|
mod whoami;
|
||||||
|
|
||||||
pub use ansi::{Ansi, AnsiLink, AnsiStrip};
|
pub use ansi::{Ansi, AnsiLink, AnsiStrip};
|
||||||
@ -22,6 +20,4 @@ pub use is_terminal::IsTerminal;
|
|||||||
pub use kill::Kill;
|
pub use kill::Kill;
|
||||||
pub use sleep::Sleep;
|
pub use sleep::Sleep;
|
||||||
pub use term_size::TermSize;
|
pub use term_size::TermSize;
|
||||||
#[cfg(unix)]
|
|
||||||
pub use ulimit::ULimit;
|
|
||||||
pub use whoami::Whoami;
|
pub use whoami::Whoami;
|
||||||
|
@ -1,603 +0,0 @@
|
|||||||
use nix::sys::resource::{rlim_t, Resource, RLIM_INFINITY};
|
|
||||||
use nu_engine::CallExt;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, Example, IntoPipelineData, PipelineData, Record, ShellError, Signature, Span,
|
|
||||||
SyntaxShape, Type, Value,
|
|
||||||
};
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
/// An object contains resource related parameters
|
|
||||||
struct ResourceInfo<'a> {
|
|
||||||
name: &'a str,
|
|
||||||
desc: &'a str,
|
|
||||||
flag: char,
|
|
||||||
multiplier: rlim_t,
|
|
||||||
resource: Resource,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ResourceInfo<'a> {
|
|
||||||
/// Create a `ResourceInfo` object
|
|
||||||
fn new(
|
|
||||||
name: &'a str,
|
|
||||||
desc: &'a str,
|
|
||||||
flag: char,
|
|
||||||
multiplier: rlim_t,
|
|
||||||
resource: Resource,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
name,
|
|
||||||
desc,
|
|
||||||
flag,
|
|
||||||
multiplier,
|
|
||||||
resource,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get unit
|
|
||||||
fn get_unit(&self) -> &str {
|
|
||||||
if self.resource == Resource::RLIMIT_CPU {
|
|
||||||
"(seconds, "
|
|
||||||
} else if self.multiplier == 1 {
|
|
||||||
"("
|
|
||||||
} else {
|
|
||||||
"(kB, "
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Default for ResourceInfo<'a> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
name: "file-size",
|
|
||||||
desc: "Maximum size of files created by the shell",
|
|
||||||
flag: 'f',
|
|
||||||
multiplier: 1024,
|
|
||||||
resource: Resource::RLIMIT_FSIZE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static RESOURCE_ARRAY: Lazy<Vec<ResourceInfo>> = Lazy::new(|| {
|
|
||||||
let resources = [
|
|
||||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
|
||||||
(
|
|
||||||
"socket-buffers",
|
|
||||||
"Maximum size of socket buffers",
|
|
||||||
'b',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_SBSIZE,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"core-size",
|
|
||||||
"Maximum size of core files created",
|
|
||||||
'c',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_CORE,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"data-size",
|
|
||||||
"Maximum size of a process's data segment",
|
|
||||||
'd',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_DATA,
|
|
||||||
),
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
|
||||||
(
|
|
||||||
"nice",
|
|
||||||
"Controls of maximum nice priority",
|
|
||||||
'e',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_NICE,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"file-size",
|
|
||||||
"Maximum size of files created by the shell",
|
|
||||||
'f',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_FSIZE,
|
|
||||||
),
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
|
||||||
(
|
|
||||||
"pending-signals",
|
|
||||||
"Maximum number of pending signals",
|
|
||||||
'i',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_SIGPENDING,
|
|
||||||
),
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "android",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "openbsd",
|
|
||||||
target_os = "linux",
|
|
||||||
target_os = "netbsd"
|
|
||||||
))]
|
|
||||||
(
|
|
||||||
"lock-size",
|
|
||||||
"Maximum size that may be locked into memory",
|
|
||||||
'l',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_MEMLOCK,
|
|
||||||
),
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "android",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "netbsd",
|
|
||||||
target_os = "openbsd",
|
|
||||||
target_os = "linux",
|
|
||||||
target_os = "aix",
|
|
||||||
))]
|
|
||||||
(
|
|
||||||
"resident-set-size",
|
|
||||||
"Maximum resident set size",
|
|
||||||
'm',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_RSS,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"file-descriptor-count",
|
|
||||||
"Maximum number of open file descriptors",
|
|
||||||
'n',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_NOFILE,
|
|
||||||
),
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
|
||||||
(
|
|
||||||
"queue-size",
|
|
||||||
"Maximum bytes in POSIX message queues",
|
|
||||||
'q',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_MSGQUEUE,
|
|
||||||
),
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
|
||||||
(
|
|
||||||
"realtime-priority",
|
|
||||||
"Maximum realtime scheduling priority",
|
|
||||||
'r',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_RTPRIO,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"stack-size",
|
|
||||||
"Maximum stack size",
|
|
||||||
's',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_STACK,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"cpu-time",
|
|
||||||
"Maximum amount of CPU time in seconds",
|
|
||||||
't',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_CPU,
|
|
||||||
),
|
|
||||||
#[cfg(any(
|
|
||||||
target_os = "android",
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "netbsd",
|
|
||||||
target_os = "openbsd",
|
|
||||||
target_os = "linux",
|
|
||||||
target_os = "aix",
|
|
||||||
))]
|
|
||||||
(
|
|
||||||
"process-count",
|
|
||||||
"Maximum number of processes available to the current user",
|
|
||||||
'u',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_NPROC,
|
|
||||||
),
|
|
||||||
#[cfg(not(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")))]
|
|
||||||
(
|
|
||||||
"virtual-memory-size",
|
|
||||||
"Maximum amount of virtual memory available to each process",
|
|
||||||
'v',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_AS,
|
|
||||||
),
|
|
||||||
#[cfg(target_os = "freebsd")]
|
|
||||||
(
|
|
||||||
"swap-size",
|
|
||||||
"Maximum swap space",
|
|
||||||
'w',
|
|
||||||
1024,
|
|
||||||
Resource::RLIMIT_SWAP,
|
|
||||||
),
|
|
||||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
|
||||||
(
|
|
||||||
"file-locks",
|
|
||||||
"Maximum number of file locks",
|
|
||||||
'x',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_LOCKS,
|
|
||||||
),
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
(
|
|
||||||
"realtime-maxtime",
|
|
||||||
"Maximum contiguous realtime CPU time",
|
|
||||||
'y',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_RTTIME,
|
|
||||||
),
|
|
||||||
#[cfg(target_os = "freebsd")]
|
|
||||||
(
|
|
||||||
"kernel-queues",
|
|
||||||
"Maximum number of kqueues",
|
|
||||||
'K',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_KQUEUES,
|
|
||||||
),
|
|
||||||
#[cfg(target_os = "freebsd")]
|
|
||||||
(
|
|
||||||
"ptys",
|
|
||||||
"Maximum number of pseudo-terminals",
|
|
||||||
'P',
|
|
||||||
1,
|
|
||||||
Resource::RLIMIT_NPTS,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut resource_array = Vec::new();
|
|
||||||
for (name, desc, flag, multiplier, res) in resources {
|
|
||||||
resource_array.push(ResourceInfo::new(name, desc, flag, multiplier, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
resource_array
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Convert `rlim_t` to `Value` representation
|
|
||||||
fn limit_to_value(limit: rlim_t, multiplier: rlim_t, span: Span) -> Result<Value, ShellError> {
|
|
||||||
if limit == RLIM_INFINITY {
|
|
||||||
return Ok(Value::string("unlimited", span));
|
|
||||||
}
|
|
||||||
|
|
||||||
let val = match i64::try_from(limit / multiplier) {
|
|
||||||
Ok(v) => v,
|
|
||||||
Err(e) => {
|
|
||||||
return Err(ShellError::CantConvert {
|
|
||||||
to_type: "i64".into(),
|
|
||||||
from_type: "rlim_t".into(),
|
|
||||||
span,
|
|
||||||
help: Some(e.to_string()),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Value::int(val, span))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get maximum length of all flag descriptions
|
|
||||||
fn max_desc_len(call: &Call, print_all: bool) -> usize {
|
|
||||||
let mut desc_len = 0;
|
|
||||||
let mut unit_len = 0;
|
|
||||||
|
|
||||||
for res in RESOURCE_ARRAY.iter() {
|
|
||||||
if !print_all && !call.has_flag(res.name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc_len = res.desc.len().max(desc_len);
|
|
||||||
unit_len = res.get_unit().len().max(unit_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use `RLIMIT_FSIZE` limit if no resource flag provided.
|
|
||||||
if desc_len == 0 {
|
|
||||||
let res = ResourceInfo::default();
|
|
||||||
desc_len = res.desc.len().max(desc_len);
|
|
||||||
unit_len = res.get_unit().len().max(unit_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// desc.len() + unit.len() + '-X)'.len()
|
|
||||||
desc_len + unit_len + 3
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fill `ResourceInfo` to the record entry
|
|
||||||
fn fill_record(
|
|
||||||
res: &ResourceInfo,
|
|
||||||
max_len: usize,
|
|
||||||
soft: bool,
|
|
||||||
hard: bool,
|
|
||||||
span: Span,
|
|
||||||
) -> Result<Record, ShellError> {
|
|
||||||
let mut record = Record::new();
|
|
||||||
let mut desc = String::new();
|
|
||||||
|
|
||||||
desc.push_str(res.desc);
|
|
||||||
|
|
||||||
debug_assert!(res.desc.len() + res.get_unit().len() + 3 <= max_len);
|
|
||||||
let width = max_len - res.desc.len() - res.get_unit().len() - 3;
|
|
||||||
if width == 0 {
|
|
||||||
desc.push_str(format!(" {}-{})", res.get_unit(), res.flag).as_str());
|
|
||||||
} else {
|
|
||||||
desc.push_str(format!("{:>width$} {}-{})", ' ', res.get_unit(), res.flag).as_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
record.push("description", Value::string(desc, span));
|
|
||||||
|
|
||||||
let (soft_limit, hard_limit) = getrlimit(res.resource)?;
|
|
||||||
|
|
||||||
if soft {
|
|
||||||
let soft_limit = limit_to_value(soft_limit, res.multiplier, span)?;
|
|
||||||
record.push("soft", soft_limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if hard {
|
|
||||||
let hard_limit = limit_to_value(hard_limit, res.multiplier, span)?;
|
|
||||||
record.push("hard", hard_limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(record)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set limits
|
|
||||||
fn set_limits(
|
|
||||||
limit_value: &Value,
|
|
||||||
res: &ResourceInfo,
|
|
||||||
soft: bool,
|
|
||||||
hard: bool,
|
|
||||||
call_span: Span,
|
|
||||||
) -> Result<(), ShellError> {
|
|
||||||
let (mut soft_limit, mut hard_limit) = getrlimit(res.resource)?;
|
|
||||||
let new_limit = parse_limit(limit_value, res, soft, soft_limit, hard_limit, call_span)?;
|
|
||||||
|
|
||||||
if hard {
|
|
||||||
hard_limit = new_limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if soft {
|
|
||||||
soft_limit = new_limit;
|
|
||||||
|
|
||||||
// Do not attempt to set the soft limit higher than the hard limit.
|
|
||||||
if (new_limit > hard_limit || new_limit == RLIM_INFINITY) && hard_limit != RLIM_INFINITY {
|
|
||||||
soft_limit = hard_limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setrlimit(res.resource, soft_limit, hard_limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print limits
|
|
||||||
fn print_limits(
|
|
||||||
call: &Call,
|
|
||||||
print_all: bool,
|
|
||||||
soft: bool,
|
|
||||||
hard: bool,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let mut output = Vec::new();
|
|
||||||
let mut print_default_limit = true;
|
|
||||||
let max_len = max_desc_len(call, print_all);
|
|
||||||
|
|
||||||
for res in RESOURCE_ARRAY.iter() {
|
|
||||||
if !print_all {
|
|
||||||
// Print specified limit.
|
|
||||||
if !call.has_flag(res.name) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let record = fill_record(res, max_len, soft, hard, call.head)?;
|
|
||||||
output.push(Value::record(record, call.head));
|
|
||||||
|
|
||||||
if print_default_limit {
|
|
||||||
print_default_limit = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print `RLIMIT_FSIZE` limit if no resource flag provided.
|
|
||||||
if print_default_limit {
|
|
||||||
let res = ResourceInfo::default();
|
|
||||||
let record = fill_record(&res, max_len, soft, hard, call.head)?;
|
|
||||||
output.push(Value::record(record, call.head));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::list(output, call.head).into_pipeline_data())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrap `nix::sys::resource::getrlimit`
|
|
||||||
fn setrlimit(res: Resource, soft_limit: rlim_t, hard_limit: rlim_t) -> Result<(), ShellError> {
|
|
||||||
nix::sys::resource::setrlimit(res, soft_limit, hard_limit).map_err(|e| {
|
|
||||||
ShellError::GenericError {
|
|
||||||
error: e.to_string(),
|
|
||||||
msg: String::new(),
|
|
||||||
span: None,
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrap `nix::sys::resource::setrlimit`
|
|
||||||
fn getrlimit(res: Resource) -> Result<(rlim_t, rlim_t), ShellError> {
|
|
||||||
nix::sys::resource::getrlimit(res).map_err(|e| ShellError::GenericError {
|
|
||||||
error: e.to_string(),
|
|
||||||
msg: String::new(),
|
|
||||||
span: None,
|
|
||||||
help: None,
|
|
||||||
inner: vec![],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse user input
|
|
||||||
fn parse_limit(
|
|
||||||
limit_value: &Value,
|
|
||||||
res: &ResourceInfo,
|
|
||||||
soft: bool,
|
|
||||||
soft_limit: rlim_t,
|
|
||||||
hard_limit: rlim_t,
|
|
||||||
call_span: Span,
|
|
||||||
) -> Result<rlim_t, ShellError> {
|
|
||||||
match limit_value {
|
|
||||||
Value::Int { val, internal_span } => {
|
|
||||||
let value = rlim_t::try_from(*val).map_err(|e| ShellError::CantConvert {
|
|
||||||
to_type: "rlim_t".into(),
|
|
||||||
from_type: "i64".into(),
|
|
||||||
span: *internal_span,
|
|
||||||
help: Some(e.to_string()),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let (limit, overflow) = value.overflowing_mul(res.multiplier);
|
|
||||||
if overflow {
|
|
||||||
Ok(RLIM_INFINITY)
|
|
||||||
} else {
|
|
||||||
Ok(limit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Filesize { val, internal_span } => {
|
|
||||||
if res.multiplier != 1024 {
|
|
||||||
return Err(ShellError::TypeMismatch {
|
|
||||||
err_message: format!(
|
|
||||||
"filesize is not compatible with resource {:?}",
|
|
||||||
res.resource
|
|
||||||
),
|
|
||||||
span: *internal_span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
rlim_t::try_from(*val).map_err(|e| ShellError::CantConvert {
|
|
||||||
to_type: "rlim_t".into(),
|
|
||||||
from_type: "i64".into(),
|
|
||||||
span: *internal_span,
|
|
||||||
help: Some(e.to_string()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Value::String { val, internal_span } => {
|
|
||||||
if val == "unlimited" {
|
|
||||||
Ok(RLIM_INFINITY)
|
|
||||||
} else if val == "soft" {
|
|
||||||
if soft {
|
|
||||||
Ok(hard_limit)
|
|
||||||
} else {
|
|
||||||
Ok(soft_limit)
|
|
||||||
}
|
|
||||||
} else if val == "hard" {
|
|
||||||
Ok(hard_limit)
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::IncorrectValue {
|
|
||||||
msg: "Only unlimited, soft and hard are supported for strings".into(),
|
|
||||||
val_span: *internal_span,
|
|
||||||
call_span,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(ShellError::TypeMismatch {
|
|
||||||
err_message: format!(
|
|
||||||
"string, int or filesize required, you provide {}",
|
|
||||||
limit_value.get_type()
|
|
||||||
),
|
|
||||||
span: limit_value.span(),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ULimit;
|
|
||||||
|
|
||||||
impl Command for ULimit {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"ulimit"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Set or get resource usage limits."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
let mut sig = Signature::build("ulimit")
|
|
||||||
.input_output_types(vec![
|
|
||||||
(Type::Nothing, Type::Table(vec![])),
|
|
||||||
(Type::Nothing, Type::Nothing),
|
|
||||||
])
|
|
||||||
.switch("soft", "Sets soft resource limit", Some('S'))
|
|
||||||
.switch("hard", "Sets hard resource limit", Some('H'))
|
|
||||||
.switch("all", "Prints all current limits", Some('a'))
|
|
||||||
.optional("limit", SyntaxShape::Any, "Limit value.")
|
|
||||||
.category(Category::Platform);
|
|
||||||
|
|
||||||
for res in RESOURCE_ARRAY.iter() {
|
|
||||||
sig = sig.switch(res.name, res.desc, Some(res.flag));
|
|
||||||
}
|
|
||||||
|
|
||||||
sig
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let mut soft = call.has_flag("soft");
|
|
||||||
let mut hard = call.has_flag("hard");
|
|
||||||
let all = call.has_flag("all");
|
|
||||||
|
|
||||||
if !hard && !soft {
|
|
||||||
// Set both hard and soft limits if neither was specified.
|
|
||||||
hard = true;
|
|
||||||
soft = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(limit_value) = call.opt::<Value>(engine_state, stack, 0)? {
|
|
||||||
let mut set_default_limit = true;
|
|
||||||
|
|
||||||
for res in RESOURCE_ARRAY.iter() {
|
|
||||||
if call.has_flag(res.name) {
|
|
||||||
set_limits(&limit_value, res, soft, hard, call.head)?;
|
|
||||||
|
|
||||||
if set_default_limit {
|
|
||||||
set_default_limit = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set `RLIMIT_FSIZE` limit if no resource flag provided.
|
|
||||||
if set_default_limit {
|
|
||||||
let res = ResourceInfo::default();
|
|
||||||
set_limits(&limit_value, &res, hard, soft, call.head)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(PipelineData::Empty)
|
|
||||||
} else {
|
|
||||||
print_limits(call, all, soft, hard)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
|
||||||
vec![
|
|
||||||
Example {
|
|
||||||
description: "Print all current limits",
|
|
||||||
example: "ulimit -a",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Print specified limits",
|
|
||||||
example: "ulimit --core-size --data-size --file-size",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Set limit",
|
|
||||||
example: "ulimit --core-size 102400",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Set stack size soft limit",
|
|
||||||
example: "ulimit -s -S 10240",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Set virtual memory size hard limit",
|
|
||||||
example: "ulimit -v -H 10240",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
Example {
|
|
||||||
description: "Set core size limit to unlimited",
|
|
||||||
example: "ulimit -c unlimited",
|
|
||||||
result: None,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
|
||||||
vec!["resource", "limits"]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +1,35 @@
|
|||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod create;
|
mod create;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod delete;
|
mod delete;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod export;
|
mod export;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod import;
|
mod import;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod insert;
|
mod insert;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod open;
|
mod open;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod reset;
|
mod reset;
|
||||||
mod stor_;
|
mod stor_;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
mod update;
|
mod update;
|
||||||
|
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use create::StorCreate;
|
pub use create::StorCreate;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use delete::StorDelete;
|
pub use delete::StorDelete;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use export::StorExport;
|
pub use export::StorExport;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use import::StorImport;
|
pub use import::StorImport;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use insert::StorInsert;
|
pub use insert::StorInsert;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use open::StorOpen;
|
pub use open::StorOpen;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use reset::StorReset;
|
pub use reset::StorReset;
|
||||||
pub use stor_::Stor;
|
pub use stor_::Stor;
|
||||||
|
#[cfg(feature = "sqlite")]
|
||||||
pub use update::StorUpdate;
|
pub use update::StorUpdate;
|
||||||
|
@ -199,10 +199,7 @@ fn detect_columns(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !(l_idx <= r_idx && (r_idx >= 0 || l_idx < (cols.len() as isize))) {
|
if !(l_idx <= r_idx && (r_idx >= 0 || l_idx < (cols.len() as isize))) {
|
||||||
return Value::record(
|
return Value::record(Record { cols, vals }, name_span);
|
||||||
Record::from_raw_cols_vals(cols, vals),
|
|
||||||
name_span,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(l_idx.max(0) as usize, (r_idx as usize + 1).min(cols.len()))
|
(l_idx.max(0) as usize, (r_idx as usize + 1).min(cols.len()))
|
||||||
@ -213,7 +210,7 @@ fn detect_columns(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Value::record(Record::from_raw_cols_vals(cols, vals), name_span);
|
return Value::record(Record { cols, vals }, name_span);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Merge Columns
|
// Merge Columns
|
||||||
@ -235,7 +232,7 @@ fn detect_columns(
|
|||||||
vals.push(binding);
|
vals.push(binding);
|
||||||
last_seg.into_iter().for_each(|v| vals.push(v));
|
last_seg.into_iter().for_each(|v| vals.push(v));
|
||||||
|
|
||||||
Value::record(Record::from_raw_cols_vals(cols, vals), name_span)
|
Value::record(Record { cols, vals }, name_span)
|
||||||
})
|
})
|
||||||
.into_pipeline_data(ctrlc))
|
.into_pipeline_data(ctrlc))
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
use nu_engine::get_full_help;
|
|
||||||
use nu_protocol::{
|
|
||||||
ast::Call,
|
|
||||||
engine::{Command, EngineState, Stack},
|
|
||||||
Category, IntoPipelineData, PipelineData, ShellError, Signature, Type, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Format;
|
|
||||||
|
|
||||||
impl Command for Format {
|
|
||||||
fn name(&self) -> &str {
|
|
||||||
"format"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signature(&self) -> Signature {
|
|
||||||
Signature::build("format")
|
|
||||||
.category(Category::Strings)
|
|
||||||
.input_output_types(vec![(Type::Nothing, Type::String)])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage(&self) -> &str {
|
|
||||||
"Various commands for formatting data."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extra_usage(&self) -> &str {
|
|
||||||
"You must use one of the following subcommands. Using this command as-is will only produce this help message."
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(
|
|
||||||
&self,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
call: &Call,
|
|
||||||
_input: PipelineData,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
Ok(Value::string(
|
|
||||||
get_full_help(
|
|
||||||
&Format.signature(),
|
|
||||||
&Format.examples(),
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
self.is_parser_keyword(),
|
|
||||||
),
|
|
||||||
call.head,
|
|
||||||
)
|
|
||||||
.into_pipeline_data())
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +1,7 @@
|
|||||||
mod date;
|
mod date;
|
||||||
mod duration;
|
mod duration;
|
||||||
mod filesize;
|
mod filesize;
|
||||||
mod format_;
|
|
||||||
|
|
||||||
|
pub use self::filesize::FormatFilesize;
|
||||||
pub use date::FormatDate;
|
pub use date::FormatDate;
|
||||||
pub use duration::FormatDuration;
|
pub use duration::FormatDuration;
|
||||||
pub use filesize::FormatFilesize;
|
|
||||||
pub use format_::Format;
|
|
||||||
|
@ -133,8 +133,8 @@ impl Command for SubCommand {
|
|||||||
result: Some(Value::test_string("Nu shell")),
|
result: Some(Value::test_string("Nu shell")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Trim a specific character (not the whitespace)",
|
description: "Trim a specific character",
|
||||||
example: "'=== Nu shell ===' | str trim --char '='",
|
example: "'=== Nu shell ===' | str trim --char '=' | str trim",
|
||||||
result: Some(Value::test_string("Nu shell")),
|
result: Some(Value::test_string("Nu shell")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
@ -142,13 +142,18 @@ impl Command for SubCommand {
|
|||||||
example: "' Nu shell ' | str trim --left",
|
example: "' Nu shell ' | str trim --left",
|
||||||
result: Some(Value::test_string("Nu shell ")),
|
result: Some(Value::test_string("Nu shell ")),
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description: "Trim a specific character",
|
||||||
|
example: "'=== Nu shell ===' | str trim --char '='",
|
||||||
|
result: Some(Value::test_string(" Nu shell ")),
|
||||||
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Trim whitespace from the end of string",
|
description: "Trim whitespace from the end of string",
|
||||||
example: "' Nu shell ' | str trim --right",
|
example: "' Nu shell ' | str trim --right",
|
||||||
result: Some(Value::test_string(" Nu shell")),
|
result: Some(Value::test_string(" Nu shell")),
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Trim a specific character only from the end of the string",
|
description: "Trim a specific character",
|
||||||
example: "'=== Nu shell ===' | str trim --right --char '='",
|
example: "'=== Nu shell ===' | str trim --right --char '='",
|
||||||
result: Some(Value::test_string("=== Nu shell ")),
|
result: Some(Value::test_string("=== Nu shell ")),
|
||||||
},
|
},
|
||||||
|
@ -101,8 +101,6 @@ impl Command for Complete {
|
|||||||
|
|
||||||
Ok(Value::record(record, call.head).into_pipeline_data())
|
Ok(Value::record(record, call.head).into_pipeline_data())
|
||||||
}
|
}
|
||||||
// bubble up errors from the previous command
|
|
||||||
PipelineData::Value(Value::Error { error, .. }, _) => Err(*error),
|
|
||||||
_ => Err(ShellError::GenericError {
|
_ => Err(ShellError::GenericError {
|
||||||
error: "Complete only works with external streams".into(),
|
error: "Complete only works with external streams".into(),
|
||||||
msg: "complete only works on external streams".into(),
|
msg: "complete only works on external streams".into(),
|
||||||
|
@ -5,6 +5,7 @@ use itertools::Itertools;
|
|||||||
not(target_os = "macos"),
|
not(target_os = "macos"),
|
||||||
not(target_os = "windows"),
|
not(target_os = "windows"),
|
||||||
not(target_os = "android"),
|
not(target_os = "android"),
|
||||||
|
not(target_os = "ios")
|
||||||
))]
|
))]
|
||||||
use nu_protocol::Span;
|
use nu_protocol::Span;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
@ -18,6 +19,7 @@ use nu_protocol::{
|
|||||||
not(target_os = "macos"),
|
not(target_os = "macos"),
|
||||||
not(target_os = "windows"),
|
not(target_os = "windows"),
|
||||||
not(target_os = "android"),
|
not(target_os = "android"),
|
||||||
|
not(target_os = "ios")
|
||||||
))]
|
))]
|
||||||
use procfs::WithCurrentSystemInfo;
|
use procfs::WithCurrentSystemInfo;
|
||||||
|
|
||||||
@ -121,6 +123,7 @@ fn run_ps(engine_state: &EngineState, call: &Call) -> Result<PipelineData, Shell
|
|||||||
not(target_os = "macos"),
|
not(target_os = "macos"),
|
||||||
not(target_os = "windows"),
|
not(target_os = "windows"),
|
||||||
not(target_os = "android"),
|
not(target_os = "android"),
|
||||||
|
not(target_os = "ios")
|
||||||
))]
|
))]
|
||||||
{
|
{
|
||||||
let proc_stat = proc
|
let proc_stat = proc
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use nu_cmd_base::hook::eval_hook;
|
use nu_cmd_base::hook::eval_hook;
|
||||||
use nu_engine::env_to_strings;
|
use nu_engine::env_to_strings;
|
||||||
use nu_engine::eval_expression;
|
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, Expr},
|
ast::{Call, Expr, Expression},
|
||||||
did_you_mean,
|
did_you_mean,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, Span, Spanned,
|
Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, Span, Spanned,
|
||||||
@ -114,6 +113,7 @@ pub fn create_external_command(
|
|||||||
trim_end_newline: bool,
|
trim_end_newline: bool,
|
||||||
) -> Result<ExternalCommand, ShellError> {
|
) -> Result<ExternalCommand, ShellError> {
|
||||||
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||||
|
let args: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
||||||
|
|
||||||
// Translate environment variables from Values to Strings
|
// Translate environment variables from Values to Strings
|
||||||
let env_vars_str = env_to_strings(engine_state, stack)?;
|
let env_vars_str = env_to_strings(engine_state, stack)?;
|
||||||
@ -132,24 +132,11 @@ pub fn create_external_command(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut spanned_args = vec![];
|
let mut spanned_args = vec![];
|
||||||
|
let args_expr: Vec<Expression> = call.positional_iter().skip(1).cloned().collect();
|
||||||
let mut arg_keep_raw = vec![];
|
let mut arg_keep_raw = vec![];
|
||||||
for (arg, spread) in call.rest_iter(1) {
|
for (one_arg, one_arg_expr) in args.into_iter().zip(args_expr) {
|
||||||
// TODO: Disallow automatic spreading entirely later. This match block will
|
match one_arg {
|
||||||
// have to be refactored, and lists will have to be disallowed in the parser too
|
|
||||||
match eval_expression(engine_state, stack, arg)? {
|
|
||||||
Value::List { vals, .. } => {
|
Value::List { vals, .. } => {
|
||||||
if !spread {
|
|
||||||
nu_protocol::report_error_new(
|
|
||||||
engine_state,
|
|
||||||
&ShellError::GenericError {
|
|
||||||
error: "Automatically spreading lists is deprecated".into(),
|
|
||||||
msg: "Spreading lists automatically when calling external commands is deprecated and will be removed in 0.91.".into(),
|
|
||||||
span: Some(arg.span),
|
|
||||||
help: Some("Use the spread operator (put a '...' before the argument)".into()),
|
|
||||||
inner: vec![],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// turn all the strings in the array into params.
|
// turn all the strings in the array into params.
|
||||||
// Example: one_arg may be something like ["ls" "-a"]
|
// Example: one_arg may be something like ["ls" "-a"]
|
||||||
// convert it to "ls" "-a"
|
// convert it to "ls" "-a"
|
||||||
@ -160,20 +147,15 @@ pub fn create_external_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val => {
|
val => {
|
||||||
if spread {
|
|
||||||
return Err(ShellError::CannotSpreadAsList { span: arg.span });
|
|
||||||
} else {
|
|
||||||
spanned_args.push(value_as_spanned(val)?);
|
spanned_args.push(value_as_spanned(val)?);
|
||||||
match arg.expr {
|
match one_arg_expr.expr {
|
||||||
// refer to `parse_dollar_expr` function
|
// refer to `parse_dollar_expr` function
|
||||||
// the expression type of $variable_name, $"($variable_name)"
|
// the expression type of $variable_name, $"($variable_name)"
|
||||||
// will be Expr::StringInterpolation, Expr::FullCellPath
|
// will be Expr::StringInterpolation, Expr::FullCellPath
|
||||||
Expr::StringInterpolation(_) | Expr::FullCellPath(_) => {
|
Expr::StringInterpolation(_) | Expr::FullCellPath(_) => arg_keep_raw.push(true),
|
||||||
arg_keep_raw.push(true)
|
|
||||||
}
|
|
||||||
_ => arg_keep_raw.push(false),
|
_ => arg_keep_raw.push(false),
|
||||||
}
|
}
|
||||||
}
|
{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use nu_protocol::{
|
|||||||
};
|
};
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
use sysinfo::{
|
use sysinfo::{
|
||||||
Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL,
|
ComponentExt, CpuExt, CpuRefreshKind, DiskExt, NetworkExt, System, SystemExt, UserExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -106,12 +106,14 @@ pub fn trim_cstyle_null(s: String) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn disks(span: Span) -> Value {
|
pub fn disks(span: Span) -> Value {
|
||||||
let disks = Disks::new_with_refreshed_list();
|
let mut sys = System::new();
|
||||||
|
sys.refresh_disks();
|
||||||
|
sys.refresh_disks_list();
|
||||||
|
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
for disk in disks.list() {
|
for disk in sys.disks() {
|
||||||
let device = trim_cstyle_null(disk.name().to_string_lossy().to_string());
|
let device = trim_cstyle_null(disk.name().to_string_lossy().to_string());
|
||||||
let typ = trim_cstyle_null(disk.file_system().to_string_lossy().to_string());
|
let typ = trim_cstyle_null(String::from_utf8_lossy(disk.file_system()).to_string());
|
||||||
|
|
||||||
let record = record! {
|
let record = record! {
|
||||||
"device" => Value::string(device, span),
|
"device" => Value::string(device, span),
|
||||||
@ -129,10 +131,12 @@ pub fn disks(span: Span) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn net(span: Span) -> Value {
|
pub fn net(span: Span) -> Value {
|
||||||
let networks = Networks::new_with_refreshed_list();
|
let mut sys = System::new();
|
||||||
|
sys.refresh_networks();
|
||||||
|
sys.refresh_networks_list();
|
||||||
|
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
for (iface, data) in networks.list() {
|
for (iface, data) in sys.networks() {
|
||||||
let record = record! {
|
let record = record! {
|
||||||
"name" => Value::string(trim_cstyle_null(iface.to_string()), span),
|
"name" => Value::string(trim_cstyle_null(iface.to_string()), span),
|
||||||
"sent" => Value::filesize(data.total_transmitted() as i64, span),
|
"sent" => Value::filesize(data.total_transmitted() as i64, span),
|
||||||
@ -150,7 +154,7 @@ pub fn cpu(span: Span) -> Value {
|
|||||||
// We must refresh the CPU twice a while apart to get valid usage data.
|
// We must refresh the CPU twice a while apart to get valid usage data.
|
||||||
// In theory we could just sleep MINIMUM_CPU_UPDATE_INTERVAL, but I've noticed that
|
// In theory we could just sleep MINIMUM_CPU_UPDATE_INTERVAL, but I've noticed that
|
||||||
// that gives poor results (error of ~5%). Decided to wait 2x that long, somewhat arbitrarily
|
// that gives poor results (error of ~5%). Decided to wait 2x that long, somewhat arbitrarily
|
||||||
std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL * 2);
|
std::thread::sleep(System::MINIMUM_CPU_UPDATE_INTERVAL * 2);
|
||||||
sys.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage());
|
sys.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage());
|
||||||
|
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
@ -159,7 +163,7 @@ pub fn cpu(span: Span) -> Value {
|
|||||||
// Round to 1DP (chosen somewhat arbitrarily) so people aren't misled by high-precision floats.
|
// Round to 1DP (chosen somewhat arbitrarily) so people aren't misled by high-precision floats.
|
||||||
let rounded_usage = (cpu.cpu_usage() * 10.0).round() / 10.0;
|
let rounded_usage = (cpu.cpu_usage() * 10.0).round() / 10.0;
|
||||||
|
|
||||||
let load_avg = System::load_average();
|
let load_avg = sys.load_average();
|
||||||
let load_avg = trim_cstyle_null(format!(
|
let load_avg = trim_cstyle_null(format!(
|
||||||
"{:.2}, {:.2}, {:.2}",
|
"{:.2}, {:.2}, {:.2}",
|
||||||
load_avg.one, load_avg.five, load_avg.fifteen
|
load_avg.one, load_avg.five, load_avg.fifteen
|
||||||
@ -207,39 +211,42 @@ pub fn mem(span: Span) -> Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn host(span: Span) -> Value {
|
pub fn host(span: Span) -> Value {
|
||||||
|
let mut sys = System::new();
|
||||||
|
sys.refresh_users_list();
|
||||||
|
|
||||||
let mut record = Record::new();
|
let mut record = Record::new();
|
||||||
|
|
||||||
if let Some(name) = System::name() {
|
if let Some(name) = sys.name() {
|
||||||
record.push("name", Value::string(trim_cstyle_null(name), span));
|
record.push("name", Value::string(trim_cstyle_null(name), span));
|
||||||
}
|
}
|
||||||
if let Some(version) = System::os_version() {
|
if let Some(version) = sys.os_version() {
|
||||||
record.push("os_version", Value::string(trim_cstyle_null(version), span));
|
record.push("os_version", Value::string(trim_cstyle_null(version), span));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(long_version) = System::long_os_version() {
|
if let Some(long_version) = sys.long_os_version() {
|
||||||
record.push(
|
record.push(
|
||||||
"long_os_version",
|
"long_os_version",
|
||||||
Value::string(trim_cstyle_null(long_version), span),
|
Value::string(trim_cstyle_null(long_version), span),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(version) = System::kernel_version() {
|
if let Some(version) = sys.kernel_version() {
|
||||||
record.push(
|
record.push(
|
||||||
"kernel_version",
|
"kernel_version",
|
||||||
Value::string(trim_cstyle_null(version), span),
|
Value::string(trim_cstyle_null(version), span),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if let Some(hostname) = System::host_name() {
|
if let Some(hostname) = sys.host_name() {
|
||||||
record.push("hostname", Value::string(trim_cstyle_null(hostname), span));
|
record.push("hostname", Value::string(trim_cstyle_null(hostname), span));
|
||||||
}
|
}
|
||||||
|
|
||||||
record.push(
|
record.push(
|
||||||
"uptime",
|
"uptime",
|
||||||
Value::duration(1000000000 * System::uptime() as i64, span),
|
Value::duration(1000000000 * sys.uptime() as i64, span),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Creates a new SystemTime from the specified number of whole seconds
|
// Creates a new SystemTime from the specified number of whole seconds
|
||||||
let d = UNIX_EPOCH + Duration::from_secs(System::boot_time());
|
let d = UNIX_EPOCH + Duration::from_secs(sys.boot_time());
|
||||||
// Create DateTime from SystemTime
|
// Create DateTime from SystemTime
|
||||||
let datetime = DateTime::<Local>::from(d);
|
let datetime = DateTime::<Local>::from(d);
|
||||||
// Convert to local time and then rfc3339
|
// Convert to local time and then rfc3339
|
||||||
@ -247,16 +254,11 @@ pub fn host(span: Span) -> Value {
|
|||||||
|
|
||||||
record.push("boot_time", Value::string(timestamp_str, span));
|
record.push("boot_time", Value::string(timestamp_str, span));
|
||||||
|
|
||||||
let users = Users::new_with_refreshed_list();
|
let mut users = vec![];
|
||||||
|
for user in sys.users() {
|
||||||
let mut users_list = vec![];
|
|
||||||
for user in users.list() {
|
|
||||||
let mut groups = vec![];
|
let mut groups = vec![];
|
||||||
for group in user.groups() {
|
for group in user.groups() {
|
||||||
groups.push(Value::string(
|
groups.push(Value::string(trim_cstyle_null(group.to_string()), span));
|
||||||
trim_cstyle_null(group.name().to_string()),
|
|
||||||
span,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let record = record! {
|
let record = record! {
|
||||||
@ -264,22 +266,24 @@ pub fn host(span: Span) -> Value {
|
|||||||
"groups" => Value::list(groups, span),
|
"groups" => Value::list(groups, span),
|
||||||
};
|
};
|
||||||
|
|
||||||
users_list.push(Value::record(record, span));
|
users.push(Value::record(record, span));
|
||||||
}
|
}
|
||||||
|
|
||||||
if !users.is_empty() {
|
if !users.is_empty() {
|
||||||
record.push("sessions", Value::list(users_list, span));
|
record.push("sessions", Value::list(users, span));
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::record(record, span)
|
Value::record(record, span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn temp(span: Span) -> Value {
|
pub fn temp(span: Span) -> Value {
|
||||||
let components = Components::new_with_refreshed_list();
|
let mut sys = System::new();
|
||||||
|
sys.refresh_components();
|
||||||
|
sys.refresh_components_list();
|
||||||
|
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
for component in components.list() {
|
for component in sys.components() {
|
||||||
let mut record = record! {
|
let mut record = record! {
|
||||||
"unit" => Value::string(component.label(), span),
|
"unit" => Value::string(component.label(), span),
|
||||||
"temp" => Value::float(component.temperature() as f64, span),
|
"temp" => Value::float(component.temperature() as f64, span),
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
use nu_test_support::nu;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn basic_stdout() {
|
|
||||||
let without_complete = nu!(r#"
|
|
||||||
nu --testbin cococo test
|
|
||||||
"#);
|
|
||||||
let with_complete = nu!(r#"
|
|
||||||
(nu --testbin cococo test | complete).stdout
|
|
||||||
"#);
|
|
||||||
|
|
||||||
assert_eq!(with_complete.out, without_complete.out);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn basic_exit_code() {
|
|
||||||
let with_complete = nu!(r#"
|
|
||||||
(nu --testbin cococo test | complete).exit_code
|
|
||||||
"#);
|
|
||||||
|
|
||||||
assert_eq!(with_complete.out, "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn error() {
|
|
||||||
let actual = nu!("do { not-found } | complete");
|
|
||||||
|
|
||||||
assert!(actual.err.contains("executable was not found"));
|
|
||||||
}
|
|
@ -197,7 +197,7 @@ fn def_wrapped_with_block() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn def_wrapped_from_module() {
|
fn def_wrapped_from_module() {
|
||||||
let actual = nu!(r#"module spam {
|
let actual = nu!(r#"module spam {
|
||||||
export def --wrapped my-echo [...rest] { nu --testbin cococo ...$rest }
|
export def --wrapped my-echo [...rest] { ^echo $rest }
|
||||||
}
|
}
|
||||||
|
|
||||||
use spam
|
use spam
|
||||||
|
@ -49,7 +49,7 @@ fn exec_misc_values() {
|
|||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: dirs.test(), pipeline(
|
cwd: dirs.test(), pipeline(
|
||||||
r#"
|
r#"
|
||||||
nu -c 'let x = "abc"; exec nu --testbin cococo $x ...[ a b c ]'
|
nu -c 'let x = "abc"; exec nu --testbin cococo $x [ a b c ]'
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ mod break_;
|
|||||||
mod cal;
|
mod cal;
|
||||||
mod cd;
|
mod cd;
|
||||||
mod compact;
|
mod compact;
|
||||||
mod complete;
|
|
||||||
mod config_env_default;
|
mod config_env_default;
|
||||||
mod config_nu_default;
|
mod config_nu_default;
|
||||||
mod continue_;
|
mod continue_;
|
||||||
@ -107,8 +106,6 @@ mod touch;
|
|||||||
mod transpose;
|
mod transpose;
|
||||||
mod try_;
|
mod try_;
|
||||||
mod ucp;
|
mod ucp;
|
||||||
#[cfg(unix)]
|
|
||||||
mod ulimit;
|
|
||||||
mod umkdir;
|
mod umkdir;
|
||||||
mod uniq;
|
mod uniq;
|
||||||
mod uniq_by;
|
mod uniq_by;
|
||||||
|
@ -38,68 +38,3 @@ fn http_delete_failed_due_to_server_error() {
|
|||||||
|
|
||||||
assert!(actual.err.contains("Bad request (400)"))
|
assert!(actual.err.contains("Bad request (400)"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_delete_follows_redirect() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server.mock("GET", "/bar").with_body("bar").create();
|
|
||||||
let _mock = server
|
|
||||||
.mock("DELETE", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!("http delete {url}/foo", url = server.url()).as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_delete_redirect_mode_manual() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("DELETE", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http delete --redirect-mode manual {url}/foo",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_delete_redirect_mode_error() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("DELETE", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http delete --redirect-mode error {url}/foo",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
||||||
assert!(&actual.err.contains(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
@ -176,71 +176,6 @@ fn http_get_full_response() {
|
|||||||
assert_eq!(header["value"], "close");
|
assert_eq!(header["value"], "close");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_get_follows_redirect() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server.mock("GET", "/bar").with_body("bar").create();
|
|
||||||
let _mock = server
|
|
||||||
.mock("GET", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!("http get {url}/foo", url = server.url()).as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_get_redirect_mode_manual() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("GET", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http get --redirect-mode manual {url}/foo",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_get_redirect_mode_error() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("GET", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http get --redirect-mode error {url}/foo",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
||||||
assert!(&actual.err.contains(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// These tests require network access; they use badssl.com which is a Google-affiliated site for testing various SSL errors.
|
// These tests require network access; they use badssl.com which is a Google-affiliated site for testing various SSL errors.
|
||||||
// Revisit this if these tests prove to be flaky or unstable.
|
// Revisit this if these tests prove to be flaky or unstable.
|
||||||
|
|
||||||
|
@ -39,75 +39,3 @@ fn http_head_failed_due_to_server_error() {
|
|||||||
|
|
||||||
assert!(actual.err.contains("Bad request (400)"))
|
assert!(actual.err.contains("Bad request (400)"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_head_follows_redirect() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("HEAD", "/bar")
|
|
||||||
.with_header("bar", "bar")
|
|
||||||
.create();
|
|
||||||
let _mock = server
|
|
||||||
.mock("HEAD", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http head {url}/foo | (where name == bar).0.value",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_head_redirect_mode_manual() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("HEAD", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http head --redirect-mode manual {url}/foo | (where name == location).0.value",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "/bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_head_redirect_mode_error() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("HEAD", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http head --redirect-mode error {url}/foo",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
||||||
assert!(&actual.err.contains(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
@ -76,68 +76,3 @@ fn http_patch_failed_due_to_unexpected_body() {
|
|||||||
|
|
||||||
assert!(actual.err.contains("Cannot make request"))
|
assert!(actual.err.contains("Cannot make request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_patch_follows_redirect() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server.mock("GET", "/bar").with_body("bar").create();
|
|
||||||
let _mock = server
|
|
||||||
.mock("PATCH", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!("http patch {url}/foo patchbody", url = server.url()).as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_patch_redirect_mode_manual() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("PATCH", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http patch --redirect-mode manual {url}/foo patchbody",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_patch_redirect_mode_error() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("PATCH", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http patch --redirect-mode error {url}/foo patchbody",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
||||||
assert!(&actual.err.contains(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
@ -112,68 +112,3 @@ fn http_post_json_list_is_success() {
|
|||||||
mock.assert();
|
mock.assert();
|
||||||
assert!(actual.out.is_empty())
|
assert!(actual.out.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_post_follows_redirect() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server.mock("GET", "/bar").with_body("bar").create();
|
|
||||||
let _mock = server
|
|
||||||
.mock("POST", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!("http post {url}/foo postbody", url = server.url()).as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_post_redirect_mode_manual() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("POST", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http post --redirect-mode manual {url}/foo postbody",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_post_redirect_mode_error() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("POST", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http post --redirect-mode error {url}/foo postbody",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
||||||
assert!(&actual.err.contains(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
@ -76,68 +76,3 @@ fn http_put_failed_due_to_unexpected_body() {
|
|||||||
|
|
||||||
assert!(actual.err.contains("Cannot make request"))
|
assert!(actual.err.contains("Cannot make request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_put_follows_redirect() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server.mock("GET", "/bar").with_body("bar").create();
|
|
||||||
let _mock = server
|
|
||||||
.mock("PUT", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!("http put {url}/foo putbody", url = server.url()).as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_put_redirect_mode_manual() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("PUT", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http put --redirect-mode manual {url}/foo putbody",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(&actual.out, "foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn http_put_redirect_mode_error() {
|
|
||||||
let mut server = Server::new();
|
|
||||||
|
|
||||||
let _mock = server
|
|
||||||
.mock("PUT", "/foo")
|
|
||||||
.with_status(301)
|
|
||||||
.with_body("foo")
|
|
||||||
.with_header("Location", "/bar")
|
|
||||||
.create();
|
|
||||||
|
|
||||||
let actual = nu!(pipeline(
|
|
||||||
format!(
|
|
||||||
"http put --redirect-mode error {url}/foo putbody",
|
|
||||||
url = server.url()
|
|
||||||
)
|
|
||||||
.as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(&actual.err.contains("nu::shell::network_failure"));
|
|
||||||
assert!(&actual.err.contains(
|
|
||||||
"Redirect encountered when redirect handling mode was 'error' (301 Moved Permanently)"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
@ -161,14 +161,9 @@ fn same_target_redirection_with_too_much_stderr_not_hang_nushell() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn redirection_keep_exit_codes() {
|
fn redirection_keep_exit_codes() {
|
||||||
Playground::setup("redirection preserves exit code", |dirs, _| {
|
let out = nu!("do -i { nu --testbin fail e> a.txt } | complete | get exit_code");
|
||||||
let out = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"do -i { nu --testbin fail e> a.txt } | complete | get exit_code"
|
|
||||||
);
|
|
||||||
// needs to use contains "1", because it complete will output `Some(RawStream)`.
|
// needs to use contains "1", because it complete will output `Some(RawStream)`.
|
||||||
assert!(out.out.contains('1'));
|
assert!(out.out.contains('1'));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -307,7 +302,6 @@ fn separate_redirection_support_variable() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn redirection_should_have_a_target() {
|
fn redirection_should_have_a_target() {
|
||||||
Playground::setup("redirection_should_have_a_target", |dirs, _| {
|
|
||||||
let scripts = [
|
let scripts = [
|
||||||
"echo asdf o+e>",
|
"echo asdf o+e>",
|
||||||
"echo asdf o>",
|
"echo asdf o>",
|
||||||
@ -319,17 +313,13 @@ fn redirection_should_have_a_target() {
|
|||||||
"echo asdf o>; echo asdf",
|
"echo asdf o>; echo asdf",
|
||||||
];
|
];
|
||||||
for code in scripts {
|
for code in scripts {
|
||||||
let actual = nu!(cwd: dirs.test(), code);
|
let actual = nu!(code);
|
||||||
assert!(
|
assert!(
|
||||||
actual.err.contains("expected redirection target",),
|
actual.err.contains("expected redirection target",),
|
||||||
"should be error, code: {code}",
|
"should be error, code: {}",
|
||||||
);
|
code
|
||||||
assert!(
|
|
||||||
!dirs.test().join("tmp.txt").exists(),
|
|
||||||
"No file should be created on error: {code}",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -362,24 +352,8 @@ fn redirection_with_pipe() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_duplicate_redirection() {
|
fn no_duplicate_redirection() {
|
||||||
Playground::setup("redirection does not accept duplicate", |dirs, _| {
|
let actual = nu!("echo 3 o> a.txt o> a.txt");
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"echo 3 o> a.txt o> a.txt"
|
|
||||||
);
|
|
||||||
assert!(actual.err.contains("Redirection can be set only once"));
|
assert!(actual.err.contains("Redirection can be set only once"));
|
||||||
assert!(
|
let actual = nu!("echo 3 e> a.txt e> a.txt");
|
||||||
!dirs.test().join("a.txt").exists(),
|
|
||||||
"No file should be created on error"
|
|
||||||
);
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"echo 3 e> a.txt e> a.txt"
|
|
||||||
);
|
|
||||||
assert!(actual.err.contains("Redirection can be set only once"));
|
assert!(actual.err.contains("Redirection can be set only once"));
|
||||||
assert!(
|
|
||||||
!dirs.test().join("a.txt").exists(),
|
|
||||||
"No file should be created on error"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -375,19 +375,6 @@ fn removes_symlink() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn removes_symlink_pointing_to_directory() {
|
|
||||||
Playground::setup("rm_symlink_to_directory", |dirs, sandbox| {
|
|
||||||
sandbox.mkdir("test").symlink("test", "test_link");
|
|
||||||
|
|
||||||
nu!(cwd: sandbox.cwd(), "rm test_link");
|
|
||||||
|
|
||||||
assert!(!dirs.test().join("test_link").exists());
|
|
||||||
// The pointed directory should not be deleted.
|
|
||||||
assert!(dirs.test().join("test").exists());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn removes_file_after_cd() {
|
fn removes_file_after_cd() {
|
||||||
Playground::setup("rm_after_cd", |dirs, sandbox| {
|
Playground::setup("rm_after_cd", |dirs, sandbox| {
|
||||||
|
@ -139,13 +139,14 @@ fn failed_command_with_semicolon_will_not_execute_following_cmds() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
#[test]
|
#[test]
|
||||||
fn external_args_with_quoted() {
|
fn external_args_with_quoted() {
|
||||||
Playground::setup("external failed command with semicolon", |dirs, _| {
|
Playground::setup("external failed command with semicolon", |dirs, _| {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: dirs.test(), pipeline(
|
cwd: dirs.test(), pipeline(
|
||||||
r#"
|
r#"
|
||||||
nu --testbin cococo "foo=bar 'hi'"
|
^echo "foo=bar 'hi'"
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -186,13 +187,14 @@ fn external_arg_with_variable_name() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
#[test]
|
#[test]
|
||||||
fn external_command_escape_args() {
|
fn external_command_escape_args() {
|
||||||
Playground::setup("external failed command with semicolon", |dirs, _| {
|
Playground::setup("external failed command with semicolon", |dirs, _| {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: dirs.test(), pipeline(
|
cwd: dirs.test(), pipeline(
|
||||||
r#"
|
r#"
|
||||||
nu --testbin cococo "\"abcd"
|
^echo "\"abcd"
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -306,12 +308,13 @@ fn can_run_batch_files_without_bat_extension() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
#[test]
|
#[test]
|
||||||
fn quotes_trimmed_when_shelling_out() {
|
fn quotes_trimmed_when_shelling_out() {
|
||||||
// regression test for a bug where we weren't trimming quotes around string args before shelling out to cmd.exe
|
// regression test for a bug where we weren't trimming quotes around string args before shelling out to cmd.exe
|
||||||
let actual = nu!(pipeline(
|
let actual = nu!(pipeline(
|
||||||
r#"
|
r#"
|
||||||
nu --testbin cococo "foo"
|
^echo "foo"
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -325,7 +328,7 @@ fn redirect_combine() {
|
|||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: dirs.test(), pipeline(
|
cwd: dirs.test(), pipeline(
|
||||||
r#"
|
r#"
|
||||||
run-external --redirect-combine sh ...[-c 'echo Foo; echo >&2 Bar']
|
run-external --redirect-combine sh [-c 'echo Foo; echo >&2 Bar']
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use nu_test_support::fs::{file_contents, Stub};
|
use nu_test_support::fs::{file_contents, Stub};
|
||||||
|
use nu_test_support::nu;
|
||||||
use nu_test_support::playground::Playground;
|
use nu_test_support::playground::Playground;
|
||||||
use nu_test_support::{nu, pipeline};
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -325,45 +325,3 @@ fn save_file_correct_relative_path() {
|
|||||||
assert_eq!(actual, "foo!");
|
assert_eq!(actual, "foo!");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn save_same_file_with_extension() {
|
|
||||||
Playground::setup("save_test_16", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
echo 'world'
|
|
||||||
| save --raw hello.md;
|
|
||||||
open --raw hello.md
|
|
||||||
| prepend 'hello'
|
|
||||||
| save --raw --force hello.md
|
|
||||||
"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual
|
|
||||||
.err
|
|
||||||
.contains("pipeline input and output are same file"));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn save_same_file_without_extension() {
|
|
||||||
Playground::setup("save_test_17", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
echo 'world'
|
|
||||||
| save hello;
|
|
||||||
open hello
|
|
||||||
| prepend 'hello'
|
|
||||||
| save --force hello
|
|
||||||
"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual
|
|
||||||
.err
|
|
||||||
.contains("pipeline input and output are same file"));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -1,218 +0,0 @@
|
|||||||
use nu_test_support::playground::Playground;
|
|
||||||
use nu_test_support::{nu, pipeline};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_soft1() {
|
|
||||||
Playground::setup("limit_set_soft1", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
let soft = (ulimit -s | first | get soft);
|
|
||||||
ulimit -s -H $soft;
|
|
||||||
let hard = (ulimit -s | first | get hard);
|
|
||||||
$soft == $hard
|
|
||||||
"
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.out.contains("true"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_soft2() {
|
|
||||||
Playground::setup("limit_set_soft2", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
let soft = (ulimit -s | first | get soft);
|
|
||||||
ulimit -s -H soft;
|
|
||||||
let hard = (ulimit -s | first | get hard);
|
|
||||||
$soft == $hard
|
|
||||||
"
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.out.contains("true"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_hard1() {
|
|
||||||
Playground::setup("limit_set_hard1", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
let hard = (ulimit -s | first | get hard);
|
|
||||||
ulimit -s $hard;
|
|
||||||
let soft = (ulimit -s | first | get soft);
|
|
||||||
$soft == $hard
|
|
||||||
"
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.out.contains("true"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_hard2() {
|
|
||||||
Playground::setup("limit_set_hard2", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
let hard = (ulimit -s | first | get hard);
|
|
||||||
ulimit -s hard;
|
|
||||||
let soft = (ulimit -s | first | get soft);
|
|
||||||
$soft == $hard
|
|
||||||
"
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.out.contains("true"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_invalid1() {
|
|
||||||
Playground::setup("limit_set_invalid1", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
let hard = (ulimit -s | first | get hard);
|
|
||||||
match $hard {
|
|
||||||
\"unlimited\" => { echo \"unlimited\" },
|
|
||||||
$x => {
|
|
||||||
let new = $x + 1;
|
|
||||||
ulimit -s $new
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
actual.out.contains("unlimited")
|
|
||||||
|| actual.err.contains("EPERM: Operation not permitted")
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
|
||||||
#[test]
|
|
||||||
fn limit_set_invalid2() {
|
|
||||||
Playground::setup("limit_set_invalid2", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"
|
|
||||||
let val = -100;
|
|
||||||
ulimit -c $val
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("can't convert i64 to rlim_t"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_invalid3() {
|
|
||||||
Playground::setup("limit_set_invalid3", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"
|
|
||||||
ulimit -c abcd
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual
|
|
||||||
.err
|
|
||||||
.contains("Only unlimited, soft and hard are supported for strings"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_invalid4() {
|
|
||||||
Playground::setup("limit_set_invalid4", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"
|
|
||||||
ulimit -c 100.0
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("string, int or filesize required"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_invalid5() {
|
|
||||||
use nix::sys::resource::rlim_t;
|
|
||||||
|
|
||||||
let max = (rlim_t::MAX / 1024) + 1;
|
|
||||||
|
|
||||||
Playground::setup("limit_set_invalid5", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
format!(
|
|
||||||
"
|
|
||||||
let hard = (ulimit -c | first | get hard);
|
|
||||||
match $hard {{
|
|
||||||
\"unlimited\" => {{
|
|
||||||
ulimit -c -S 0;
|
|
||||||
ulimit -c {max};
|
|
||||||
ulimit -c
|
|
||||||
| first
|
|
||||||
| get soft
|
|
||||||
}},
|
|
||||||
_ => {{
|
|
||||||
echo \"unlimited\"
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
").as_str()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.out.eq("unlimited"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_filesize1() {
|
|
||||||
Playground::setup("limit_set_filesize1", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(), pipeline(
|
|
||||||
"
|
|
||||||
let hard = (ulimit -c | first | get hard);
|
|
||||||
match $hard {
|
|
||||||
\"unlimited\" => {
|
|
||||||
ulimit -c 1Mib;
|
|
||||||
ulimit -c
|
|
||||||
| first
|
|
||||||
| get soft
|
|
||||||
},
|
|
||||||
$x if $x >= 1024 * 1024 => {
|
|
||||||
ulimit -c 1Mib;
|
|
||||||
ulimit -c
|
|
||||||
| first
|
|
||||||
| get soft
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
echo \"hard limit too small\"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.out.eq("1024") || actual.out.eq("hard limit too small"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn limit_set_filesize2() {
|
|
||||||
Playground::setup("limit_set_filesize2", |dirs, _sandbox| {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: dirs.test(),
|
|
||||||
"
|
|
||||||
ulimit -n 10Kib
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual
|
|
||||||
.err
|
|
||||||
.contains("filesize is not compatible with resource RLIMIT_NOFILE"));
|
|
||||||
});
|
|
||||||
}
|
|
@ -22,39 +22,3 @@ fn table_to_xml_text_and_from_xml_text_back_into_table() {
|
|||||||
|
|
||||||
assert_eq!(actual.out, "true");
|
assert_eq!(actual.out, "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_xml_error_unknown_column() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: "tests/fixtures/formats", pipeline(
|
|
||||||
r#"
|
|
||||||
{tag: a bad_column: b} | to xml
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Invalid column \"bad_column\""));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_xml_error_no_tag() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: "tests/fixtures/formats", pipeline(
|
|
||||||
r#"
|
|
||||||
{attributes: {a: b c: d}} | to xml
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.err.contains("Tag missing"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_xml_error_tag_not_string() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: "tests/fixtures/formats", pipeline(
|
|
||||||
r#"
|
|
||||||
{tag: 1 attributes: {a: b c: d}} | to xml
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(actual.err.contains("not a string"));
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, Expression},
|
ast::Call,
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
eval_const::eval_constant,
|
eval_const::eval_constant,
|
||||||
FromValue, ShellError, Value,
|
FromValue, ShellError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::eval_expression;
|
use crate::eval_expression;
|
||||||
@ -34,10 +34,6 @@ pub trait CallExt {
|
|||||||
starting_pos: usize,
|
starting_pos: usize,
|
||||||
) -> Result<Vec<T>, ShellError>;
|
) -> Result<Vec<T>, ShellError>;
|
||||||
|
|
||||||
fn rest_iter_flattened<F>(&self, start: usize, eval: F) -> Result<Vec<Value>, ShellError>
|
|
||||||
where
|
|
||||||
F: FnMut(&Expression) -> Result<Value, ShellError>;
|
|
||||||
|
|
||||||
fn opt<T: FromValue>(
|
fn opt<T: FromValue>(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
@ -74,7 +70,7 @@ impl CallExt for Call {
|
|||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<Option<T>, ShellError> {
|
) -> Result<Option<T>, ShellError> {
|
||||||
if let Some(expr) = self.get_flag_expr(name) {
|
if let Some(expr) = self.get_flag_expr(name) {
|
||||||
let result = eval_expression(engine_state, stack, expr)?;
|
let result = eval_expression(engine_state, stack, &expr)?;
|
||||||
FromValue::from_value(result).map(Some)
|
FromValue::from_value(result).map(Some)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -87,7 +83,7 @@ impl CallExt for Call {
|
|||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<Option<T>, ShellError> {
|
) -> Result<Option<T>, ShellError> {
|
||||||
if let Some(expr) = self.get_flag_expr(name) {
|
if let Some(expr) = self.get_flag_expr(name) {
|
||||||
let result = eval_constant(working_set, expr)?;
|
let result = eval_constant(working_set, &expr)?;
|
||||||
FromValue::from_value(result).map(Some)
|
FromValue::from_value(result).map(Some)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -102,9 +98,8 @@ impl CallExt for Call {
|
|||||||
) -> Result<Vec<T>, ShellError> {
|
) -> Result<Vec<T>, ShellError> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
for result in self.rest_iter_flattened(starting_pos, |expr| {
|
for expr in self.positional_iter().skip(starting_pos) {
|
||||||
eval_expression(engine_state, stack, expr)
|
let result = eval_expression(engine_state, stack, expr)?;
|
||||||
})? {
|
|
||||||
output.push(FromValue::from_value(result)?);
|
output.push(FromValue::from_value(result)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,36 +113,14 @@ impl CallExt for Call {
|
|||||||
) -> Result<Vec<T>, ShellError> {
|
) -> Result<Vec<T>, ShellError> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
for result in
|
for expr in self.positional_iter().skip(starting_pos) {
|
||||||
self.rest_iter_flattened(starting_pos, |expr| eval_constant(working_set, expr))?
|
let result = eval_constant(working_set, expr)?;
|
||||||
{
|
|
||||||
output.push(FromValue::from_value(result)?);
|
output.push(FromValue::from_value(result)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rest_iter_flattened<F>(&self, start: usize, mut eval: F) -> Result<Vec<Value>, ShellError>
|
|
||||||
where
|
|
||||||
F: FnMut(&Expression) -> Result<Value, ShellError>,
|
|
||||||
{
|
|
||||||
let mut output = Vec::new();
|
|
||||||
|
|
||||||
for (expr, spread) in self.rest_iter(start) {
|
|
||||||
let result = eval(expr)?;
|
|
||||||
if spread {
|
|
||||||
match result {
|
|
||||||
Value::List { mut vals, .. } => output.append(&mut vals),
|
|
||||||
_ => return Err(ShellError::CannotSpreadAsList { span: expr.span }),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
output.push(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn opt<T: FromValue>(
|
fn opt<T: FromValue>(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::{call_ext::CallExt, current_dir_str, get_full_help};
|
use crate::{current_dir_str, get_full_help};
|
||||||
use nu_path::expand_path_with;
|
use nu_path::expand_path_with;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{
|
ast::{
|
||||||
Argument, Assignment, Block, Call, Expr, Expression, ExternalArgument, PathMember,
|
Argument, Assignment, Block, Call, Expr, Expression, PathMember, PipelineElement,
|
||||||
PipelineElement, Redirection,
|
Redirection,
|
||||||
},
|
},
|
||||||
engine::{Closure, EngineState, Stack},
|
engine::{Closure, EngineState, Stack},
|
||||||
eval_base::Eval,
|
eval_base::Eval,
|
||||||
@ -66,11 +66,11 @@ pub fn eval_call(
|
|||||||
if let Some(rest_positional) = decl.signature().rest_positional {
|
if let Some(rest_positional) = decl.signature().rest_positional {
|
||||||
let mut rest_items = vec![];
|
let mut rest_items = vec![];
|
||||||
|
|
||||||
for result in call.rest_iter_flattened(
|
for arg in call.positional_iter().skip(
|
||||||
decl.signature().required_positional.len()
|
decl.signature().required_positional.len()
|
||||||
+ decl.signature().optional_positional.len(),
|
+ decl.signature().optional_positional.len(),
|
||||||
|expr| eval_expression(engine_state, caller_stack, expr),
|
) {
|
||||||
)? {
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
||||||
rest_items.push(result);
|
rest_items.push(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +182,7 @@ fn eval_external(
|
|||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
head: &Expression,
|
head: &Expression,
|
||||||
args: &[ExternalArgument],
|
args: &[Expression],
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
redirect_target: RedirectTarget,
|
redirect_target: RedirectTarget,
|
||||||
is_subexpression: bool,
|
is_subexpression: bool,
|
||||||
@ -198,10 +198,7 @@ fn eval_external(
|
|||||||
call.add_positional(head.clone());
|
call.add_positional(head.clone());
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
match arg {
|
call.add_positional(arg.clone())
|
||||||
ExternalArgument::Regular(expr) => call.add_positional(expr.clone()),
|
|
||||||
ExternalArgument::Spread(expr) => call.add_spread(expr.clone()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match redirect_target {
|
match redirect_target {
|
||||||
@ -950,7 +947,7 @@ impl Eval for EvalRuntime {
|
|||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
head: &Expression,
|
head: &Expression,
|
||||||
args: &[ExternalArgument],
|
args: &[Expression],
|
||||||
is_subexpression: bool,
|
is_subexpression: bool,
|
||||||
_: Span,
|
_: Span,
|
||||||
) -> Result<Value, ShellError> {
|
) -> Result<Value, ShellError> {
|
||||||
@ -1102,18 +1099,7 @@ impl Eval for EvalRuntime {
|
|||||||
.get_block(block_id)
|
.get_block(block_id)
|
||||||
.captures
|
.captures
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&id| {
|
.map(|&id| stack.get_var(id, span).map(|var| (id, var)))
|
||||||
stack
|
|
||||||
.get_var(id, span)
|
|
||||||
.or_else(|_| {
|
|
||||||
engine_state
|
|
||||||
.get_var(id)
|
|
||||||
.const_val
|
|
||||||
.clone()
|
|
||||||
.ok_or(ShellError::VariableNotFoundAtRuntime { span })
|
|
||||||
})
|
|
||||||
.map(|var| (id, var))
|
|
||||||
})
|
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
Ok(Value::closure(Closure { block_id, captures }, span))
|
Ok(Value::closure(Closure { block_id, captures }, span))
|
||||||
|
@ -20,10 +20,10 @@ nu-table = { path = "../nu-table", version = "0.88.2" }
|
|||||||
nu-json = { path = "../nu-json", version = "0.88.2" }
|
nu-json = { path = "../nu-json", version = "0.88.2" }
|
||||||
nu-utils = { path = "../nu-utils", version = "0.88.2" }
|
nu-utils = { path = "../nu-utils", version = "0.88.2" }
|
||||||
|
|
||||||
terminal_size = "0.3"
|
terminal_size = "0.2"
|
||||||
strip-ansi-escapes = "0.2.0"
|
strip-ansi-escapes = "0.2.0"
|
||||||
crossterm = "0.27"
|
crossterm = "0.27"
|
||||||
ratatui = "0.23"
|
ratatui = "0.23"
|
||||||
ansi-str = "0.8"
|
ansi-str = "0.8"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
lscolors = { version = "0.16", default-features = false, features = ["nu-ansi-term"] }
|
lscolors = { version = "0.15", default-features = false, features = ["nu-ansi-term"] }
|
||||||
|
@ -15,7 +15,7 @@ nu-protocol = { path = "../nu-protocol", version = "0.88.2" }
|
|||||||
reedline = { version = "0.27" }
|
reedline = { version = "0.27" }
|
||||||
|
|
||||||
crossbeam-channel = "0.5.8"
|
crossbeam-channel = "0.5.8"
|
||||||
lsp-types = "0.95.0"
|
lsp-types = "0.94.1"
|
||||||
lsp-server = "0.7.5"
|
lsp-server = "0.7.5"
|
||||||
miette = "5.10"
|
miette = "5.10"
|
||||||
ropey = "1.6.1"
|
ropey = "1.6.1"
|
||||||
|
@ -312,7 +312,7 @@ impl LanguageServer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Id::Value(_) => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -347,22 +347,11 @@ impl LanguageServer {
|
|||||||
Id::Declaration(decl_id) => {
|
Id::Declaration(decl_id) => {
|
||||||
let decl = working_set.get_decl(decl_id);
|
let decl = working_set.get_decl(decl_id);
|
||||||
|
|
||||||
let mut description = String::new();
|
let mut description = "\n### Signature\n```\n".to_string();
|
||||||
|
|
||||||
// First description
|
|
||||||
description.push_str(&format!("{}\n", decl.usage().replace('\r', "")));
|
|
||||||
|
|
||||||
// Additional description
|
|
||||||
if !decl.extra_usage().is_empty() {
|
|
||||||
description.push_str(&format!("\n{}\n", decl.extra_usage()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
description.push_str("### Usage \n```\n");
|
|
||||||
let signature = decl.signature();
|
let signature = decl.signature();
|
||||||
description.push_str(&format!(" {}", signature.name));
|
description.push_str(&format!(" {}", signature.name));
|
||||||
if !signature.named.is_empty() {
|
if !signature.named.is_empty() {
|
||||||
description.push_str(" {flags}");
|
description.push_str(" {flags}")
|
||||||
}
|
}
|
||||||
for required_arg in &signature.required_positional {
|
for required_arg in &signature.required_positional {
|
||||||
description.push_str(&format!(" <{}>", required_arg.name));
|
description.push_str(&format!(" <{}>", required_arg.name));
|
||||||
@ -374,39 +363,6 @@ impl LanguageServer {
|
|||||||
description.push_str(&format!(" <...{}>", arg.name));
|
description.push_str(&format!(" <...{}>", arg.name));
|
||||||
}
|
}
|
||||||
description.push_str("\n```\n");
|
description.push_str("\n```\n");
|
||||||
|
|
||||||
// Flags
|
|
||||||
if !signature.named.is_empty() {
|
|
||||||
description.push_str("\n### Flags\n\n");
|
|
||||||
let mut first = true;
|
|
||||||
for named in &signature.named {
|
|
||||||
if first {
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
description.push('\n');
|
|
||||||
}
|
|
||||||
description.push_str(" ");
|
|
||||||
if let Some(short_flag) = &named.short {
|
|
||||||
description.push_str(&format!("`-{short_flag}`"));
|
|
||||||
}
|
|
||||||
if !named.long.is_empty() {
|
|
||||||
if named.short.is_some() {
|
|
||||||
description.push_str(", ");
|
|
||||||
}
|
|
||||||
description.push_str(&format!("`--{}`", named.long));
|
|
||||||
}
|
|
||||||
if let Some(arg) = &named.arg {
|
|
||||||
description.push_str(&format!(" `<{}>`", arg.to_type()));
|
|
||||||
}
|
|
||||||
if !named.desc.is_empty() {
|
|
||||||
description.push_str(&format!(" - {}", named.desc));
|
|
||||||
}
|
|
||||||
description.push('\n');
|
|
||||||
}
|
|
||||||
description.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parameters
|
|
||||||
if !signature.required_positional.is_empty()
|
if !signature.required_positional.is_empty()
|
||||||
|| !signature.optional_positional.is_empty()
|
|| !signature.optional_positional.is_empty()
|
||||||
|| signature.rest_positional.is_some()
|
|| signature.rest_positional.is_some()
|
||||||
@ -414,10 +370,10 @@ impl LanguageServer {
|
|||||||
description.push_str("\n### Parameters\n\n");
|
description.push_str("\n### Parameters\n\n");
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for required_arg in &signature.required_positional {
|
for required_arg in &signature.required_positional {
|
||||||
if first {
|
if !first {
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
description.push('\n');
|
description.push('\n');
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
description.push_str(&format!(
|
description.push_str(&format!(
|
||||||
" `{}: {}`",
|
" `{}: {}`",
|
||||||
@ -430,10 +386,10 @@ impl LanguageServer {
|
|||||||
description.push('\n');
|
description.push('\n');
|
||||||
}
|
}
|
||||||
for optional_arg in &signature.optional_positional {
|
for optional_arg in &signature.optional_positional {
|
||||||
if first {
|
if !first {
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
description.push('\n');
|
description.push('\n');
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
description.push_str(&format!(
|
description.push_str(&format!(
|
||||||
" `{}: {}`",
|
" `{}: {}`",
|
||||||
@ -461,10 +417,36 @@ impl LanguageServer {
|
|||||||
}
|
}
|
||||||
description.push('\n');
|
description.push('\n');
|
||||||
}
|
}
|
||||||
|
if !signature.named.is_empty() {
|
||||||
// Input/output types
|
description.push_str("\n### Flags\n\n");
|
||||||
|
let mut first = true;
|
||||||
|
for named in &signature.named {
|
||||||
|
if !first {
|
||||||
|
description.push('\n');
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
description.push_str(" ");
|
||||||
|
if let Some(short_flag) = &named.short {
|
||||||
|
description.push_str(&format!("`-{}`", short_flag));
|
||||||
|
}
|
||||||
|
if !named.long.is_empty() {
|
||||||
|
if named.short.is_some() {
|
||||||
|
description.push_str(", ")
|
||||||
|
}
|
||||||
|
description.push_str(&format!("`--{}`", named.long));
|
||||||
|
}
|
||||||
|
if let Some(arg) = &named.arg {
|
||||||
|
description.push_str(&format!(" `<{}>`", arg.to_type()))
|
||||||
|
}
|
||||||
|
if !named.desc.is_empty() {
|
||||||
|
description.push_str(&format!(" - {}", named.desc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
description.push('\n');
|
||||||
|
}
|
||||||
if !signature.input_output_types.is_empty() {
|
if !signature.input_output_types.is_empty() {
|
||||||
description.push_str("\n### Input/output types\n");
|
description.push_str("\n### Input/output\n");
|
||||||
description.push_str("\n```\n");
|
description.push_str("\n```\n");
|
||||||
for input_output in &signature.input_output_types {
|
for input_output in &signature.input_output_types {
|
||||||
description
|
description
|
||||||
@ -472,8 +454,14 @@ impl LanguageServer {
|
|||||||
}
|
}
|
||||||
description.push_str("\n```\n");
|
description.push_str("\n```\n");
|
||||||
}
|
}
|
||||||
|
description.push_str(&format!(
|
||||||
// Examples
|
"### Usage\n {}\n",
|
||||||
|
decl.usage().replace('\r', "")
|
||||||
|
));
|
||||||
|
if !decl.extra_usage().is_empty() {
|
||||||
|
description
|
||||||
|
.push_str(&format!("\n### Extra usage:\n {}\n", decl.extra_usage()));
|
||||||
|
}
|
||||||
if !decl.examples().is_empty() {
|
if !decl.examples().is_empty() {
|
||||||
description.push_str("### Example(s)\n");
|
description.push_str("### Example(s)\n");
|
||||||
for example in decl.examples() {
|
for example in decl.examples() {
|
||||||
@ -590,9 +578,8 @@ mod tests {
|
|||||||
},
|
},
|
||||||
request::{Completion, GotoDefinition, HoverRequest, Initialize, Request, Shutdown},
|
request::{Completion, GotoDefinition, HoverRequest, Initialize, Request, Shutdown},
|
||||||
CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams,
|
CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams,
|
||||||
GotoDefinitionParams, InitializeParams, InitializedParams, PartialResultParams,
|
GotoDefinitionParams, InitializeParams, InitializedParams, TextDocumentContentChangeEvent,
|
||||||
TextDocumentContentChangeEvent, TextDocumentIdentifier, TextDocumentItem,
|
TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, Url,
|
||||||
TextDocumentPositionParams, Url, WorkDoneProgressParams,
|
|
||||||
};
|
};
|
||||||
use nu_test_support::fs::{fixtures, root};
|
use nu_test_support::fs::{fixtures, root};
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
@ -684,8 +671,8 @@ mod tests {
|
|||||||
character: 0,
|
character: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
work_done_progress_params: Default::default(),
|
||||||
partial_result_params: PartialResultParams::default(),
|
partial_result_params: Default::default(),
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}))
|
}))
|
||||||
@ -790,8 +777,8 @@ mod tests {
|
|||||||
text_document: TextDocumentIdentifier { uri },
|
text_document: TextDocumentIdentifier { uri },
|
||||||
position: lsp_types::Position { line, character },
|
position: lsp_types::Position { line, character },
|
||||||
},
|
},
|
||||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
work_done_progress_params: Default::default(),
|
||||||
partial_result_params: PartialResultParams::default(),
|
partial_result_params: Default::default(),
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}))
|
}))
|
||||||
@ -907,7 +894,7 @@ mod tests {
|
|||||||
text_document: TextDocumentIdentifier { uri },
|
text_document: TextDocumentIdentifier { uri },
|
||||||
position: lsp_types::Position { line, character },
|
position: lsp_types::Position { line, character },
|
||||||
},
|
},
|
||||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
work_done_progress_params: Default::default(),
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
}))
|
}))
|
||||||
@ -970,7 +957,7 @@ mod tests {
|
|||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"contents": {
|
"contents": {
|
||||||
"kind": "markdown",
|
"kind": "markdown",
|
||||||
"value": "Renders some greeting message\n### Usage \n```\n hello {flags}\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n\n"
|
"value": "\n### Signature\n```\n hello {flags}\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n### Usage\n Renders some greeting message\n"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -987,8 +974,8 @@ mod tests {
|
|||||||
text_document: TextDocumentIdentifier { uri },
|
text_document: TextDocumentIdentifier { uri },
|
||||||
position: lsp_types::Position { line, character },
|
position: lsp_types::Position { line, character },
|
||||||
},
|
},
|
||||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
work_done_progress_params: Default::default(),
|
||||||
partial_result_params: PartialResultParams::default(),
|
partial_result_params: Default::default(),
|
||||||
context: None,
|
context: None,
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -121,7 +121,7 @@ mod tests {
|
|||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"contents": {
|
"contents": {
|
||||||
"kind": "markdown",
|
"kind": "markdown",
|
||||||
"value": "Create a variable and give it a value.\n\nThis command is a parser keyword. For details, check:\n https://www.nushell.sh/book/thinking_in_nu.html\n### Usage \n```\n let {flags} <var_name> <initial_value>\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n\n\n### Parameters\n\n `var_name: any` - Variable name.\n\n `initial_value: any` - Equals sign followed by value.\n\n\n### Input/output types\n\n```\n any | nothing\n\n```\n### Example(s)\n Set a variable to a value\n```\n let x = 10\n```\n Set a variable to the result of an expression\n```\n let x = 10 + 100\n```\n Set a variable based on the condition\n```\n let x = if false { -1 } else { 1 }\n```\n"
|
"value": "\n### Signature\n```\n let {flags} <var_name> <initial_value>\n```\n\n### Parameters\n\n `var_name: any` - Variable name.\n\n `initial_value: any` - Equals sign followed by value.\n\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n\n### Input/output\n\n```\n any | nothing\n\n```\n### Usage\n Create a variable and give it a value.\n\n### Extra usage:\n This command is a parser keyword. For details, check:\n https://www.nushell.sh/book/thinking_in_nu.html\n### Example(s)\n Set a variable to a value\n```\n let x = 10\n```\n Set a variable to the result of an expression\n```\n let x = 10 + 100\n```\n Set a variable based on the condition\n```\n let x = if false { -1 } else { 1 }\n```\n"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -162,7 +162,7 @@ hello"#,
|
|||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"contents": {
|
"contents": {
|
||||||
"kind": "markdown",
|
"kind": "markdown",
|
||||||
"value": "Renders some updated greeting message\n### Usage \n```\n hello {flags}\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n\n"
|
"value": "\n### Signature\n```\n hello {flags}\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n### Usage\n Renders some updated greeting message\n"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -207,7 +207,7 @@ hello"#,
|
|||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"contents": {
|
"contents": {
|
||||||
"kind": "markdown",
|
"kind": "markdown",
|
||||||
"value": "Renders some updated greeting message\n### Usage \n```\n hello {flags}\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n\n"
|
"value": "\n### Signature\n```\n hello {flags}\n```\n\n### Flags\n\n `-h`, `--help` - Display the help message for this command\n### Usage\n Renders some updated greeting message\n"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user