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"
|
||||
ratatui = "ratatui"
|
||||
doas = "doas"
|
||||
wheres = "wheres"
|
||||
|
33
.github/workflows/ci.yml
vendored
33
.github/workflows/ci.yml
vendored
@ -92,17 +92,6 @@ jobs:
|
||||
- name: Tests
|
||||
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:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
@ -140,17 +129,6 @@ jobs:
|
||||
run: nu scripts/test_virtualenv.nu
|
||||
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:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
@ -172,14 +150,3 @@ jobs:
|
||||
|
||||
- name: Tests
|
||||
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
|
||||
target_rustflags: ''
|
||||
- target: riscv64gc-unknown-linux-gnu
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
|
||||
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
|
||||
# ----------------------------------------------------------------------------
|
||||
if $os in [$USE_UBUNTU, 'macos-latest', 'ubuntu-latest'] {
|
||||
if $os starts-with ubuntu {
|
||||
if $os in [$USE_UBUNTU, 'macos-latest'] {
|
||||
if $os == $USE_UBUNTU {
|
||||
sudo apt update
|
||||
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?'
|
||||
# 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
|
||||
}
|
||||
}
|
||||
@ -153,7 +153,7 @@ if ($ver | str trim | is-empty) {
|
||||
# Create a release archive and send it to output for the following steps
|
||||
# ----------------------------------------------------------------------------
|
||||
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 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
|
||||
target_rustflags: ''
|
||||
- target: riscv64gc-unknown-linux-gnu
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
|
||||
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
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@v1.17.0
|
||||
uses: crate-ci/typos@v1.16.24
|
||||
with:
|
||||
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"
|
||||
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]]
|
||||
name = "fancy-regex"
|
||||
version = "0.12.0"
|
||||
@ -1281,7 +1291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -1788,7 +1798,7 @@ dependencies = [
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core 0.51.1",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1802,9 +1812,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ical"
|
||||
version = "0.9.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26393c372d4c4d51616084afe36c0b44e4467febaa6f91f11f789094b4863bf9"
|
||||
checksum = "356d82bd58997815d55ea6f9081bd4cac149e50ca943f7a4f7c050fec7271c1f"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
@ -1884,6 +1894,17 @@ version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "is-docker"
|
||||
version = "0.2.0"
|
||||
@ -1900,7 +1921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -1953,15 +1974,6 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.10"
|
||||
@ -2222,6 +2234,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.12"
|
||||
@ -2255,9 +2273,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lscolors"
|
||||
version = "0.16.0"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab0b209ec3976527806024406fe765474b9a1750a0ed4b8f0372364741f50e7b"
|
||||
checksum = "bf7015a04103ad78abb77e4b79ed151e767922d1cfde5f62640471c629a2320d"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
]
|
||||
@ -2276,9 +2294,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lsp-types"
|
||||
version = "0.95.0"
|
||||
version = "0.94.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "158c1911354ef73e8fe42da6b10c0484cb65c7f1007f28022e847706c1ab6984"
|
||||
checksum = "c66bfd44a06ae10647fe3f8214762e9369fd4248df1350924b4ef9e770a85ea1"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"serde",
|
||||
@ -2659,7 +2677,7 @@ version = "0.88.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossterm",
|
||||
"fancy-regex",
|
||||
"fancy-regex 0.11.0",
|
||||
"fuzzy-matcher",
|
||||
"is_executable",
|
||||
"log",
|
||||
@ -2680,7 +2698,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"reedline",
|
||||
"rstest",
|
||||
"sysinfo 0.30.4",
|
||||
"sysinfo",
|
||||
"unicode-segmentation",
|
||||
"uuid",
|
||||
"which 5.0.0",
|
||||
@ -2708,7 +2726,7 @@ version = "0.88.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"fancy-regex",
|
||||
"fancy-regex 0.12.0",
|
||||
"indexmap",
|
||||
"nu-cmd-lang",
|
||||
"nu-engine",
|
||||
@ -2730,7 +2748,7 @@ name = "nu-cmd-extra"
|
||||
version = "0.88.2"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"fancy-regex",
|
||||
"fancy-regex 0.11.0",
|
||||
"heck",
|
||||
"htmlescape",
|
||||
"nu-ansi-term",
|
||||
@ -2754,8 +2772,8 @@ dependencies = [
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.88.2"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"itertools 0.12.0",
|
||||
"fancy-regex 0.11.0",
|
||||
"itertools 0.11.0",
|
||||
"nu-ansi-term",
|
||||
"nu-engine",
|
||||
"nu-parser",
|
||||
@ -2798,7 +2816,7 @@ dependencies = [
|
||||
"dirs-next",
|
||||
"dtparse",
|
||||
"encoding_rs",
|
||||
"fancy-regex",
|
||||
"fancy-regex 0.11.0",
|
||||
"filesize",
|
||||
"filetime",
|
||||
"fs_extra",
|
||||
@ -2806,7 +2824,7 @@ dependencies = [
|
||||
"human-date-parser",
|
||||
"indexmap",
|
||||
"indicatif",
|
||||
"itertools 0.12.0",
|
||||
"itertools 0.11.0",
|
||||
"libc",
|
||||
"log",
|
||||
"lscolors",
|
||||
@ -2859,7 +2877,7 @@ dependencies = [
|
||||
"serde_urlencoded",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"sysinfo 0.30.4",
|
||||
"sysinfo",
|
||||
"tabled",
|
||||
"terminal_size 0.3.0",
|
||||
"titlecase",
|
||||
@ -2876,7 +2894,7 @@ dependencies = [
|
||||
"uuid",
|
||||
"wax",
|
||||
"which 5.0.0",
|
||||
"windows 0.52.0",
|
||||
"windows 0.48.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
@ -2907,7 +2925,7 @@ dependencies = [
|
||||
"nu-utils",
|
||||
"ratatui",
|
||||
"strip-ansi-escapes",
|
||||
"terminal_size 0.3.0",
|
||||
"terminal_size 0.2.6",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
@ -2955,7 +2973,7 @@ version = "0.88.2"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"chrono",
|
||||
"itertools 0.12.0",
|
||||
"itertools 0.11.0",
|
||||
"log",
|
||||
"nu-engine",
|
||||
"nu-path",
|
||||
@ -3002,7 +3020,7 @@ dependencies = [
|
||||
"byte-unit",
|
||||
"chrono",
|
||||
"chrono-humanize",
|
||||
"fancy-regex",
|
||||
"fancy-regex 0.11.0",
|
||||
"indexmap",
|
||||
"lru",
|
||||
"miette",
|
||||
@ -3043,15 +3061,15 @@ dependencies = [
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"procfs",
|
||||
"sysinfo 0.30.4",
|
||||
"windows 0.52.0",
|
||||
"sysinfo",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-table"
|
||||
version = "0.88.2"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"fancy-regex 0.11.0",
|
||||
"nu-ansi-term",
|
||||
"nu-color-config",
|
||||
"nu-engine",
|
||||
@ -3396,9 +3414,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
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"
|
||||
checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085"
|
||||
checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
@ -4072,7 +4090,7 @@ dependencies = [
|
||||
"polars-error",
|
||||
"rayon",
|
||||
"smartstring",
|
||||
"sysinfo 0.29.11",
|
||||
"sysinfo",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@ -4177,7 +4195,7 @@ dependencies = [
|
||||
"hex",
|
||||
"lazy_static",
|
||||
"procfs-core",
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4374,13 +4392,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "reedline"
|
||||
version = "0.27.1"
|
||||
source = "git+https://github.com/nushell/reedline.git?branch=main#b68ce33c750b700bb4f8adccbc2e160d1b7c8742"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147452ce32c2cba4900b410f1d18b9ca29b67301a8eed76676e42e720d71cc39"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossterm",
|
||||
"fd-lock",
|
||||
"itertools 0.12.0",
|
||||
"itertools 0.10.5",
|
||||
"nu-ansi-term",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
@ -4627,6 +4646,20 @@ dependencies = [
|
||||
"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]]
|
||||
name = "rustix"
|
||||
version = "0.38.28"
|
||||
@ -4636,7 +4669,7 @@ dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.4.12",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
@ -4868,9 +4901,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "shadow-rs"
|
||||
version = "0.26.0"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "878cb1e3162d98ee1016b832efbb683ad6302b462a2894c54f488dc0bd96f11c"
|
||||
checksum = "f9198caff1c94f1a5df6664bddbc379896b51b98a55b0b3fedcb23078fe00c77"
|
||||
dependencies = [
|
||||
"const_format",
|
||||
"is_debug",
|
||||
@ -5243,20 +5276,6 @@ name = "sysinfo"
|
||||
version = "0.29.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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 = [
|
||||
"cfg-if",
|
||||
"core-foundation-sys",
|
||||
@ -5264,7 +5283,7 @@ dependencies = [
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"rayon",
|
||||
"windows 0.52.0",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5294,7 +5313,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -5328,13 +5347,23 @@ dependencies = [
|
||||
"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]]
|
||||
name = "terminal_size"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -5718,9 +5747,9 @@ checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.10"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
|
||||
checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
@ -6042,7 +6071,7 @@ dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6054,7 +6083,7 @@ dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"rustix 0.38.28",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@ -6109,12 +6138,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6126,15 +6154,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
@ -6369,8 +6388,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"rustix",
|
||||
"linux-raw-sys 0.4.12",
|
||||
"rustix 0.38.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -33,11 +33,7 @@ members = [
|
||||
"crates/nu-cmd-lang",
|
||||
"crates/nu-cmd-dataframe",
|
||||
"crates/nu-command",
|
||||
"crates/nu-color-config",
|
||||
"crates/nu-explore",
|
||||
"crates/nu-json",
|
||||
"crates/nu-lsp",
|
||||
"crates/nu-pretty-hex",
|
||||
"crates/nu-protocol",
|
||||
"crates/nu-plugin",
|
||||
"crates/nu_plugin_inc",
|
||||
@ -47,8 +43,6 @@ members = [
|
||||
"crates/nu_plugin_custom_values",
|
||||
"crates/nu_plugin_formats",
|
||||
"crates/nu-std",
|
||||
"crates/nu-table",
|
||||
"crates/nu-term-grid",
|
||||
"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-std = { path = "./crates/nu-std", version = "0.88.2" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.88.2" }
|
||||
|
||||
nu-ansi-term = "0.49.0"
|
||||
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
|
||||
# changing versions in each sub-crate of the workspace is tedious
|
||||
[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"}
|
||||
# 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 {
|
||||
nu_path::home_dir()
|
||||
.map(|path| canonicalize_path(engine_state, &path))
|
||||
.unwrap_or_default()
|
||||
let home_path = if let Some(path) = nu_path::home_dir() {
|
||||
let canon_home_path = canonicalize_path(engine_state, &path);
|
||||
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.
|
||||
|
@ -29,7 +29,7 @@ reedline = { version = "0.27.0", features = ["bashisms", "sqlite"] }
|
||||
|
||||
chrono = { default-features = false, features = ["std"], version = "0.4" }
|
||||
crossterm = "0.27"
|
||||
fancy-regex = "0.12"
|
||||
fancy-regex = "0.11"
|
||||
fuzzy-matcher = "0.3"
|
||||
is_executable = "1.0"
|
||||
log = "0.4"
|
||||
@ -37,7 +37,7 @@ miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
||||
once_cell = "1.18"
|
||||
percent-encoding = "2"
|
||||
pathdiff = "0.2"
|
||||
sysinfo = "0.30"
|
||||
sysinfo = "0.29"
|
||||
unicode-segmentation = "1.10"
|
||||
uuid = { version = "1.6.0", features = ["v4"] }
|
||||
which = "5.0.0"
|
||||
|
@ -250,9 +250,7 @@ impl NuCompleter {
|
||||
working_set.get_span_contents(previous_expr.0).to_vec();
|
||||
|
||||
// Completion for .nu files
|
||||
if prev_expr_str == b"use"
|
||||
|| prev_expr_str == b"overlay use"
|
||||
|| prev_expr_str == b"source-env"
|
||||
if prev_expr_str == b"use" || prev_expr_str == b"source-env"
|
||||
{
|
||||
let mut completer =
|
||||
DotNuCompletion::new(self.engine_state.clone());
|
||||
@ -354,9 +352,11 @@ impl NuCompleter {
|
||||
if let Some(external_result) = self.external_completion(
|
||||
block_id, &spans, offset, new_span,
|
||||
) {
|
||||
if !external_result.is_empty() {
|
||||
return external_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for file completion
|
||||
let mut completer =
|
||||
|
@ -22,10 +22,7 @@ fn complete_rec(
|
||||
Some(base) if matches(base, &entry_name, options) => {
|
||||
let partial = &partial[1..];
|
||||
if !partial.is_empty() || isdir {
|
||||
completions.extend(complete_rec(partial, &path, options, dir, isdir));
|
||||
if entry_name.eq(base) {
|
||||
break;
|
||||
}
|
||||
completions.extend(complete_rec(partial, &path, options, dir, isdir))
|
||||
} else {
|
||||
completions.push(path)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use nu_protocol::{
|
||||
};
|
||||
use reedline::Suggestion;
|
||||
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,
|
||||
};
|
||||
|
||||
@ -91,22 +91,17 @@ impl Completer for DotNuCompletion {
|
||||
// and transform them into suggestions
|
||||
let output: Vec<Suggestion> = search_dirs
|
||||
.into_iter()
|
||||
.flat_map(|search_dir| {
|
||||
let completions = file_path_completion(span, &partial, &search_dir, options);
|
||||
completions
|
||||
.flat_map(|it| {
|
||||
file_path_completion(span, &partial, &it, options)
|
||||
.into_iter()
|
||||
.filter(move |it| {
|
||||
.filter(|it| {
|
||||
// Different base dir, so we list the .nu files or folders
|
||||
if !is_current_folder {
|
||||
it.1.ends_with(".nu") || it.1.ends_with(SEP)
|
||||
} else {
|
||||
// Lib dirs, so we filter only the .nu files or directory modules
|
||||
if it.1.ends_with(SEP) {
|
||||
Path::new(&search_dir).join(&it.1).join("mod.nu").exists()
|
||||
} else {
|
||||
// Lib dirs, so we filter only the .nu files
|
||||
it.1.ends_with(".nu")
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(move |x| Suggestion {
|
||||
value: x.1,
|
||||
|
@ -35,10 +35,6 @@ pub fn evaluate_commands(
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
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() {
|
||||
report_error(&working_set, err);
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::prompt_update::{POST_PROMPT_MARKER, PRE_PROMPT_MARKER};
|
||||
#[cfg(windows)]
|
||||
use nu_utils::enable_vt_processing;
|
||||
use reedline::DefaultPrompt;
|
||||
@ -12,7 +11,6 @@ use {
|
||||
/// Nushell prompt definition
|
||||
#[derive(Clone)]
|
||||
pub struct NushellPrompt {
|
||||
shell_integration: bool,
|
||||
left_prompt_string: Option<String>,
|
||||
right_prompt_string: Option<String>,
|
||||
default_prompt_indicator: Option<String>,
|
||||
@ -22,10 +20,15 @@ pub struct NushellPrompt {
|
||||
render_right_prompt_on_last_line: bool,
|
||||
}
|
||||
|
||||
impl Default for NushellPrompt {
|
||||
fn default() -> Self {
|
||||
NushellPrompt::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl NushellPrompt {
|
||||
pub fn new(shell_integration: bool) -> NushellPrompt {
|
||||
pub fn new() -> NushellPrompt {
|
||||
NushellPrompt {
|
||||
shell_integration,
|
||||
left_prompt_string: None,
|
||||
right_prompt_string: None,
|
||||
default_prompt_indicator: None,
|
||||
@ -108,13 +111,9 @@ impl Prompt for NushellPrompt {
|
||||
.to_string()
|
||||
.replace('\n', "\r\n");
|
||||
|
||||
if self.shell_integration {
|
||||
format!("{PRE_PROMPT_MARKER}{prompt}{POST_PROMPT_MARKER}").into()
|
||||
} else {
|
||||
prompt.into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_prompt_right(&self) -> Cow<str> {
|
||||
if let Some(prompt_string) = &self.right_prompt_string {
|
||||
|
@ -7,6 +7,8 @@ use nu_protocol::{
|
||||
Config, PipelineData, Value,
|
||||
};
|
||||
use reedline::Prompt;
|
||||
use std::borrow::Cow;
|
||||
use std::sync::Arc;
|
||||
|
||||
// Name of environment variable where the prompt could be stored
|
||||
pub(crate) const PROMPT_COMMAND: &str = "PROMPT_COMMAND";
|
||||
@ -26,8 +28,8 @@ pub(crate) const TRANSIENT_PROMPT_MULTILINE_INDICATOR: &str =
|
||||
"TRANSIENT_PROMPT_MULTILINE_INDICATOR";
|
||||
// According to Daniel Imms @Tyriar, we need to do these this way:
|
||||
// <133 A><prompt><133 B><command><133 C><command output>
|
||||
pub(crate) const PRE_PROMPT_MARKER: &str = "\x1b]133;A\x1b\\";
|
||||
pub(crate) const POST_PROMPT_MARKER: &str = "\x1b]133;B\x1b\\";
|
||||
const PRE_PROMPT_MARKER: &str = "\x1b]133;A\x1b\\";
|
||||
const POST_PROMPT_MARKER: &str = "\x1b]133;B\x1b\\";
|
||||
|
||||
fn get_prompt_string(
|
||||
prompt: &str,
|
||||
@ -96,12 +98,12 @@ fn get_prompt_string(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn update_prompt(
|
||||
pub(crate) fn update_prompt<'prompt>(
|
||||
config: &Config,
|
||||
engine_state: &EngineState,
|
||||
stack: &Stack,
|
||||
nu_prompt: &mut NushellPrompt,
|
||||
) {
|
||||
nu_prompt: &'prompt mut NushellPrompt,
|
||||
) -> &'prompt dyn Prompt {
|
||||
let mut stack = stack.clone();
|
||||
|
||||
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),
|
||||
config.render_right_prompt_on_last_line,
|
||||
);
|
||||
|
||||
let ret_val = nu_prompt as &dyn Prompt;
|
||||
trace!("update_prompt {}:{}:{}", file!(), line!(), column!());
|
||||
|
||||
ret_val
|
||||
}
|
||||
|
||||
/// Construct the transient prompt based on the normal nu_prompt
|
||||
pub(crate) fn make_transient_prompt(
|
||||
struct TransientPrompt {
|
||||
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,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
nu_prompt: &NushellPrompt,
|
||||
) -> Box<dyn Prompt> {
|
||||
let mut nu_prompt = nu_prompt.clone();
|
||||
|
||||
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND, config, engine_state, stack) {
|
||||
nu_prompt.update_prompt_left(Some(s))
|
||||
) -> Option<String> {
|
||||
get_prompt_string(transient_prompt, config, engine_state, stack)
|
||||
.or_else(|| get_prompt_string(prompt, config, engine_state, stack))
|
||||
}
|
||||
|
||||
if let Some(s) = get_prompt_string(TRANSIENT_PROMPT_COMMAND_RIGHT, config, engine_state, stack)
|
||||
{
|
||||
nu_prompt.update_prompt_right(Some(s), config.render_right_prompt_on_last_line)
|
||||
impl Prompt for TransientPrompt {
|
||||
fn render_prompt_left(&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_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) {
|
||||
nu_prompt.update_prompt_indicator(Some(s))
|
||||
fn render_prompt_right(&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_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,
|
||||
PROMPT_INDICATOR_VI_INSERT,
|
||||
config,
|
||||
engine_state,
|
||||
stack,
|
||||
) {
|
||||
nu_prompt.update_prompt_vi_insert(Some(s))
|
||||
}
|
||||
if let Some(s) = get_prompt_string(
|
||||
&self.engine_state,
|
||||
&mut stack,
|
||||
));
|
||||
nu_prompt.update_prompt_vi_normal(get_transient_prompt_string(
|
||||
TRANSIENT_PROMPT_INDICATOR_VI_NORMAL,
|
||||
PROMPT_INDICATOR_VI_NORMAL,
|
||||
config,
|
||||
engine_state,
|
||||
stack,
|
||||
) {
|
||||
nu_prompt.update_prompt_vi_normal(Some(s))
|
||||
&self.engine_state,
|
||||
&mut stack,
|
||||
));
|
||||
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,
|
||||
PROMPT_MULTILINE_INDICATOR,
|
||||
config,
|
||||
engine_state,
|
||||
stack,
|
||||
) {
|
||||
nu_prompt.update_prompt_multiline(Some(s))
|
||||
&self.engine_state,
|
||||
&mut stack,
|
||||
));
|
||||
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,
|
||||
time::Instant,
|
||||
};
|
||||
use sysinfo::System;
|
||||
use sysinfo::SystemExt;
|
||||
|
||||
// According to Daniel Imms @Tyriar, we need to do these this way:
|
||||
// <133 A><prompt><133 B><command><133 C><command output>
|
||||
@ -54,8 +54,7 @@ pub fn evaluate_repl(
|
||||
) -> Result<()> {
|
||||
use nu_cmd_base::hook;
|
||||
use reedline::Signal;
|
||||
let config = engine_state.get_config();
|
||||
let use_color = config.use_ansi_coloring;
|
||||
let use_color = engine_state.get_config().use_ansi_coloring;
|
||||
|
||||
// Guard against invocation without a connected terminal.
|
||||
// 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 nu_prompt = NushellPrompt::new(config.shell_integration);
|
||||
let mut nu_prompt = NushellPrompt::new();
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
// Translate environment variables from Strings to Values
|
||||
@ -135,6 +134,17 @@ pub fn evaluate_repl(
|
||||
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 {
|
||||
eval_source(
|
||||
engine_state,
|
||||
@ -202,6 +212,20 @@ pub fn evaluate_repl(
|
||||
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();
|
||||
let config = engine_state.get_config();
|
||||
|
||||
@ -243,7 +267,11 @@ pub fn evaluate_repl(
|
||||
.with_quick_completions(config.quick_completions)
|
||||
.with_partial_completions(config.partial_completions)
|
||||
.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(
|
||||
"reedline builder",
|
||||
start_time,
|
||||
@ -396,9 +424,7 @@ pub fn evaluate_repl(
|
||||
|
||||
start_time = std::time::Instant::now();
|
||||
let config = &engine_state.get_config().clone();
|
||||
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);
|
||||
let prompt = prompt_update::update_prompt(config, engine_state, stack, &mut nu_prompt);
|
||||
perf(
|
||||
"update_prompt",
|
||||
start_time,
|
||||
@ -411,13 +437,12 @@ pub fn evaluate_repl(
|
||||
entry_num += 1;
|
||||
|
||||
start_time = std::time::Instant::now();
|
||||
line_editor = line_editor.with_transient_prompt(transient_prompt);
|
||||
let input = line_editor.read_line(&nu_prompt);
|
||||
let input = line_editor.read_line(prompt);
|
||||
let shell_integration = config.shell_integration;
|
||||
|
||||
match input {
|
||||
Ok(Signal::Success(s)) => {
|
||||
let hostname = System::host_name();
|
||||
let hostname = sys.host_name();
|
||||
let history_supports_meta =
|
||||
matches!(config.history_file_format, HistoryFileFormat::Sqlite);
|
||||
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
|
||||
.get_env_var(engine_state, "LAST_EXIT_CODE")
|
||||
.and_then(|e| e.as_i64().ok());
|
||||
|
@ -329,6 +329,7 @@ fn find_matching_block_end_in_expr(
|
||||
Expr::ImportPattern(_) => None,
|
||||
Expr::Overlay(_) => None,
|
||||
Expr::Signature(_) => None,
|
||||
Expr::MatchPattern(_) => None,
|
||||
Expr::MatchBlock(_) => None,
|
||||
Expr::Nothing => None,
|
||||
Expr::Garbage => None,
|
||||
@ -385,7 +386,6 @@ fn find_matching_block_end_in_expr(
|
||||
Argument::Named((_, _, opt_expr)) => opt_expr.as_ref(),
|
||||
Argument::Positional(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 {
|
||||
|
@ -220,10 +220,6 @@ pub fn eval_source(
|
||||
source,
|
||||
false,
|
||||
);
|
||||
if let Some(warning) = working_set.parse_warnings.first() {
|
||||
report_error(&working_set, warning);
|
||||
}
|
||||
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
set_last_exit_code(stack, 1);
|
||||
report_error(&working_set, err);
|
||||
|
@ -91,7 +91,7 @@ fn variables_dollar_sign_with_varialblecompletion() {
|
||||
let target_dir = "$ ";
|
||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||
|
||||
assert_eq!(8, suggestions.len());
|
||||
assert_eq!(7, suggestions.len());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
@ -144,34 +144,15 @@ fn dotnu_completions() {
|
||||
let completion_str = "source-env ".to_string();
|
||||
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);
|
||||
#[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
|
||||
let completion_str = "use ".to_string();
|
||||
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);
|
||||
#[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]
|
||||
@ -227,7 +208,6 @@ fn file_completions() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
folder(dir.join("another")),
|
||||
file(dir.join("custom_completion.nu")),
|
||||
folder(dir.join("directory_completion")),
|
||||
file(dir.join("nushell")),
|
||||
folder(dir.join("test_a")),
|
||||
folder(dir.join("test_b")),
|
||||
@ -343,7 +323,6 @@ fn command_ls_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -354,7 +333,6 @@ fn command_ls_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -377,7 +355,6 @@ fn command_open_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -388,7 +365,6 @@ fn command_open_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -412,7 +388,6 @@ fn command_rm_with_globcompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -423,7 +398,6 @@ fn command_rm_with_globcompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -447,7 +421,6 @@ fn command_cp_with_globcompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -458,7 +431,6 @@ fn command_cp_with_globcompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -482,7 +454,6 @@ fn command_save_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -493,7 +464,6 @@ fn command_save_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -517,7 +487,6 @@ fn command_touch_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -528,7 +497,6 @@ fn command_touch_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -552,7 +520,6 @@ fn command_watch_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -563,7 +530,6 @@ fn command_watch_with_filecompletion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -659,7 +625,6 @@ fn folder_with_directorycompletions() {
|
||||
// Create the expected values
|
||||
let expected_paths: Vec<String> = vec![
|
||||
folder(dir.join("another")),
|
||||
folder(dir.join("directory_completion")),
|
||||
folder(dir.join("test_a")),
|
||||
folder(dir.join("test_b")),
|
||||
folder(dir.join(".hidden_folder")),
|
||||
@ -874,7 +839,6 @@ fn unknown_command_completion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -885,7 +849,6 @@ fn unknown_command_completion() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
@ -936,7 +899,6 @@ fn filecompletions_triggers_after_cursor() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another\\".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion\\".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a\\".to_string(),
|
||||
"test_b\\".to_string(),
|
||||
@ -947,7 +909,6 @@ fn filecompletions_triggers_after_cursor() {
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"another/".to_string(),
|
||||
"custom_completion.nu".to_string(),
|
||||
"directory_completion/".to_string(),
|
||||
"nushell".to_string(),
|
||||
"test_a/".to_string(),
|
||||
"test_b/".to_string(),
|
||||
|
@ -26,9 +26,9 @@ num = { version = "0.4", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
sqlparser = { version = "0.39", optional = true }
|
||||
polars-io = { version = "0.35", features = ["avro"], optional = true }
|
||||
polars-arrow = { version = "0.35", optional = true }
|
||||
polars-ops = { version = "0.35", optional = true }
|
||||
polars-plan = { version = "0.35", optional = true }
|
||||
polars-arrow = "0.35"
|
||||
polars-ops = "0.35"
|
||||
polars-plan = "0.35"
|
||||
|
||||
[dependencies.polars]
|
||||
features = [
|
||||
@ -65,7 +65,7 @@ optional = true
|
||||
version = "0.35"
|
||||
|
||||
[features]
|
||||
dataframe = ["num", "polars", "polars-io", "polars-arrow", "polars-ops", "polars-plan", "sqlparser"]
|
||||
dataframe = ["num", "polars", "polars-io", "sqlparser"]
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -874,7 +874,7 @@ fn series_to_values(
|
||||
.iter()
|
||||
.map(|field| field.name.to_string())
|
||||
.collect();
|
||||
let record = Record::from_raw_cols_vals(cols, vals?);
|
||||
let record = Record { cols, vals: vals? };
|
||||
Ok(Value::record(record, span))
|
||||
})
|
||||
.collect();
|
||||
@ -982,7 +982,10 @@ fn any_value_to_value(any_value: &AnyValue, span: Span) -> Result<Value, ShellEr
|
||||
.map(|f| f.name().to_string())
|
||||
.collect();
|
||||
Ok(Value::Record {
|
||||
val: Record::from_raw_cols_vals(fields, values?),
|
||||
val: Record {
|
||||
cols: fields,
|
||||
vals: values?,
|
||||
},
|
||||
internal_span: span,
|
||||
})
|
||||
}
|
||||
@ -1056,7 +1059,6 @@ fn time_from_midnight(nanos: i64, span: Span) -> Result<Value, ShellError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use indexmap::indexmap;
|
||||
use nu_protocol::record;
|
||||
use polars::export::arrow::array::{BooleanArray, PrimitiveArray};
|
||||
use polars::prelude::Field;
|
||||
use polars_io::prelude::StructArray;
|
||||
@ -1247,10 +1249,13 @@ mod tests {
|
||||
Field::new(field_name_1, DataType::Boolean),
|
||||
];
|
||||
let test_owned_struct = AnyValue::StructOwned(Box::new((values, fields.clone())));
|
||||
let comparison_owned_record = Value::test_record(record!(
|
||||
field_name_0 => Value::int(1, span),
|
||||
field_name_1 => Value::bool(true, span),
|
||||
));
|
||||
let comparison_owned_record = Value::record(
|
||||
Record {
|
||||
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!(
|
||||
any_value_to_value(&test_owned_struct, span)?,
|
||||
comparison_owned_record.clone()
|
||||
|
@ -158,10 +158,7 @@ impl NuDataFrame {
|
||||
.map(|i| format!("{i}"))
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
conversion::insert_record(
|
||||
&mut column_values,
|
||||
Record::from_raw_cols_vals(cols, vals),
|
||||
)?
|
||||
conversion::insert_record(&mut column_values, Record { cols, vals })?
|
||||
}
|
||||
Value::Record { val: record, .. } => {
|
||||
conversion::insert_record(&mut column_values, record)?
|
||||
|
@ -24,7 +24,7 @@ heck = "0.4.1"
|
||||
num-traits = "0.2"
|
||||
ahash = "0.8.3"
|
||||
nu-ansi-term = "0.49.0"
|
||||
fancy-regex = "0.12.0"
|
||||
fancy-regex = "0.11.0"
|
||||
rust-embed = "8.0.0"
|
||||
serde = "1.0.164"
|
||||
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!(
|
||||
strings::format::FormatPattern,
|
||||
strings::format::Format,
|
||||
strings::encode_decode::EncodeHex,
|
||||
strings::encode_decode::DecodeHex,
|
||||
strings::str_::case::Str,
|
||||
|
@ -10,15 +10,15 @@ use nu_protocol::{
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FormatPattern;
|
||||
pub struct Format;
|
||||
|
||||
impl Command for FormatPattern {
|
||||
impl Command for Format {
|
||||
fn name(&self) -> &str {
|
||||
"format pattern"
|
||||
"format"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("format pattern")
|
||||
Signature::build("format")
|
||||
.input_output_types(vec![
|
||||
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
||||
(Type::Record(vec![]), Type::Any),
|
||||
@ -80,12 +80,12 @@ impl Command for FormatPattern {
|
||||
vec![
|
||||
Example {
|
||||
description: "Print filenames with their sizes",
|
||||
example: "ls | format pattern '{name}: {size}'",
|
||||
example: "ls | format '{name}: {size}'",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
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(
|
||||
vec![Value::test_string("v2"), Value::test_string("v4")],
|
||||
Span::test_data(),
|
||||
@ -318,8 +318,8 @@ fn format_record(
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_examples() {
|
||||
use super::FormatPattern;
|
||||
use super::Format;
|
||||
use crate::test_examples;
|
||||
test_examples(FormatPattern {})
|
||||
test_examples(Format {})
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
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-ansi-term = "0.49.0"
|
||||
|
||||
fancy-regex = "0.12"
|
||||
itertools = "0.12"
|
||||
shadow-rs = { version = "0.26", default-features = false }
|
||||
fancy-regex = "0.11"
|
||||
itertools = "0.11"
|
||||
shadow-rs = { version = "0.24", default-features = false }
|
||||
|
||||
[build-dependencies]
|
||||
shadow-rs = { version = "0.26", default-features = false }
|
||||
shadow-rs = { version = "0.24", default-features = false }
|
||||
|
||||
[features]
|
||||
mimalloc = []
|
||||
|
@ -290,6 +290,7 @@ fn describe_value(
|
||||
| Value::Date { .. }
|
||||
| Value::Range { .. }
|
||||
| Value::String { .. }
|
||||
| Value::MatchPattern { .. }
|
||||
| Value::Nothing { .. } => Value::record(
|
||||
record!(
|
||||
"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)?;
|
||||
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 {
|
||||
use super::*;
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_protocol::{record, Span, Value};
|
||||
use nu_protocol::{Span, Value};
|
||||
|
||||
#[test]
|
||||
fn test_color_string_to_nustyle_empty_string() {
|
||||
@ -120,10 +120,13 @@ mod tests {
|
||||
#[test]
|
||||
fn test_get_style_from_value() {
|
||||
// Test case 1: all values are valid
|
||||
let record = record! {
|
||||
"bg" => Value::test_string("red"),
|
||||
"fg" => Value::test_string("blue"),
|
||||
"attr" => Value::test_string("bold"),
|
||||
let record = Record {
|
||||
cols: vec!["bg".to_string(), "fg".to_string(), "attr".to_string()],
|
||||
vals: vec![
|
||||
Value::string("red", Span::unknown()),
|
||||
Value::string("blue", Span::unknown()),
|
||||
Value::string("bold", Span::unknown()),
|
||||
],
|
||||
};
|
||||
let expected_style = NuStyle {
|
||||
bg: Some("red".to_string()),
|
||||
@ -133,15 +136,19 @@ mod tests {
|
||||
assert_eq!(get_style_from_value(&record), Some(expected_style));
|
||||
|
||||
// Test case 2: no values are valid
|
||||
let record = record! {
|
||||
"invalid" => Value::nothing(Span::test_data()),
|
||||
let record = Record {
|
||||
cols: vec!["invalid".to_string()],
|
||||
vals: vec![Value::nothing(Span::unknown())],
|
||||
};
|
||||
assert_eq!(get_style_from_value(&record), None);
|
||||
|
||||
// Test case 3: some values are valid
|
||||
let record = record! {
|
||||
"bg" => Value::test_string("green"),
|
||||
"invalid" => Value::nothing(Span::unknown()),
|
||||
let record = Record {
|
||||
cols: vec!["bg".to_string(), "invalid".to_string()],
|
||||
vals: vec![
|
||||
Value::string("green", Span::unknown()),
|
||||
Value::nothing(Span::unknown()),
|
||||
],
|
||||
};
|
||||
let expected_style = NuStyle {
|
||||
bg: Some("green".to_string()),
|
||||
|
@ -131,7 +131,8 @@ impl<'a> StyleComputer<'a> {
|
||||
Value::Closure { .. }
|
||||
| Value::CustomValue { .. }
|
||||
| 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" }
|
||||
dtparse = "2.0"
|
||||
encoding_rs = "0.8"
|
||||
fancy-regex = "0.12"
|
||||
fancy-regex = "0.11"
|
||||
filesize = "0.2"
|
||||
filetime = "0.2"
|
||||
fs_extra = "1.3"
|
||||
@ -50,9 +50,9 @@ htmlescape = "0.3"
|
||||
human-date-parser = "0.1.1"
|
||||
indexmap = "2.1"
|
||||
indicatif = "0.17"
|
||||
itertools = "0.12"
|
||||
itertools = "0.11"
|
||||
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" }
|
||||
miette = { version = "5.10", features = ["fancy-no-backtrace"] }
|
||||
mime = "0.3"
|
||||
@ -80,7 +80,7 @@ serde_json = "1.0"
|
||||
serde_urlencoded = "0.7"
|
||||
serde_yaml = "0.9"
|
||||
sha2 = "0.10"
|
||||
sysinfo = "0.30"
|
||||
sysinfo = "0.29"
|
||||
tabled = { version = "0.14.0", features = ["color"], default-features = false }
|
||||
terminal_size = "0.3"
|
||||
titlecase = "2.0"
|
||||
@ -104,9 +104,9 @@ winreg = "0.52"
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
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"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
||||
@ -122,7 +122,7 @@ features = [
|
||||
"Win32_Security",
|
||||
"Win32_System_Threading",
|
||||
]
|
||||
version = "0.52"
|
||||
version = "0.48"
|
||||
|
||||
[features]
|
||||
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::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
@ -48,7 +48,8 @@ impl Command for BytesBuild {
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
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 {
|
||||
Value::Binary { mut val, .. } => output.append(&mut val),
|
||||
// Explicitly propagate errors instead of dropping them.
|
||||
|
@ -105,13 +105,6 @@ impl Command for BytesRemove {
|
||||
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 {
|
||||
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",
|
||||
@ -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
|
||||
// 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();
|
||||
result.append(&mut remain);
|
||||
}
|
||||
result = result.into_iter().rev().collect();
|
||||
Value::binary(result, span)
|
||||
} else {
|
||||
|
@ -258,16 +258,16 @@ fn histogram_impl(
|
||||
result.push((
|
||||
count, // attach count first for easily sorting.
|
||||
Value::record(
|
||||
Record::from_raw_cols_vals(
|
||||
result_cols.clone(),
|
||||
vec![
|
||||
Record {
|
||||
cols: result_cols.clone(),
|
||||
vals: vec![
|
||||
val.into_value(),
|
||||
Value::int(count, span),
|
||||
Value::float(quantile, span),
|
||||
Value::string(percentage, span),
|
||||
Value::string(freq, span),
|
||||
],
|
||||
),
|
||||
},
|
||||
span,
|
||||
),
|
||||
));
|
||||
|
@ -260,6 +260,7 @@ fn nu_value_to_string(value: Value, separator: &str) -> String {
|
||||
Value::Binary { val, .. } => format!("{val:?}"),
|
||||
Value::CellPath { val, .. } => val.to_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);
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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_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! {
|
||||
"arg_type" => Value::string(arg_type, 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::CellPath { val, .. } => val.to_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,
|
||||
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 = {
|
||||
#[cfg(target_family = "windows")]
|
||||
{
|
||||
@ -98,9 +98,8 @@ impl LazySystemInfoRecord {
|
||||
}
|
||||
"system" => {
|
||||
// only get information requested
|
||||
let system_opt = SystemOpt::from((system_option, || {
|
||||
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
|
||||
}));
|
||||
let system_opt =
|
||||
SystemOpt::from((system_option, || RefreshKind::new().with_memory()));
|
||||
|
||||
let system = system_opt.get_system();
|
||||
|
||||
@ -136,26 +135,14 @@ impl LazySystemInfoRecord {
|
||||
"virtual_memory" => Value::filesize(p.virtual_memory() as i64, self.span),
|
||||
"status" => Value::string(p.status().to_string(), self.span),
|
||||
"root" => {
|
||||
if let Some(path) = p.exe().and_then(|p| p.parent()) {
|
||||
Value::string(path.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)
|
||||
if let Some(filename) = p.exe().parent() {
|
||||
Value::string(filename.to_string_lossy().to_string(), self.span)
|
||||
} else {
|
||||
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),
|
||||
"name" => Value::string(p.name().to_string(), self.span),
|
||||
"environment" => {
|
||||
@ -193,9 +180,8 @@ impl LazySystemInfoRecord {
|
||||
} else {
|
||||
// If we can't get the process information, just return the system information
|
||||
// only get information requested
|
||||
let system_opt = SystemOpt::from((system_option, || {
|
||||
RefreshKind::new().with_memory(MemoryRefreshKind::everything())
|
||||
}));
|
||||
let system_opt =
|
||||
SystemOpt::from((system_option, || RefreshKind::new().with_memory()));
|
||||
let system = system_opt.get_system();
|
||||
|
||||
Ok(Value::record(
|
||||
@ -242,7 +228,7 @@ impl<'a> LazyRecord<'a> for LazySystemInfoRecord {
|
||||
.without_disk_usage()
|
||||
.without_user(),
|
||||
)
|
||||
.with_memory(MemoryRefreshKind::everything());
|
||||
.with_memory();
|
||||
// only get information requested
|
||||
let system = System::new_with_specifics(rk);
|
||||
|
||||
|
@ -86,12 +86,6 @@ impl Command for Metadata {
|
||||
PipelineMetadata {
|
||||
data_source: DataSource::HtmlThemes,
|
||||
} => 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 {
|
||||
data_source: DataSource::HtmlThemes,
|
||||
} => 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,
|
||||
StrTrim,
|
||||
StrUpcase,
|
||||
Format,
|
||||
FormatDate,
|
||||
FormatDuration,
|
||||
FormatFilesize,
|
||||
@ -233,9 +232,6 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
||||
Whoami,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
bind_command! { ULimit };
|
||||
|
||||
// Date
|
||||
bind_command! {
|
||||
Date,
|
||||
|
@ -66,17 +66,16 @@ fn is_root_impl() -> bool {
|
||||
System::Threading::{GetCurrentProcess, OpenProcessToken},
|
||||
};
|
||||
|
||||
let mut handle = HANDLE::default();
|
||||
let mut elevated = false;
|
||||
|
||||
// Checks whether the access token associated with the current process has elevated privileges.
|
||||
// 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`.
|
||||
unsafe {
|
||||
let mut handle = HANDLE::default();
|
||||
|
||||
// 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 size = std::mem::size_of::<TOKEN_ELEVATION>() as u32;
|
||||
|
||||
@ -90,7 +89,7 @@ fn is_root_impl() -> bool {
|
||||
size,
|
||||
&mut size,
|
||||
)
|
||||
.is_ok()
|
||||
.as_bool()
|
||||
{
|
||||
// Whether the token has elevated privileges.
|
||||
// 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() {
|
||||
// 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"))]
|
||||
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"))))]
|
||||
#[cfg(unix)]
|
||||
fn any_group(current_user_gid: gid_t, owner_group: u32) -> bool {
|
||||
use crate::filesystem::util::users;
|
||||
|
||||
|
@ -1,11 +1,10 @@
|
||||
use nu_engine::{current_dir, eval_block, CallExt};
|
||||
use nu_path::expand_to_real_path;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::util::BufferedReader;
|
||||
use nu_protocol::{
|
||||
Category, DataSource, Example, IntoInterruptiblePipelineData, PipelineData, PipelineMetadata,
|
||||
RawStream, ShellError, Signature, Spanned, SyntaxShape, Type, Value,
|
||||
Category, Example, IntoInterruptiblePipelineData, PipelineData, RawStream, ShellError,
|
||||
Signature, Spanned, SyntaxShape, Type, Value,
|
||||
};
|
||||
use std::io::BufReader;
|
||||
|
||||
@ -158,7 +157,6 @@ impl Command for Open {
|
||||
};
|
||||
|
||||
let buf_reader = BufReader::new(file);
|
||||
let real_path = expand_to_real_path(path);
|
||||
|
||||
let file_contents = PipelineData::ExternalStream {
|
||||
stdout: Some(RawStream::new(
|
||||
@ -170,9 +168,7 @@ impl Command for Open {
|
||||
stderr: None,
|
||||
exit_code: None,
|
||||
span: call_span,
|
||||
metadata: Some(PipelineMetadata {
|
||||
data_source: DataSource::FilePath(real_path),
|
||||
}),
|
||||
metadata: None,
|
||||
trim_end_newline: false,
|
||||
};
|
||||
let exts_opt: Option<Vec<String>> = if raw {
|
||||
|
@ -381,23 +381,11 @@ fn rm(
|
||||
{
|
||||
unreachable!()
|
||||
}
|
||||
} else if metadata.is_symlink() {
|
||||
// In Windows, symlink pointing to a directory can be removed using
|
||||
// std::fs::remove_dir instead of std::fs::remove_file.
|
||||
#[cfg(windows)]
|
||||
} else if metadata.is_file()
|
||||
|| is_socket
|
||||
|| is_fifo
|
||||
|| 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)
|
||||
} else {
|
||||
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::engine::{Command, EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
Category, DataSource, Example, PipelineData, PipelineMetadata, RawStream, ShellError,
|
||||
Signature, Span, Spanned, SyntaxShape, Type, Value,
|
||||
Category, Example, PipelineData, RawStream, ShellError, Signature, Span, Spanned, SyntaxShape,
|
||||
Type, Value,
|
||||
};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
@ -149,42 +149,9 @@ impl Command for Save {
|
||||
res
|
||||
}
|
||||
}
|
||||
PipelineData::ListStream(ls, pipeline_metadata)
|
||||
PipelineData::ListStream(ls, _)
|
||||
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(
|
||||
&path,
|
||||
stderr_path.as_ref(),
|
||||
@ -373,7 +340,10 @@ fn prepare_path(
|
||||
|
||||
fn open_file(path: &Path, span: Span, append: bool) -> Result<File, ShellError> {
|
||||
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),
|
||||
};
|
||||
|
||||
|
@ -165,8 +165,9 @@ pub fn is_older(src: &Path, dst: &Path) -> Option<bool> {
|
||||
|
||||
#[cfg(unix)]
|
||||
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 std::ffi::CString;
|
||||
|
||||
pub fn get_user_by_uid(uid: uid_t) -> Option<User> {
|
||||
User::from_uid(Uid::from_raw(uid)).ok().flatten()
|
||||
@ -184,7 +185,6 @@ pub mod users {
|
||||
Gid::current().as_raw()
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
pub fn get_current_username() -> Option<String> {
|
||||
User::from_uid(Uid::current())
|
||||
.ok()
|
||||
@ -192,30 +192,6 @@ pub mod users {
|
||||
.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.
|
||||
///
|
||||
/// # libc functions used
|
||||
@ -231,9 +207,7 @@ pub mod users {
|
||||
/// 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>> {
|
||||
use std::ffi::CString;
|
||||
// MacOS uses i32 instead of gid_t in getgrouplist for unknown reasons
|
||||
#[cfg(target_os = "macos")]
|
||||
let mut buff: Vec<i32> = vec![0; 1024];
|
||||
@ -244,7 +218,7 @@ pub mod users {
|
||||
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
|
||||
// SAFETY:
|
||||
|
@ -516,6 +516,7 @@ fn value_should_be_printed(
|
||||
Err(_) => false,
|
||||
},
|
||||
Value::Binary { .. } => false,
|
||||
Value::MatchPattern { .. } => false,
|
||||
});
|
||||
if invert {
|
||||
match_found = !match_found;
|
||||
|
@ -174,7 +174,7 @@ pub fn group_by(
|
||||
Value::CellPath { val, .. } => group_cell_path(val, values)?,
|
||||
Value::Block { .. } | Value::Closure { .. } => {
|
||||
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)
|
||||
}
|
||||
|
||||
// TODO: refactor this, it's a bit of a mess
|
||||
fn group_closure(
|
||||
values: Vec<Value>,
|
||||
values: &[Value],
|
||||
span: Span,
|
||||
block: Option<Closure>,
|
||||
stack: &mut Stack,
|
||||
@ -240,13 +241,13 @@ fn group_closure(
|
||||
call: &Call,
|
||||
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||
let error_key = "error";
|
||||
let mut groups: IndexMap<String, Vec<Value>> = IndexMap::new();
|
||||
|
||||
if let Some(capture_block) = &block {
|
||||
let block = engine_state.get_block(capture_block.block_id);
|
||||
let mut keys: Vec<Result<String, ShellError>> = vec![];
|
||||
let value_list = Value::list(values.to_vec(), span);
|
||||
|
||||
for value in values {
|
||||
if let Some(capture_block) = &block {
|
||||
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(
|
||||
engine_state,
|
||||
&mut stack,
|
||||
@ -256,16 +257,11 @@ fn group_closure(
|
||||
call.redirect_stderr,
|
||||
);
|
||||
|
||||
let group_key = match pipeline {
|
||||
match pipeline {
|
||||
Ok(s) => {
|
||||
let mut s = s.into_iter();
|
||||
let collection: Vec<Value> = s.into_iter().collect();
|
||||
|
||||
let key = match s.next() {
|
||||
Some(Value::Error { .. }) | None => error_key.into(),
|
||||
Some(return_value) => return_value.as_string()?,
|
||||
};
|
||||
|
||||
if s.next().is_some() {
|
||||
if collection.len() > 1 {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "expected one value from the block".into(),
|
||||
msg: "requires a table with one value for grouping".into(),
|
||||
@ -275,13 +271,38 @@ fn group_closure(
|
||||
});
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
Err(_) => error_key.into(),
|
||||
let value = match collection.first() {
|
||||
Some(Value::Error { .. }) | None => Value::string(error_key, span),
|
||||
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)
|
||||
|
@ -55,7 +55,10 @@ fn from_delimited_string_to_value(
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
rows.push(Value::record(
|
||||
Record::from_raw_cols_vals(headers.clone(), output_row),
|
||||
Record {
|
||||
cols: headers.clone(),
|
||||
vals: output_row,
|
||||
},
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
@ -242,6 +242,12 @@ fn convert_to_value(
|
||||
msg: "extra tokens in input file".into(),
|
||||
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::ImportPattern(..) => Err(ShellError::OutsideSpannedLabeledError {
|
||||
src: original_text.to_string(),
|
||||
@ -403,7 +409,13 @@ fn convert_to_value(
|
||||
}
|
||||
|
||||
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 {
|
||||
src: original_text.to_string(),
|
||||
error: "Error when loading".into(),
|
||||
@ -411,13 +423,12 @@ fn convert_to_value(
|
||||
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(
|
||||
Record::from_raw_cols_vals(cols.clone(), vals),
|
||||
Record {
|
||||
cols: cols.clone(),
|
||||
vals,
|
||||
},
|
||||
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::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, .. } => {
|
||||
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::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::CellPath { val, .. } => val.to_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>>()?,
|
||||
),
|
||||
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 {
|
||||
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:
|
||||
1. Tag entry: `{tag: <tag name> attributes: {<attr name>: "<string value>" ...} content: [<entries>]}`
|
||||
2. Comment entry: `{tag: '!' attributes: null content: "<comment string>"}`
|
||||
3. Processing instruction (PI): `{tag: '?<pi name>' attributes: null content: "<pi content string>"}`
|
||||
4. Text: `{tag: null attributes: null content: "<text>"}`. Or as plain `<text>` instead of record.
|
||||
1. Tag entry: `{tag: <tag name> attrs: {<attr name>: "<string value>" ...} content: [<entries>]}`
|
||||
2. Comment entry: `{tag: '!' attrs: null content: "<comment string>"}`
|
||||
3. Processing instruction (PI): `{tag: '?<pi name>' attrs: null content: "<pi content string>"}`
|
||||
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."#
|
||||
}
|
||||
@ -46,7 +46,7 @@ Additionally any field which is: empty record, empty list or null, can be omitte
|
||||
vec![
|
||||
Example {
|
||||
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(
|
||||
"<note><remember>Event</remember></note>",
|
||||
)),
|
||||
@ -110,17 +110,6 @@ fn to_xml_entry<W: Write>(
|
||||
}
|
||||
|
||||
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
|
||||
// user can write a tag like {tag: a content: [...]} instead
|
||||
// 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(
|
||||
entry_span, tag_name, tag_span, attrs, children, top_level, writer,
|
||||
),
|
||||
_ => Err(ShellError::CantConvert {
|
||||
to_type: "XML".into(),
|
||||
from_type: "record".into(),
|
||||
span: entry_span,
|
||||
help: Some("Tag missing or is not a string".into()),
|
||||
}),
|
||||
_ => Ok(()),
|
||||
}
|
||||
} else {
|
||||
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.
|
||||
fn to_tag_like<W: Write>(
|
||||
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>>()?,
|
||||
),
|
||||
Value::CustomValue { .. } => serde_yaml::Value::Null,
|
||||
Value::MatchPattern { .. } => serde_yaml::Value::Null,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,6 @@ mod random;
|
||||
mod removed;
|
||||
mod shells;
|
||||
mod sort_utils;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod stor;
|
||||
mod strings;
|
||||
mod system;
|
||||
|
@ -5,8 +5,7 @@ use base64::{alphabet, Engine};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{EngineState, Stack};
|
||||
use nu_protocol::{
|
||||
record, BufferedReader, IntoPipelineData, PipelineData, RawStream, ShellError, Span, Spanned,
|
||||
Value,
|
||||
record, BufferedReader, IntoPipelineData, PipelineData, RawStream, ShellError, Span, Value,
|
||||
};
|
||||
use ureq::{Error, ErrorKind, Request, Response};
|
||||
|
||||
@ -27,45 +26,29 @@ pub enum BodyType {
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum RedirectMode {
|
||||
Follow,
|
||||
Error,
|
||||
Manual,
|
||||
}
|
||||
|
||||
// Only panics if the user agent is invalid but we define it statically so either
|
||||
// it always or never fails
|
||||
pub fn http_client(
|
||||
allow_insecure: bool,
|
||||
redirect_mode: RedirectMode,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
) -> Result<ureq::Agent, ShellError> {
|
||||
) -> ureq::Agent {
|
||||
let tls = native_tls::TlsConnector::builder()
|
||||
.danger_accept_invalid_certs(allow_insecure)
|
||||
.build()
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: format!("Failed to build network tls: {}", e),
|
||||
msg: String::new(),
|
||||
span: None,
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
.expect("Failed to build network tls");
|
||||
|
||||
let mut agent_builder = ureq::builder()
|
||||
.user_agent("nushell")
|
||||
.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 Ok(proxy) = ureq::Proxy::new(http_proxy) {
|
||||
agent_builder = agent_builder.proxy(proxy);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(agent_builder.build())
|
||||
agent_builder.build()
|
||||
}
|
||||
|
||||
pub fn http_parse_url(
|
||||
@ -85,18 +68,6 @@ pub fn http_parse_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(
|
||||
response: Response,
|
||||
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(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
|
@ -2,13 +2,12 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
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::{
|
||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
||||
request_set_timeout, send_request,
|
||||
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||
request_handle_response, request_set_timeout, send_request,
|
||||
};
|
||||
|
||||
use super::client::RequestFlags;
|
||||
@ -80,11 +79,6 @@ impl Command for SubCommand {
|
||||
"allow-errors",
|
||||
"do not fail if the server returns an error code",
|
||||
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()
|
||||
.category(Category::Network)
|
||||
@ -156,7 +150,6 @@ struct Arguments {
|
||||
timeout: Option<Value>,
|
||||
full: bool,
|
||||
allow_errors: bool,
|
||||
redirect: Option<Spanned<String>>,
|
||||
}
|
||||
|
||||
fn run_delete(
|
||||
@ -177,7 +170,6 @@ fn run_delete(
|
||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||
full: call.has_flag("full"),
|
||||
allow_errors: call.has_flag("allow-errors"),
|
||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
||||
};
|
||||
|
||||
helper(engine_state, stack, call, args)
|
||||
@ -194,9 +186,8 @@ fn helper(
|
||||
let span = args.url.span();
|
||||
let ctrl_c = engine_state.ctrlc.clone();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
@ -211,7 +202,6 @@ fn helper(
|
||||
allow_errors: args.allow_errors,
|
||||
};
|
||||
|
||||
check_response_redirection(redirect_mode, span, &response)?;
|
||||
request_handle_response(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -2,15 +2,16 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
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::{
|
||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
||||
request_set_timeout, send_request, RequestFlags,
|
||||
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||
request_handle_response, request_set_timeout, send_request,
|
||||
};
|
||||
|
||||
use super::client::RequestFlags;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
||||
@ -72,12 +73,6 @@ impl Command for SubCommand {
|
||||
"do not fail if the server returns an error code",
|
||||
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()
|
||||
.category(Category::Network)
|
||||
}
|
||||
@ -142,7 +137,6 @@ struct Arguments {
|
||||
timeout: Option<Value>,
|
||||
full: bool,
|
||||
allow_errors: bool,
|
||||
redirect: Option<Spanned<String>>,
|
||||
}
|
||||
|
||||
fn run_get(
|
||||
@ -161,7 +155,6 @@ fn run_get(
|
||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||
full: call.has_flag("full"),
|
||||
allow_errors: call.has_flag("allow-errors"),
|
||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
||||
};
|
||||
helper(engine_state, stack, call, args)
|
||||
}
|
||||
@ -177,9 +170,8 @@ fn helper(
|
||||
let span = args.url.span();
|
||||
let ctrl_c = engine_state.ctrlc.clone();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
@ -194,7 +186,6 @@ fn helper(
|
||||
allow_errors: args.allow_errors,
|
||||
};
|
||||
|
||||
check_response_redirection(redirect_mode, span, &response)?;
|
||||
request_handle_response(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -5,13 +5,12 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
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::{
|
||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
||||
request_add_authorization_header, request_add_custom_headers, request_handle_response_headers,
|
||||
request_set_timeout, send_request,
|
||||
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||
request_handle_response_headers, request_set_timeout, send_request,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -59,11 +58,6 @@ impl Command for SubCommand {
|
||||
"insecure",
|
||||
"allow insecure server connections when using SSL",
|
||||
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()
|
||||
.category(Category::Network)
|
||||
@ -120,7 +114,6 @@ struct Arguments {
|
||||
user: Option<String>,
|
||||
password: Option<String>,
|
||||
timeout: Option<Value>,
|
||||
redirect: Option<Spanned<String>>,
|
||||
}
|
||||
|
||||
fn run_head(
|
||||
@ -136,7 +129,6 @@ fn run_head(
|
||||
user: call.get_flag(engine_state, stack, "user")?,
|
||||
password: call.get_flag(engine_state, stack, "password")?,
|
||||
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();
|
||||
|
||||
@ -154,9 +146,8 @@ fn helper(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = args.url.span();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
@ -164,7 +155,6 @@ fn helper(
|
||||
request = request_add_custom_headers(args.headers, request)?;
|
||||
|
||||
let response = send_request(request, None, None, ctrlc);
|
||||
check_response_redirection(redirect_mode, 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,
|
||||
};
|
||||
|
||||
use super::client::{RedirectMode, RequestFlags};
|
||||
use super::client::RequestFlags;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
@ -160,7 +160,7 @@ fn helper(
|
||||
let ctrl_c = engine_state.ctrlc.clone();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
|
@ -2,13 +2,12 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
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::{
|
||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
||||
request_set_timeout, send_request,
|
||||
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||
request_handle_response, request_set_timeout, send_request,
|
||||
};
|
||||
|
||||
use super::client::RequestFlags;
|
||||
@ -76,11 +75,6 @@ impl Command for SubCommand {
|
||||
"allow-errors",
|
||||
"do not fail if the server returns an error code",
|
||||
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()
|
||||
.category(Category::Network)
|
||||
@ -148,7 +142,6 @@ struct Arguments {
|
||||
timeout: Option<Value>,
|
||||
full: bool,
|
||||
allow_errors: bool,
|
||||
redirect: Option<Spanned<String>>,
|
||||
}
|
||||
|
||||
fn run_patch(
|
||||
@ -169,7 +162,6 @@ fn run_patch(
|
||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||
full: call.has_flag("full"),
|
||||
allow_errors: call.has_flag("allow-errors"),
|
||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
||||
};
|
||||
|
||||
helper(engine_state, stack, call, args)
|
||||
@ -186,9 +178,8 @@ fn helper(
|
||||
let span = args.url.span();
|
||||
let ctrl_c = engine_state.ctrlc.clone();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
@ -203,7 +194,6 @@ fn helper(
|
||||
allow_errors: args.allow_errors,
|
||||
};
|
||||
|
||||
check_response_redirection(redirect_mode, span, &response)?;
|
||||
request_handle_response(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -2,13 +2,12 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
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::{
|
||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
||||
request_set_timeout, send_request,
|
||||
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||
request_handle_response, request_set_timeout, send_request,
|
||||
};
|
||||
|
||||
use super::client::RequestFlags;
|
||||
@ -76,11 +75,6 @@ impl Command for SubCommand {
|
||||
"allow-errors",
|
||||
"do not fail if the server returns an error code",
|
||||
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()
|
||||
.category(Category::Network)
|
||||
@ -146,7 +140,6 @@ struct Arguments {
|
||||
timeout: Option<Value>,
|
||||
full: bool,
|
||||
allow_errors: bool,
|
||||
redirect: Option<Spanned<String>>,
|
||||
}
|
||||
|
||||
fn run_post(
|
||||
@ -167,7 +160,6 @@ fn run_post(
|
||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||
full: call.has_flag("full"),
|
||||
allow_errors: call.has_flag("allow-errors"),
|
||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
||||
};
|
||||
|
||||
helper(engine_state, stack, call, args)
|
||||
@ -184,9 +176,8 @@ fn helper(
|
||||
let span = args.url.span();
|
||||
let ctrl_c = engine_state.ctrlc.clone();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
@ -201,7 +192,6 @@ fn helper(
|
||||
allow_errors: args.allow_errors,
|
||||
};
|
||||
|
||||
check_response_redirection(redirect_mode, span, &response)?;
|
||||
request_handle_response(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -2,13 +2,12 @@ use nu_engine::CallExt;
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||
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::{
|
||||
check_response_redirection, http_client, http_parse_redirect_mode, http_parse_url,
|
||||
request_add_authorization_header, request_add_custom_headers, request_handle_response,
|
||||
request_set_timeout, send_request,
|
||||
http_client, http_parse_url, request_add_authorization_header, request_add_custom_headers,
|
||||
request_handle_response, request_set_timeout, send_request,
|
||||
};
|
||||
|
||||
use super::client::RequestFlags;
|
||||
@ -76,11 +75,6 @@ impl Command for SubCommand {
|
||||
"allow-errors",
|
||||
"do not fail if the server returns an error code",
|
||||
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()
|
||||
.category(Category::Network)
|
||||
@ -146,7 +140,6 @@ struct Arguments {
|
||||
timeout: Option<Value>,
|
||||
full: bool,
|
||||
allow_errors: bool,
|
||||
redirect: Option<Spanned<String>>,
|
||||
}
|
||||
|
||||
fn run_put(
|
||||
@ -167,7 +160,6 @@ fn run_put(
|
||||
timeout: call.get_flag(engine_state, stack, "max-time")?,
|
||||
full: call.has_flag("full"),
|
||||
allow_errors: call.has_flag("allow-errors"),
|
||||
redirect: call.get_flag(engine_state, stack, "redirect-mode")?,
|
||||
};
|
||||
|
||||
helper(engine_state, stack, call, args)
|
||||
@ -184,9 +176,8 @@ fn helper(
|
||||
let span = args.url.span();
|
||||
let ctrl_c = engine_state.ctrlc.clone();
|
||||
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);
|
||||
|
||||
request = request_set_timeout(args.timeout, request)?;
|
||||
@ -201,7 +192,6 @@ fn helper(
|
||||
allow_errors: args.allow_errors,
|
||||
};
|
||||
|
||||
check_response_redirection(redirect_mode, span, &response)?;
|
||||
request_handle_response(
|
||||
engine_state,
|
||||
stack,
|
||||
|
@ -7,8 +7,6 @@ mod is_terminal;
|
||||
mod kill;
|
||||
mod sleep;
|
||||
mod term_size;
|
||||
#[cfg(unix)]
|
||||
mod ulimit;
|
||||
mod whoami;
|
||||
|
||||
pub use ansi::{Ansi, AnsiLink, AnsiStrip};
|
||||
@ -22,6 +20,4 @@ pub use is_terminal::IsTerminal;
|
||||
pub use kill::Kill;
|
||||
pub use sleep::Sleep;
|
||||
pub use term_size::TermSize;
|
||||
#[cfg(unix)]
|
||||
pub use ulimit::ULimit;
|
||||
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;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod delete;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod export;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod import;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod insert;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod open;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod reset;
|
||||
mod stor_;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod update;
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use create::StorCreate;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use delete::StorDelete;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use export::StorExport;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use import::StorImport;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use insert::StorInsert;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use open::StorOpen;
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub use reset::StorReset;
|
||||
pub use stor_::Stor;
|
||||
#[cfg(feature = "sqlite")]
|
||||
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))) {
|
||||
return Value::record(
|
||||
Record::from_raw_cols_vals(cols, vals),
|
||||
name_span,
|
||||
);
|
||||
return Value::record(Record { cols, vals }, name_span);
|
||||
}
|
||||
|
||||
(l_idx.max(0) as usize, (r_idx as usize + 1).min(cols.len()))
|
||||
@ -213,7 +210,7 @@ fn detect_columns(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Value::record(Record::from_raw_cols_vals(cols, vals), name_span);
|
||||
return Value::record(Record { cols, vals }, name_span);
|
||||
};
|
||||
|
||||
// Merge Columns
|
||||
@ -235,7 +232,7 @@ fn detect_columns(
|
||||
vals.push(binding);
|
||||
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))
|
||||
} 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 duration;
|
||||
mod filesize;
|
||||
mod format_;
|
||||
|
||||
pub use self::filesize::FormatFilesize;
|
||||
pub use date::FormatDate;
|
||||
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")),
|
||||
},
|
||||
Example {
|
||||
description: "Trim a specific character (not the whitespace)",
|
||||
example: "'=== Nu shell ===' | str trim --char '='",
|
||||
description: "Trim a specific character",
|
||||
example: "'=== Nu shell ===' | str trim --char '=' | str trim",
|
||||
result: Some(Value::test_string("Nu shell")),
|
||||
},
|
||||
Example {
|
||||
@ -142,13 +142,18 @@ impl Command for SubCommand {
|
||||
example: "' Nu shell ' | str trim --left",
|
||||
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 {
|
||||
description: "Trim whitespace from the end of string",
|
||||
example: "' Nu shell ' | str trim --right",
|
||||
result: Some(Value::test_string(" Nu shell")),
|
||||
},
|
||||
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 '='",
|
||||
result: Some(Value::test_string("=== Nu shell ")),
|
||||
},
|
||||
|
@ -101,8 +101,6 @@ impl Command for Complete {
|
||||
|
||||
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 {
|
||||
error: "Complete only works with 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 = "windows"),
|
||||
not(target_os = "android"),
|
||||
not(target_os = "ios")
|
||||
))]
|
||||
use nu_protocol::Span;
|
||||
use nu_protocol::{
|
||||
@ -18,6 +19,7 @@ use nu_protocol::{
|
||||
not(target_os = "macos"),
|
||||
not(target_os = "windows"),
|
||||
not(target_os = "android"),
|
||||
not(target_os = "ios")
|
||||
))]
|
||||
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 = "windows"),
|
||||
not(target_os = "android"),
|
||||
not(target_os = "ios")
|
||||
))]
|
||||
{
|
||||
let proc_stat = proc
|
||||
|
@ -1,9 +1,8 @@
|
||||
use nu_cmd_base::hook::eval_hook;
|
||||
use nu_engine::env_to_strings;
|
||||
use nu_engine::eval_expression;
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, Expr},
|
||||
ast::{Call, Expr, Expression},
|
||||
did_you_mean,
|
||||
engine::{Command, EngineState, Stack},
|
||||
Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, Span, Spanned,
|
||||
@ -114,6 +113,7 @@ pub fn create_external_command(
|
||||
trim_end_newline: bool,
|
||||
) -> Result<ExternalCommand, ShellError> {
|
||||
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
|
||||
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 args_expr: Vec<Expression> = call.positional_iter().skip(1).cloned().collect();
|
||||
let mut arg_keep_raw = vec![];
|
||||
for (arg, spread) in call.rest_iter(1) {
|
||||
// TODO: Disallow automatic spreading entirely later. This match block will
|
||||
// have to be refactored, and lists will have to be disallowed in the parser too
|
||||
match eval_expression(engine_state, stack, arg)? {
|
||||
for (one_arg, one_arg_expr) in args.into_iter().zip(args_expr) {
|
||||
match one_arg {
|
||||
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.
|
||||
// Example: one_arg may be something like ["ls" "-a"]
|
||||
// convert it to "ls" "-a"
|
||||
@ -160,20 +147,15 @@ pub fn create_external_command(
|
||||
}
|
||||
}
|
||||
val => {
|
||||
if spread {
|
||||
return Err(ShellError::CannotSpreadAsList { span: arg.span });
|
||||
} else {
|
||||
spanned_args.push(value_as_spanned(val)?);
|
||||
match arg.expr {
|
||||
match one_arg_expr.expr {
|
||||
// refer to `parse_dollar_expr` function
|
||||
// the expression type of $variable_name, $"($variable_name)"
|
||||
// will be Expr::StringInterpolation, Expr::FullCellPath
|
||||
Expr::StringInterpolation(_) | Expr::FullCellPath(_) => {
|
||||
arg_keep_raw.push(true)
|
||||
}
|
||||
Expr::StringInterpolation(_) | Expr::FullCellPath(_) => arg_keep_raw.push(true),
|
||||
_ => arg_keep_raw.push(false),
|
||||
}
|
||||
}
|
||||
{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use nu_protocol::{
|
||||
};
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
use sysinfo::{
|
||||
Components, CpuRefreshKind, Disks, Networks, System, Users, MINIMUM_CPU_UPDATE_INTERVAL,
|
||||
ComponentExt, CpuExt, CpuRefreshKind, DiskExt, NetworkExt, System, SystemExt, UserExt,
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -106,12 +106,14 @@ pub fn trim_cstyle_null(s: String) -> String {
|
||||
}
|
||||
|
||||
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![];
|
||||
for disk in disks.list() {
|
||||
for disk in sys.disks() {
|
||||
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! {
|
||||
"device" => Value::string(device, span),
|
||||
@ -129,10 +131,12 @@ pub fn disks(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![];
|
||||
for (iface, data) in networks.list() {
|
||||
for (iface, data) in sys.networks() {
|
||||
let record = record! {
|
||||
"name" => Value::string(trim_cstyle_null(iface.to_string()), 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.
|
||||
// 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
|
||||
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());
|
||||
|
||||
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.
|
||||
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!(
|
||||
"{:.2}, {:.2}, {:.2}",
|
||||
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 {
|
||||
let mut sys = System::new();
|
||||
sys.refresh_users_list();
|
||||
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
if let Some(long_version) = System::long_os_version() {
|
||||
if let Some(long_version) = sys.long_os_version() {
|
||||
record.push(
|
||||
"long_os_version",
|
||||
Value::string(trim_cstyle_null(long_version), span),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(version) = System::kernel_version() {
|
||||
if let Some(version) = sys.kernel_version() {
|
||||
record.push(
|
||||
"kernel_version",
|
||||
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(
|
||||
"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
|
||||
let d = UNIX_EPOCH + Duration::from_secs(System::boot_time());
|
||||
let d = UNIX_EPOCH + Duration::from_secs(sys.boot_time());
|
||||
// Create DateTime from SystemTime
|
||||
let datetime = DateTime::<Local>::from(d);
|
||||
// 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));
|
||||
|
||||
let users = Users::new_with_refreshed_list();
|
||||
|
||||
let mut users_list = vec![];
|
||||
for user in users.list() {
|
||||
let mut users = vec![];
|
||||
for user in sys.users() {
|
||||
let mut groups = vec![];
|
||||
for group in user.groups() {
|
||||
groups.push(Value::string(
|
||||
trim_cstyle_null(group.name().to_string()),
|
||||
span,
|
||||
));
|
||||
groups.push(Value::string(trim_cstyle_null(group.to_string()), span));
|
||||
}
|
||||
|
||||
let record = record! {
|
||||
@ -264,22 +266,24 @@ pub fn host(span: Span) -> Value {
|
||||
"groups" => Value::list(groups, span),
|
||||
};
|
||||
|
||||
users_list.push(Value::record(record, span));
|
||||
users.push(Value::record(record, span));
|
||||
}
|
||||
|
||||
if !users.is_empty() {
|
||||
record.push("sessions", Value::list(users_list, span));
|
||||
record.push("sessions", Value::list(users, span));
|
||||
}
|
||||
|
||||
Value::record(record, span)
|
||||
}
|
||||
|
||||
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![];
|
||||
|
||||
for component in components.list() {
|
||||
for component in sys.components() {
|
||||
let mut record = record! {
|
||||
"unit" => Value::string(component.label(), 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]
|
||||
fn def_wrapped_from_module() {
|
||||
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
|
||||
|
@ -49,7 +49,7 @@ fn exec_misc_values() {
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
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 cd;
|
||||
mod compact;
|
||||
mod complete;
|
||||
mod config_env_default;
|
||||
mod config_nu_default;
|
||||
mod continue_;
|
||||
@ -107,8 +106,6 @@ mod touch;
|
||||
mod transpose;
|
||||
mod try_;
|
||||
mod ucp;
|
||||
#[cfg(unix)]
|
||||
mod ulimit;
|
||||
mod umkdir;
|
||||
mod uniq;
|
||||
mod uniq_by;
|
||||
|
@ -38,68 +38,3 @@ fn http_delete_failed_due_to_server_error() {
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
#[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.
|
||||
// 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)"))
|
||||
}
|
||||
|
||||
#[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"))
|
||||
}
|
||||
|
||||
#[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();
|
||||
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"))
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn redirection_keep_exit_codes() {
|
||||
Playground::setup("redirection preserves exit code", |dirs, _| {
|
||||
let out = nu!(
|
||||
cwd: dirs.test(),
|
||||
"do -i { nu --testbin fail e> a.txt } | complete | get exit_code"
|
||||
);
|
||||
let out = nu!("do -i { nu --testbin fail e> a.txt } | complete | get exit_code");
|
||||
// needs to use contains "1", because it complete will output `Some(RawStream)`.
|
||||
assert!(out.out.contains('1'));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -307,7 +302,6 @@ fn separate_redirection_support_variable() {
|
||||
|
||||
#[test]
|
||||
fn redirection_should_have_a_target() {
|
||||
Playground::setup("redirection_should_have_a_target", |dirs, _| {
|
||||
let scripts = [
|
||||
"echo asdf o+e>",
|
||||
"echo asdf o>",
|
||||
@ -319,17 +313,13 @@ fn redirection_should_have_a_target() {
|
||||
"echo asdf o>; echo asdf",
|
||||
];
|
||||
for code in scripts {
|
||||
let actual = nu!(cwd: dirs.test(), code);
|
||||
let actual = nu!(code);
|
||||
assert!(
|
||||
actual.err.contains("expected redirection target",),
|
||||
"should be error, code: {code}",
|
||||
);
|
||||
assert!(
|
||||
!dirs.test().join("tmp.txt").exists(),
|
||||
"No file should be created on error: {code}",
|
||||
"should be error, code: {}",
|
||||
code
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -362,24 +352,8 @@ fn redirection_with_pipe() {
|
||||
|
||||
#[test]
|
||||
fn no_duplicate_redirection() {
|
||||
Playground::setup("redirection does not accept duplicate", |dirs, _| {
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(),
|
||||
"echo 3 o> a.txt o> a.txt"
|
||||
);
|
||||
let actual = nu!("echo 3 o> a.txt o> a.txt");
|
||||
assert!(actual.err.contains("Redirection can be set only once"));
|
||||
assert!(
|
||||
!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"
|
||||
);
|
||||
let actual = nu!("echo 3 e> a.txt e> a.txt");
|
||||
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]
|
||||
fn removes_file_after_cd() {
|
||||
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]
|
||||
fn external_args_with_quoted() {
|
||||
Playground::setup("external failed command with semicolon", |dirs, _| {
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
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]
|
||||
fn external_command_escape_args() {
|
||||
Playground::setup("external failed command with semicolon", |dirs, _| {
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
r#"
|
||||
nu --testbin cococo "\"abcd"
|
||||
^echo "\"abcd"
|
||||
"#
|
||||
));
|
||||
|
||||
@ -306,12 +308,13 @@ fn can_run_batch_files_without_bat_extension() {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
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
|
||||
let actual = nu!(pipeline(
|
||||
r#"
|
||||
nu --testbin cococo "foo"
|
||||
^echo "foo"
|
||||
"#
|
||||
));
|
||||
|
||||
@ -325,7 +328,7 @@ fn redirect_combine() {
|
||||
let actual = nu!(
|
||||
cwd: dirs.test(), pipeline(
|
||||
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::nu;
|
||||
use nu_test_support::playground::Playground;
|
||||
use nu_test_support::{nu, pipeline};
|
||||
use std::io::Write;
|
||||
|
||||
#[test]
|
||||
@ -325,45 +325,3 @@ fn save_file_correct_relative_path() {
|
||||
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");
|
||||
}
|
||||
|
||||
#[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::{
|
||||
ast::{Call, Expression},
|
||||
ast::Call,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
eval_const::eval_constant,
|
||||
FromValue, ShellError, Value,
|
||||
FromValue, ShellError,
|
||||
};
|
||||
|
||||
use crate::eval_expression;
|
||||
@ -34,10 +34,6 @@ pub trait CallExt {
|
||||
starting_pos: usize,
|
||||
) -> 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>(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
@ -74,7 +70,7 @@ impl CallExt for Call {
|
||||
name: &str,
|
||||
) -> Result<Option<T>, ShellError> {
|
||||
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)
|
||||
} else {
|
||||
Ok(None)
|
||||
@ -87,7 +83,7 @@ impl CallExt for Call {
|
||||
name: &str,
|
||||
) -> Result<Option<T>, ShellError> {
|
||||
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)
|
||||
} else {
|
||||
Ok(None)
|
||||
@ -102,9 +98,8 @@ impl CallExt for Call {
|
||||
) -> Result<Vec<T>, ShellError> {
|
||||
let mut output = vec![];
|
||||
|
||||
for result in self.rest_iter_flattened(starting_pos, |expr| {
|
||||
eval_expression(engine_state, stack, expr)
|
||||
})? {
|
||||
for expr in self.positional_iter().skip(starting_pos) {
|
||||
let result = eval_expression(engine_state, stack, expr)?;
|
||||
output.push(FromValue::from_value(result)?);
|
||||
}
|
||||
|
||||
@ -118,36 +113,14 @@ impl CallExt for Call {
|
||||
) -> Result<Vec<T>, ShellError> {
|
||||
let mut output = vec![];
|
||||
|
||||
for result in
|
||||
self.rest_iter_flattened(starting_pos, |expr| eval_constant(working_set, expr))?
|
||||
{
|
||||
for expr in self.positional_iter().skip(starting_pos) {
|
||||
let result = eval_constant(working_set, expr)?;
|
||||
output.push(FromValue::from_value(result)?);
|
||||
}
|
||||
|
||||
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>(
|
||||
&self,
|
||||
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_protocol::{
|
||||
ast::{
|
||||
Argument, Assignment, Block, Call, Expr, Expression, ExternalArgument, PathMember,
|
||||
PipelineElement, Redirection,
|
||||
Argument, Assignment, Block, Call, Expr, Expression, PathMember, PipelineElement,
|
||||
Redirection,
|
||||
},
|
||||
engine::{Closure, EngineState, Stack},
|
||||
eval_base::Eval,
|
||||
@ -66,11 +66,11 @@ pub fn eval_call(
|
||||
if let Some(rest_positional) = decl.signature().rest_positional {
|
||||
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().optional_positional.len(),
|
||||
|expr| eval_expression(engine_state, caller_stack, expr),
|
||||
)? {
|
||||
) {
|
||||
let result = eval_expression(engine_state, caller_stack, arg)?;
|
||||
rest_items.push(result);
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ fn eval_external(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
head: &Expression,
|
||||
args: &[ExternalArgument],
|
||||
args: &[Expression],
|
||||
input: PipelineData,
|
||||
redirect_target: RedirectTarget,
|
||||
is_subexpression: bool,
|
||||
@ -198,10 +198,7 @@ fn eval_external(
|
||||
call.add_positional(head.clone());
|
||||
|
||||
for arg in args {
|
||||
match arg {
|
||||
ExternalArgument::Regular(expr) => call.add_positional(expr.clone()),
|
||||
ExternalArgument::Spread(expr) => call.add_spread(expr.clone()),
|
||||
}
|
||||
call.add_positional(arg.clone())
|
||||
}
|
||||
|
||||
match redirect_target {
|
||||
@ -950,7 +947,7 @@ impl Eval for EvalRuntime {
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
head: &Expression,
|
||||
args: &[ExternalArgument],
|
||||
args: &[Expression],
|
||||
is_subexpression: bool,
|
||||
_: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
@ -1102,18 +1099,7 @@ impl Eval for EvalRuntime {
|
||||
.get_block(block_id)
|
||||
.captures
|
||||
.iter()
|
||||
.map(|&id| {
|
||||
stack
|
||||
.get_var(id, span)
|
||||
.or_else(|_| {
|
||||
engine_state
|
||||
.get_var(id)
|
||||
.const_val
|
||||
.clone()
|
||||
.ok_or(ShellError::VariableNotFoundAtRuntime { span })
|
||||
})
|
||||
.map(|var| (id, var))
|
||||
})
|
||||
.map(|&id| stack.get_var(id, span).map(|var| (id, var)))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
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-utils = { path = "../nu-utils", version = "0.88.2" }
|
||||
|
||||
terminal_size = "0.3"
|
||||
terminal_size = "0.2"
|
||||
strip-ansi-escapes = "0.2.0"
|
||||
crossterm = "0.27"
|
||||
ratatui = "0.23"
|
||||
ansi-str = "0.8"
|
||||
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" }
|
||||
|
||||
crossbeam-channel = "0.5.8"
|
||||
lsp-types = "0.95.0"
|
||||
lsp-types = "0.94.1"
|
||||
lsp-server = "0.7.5"
|
||||
miette = "5.10"
|
||||
ropey = "1.6.1"
|
||||
|
@ -312,7 +312,7 @@ impl LanguageServer {
|
||||
}
|
||||
}
|
||||
}
|
||||
Id::Value(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -347,22 +347,11 @@ impl LanguageServer {
|
||||
Id::Declaration(decl_id) => {
|
||||
let decl = working_set.get_decl(decl_id);
|
||||
|
||||
let mut description = String::new();
|
||||
|
||||
// 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 mut description = "\n### Signature\n```\n".to_string();
|
||||
let signature = decl.signature();
|
||||
description.push_str(&format!(" {}", signature.name));
|
||||
if !signature.named.is_empty() {
|
||||
description.push_str(" {flags}");
|
||||
description.push_str(" {flags}")
|
||||
}
|
||||
for required_arg in &signature.required_positional {
|
||||
description.push_str(&format!(" <{}>", required_arg.name));
|
||||
@ -374,39 +363,6 @@ impl LanguageServer {
|
||||
description.push_str(&format!(" <...{}>", arg.name));
|
||||
}
|
||||
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()
|
||||
|| !signature.optional_positional.is_empty()
|
||||
|| signature.rest_positional.is_some()
|
||||
@ -414,10 +370,10 @@ impl LanguageServer {
|
||||
description.push_str("\n### Parameters\n\n");
|
||||
let mut first = true;
|
||||
for required_arg in &signature.required_positional {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
if !first {
|
||||
description.push('\n');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
description.push_str(&format!(
|
||||
" `{}: {}`",
|
||||
@ -430,10 +386,10 @@ impl LanguageServer {
|
||||
description.push('\n');
|
||||
}
|
||||
for optional_arg in &signature.optional_positional {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
if !first {
|
||||
description.push('\n');
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
description.push_str(&format!(
|
||||
" `{}: {}`",
|
||||
@ -461,10 +417,36 @@ impl LanguageServer {
|
||||
}
|
||||
description.push('\n');
|
||||
}
|
||||
|
||||
// Input/output types
|
||||
if !signature.named.is_empty() {
|
||||
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() {
|
||||
description.push_str("\n### Input/output types\n");
|
||||
description.push_str("\n### Input/output\n");
|
||||
description.push_str("\n```\n");
|
||||
for input_output in &signature.input_output_types {
|
||||
description
|
||||
@ -472,8 +454,14 @@ impl LanguageServer {
|
||||
}
|
||||
description.push_str("\n```\n");
|
||||
}
|
||||
|
||||
// Examples
|
||||
description.push_str(&format!(
|
||||
"### 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() {
|
||||
description.push_str("### Example(s)\n");
|
||||
for example in decl.examples() {
|
||||
@ -590,9 +578,8 @@ mod tests {
|
||||
},
|
||||
request::{Completion, GotoDefinition, HoverRequest, Initialize, Request, Shutdown},
|
||||
CompletionParams, DidChangeTextDocumentParams, DidOpenTextDocumentParams,
|
||||
GotoDefinitionParams, InitializeParams, InitializedParams, PartialResultParams,
|
||||
TextDocumentContentChangeEvent, TextDocumentIdentifier, TextDocumentItem,
|
||||
TextDocumentPositionParams, Url, WorkDoneProgressParams,
|
||||
GotoDefinitionParams, InitializeParams, InitializedParams, TextDocumentContentChangeEvent,
|
||||
TextDocumentIdentifier, TextDocumentItem, TextDocumentPositionParams, Url,
|
||||
};
|
||||
use nu_test_support::fs::{fixtures, root};
|
||||
use std::sync::mpsc::Receiver;
|
||||
@ -684,8 +671,8 @@ mod tests {
|
||||
character: 0,
|
||||
},
|
||||
},
|
||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||
partial_result_params: PartialResultParams::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
})
|
||||
.unwrap(),
|
||||
}))
|
||||
@ -790,8 +777,8 @@ mod tests {
|
||||
text_document: TextDocumentIdentifier { uri },
|
||||
position: lsp_types::Position { line, character },
|
||||
},
|
||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||
partial_result_params: PartialResultParams::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
})
|
||||
.unwrap(),
|
||||
}))
|
||||
@ -907,7 +894,7 @@ mod tests {
|
||||
text_document: TextDocumentIdentifier { uri },
|
||||
position: lsp_types::Position { line, character },
|
||||
},
|
||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
})
|
||||
.unwrap(),
|
||||
}))
|
||||
@ -970,7 +957,7 @@ mod tests {
|
||||
serde_json::json!({
|
||||
"contents": {
|
||||
"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 },
|
||||
position: lsp_types::Position { line, character },
|
||||
},
|
||||
work_done_progress_params: WorkDoneProgressParams::default(),
|
||||
partial_result_params: PartialResultParams::default(),
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
context: None,
|
||||
})
|
||||
.unwrap(),
|
||||
|
@ -121,7 +121,7 @@ mod tests {
|
||||
serde_json::json!({
|
||||
"contents": {
|
||||
"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!({
|
||||
"contents": {
|
||||
"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!({
|
||||
"contents": {
|
||||
"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