mirror of
https://github.com/nushell/nushell.git
synced 2025-07-01 07:00:37 +02:00
Compare commits
132 Commits
Author | SHA1 | Date | |
---|---|---|---|
1291b647ae | |||
91df6c236f | |||
58cea7e8b4 | |||
b01f50bd70 | |||
5f48452e3b | |||
dae1b9a996 | |||
a21af0ade4 | |||
28123841ba | |||
183be911d0 | |||
1966809502 | |||
c3c41a61b0 | |||
90849a067f | |||
705f12c1d9 | |||
0826e66fe0 | |||
774769a7ad | |||
e72cecf457 | |||
9c1a3aa244 | |||
2d07c6eedb | |||
fdd92b2dda | |||
8c70189422 | |||
075c83b3a1 | |||
d3a19c5ac7 | |||
080874df10 | |||
24848a1e35 | |||
e215fbbd08 | |||
33aea56ccd | |||
b6683a3010 | |||
578ef04988 | |||
735a7a21bd | |||
80a69224f7 | |||
e0bf17930b | |||
db3177a5aa | |||
98b9839e3d | |||
0db4d89838 | |||
52278f8562 | |||
c19d9597fd | |||
d9d9916ccc | |||
26759c4af2 | |||
e529746294 | |||
0c4d4632ef | |||
e2c1216c1b | |||
d83dbc3670 | |||
0242b30027 | |||
0c656fd276 | |||
b7a3e5989d | |||
5b5f1d1b92 | |||
35bea5e044 | |||
7917cf9f00 | |||
5036672a58 | |||
585ab56ea4 | |||
9009f68e09 | |||
2bacc29d30 | |||
4d7d97e0e6 | |||
f1000a17b4 | |||
f43edbccdc | |||
6b4282eadf | |||
7e2781a2af | |||
32a53450a6 | |||
ce78817f41 | |||
f0e93c2fa9 | |||
fa6bb147ea | |||
220b105efb | |||
b56ad92e25 | |||
fc5fe4b445 | |||
c01d44e37d | |||
5a0e86aa70 | |||
b4529a20e8 | |||
b938adefaa | |||
b39d797c1f | |||
4240bfb7b1 | |||
b7572f107f | |||
379e3d70ca | |||
6fc87fad72 | |||
fa15a2856a | |||
eaec480f42 | |||
d18587330a | |||
5114dfca7d | |||
3395beaa56 | |||
df66d9fcdf | |||
1af1e0b5a3 | |||
9b41f9ecb8 | |||
48ade4993d | |||
4ecc807dbb | |||
86b69cc5d1 | |||
017a13fa3f | |||
ca12b2e30e | |||
db6c804b17 | |||
57ff668d2e | |||
9fb9b16b38 | |||
41178dff90 | |||
12deff5d1b | |||
21a645b1a9 | |||
e8a55aa647 | |||
6295b20545 | |||
850ecf648a | |||
e6cf18ea43 | |||
d28624796c | |||
380c216d77 | |||
ee5a387300 | |||
3ac36879e0 | |||
bc0c9ab698 | |||
5762489070 | |||
fcdc474731 | |||
f491d3e1e1 | |||
94c89eb623 | |||
cf0a18be51 | |||
0621ab6652 | |||
64a028cc76 | |||
f71a45235a | |||
718ee3d545 | |||
e92678ea2c | |||
1f175d4c98 | |||
4d6ccf2540 | |||
aa6c3936d2 | |||
4f05994b36 | |||
b27d6b2cb1 | |||
64f226f7da | |||
5c1606ed82 | |||
11977759ce | |||
bc3dc98b34 | |||
6fadc72553 | |||
a9e6b1ec6b | |||
cbc7b94b02 | |||
45c66e2090 | |||
11b2423544 | |||
1f9907d2ff | |||
fd503fceaf | |||
b7e5790cd1 | |||
3caab5de36 | |||
fa97e819eb | |||
bdc4bf97a7 | |||
cfb0f3961b |
43
.github/workflows/ci.yml
vendored
43
.github/workflows/ci.yml
vendored
@ -11,7 +11,10 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
platform: [windows-latest, macos-latest, ubuntu-latest]
|
||||
# Pinning to Ubuntu 20.04 because building on newer Ubuntu versions causes linux-gnu
|
||||
# builds to link against a too-new-for-many-Linux-installs glibc version. Consider
|
||||
# revisiting this when 20.04 is closer to EOL (April 2025)
|
||||
platform: [windows-latest, macos-latest, ubuntu-20.04]
|
||||
rust:
|
||||
- stable
|
||||
|
||||
@ -25,17 +28,11 @@ jobs:
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.3.4
|
||||
|
||||
- name: Rustfmt
|
||||
uses: actions-rs/cargo@v1.0.1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- name: cargo fmt
|
||||
run: cargo fmt --all -- --check
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1.0.1
|
||||
with:
|
||||
command: clippy
|
||||
args: --workspace --exclude nu_plugin_* -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
|
||||
run: cargo clippy --workspace --exclude nu_plugin_* -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
|
||||
|
||||
nu-tests:
|
||||
env:
|
||||
@ -44,7 +41,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
platform: [windows-latest, macos-latest, ubuntu-latest]
|
||||
platform: [windows-latest, macos-latest, ubuntu-20.04]
|
||||
style: [default, dataframe]
|
||||
rust:
|
||||
- stable
|
||||
@ -69,10 +66,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.3.4
|
||||
|
||||
- name: Tests
|
||||
uses: actions-rs/cargo@v1.0.1
|
||||
with:
|
||||
command: test
|
||||
args: --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
|
||||
run: cargo test --workspace --profile ci --exclude nu_plugin_* ${{ matrix.flags }}
|
||||
|
||||
python-virtualenv:
|
||||
env:
|
||||
@ -81,7 +75,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
platform: [ubuntu-latest, macos-latest, windows-latest]
|
||||
platform: [ubuntu-20.04, macos-latest, windows-latest]
|
||||
rust:
|
||||
- stable
|
||||
py:
|
||||
@ -96,10 +90,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.3.4
|
||||
|
||||
- name: Install Nushell
|
||||
uses: actions-rs/cargo@v1.0.1
|
||||
with:
|
||||
command: install
|
||||
args: --locked --path=. --profile ci --no-default-features
|
||||
run: cargo install --locked --path=. --profile ci --no-default-features
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v4
|
||||
@ -125,7 +116,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
platform: [windows-latest, macos-latest, ubuntu-latest]
|
||||
platform: [windows-latest, macos-latest, ubuntu-20.04]
|
||||
rust:
|
||||
- stable
|
||||
|
||||
@ -138,13 +129,7 @@ jobs:
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.3.4
|
||||
|
||||
- name: Clippy
|
||||
uses: actions-rs/cargo@v1.0.1
|
||||
with:
|
||||
command: clippy
|
||||
args: --package nu_plugin_* ${{ matrix.flags }} -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
|
||||
run: cargo clippy --package nu_plugin_* ${{ matrix.flags }} -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect
|
||||
|
||||
- name: Tests
|
||||
uses: actions-rs/cargo@v1.0.1
|
||||
with:
|
||||
command: test
|
||||
args: --profile ci --package nu_plugin_*
|
||||
run: cargo test --profile ci --package nu_plugin_*
|
||||
|
41
.github/workflows/release-pkg.nu
vendored
41
.github/workflows/release-pkg.nu
vendored
@ -6,6 +6,21 @@
|
||||
# REF:
|
||||
# 1. https://github.com/volks73/cargo-wix
|
||||
|
||||
# Added 2022-11-29 when Windows packaging wouldn't work
|
||||
# because softprops/action-gh-release was broken
|
||||
# To run this manual for windows
|
||||
# let-env TARGET = 'x86_64-pc-windows-msvc'
|
||||
# let-env TARGET_RUSTFLAGS = ''
|
||||
# let-env GITHUB_WORKSPACE = 'C:\Users\dschroeder\source\repos\forks\nushell'
|
||||
# Pass 1 let-env _EXTRA_ = 'bin'
|
||||
# Pass 2 let-env _EXTRA_ = 'msi'
|
||||
# make sure 7z.exe is in your path https://www.7-zip.org/download.html
|
||||
# make sure aria2c.exe is in your path https://github.com/aria2/aria2
|
||||
# make sure you have the wixtools installed https://wixtoolset.org/
|
||||
# set os below like this because it's what github's runner is named
|
||||
# let os = 'windows-latest'
|
||||
|
||||
|
||||
# The main binary file to be released
|
||||
let bin = 'nu'
|
||||
let os = $env.OS
|
||||
@ -16,8 +31,13 @@ let flags = $env.TARGET_RUSTFLAGS
|
||||
let dist = $'($env.GITHUB_WORKSPACE)/output'
|
||||
let version = (open Cargo.toml | get package.version)
|
||||
|
||||
$'Debugging info:'
|
||||
print { version: $version, bin: $bin, os: $os, target: $target, src: $src, flags: $flags, dist: $dist }; hr-line -b
|
||||
|
||||
# $env
|
||||
|
||||
let USE_UBUNTU = 'ubuntu-20.04'
|
||||
|
||||
$'(char nl)Packaging ($bin) v($version) for ($target) in ($src)...'; hr-line -b
|
||||
if not ('Cargo.lock' | path exists) { cargo generate-lockfile }
|
||||
|
||||
@ -26,8 +46,9 @@ $'Start building ($bin)...'; hr-line
|
||||
# ----------------------------------------------------------------------------
|
||||
# Build for Ubuntu and macOS
|
||||
# ----------------------------------------------------------------------------
|
||||
if $os in ['ubuntu-latest', 'macos-latest'] {
|
||||
if $os == 'ubuntu-latest' {
|
||||
if $os in [$USE_UBUNTU, 'macos-latest'] {
|
||||
if $os == $USE_UBUNTU {
|
||||
sudo apt update
|
||||
sudo apt-get install libxcb-composite0-dev -y
|
||||
}
|
||||
if $target == 'aarch64-unknown-linux-gnu' {
|
||||
@ -38,10 +59,14 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
||||
sudo apt-get install pkg-config gcc-arm-linux-gnueabihf -y
|
||||
let-env CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER = 'arm-linux-gnueabihf-gcc'
|
||||
cargo-build-nu $flags
|
||||
} else if $target == 'riscv64gc-unknown-linux-gnu' {
|
||||
sudo apt-get install gcc-riscv64-linux-gnu -y
|
||||
let-env CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER = 'riscv64-linux-gnu-gcc'
|
||||
cargo-build-nu $flags
|
||||
} else {
|
||||
# musl-tools to fix 'Failed to find tool. Is `musl-gcc` installed?'
|
||||
# Actually just for x86_64-unknown-linux-musl target
|
||||
if $os == 'ubuntu-latest' { sudo apt install musl-tools -y }
|
||||
if $os == $USE_UBUNTU { sudo apt install musl-tools -y }
|
||||
cargo-build-nu $flags
|
||||
}
|
||||
}
|
||||
@ -88,7 +113,7 @@ if ($ver | str trim | is-empty) {
|
||||
# Create a release archive and send it to output for the following steps
|
||||
# ----------------------------------------------------------------------------
|
||||
cd $dist; $'(char nl)Creating release archive...'; hr-line
|
||||
if $os in ['ubuntu-latest', 'macos-latest'] {
|
||||
if $os in [$USE_UBUNTU, 'macos-latest'] {
|
||||
|
||||
let files = (ls | get name)
|
||||
let dest = $'($bin)-($version)-($target)'
|
||||
@ -101,7 +126,8 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
||||
|
||||
tar -czf $archive $dest
|
||||
print $'archive: ---> ($archive)'; ls $archive
|
||||
echo $'::set-output name=archive::($archive)'
|
||||
# REF: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/
|
||||
echo $"archive=($archive)" | save --append $env.GITHUB_OUTPUT
|
||||
|
||||
} else if $os == 'windows-latest' {
|
||||
|
||||
@ -121,7 +147,8 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
||||
cp -r $'($dist)/*' target/release/
|
||||
cargo install cargo-wix --version 0.3.3
|
||||
cargo wix --no-build --nocapture --package nu --output $wixRelease
|
||||
echo $'::set-output name=archive::($wixRelease)'
|
||||
print $'archive: ---> ($wixRelease)';
|
||||
echo $"archive=($wixRelease)" | save --append $env.GITHUB_OUTPUT
|
||||
|
||||
} else {
|
||||
|
||||
@ -131,7 +158,7 @@ if $os in ['ubuntu-latest', 'macos-latest'] {
|
||||
print $'archive: ---> ($archive)';
|
||||
let pkg = (ls -f $archive | get name)
|
||||
if not ($pkg | is-empty) {
|
||||
echo $'::set-output name=archive::($pkg | get 0)'
|
||||
echo $"archive=($pkg | get 0)" | save --append $env.GITHUB_OUTPUT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
31
.github/workflows/release.yml
vendored
31
.github/workflows/release.yml
vendored
@ -27,6 +27,7 @@ jobs:
|
||||
- x86_64-unknown-linux-musl
|
||||
- aarch64-unknown-linux-gnu
|
||||
- armv7-unknown-linux-gnueabihf
|
||||
- riscv64gc-unknown-linux-gnu
|
||||
extra: ['bin']
|
||||
include:
|
||||
- target: aarch64-apple-darwin
|
||||
@ -44,35 +45,37 @@ jobs:
|
||||
os: windows-latest
|
||||
target_rustflags: ''
|
||||
- target: x86_64-unknown-linux-gnu
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
- target: x86_64-unknown-linux-musl
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
- target: armv7-unknown-linux-gnueabihf
|
||||
os: ubuntu-latest
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
- target: riscv64gc-unknown-linux-gnu
|
||||
os: ubuntu-20.04
|
||||
target_rustflags: ''
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3.0.2
|
||||
- uses: actions/checkout@v3.1.0
|
||||
|
||||
- name: Install Rust Toolchain Components
|
||||
uses: actions-rs/toolchain@v1.0.6
|
||||
with:
|
||||
override: true
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
target: ${{ matrix.target }}
|
||||
- name: Update Rust Toolchain Target
|
||||
run: |
|
||||
echo "targets = ['${{matrix.target}}']" >> rust-toolchain.toml
|
||||
|
||||
- name: Setup Rust toolchain and cache
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1.3.4
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v2.1
|
||||
uses: hustcer/setup-nu@v3
|
||||
with:
|
||||
version: 0.69.1
|
||||
version: 0.72.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
267
Cargo.lock
generated
267
Cargo.lock
generated
@ -89,6 +89,15 @@ dependencies = [
|
||||
"ansitok",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi-str"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b1ed1c166829a0ccb5d79caa0f75cb4abd4adb2ce2c096755b7ad5ffdb0990"
|
||||
dependencies = [
|
||||
"ansitok",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansitok"
|
||||
version = "0.2.0"
|
||||
@ -101,9 +110,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.65"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
|
||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||
|
||||
[[package]]
|
||||
name = "array-init-cursor"
|
||||
@ -430,19 +439,25 @@ checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70"
|
||||
|
||||
[[package]]
|
||||
name = "calamine"
|
||||
version = "0.18.0"
|
||||
version = "0.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b86ca78da4bdce5ac0f0bdbc0218ad14232f1e668376e044233f64c527cf5abb"
|
||||
checksum = "6381d1037ee9b8a6c8eb97936add0331a1aabd148d5b6f35f1cda6e5dec44f40"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"codepage",
|
||||
"encoding_rs",
|
||||
"log",
|
||||
"quick-xml 0.19.0",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
@ -1256,12 +1271,6 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
@ -1880,9 +1889,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "json_to_table"
|
||||
version = "0.2.0"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "408f09e42613f7a9902ecf2f30bcd053cf9f5668d0b1493ae1669070338d661b"
|
||||
checksum = "a0be33515faeb3773f550c80fd7a889148164e58f7e3cf36467718c8ce71ee55"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"tabled",
|
||||
@ -2469,7 +2478,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"atty",
|
||||
@ -2523,7 +2532,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-cli"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"chrono",
|
||||
@ -2531,7 +2540,6 @@ dependencies = [
|
||||
"fancy-regex",
|
||||
"fuzzy-matcher",
|
||||
"is_executable",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"miette",
|
||||
"nu-ansi-term",
|
||||
@ -2543,6 +2551,7 @@ dependencies = [
|
||||
"nu-protocol",
|
||||
"nu-test-support",
|
||||
"nu-utils",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"reedline",
|
||||
"rstest",
|
||||
@ -2552,21 +2561,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-color-config"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-engine",
|
||||
"nu-json",
|
||||
"nu-protocol",
|
||||
"nu-table",
|
||||
"nu-test-support",
|
||||
"nu-utils",
|
||||
"serde",
|
||||
"tabled",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-command"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"Inflector",
|
||||
"alphanumeric-sort",
|
||||
"atty",
|
||||
"base64",
|
||||
"byteorder",
|
||||
"bytesize",
|
||||
@ -2592,7 +2605,6 @@ dependencies = [
|
||||
"indexmap",
|
||||
"is-root",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"lscolors",
|
||||
@ -2603,6 +2615,7 @@ dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-color-config",
|
||||
"nu-engine",
|
||||
"nu-explore",
|
||||
"nu-glob",
|
||||
"nu-json",
|
||||
"nu-parser",
|
||||
@ -2622,12 +2635,13 @@ dependencies = [
|
||||
"polars",
|
||||
"powierza-coefficient",
|
||||
"proptest",
|
||||
"quick-xml 0.23.1",
|
||||
"quick-xml",
|
||||
"quickcheck",
|
||||
"quickcheck_macros",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
"reedline",
|
||||
"regex",
|
||||
"reqwest",
|
||||
"roxmltree",
|
||||
"rstest",
|
||||
@ -2654,13 +2668,13 @@ dependencies = [
|
||||
"uuid",
|
||||
"wax",
|
||||
"which",
|
||||
"windows 0.42.0",
|
||||
"windows",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nu-glob",
|
||||
@ -2670,30 +2684,45 @@ dependencies = [
|
||||
"sysinfo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-explore"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"ansi-str 0.7.2",
|
||||
"crossterm 0.24.0",
|
||||
"lscolors",
|
||||
"nu-ansi-term",
|
||||
"nu-color-config",
|
||||
"nu-engine",
|
||||
"nu-json",
|
||||
"nu-parser",
|
||||
"nu-protocol",
|
||||
"nu-table",
|
||||
"nu-utils",
|
||||
"strip-ansi-escapes",
|
||||
"terminal_size 0.2.1",
|
||||
"tui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"doc-comment",
|
||||
"tempdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-json"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"lazy_static",
|
||||
"linked-hash-map",
|
||||
"nu-path",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-parser"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"chrono",
|
||||
@ -2710,7 +2739,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"dirs-next",
|
||||
"omnipath",
|
||||
@ -2719,7 +2748,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"criterion",
|
||||
@ -2733,7 +2762,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"nu-ansi-term",
|
||||
@ -2742,7 +2771,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"byte-unit",
|
||||
"chrono",
|
||||
@ -2751,6 +2780,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"miette",
|
||||
"nu-json",
|
||||
"nu-test-support",
|
||||
"nu-utils",
|
||||
"num-format",
|
||||
"serde",
|
||||
@ -2764,7 +2794,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"chrono",
|
||||
@ -2782,12 +2812,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-table"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"json_to_table",
|
||||
"nu-ansi-term",
|
||||
"nu-color-config",
|
||||
"nu-engine",
|
||||
"nu-protocol",
|
||||
"nu-test-support",
|
||||
"nu-utils",
|
||||
"serde_json",
|
||||
"tabled",
|
||||
@ -2795,7 +2828,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-term-grid"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"nu-utils",
|
||||
"unicode-width",
|
||||
@ -2803,21 +2836,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu-test-support"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"getset",
|
||||
"hamcrest2",
|
||||
"lazy_static",
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
"nu-utils",
|
||||
"num-format",
|
||||
"once_cell",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"crossterm_winapi",
|
||||
"lscolors",
|
||||
@ -2838,7 +2871,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_example"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
@ -2846,7 +2879,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_gstat"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"nu-engine",
|
||||
@ -2856,7 +2889,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_inc"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
@ -2865,7 +2898,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_query"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
dependencies = [
|
||||
"gjson",
|
||||
"nu-engine",
|
||||
@ -3138,7 +3171,7 @@ version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1526bb6aa9f10ec339fb10360f22c57edf81d5678d0278e93bc12a47ffbe4b01"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"ansi-str 0.5.0",
|
||||
"ansitok",
|
||||
"bytecount",
|
||||
"fnv",
|
||||
@ -3771,23 +3804,14 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.19.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d72d5477478f85bd00b6521780dfba1ec6cdaadcf90b8b181c36d7de561f9b"
|
||||
checksum = "58e21a144a0ffb5fad7b464babcdab934a325ad69b7c0373bcfef5cbd9799ca9"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11bafc859c6815fbaffbbbf4229ecb767ac913fecb27f9ad4343662e9ef099ea"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quickcheck"
|
||||
version = "1.0.3"
|
||||
@ -3819,19 +3843,6 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
|
||||
dependencies = [
|
||||
"fuchsia-cprng",
|
||||
"libc",
|
||||
"rand_core 0.3.1",
|
||||
"rdrand",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
@ -3877,21 +3888,6 @@ dependencies = [
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
|
||||
dependencies = [
|
||||
"rand_core 0.4.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
@ -3971,15 +3967,6 @@ dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
|
||||
dependencies = [
|
||||
"rand_core 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
@ -4142,9 +4129,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.14.1"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
|
||||
checksum = "fb6d47b59770b0ae88c7f270c68502832ec14d8c7ab5f7a584f204bb76dbfd8e"
|
||||
dependencies = [
|
||||
"xmlparser",
|
||||
]
|
||||
@ -4877,7 +4864,7 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c3ee73732ffceaea7b8f6b719ce3bb17f253fa27461ffeaf568ebd0cdb4b85"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"ansi-str 0.5.0",
|
||||
"papergrid",
|
||||
"tabled_derive",
|
||||
"unicode-width",
|
||||
@ -4896,16 +4883,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
dependencies = [
|
||||
"rand 0.4.6",
|
||||
"remove_dir_all",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
@ -5164,9 +5141,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "trash"
|
||||
version = "2.1.5"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe090367848cd40c4230ff3ce4e2ff6a2fd511c1e14ae047a4a4c37ef7965236"
|
||||
checksum = "6f74274f95c7e7340d7c5bcd4863af87a9ed6a117cf73cf483c71cb4d744a948"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"libc",
|
||||
@ -5175,7 +5152,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"scopeguard",
|
||||
"url",
|
||||
"windows 0.37.0",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -5184,6 +5161,19 @@ version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||
|
||||
[[package]]
|
||||
name = "tui"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cassowary",
|
||||
"crossterm 0.25.0",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typed-arena"
|
||||
version = "1.7.0"
|
||||
@ -5618,22 +5608,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.37.0"
|
||||
version = "0.43.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc 0.37.0",
|
||||
"windows_i686_gnu 0.37.0",
|
||||
"windows_i686_msvc 0.37.0",
|
||||
"windows_x86_64_gnu 0.37.0",
|
||||
"windows_x86_64_msvc 0.37.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0286ba339aa753e70765d521bb0242cc48e1194562bfa2a2ad7ac8a6de28f5d5"
|
||||
checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc 0.42.0",
|
||||
@ -5669,12 +5646,6 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
@ -5687,12 +5658,6 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.0"
|
||||
@ -5705,12 +5670,6 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.0"
|
||||
@ -5723,12 +5682,6 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.0"
|
||||
@ -5747,12 +5700,6 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.0"
|
||||
@ -5789,9 +5736,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xmlparser"
|
||||
version = "0.13.3"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
|
||||
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
@ -5801,14 +5748,14 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.5.13"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815"
|
||||
checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"flate2",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
32
Cargo.toml
32
Cargo.toml
@ -10,7 +10,7 @@ license = "MIT"
|
||||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.60"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -45,20 +45,20 @@ ctrlc = "3.2.1"
|
||||
log = "0.4"
|
||||
miette = { version = "5.1.0", features = ["fancy-no-backtrace"] }
|
||||
nu-ansi-term = "0.46.0"
|
||||
nu-cli = { path="./crates/nu-cli", version = "0.72.0" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.72.0" }
|
||||
nu-command = { path="./crates/nu-command", version = "0.72.0" }
|
||||
nu-engine = { path="./crates/nu-engine", version = "0.72.0" }
|
||||
nu-json = { path="./crates/nu-json", version = "0.72.0" }
|
||||
nu-parser = { path="./crates/nu-parser", version = "0.72.0" }
|
||||
nu-path = { path="./crates/nu-path", version = "0.72.0" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.72.0" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.72.0" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.72.0" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.72.0" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.72.0" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.72.0" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.72.0" }
|
||||
nu-cli = { path="./crates/nu-cli", version = "0.73.0" }
|
||||
nu-color-config = { path = "./crates/nu-color-config", version = "0.73.0" }
|
||||
nu-command = { path="./crates/nu-command", version = "0.73.0" }
|
||||
nu-engine = { path="./crates/nu-engine", version = "0.73.0" }
|
||||
nu-json = { path="./crates/nu-json", version = "0.73.0" }
|
||||
nu-parser = { path="./crates/nu-parser", version = "0.73.0" }
|
||||
nu-path = { path="./crates/nu-path", version = "0.73.0" }
|
||||
nu-plugin = { path = "./crates/nu-plugin", optional = true, version = "0.73.0" }
|
||||
nu-pretty-hex = { path = "./crates/nu-pretty-hex", version = "0.73.0" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.73.0" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.73.0" }
|
||||
nu-table = { path = "./crates/nu-table", version = "0.73.0" }
|
||||
nu-term-grid = { path = "./crates/nu-term-grid", version = "0.73.0" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.73.0" }
|
||||
reedline = { version = "0.14.0", features = ["bashisms", "sqlite"]}
|
||||
|
||||
rayon = "1.5.1"
|
||||
@ -80,7 +80,7 @@ nix = { version = "0.25", default-features = false, features = ["signal", "proce
|
||||
atty = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path="./crates/nu-test-support", version = "0.72.0" }
|
||||
nu-test-support = { path="./crates/nu-test-support", version = "0.73.0" }
|
||||
tempfile = "3.2.0"
|
||||
assert_cmd = "2.0.2"
|
||||
pretty_assertions = "1.0.0"
|
||||
|
13
README.md
13
README.md
@ -1,6 +1,6 @@
|
||||
# Nushell <!-- omit in toc -->
|
||||
[](https://crates.io/crates/nu)
|
||||

|
||||

|
||||
[](https://discord.gg/NtAbbGn)
|
||||
[](https://changelog.com/podcast/363)
|
||||
[](https://twitter.com/nu_shell)
|
||||
@ -126,12 +126,13 @@ For example, you can load a .toml file as structured data and explore it:
|
||||
> open Cargo.toml
|
||||
╭──────────────────┬────────────────────╮
|
||||
│ bin │ [table 1 row] │
|
||||
│ dependencies │ {record 24 fields} │
|
||||
│ dependencies │ {record 25 fields} │
|
||||
│ dev-dependencies │ {record 8 fields} │
|
||||
│ features │ {record 10 fields} │
|
||||
│ package │ {record 13 fields} │
|
||||
│ patch │ {record 1 field} │
|
||||
│ profile │ {record 3 fields} │
|
||||
│ target │ {record 2 fields} │
|
||||
│ target │ {record 3 fields} │
|
||||
│ workspace │ {record 1 field} │
|
||||
╰──────────────────┴────────────────────╯
|
||||
```
|
||||
@ -149,11 +150,11 @@ We can pipe this into a command that gets the contents of one of the columns:
|
||||
│ exclude │ [list 1 item] │
|
||||
│ homepage │ https://www.nushell.sh │
|
||||
│ license │ MIT │
|
||||
│ metadata │ {record 1 field} │
|
||||
│ name │ nu │
|
||||
│ readme │ README.md │
|
||||
│ repository │ https://github.com/nushell/nushell │
|
||||
│ rust-version │ 1.60 │
|
||||
│ version │ 0.63.1 │
|
||||
│ version │ 0.72.0 │
|
||||
╰───────────────┴────────────────────────────────────╯
|
||||
```
|
||||
|
||||
@ -161,7 +162,7 @@ And if needed we can drill down further:
|
||||
|
||||
```shell
|
||||
> open Cargo.toml | get package.version
|
||||
0.63.1
|
||||
0.72.0
|
||||
```
|
||||
|
||||
### Plugins
|
||||
|
@ -5,21 +5,21 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path="../nu-test-support", version = "0.72.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.72.0" }
|
||||
nu-test-support = { path="../nu-test-support", version = "0.73.0" }
|
||||
nu-command = { path = "../nu-command", version = "0.73.0" }
|
||||
rstest = {version = "0.15.0", default-features = false}
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.72.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.72.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.72.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.72.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.72.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.73.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.73.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.73.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.73.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.73.0" }
|
||||
nu-ansi-term = "0.46.0"
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.72.0" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.73.0" }
|
||||
reedline = { version = "0.14.0", features = ["bashisms", "sqlite"]}
|
||||
|
||||
atty = "0.2.14"
|
||||
@ -28,7 +28,7 @@ crossterm = "0.24.0"
|
||||
fancy-regex = "0.10.0"
|
||||
fuzzy-matcher = "0.3.7"
|
||||
is_executable = "1.0.1"
|
||||
lazy_static = "1.4.0"
|
||||
once_cell = "1.16.0"
|
||||
log = "0.4"
|
||||
miette = { version = "5.1.0", features = ["fancy-no-backtrace"] }
|
||||
percent-encoding = "2"
|
||||
|
@ -94,10 +94,7 @@ impl CommandCompletion {
|
||||
value: String::from_utf8_lossy(&x.0).to_string(),
|
||||
description: x.1,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
span: reedline::Span::new(span.start - offset, span.end - offset),
|
||||
append_whitespace: true,
|
||||
});
|
||||
|
||||
@ -108,10 +105,7 @@ impl CommandCompletion {
|
||||
value: String::from_utf8_lossy(&x).to_string(),
|
||||
description: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
span: reedline::Span::new(span.start - offset, span.end - offset),
|
||||
append_whitespace: true,
|
||||
});
|
||||
|
||||
@ -128,15 +122,15 @@ impl CommandCompletion {
|
||||
value: x,
|
||||
description: None,
|
||||
extra: None,
|
||||
span: reedline::Span {
|
||||
start: span.start - offset,
|
||||
end: span.end - offset,
|
||||
},
|
||||
span: reedline::Span::new(span.start - offset, span.end - offset),
|
||||
append_whitespace: true,
|
||||
});
|
||||
|
||||
let results_strings: Vec<String> =
|
||||
results.clone().into_iter().map(|x| x.value).collect();
|
||||
|
||||
for external in results_external {
|
||||
if results.contains(&external) {
|
||||
if results_strings.contains(&external.value) {
|
||||
results.push(Suggestion {
|
||||
value: format!("^{}", external.value),
|
||||
description: None,
|
||||
@ -187,10 +181,7 @@ impl Completer for CommandCompletion {
|
||||
let subcommands = if let Some(last) = last {
|
||||
self.complete_commands(
|
||||
working_set,
|
||||
Span {
|
||||
start: last.0.start,
|
||||
end: pos,
|
||||
},
|
||||
Span::new(last.0.start, pos),
|
||||
offset,
|
||||
false,
|
||||
options.match_algorithm,
|
||||
|
@ -77,10 +77,7 @@ impl NuCompleter {
|
||||
Value::List {
|
||||
vals: spans
|
||||
.iter()
|
||||
.map(|it| Value::String {
|
||||
val: it.to_string(),
|
||||
span: Span::unknown(),
|
||||
})
|
||||
.map(|it| Value::string(it, Span::unknown()))
|
||||
.collect(),
|
||||
span: Span::unknown(),
|
||||
},
|
||||
@ -92,7 +89,7 @@ impl NuCompleter {
|
||||
&self.engine_state,
|
||||
&mut callee_stack,
|
||||
block,
|
||||
PipelineData::new(span),
|
||||
PipelineData::empty(),
|
||||
true,
|
||||
true,
|
||||
);
|
||||
@ -101,14 +98,8 @@ impl NuCompleter {
|
||||
Ok(pd) => {
|
||||
let value = pd.into_value(span);
|
||||
if let Value::List { vals, span: _ } = value {
|
||||
let result = map_value_completions(
|
||||
vals.iter(),
|
||||
Span {
|
||||
start: span.start,
|
||||
end: span.end,
|
||||
},
|
||||
offset,
|
||||
);
|
||||
let result =
|
||||
map_value_completions(vals.iter(), Span::new(span.start, span.end), offset);
|
||||
|
||||
return Some(result);
|
||||
}
|
||||
@ -165,15 +156,12 @@ impl NuCompleter {
|
||||
|
||||
// Create a new span
|
||||
let new_span = if flat_idx == 0 {
|
||||
Span {
|
||||
start: flat.0.start,
|
||||
end: flat.0.end - 1 - span_offset,
|
||||
}
|
||||
Span::new(flat.0.start, flat.0.end - 1 - span_offset)
|
||||
} else {
|
||||
Span {
|
||||
start: flat.0.start - span_offset,
|
||||
end: flat.0.end - 1 - span_offset,
|
||||
}
|
||||
Span::new(
|
||||
flat.0.start - span_offset,
|
||||
flat.0.end - 1 - span_offset,
|
||||
)
|
||||
};
|
||||
|
||||
// Parses the prefix. Completion should look up to the cursor position, not after.
|
||||
|
@ -52,13 +52,13 @@ impl Completer for CustomCompletion {
|
||||
head: span,
|
||||
arguments: vec![
|
||||
Argument::Positional(Expression {
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
ty: Type::String,
|
||||
expr: Expr::String(self.line.clone()),
|
||||
custom_completion: None,
|
||||
}),
|
||||
Argument::Positional(Expression {
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
ty: Type::Int,
|
||||
expr: Expr::Int(line_pos as i64),
|
||||
custom_completion: None,
|
||||
@ -67,7 +67,7 @@ impl Completer for CustomCompletion {
|
||||
redirect_stdout: true,
|
||||
redirect_stderr: true,
|
||||
},
|
||||
PipelineData::new(span),
|
||||
PipelineData::empty(),
|
||||
);
|
||||
|
||||
let mut custom_completion_options = None;
|
||||
|
@ -136,8 +136,12 @@ pub fn directory_completion(
|
||||
file_name.push(SEP);
|
||||
}
|
||||
|
||||
// Fix files or folders with quotes
|
||||
if path.contains('\'') || path.contains('"') || path.contains(' ') {
|
||||
// Fix files or folders with quotes or hash
|
||||
if path.contains('\'')
|
||||
|| path.contains('"')
|
||||
|| path.contains(' ')
|
||||
|| path.contains('#')
|
||||
{
|
||||
path = format!("`{}`", path);
|
||||
}
|
||||
|
||||
|
@ -141,8 +141,12 @@ pub fn file_path_completion(
|
||||
file_name.push(SEP);
|
||||
}
|
||||
|
||||
// Fix files or folders with quotes
|
||||
if path.contains('\'') || path.contains('"') || path.contains(' ') {
|
||||
// Fix files or folders with quotes or hashes
|
||||
if path.contains('\'')
|
||||
|| path.contains('"')
|
||||
|| path.contains(' ')
|
||||
|| path.contains('#')
|
||||
{
|
||||
path = format!("`{}`", path);
|
||||
}
|
||||
|
||||
|
@ -111,10 +111,7 @@ impl Completer for VariableCompletion {
|
||||
&self.engine_state,
|
||||
&self.stack,
|
||||
nu_protocol::NU_VARIABLE_ID,
|
||||
nu_protocol::Span {
|
||||
start: current_span.start,
|
||||
end: current_span.end,
|
||||
},
|
||||
nu_protocol::Span::new(current_span.start, current_span.end),
|
||||
) {
|
||||
for suggestion in
|
||||
nested_suggestions(nuval, self.var_context.1.clone(), current_span)
|
||||
@ -134,13 +131,7 @@ impl Completer for VariableCompletion {
|
||||
// Completion other variable types
|
||||
if let Some(var_id) = var_id {
|
||||
// Extract the variable value from the stack
|
||||
let var = self.stack.get_var(
|
||||
var_id,
|
||||
Span {
|
||||
start: span.start,
|
||||
end: span.end,
|
||||
},
|
||||
);
|
||||
let var = self.stack.get_var(var_id, Span::new(span.start, span.end));
|
||||
|
||||
// If the value exists and it's of type Record
|
||||
if let Ok(value) = var {
|
||||
@ -281,7 +272,7 @@ fn recursive_value(val: Value, sublevels: Vec<Vec<u8>>) -> Value {
|
||||
|
||||
// Current sublevel value not found
|
||||
return Value::Nothing {
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
};
|
||||
}
|
||||
_ => return val,
|
||||
|
@ -8,7 +8,7 @@ use nu_path::canonicalize_with;
|
||||
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
|
||||
#[cfg(feature = "plugin")]
|
||||
use nu_protocol::Spanned;
|
||||
use nu_protocol::{HistoryFileFormat, PipelineData, Span};
|
||||
use nu_protocol::{HistoryFileFormat, PipelineData};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
@ -38,7 +38,7 @@ pub fn read_plugin_file(
|
||||
stack,
|
||||
&contents,
|
||||
&plugin_filename,
|
||||
PipelineData::new(Span::new(0, 0)),
|
||||
PipelineData::empty(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -85,7 +85,7 @@ pub fn eval_config_contents(
|
||||
stack,
|
||||
&contents,
|
||||
&config_filename,
|
||||
PipelineData::new(Span::new(0, 0)),
|
||||
PipelineData::empty(),
|
||||
);
|
||||
|
||||
// Merge the environment in case env vars changed in the config
|
||||
|
@ -2,13 +2,13 @@ use crate::util::{eval_source, report_error};
|
||||
use log::info;
|
||||
use log::trace;
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use nu_engine::convert_env_values;
|
||||
use nu_engine::{convert_env_values, current_dir};
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::Type;
|
||||
use nu_path::canonicalize_with;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Config, PipelineData, Span, Value,
|
||||
Config, PipelineData, ShellError, Span, Type, Value,
|
||||
};
|
||||
use nu_utils::stdout_write_all_and_flush;
|
||||
|
||||
@ -27,14 +27,75 @@ pub fn evaluate_file(
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let file = std::fs::read(&path).into_diagnostic()?;
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
|
||||
engine_state.start_in_file(Some(&path));
|
||||
let file_path = {
|
||||
match canonicalize_with(&path, &cwd) {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::FileNotFoundCustom(
|
||||
format!("Could not access file '{}': {:?}", path, e.to_string()),
|
||||
Span::unknown(),
|
||||
),
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let file_path_str = match file_path.to_str() {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::NonUtf8Custom(
|
||||
format!(
|
||||
"Input file name '{}' is not valid UTF8",
|
||||
file_path.to_string_lossy()
|
||||
),
|
||||
Span::unknown(),
|
||||
),
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let file = match std::fs::read(&file_path).into_diagnostic() {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(
|
||||
&working_set,
|
||||
&ShellError::FileNotFoundCustom(
|
||||
format!(
|
||||
"Could not read file '{}': {:?}",
|
||||
file_path_str,
|
||||
e.to_string()
|
||||
),
|
||||
Span::unknown(),
|
||||
),
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
engine_state.start_in_file(Some(file_path_str));
|
||||
|
||||
let mut parent = file_path.clone();
|
||||
parent.pop();
|
||||
|
||||
stack.add_env_var(
|
||||
"FILE_PWD".to_string(),
|
||||
Value::string(parent.to_string_lossy(), Span::unknown()),
|
||||
);
|
||||
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
trace!("parsing file: {}", path);
|
||||
|
||||
let _ = parse(&mut working_set, Some(&path), &file, false, &[]);
|
||||
trace!("parsing file: {}", file_path_str);
|
||||
let _ = parse(&mut working_set, Some(file_path_str), &file, false, &[]);
|
||||
|
||||
if working_set.find_decl(b"main", &Type::Any).is_some() {
|
||||
let args = format!("main {}", args.join(" "));
|
||||
@ -43,15 +104,15 @@ pub fn evaluate_file(
|
||||
engine_state,
|
||||
stack,
|
||||
&file,
|
||||
&path,
|
||||
PipelineData::new(Span::new(0, 0)),
|
||||
file_path_str,
|
||||
PipelineData::empty(),
|
||||
) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
if !eval_source(engine_state, stack, args.as_bytes(), "<commandline>", input) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
} else if !eval_source(engine_state, stack, &file, &path, input) {
|
||||
} else if !eval_source(engine_state, stack, &file, file_path_str, input) {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
|
@ -42,20 +42,14 @@ impl Completer for NuMenuCompleter {
|
||||
|
||||
if let Some(buffer) = block.signature.get_positional(0) {
|
||||
if let Some(buffer_id) = &buffer.var_id {
|
||||
let line_buffer = Value::String {
|
||||
val: parsed.remainder.to_string(),
|
||||
span: self.span,
|
||||
};
|
||||
let line_buffer = Value::string(parsed.remainder, self.span);
|
||||
self.stack.add_var(*buffer_id, line_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(position) = block.signature.get_positional(1) {
|
||||
if let Some(position_id) = &position.var_id {
|
||||
let line_buffer = Value::Int {
|
||||
val: pos as i64,
|
||||
span: self.span,
|
||||
};
|
||||
let line_buffer = Value::int(pos as i64, self.span);
|
||||
self.stack.add_var(*position_id, line_buffer);
|
||||
}
|
||||
}
|
||||
|
@ -50,14 +50,13 @@ Since this command has no output, there is no point in piping it with other comm
|
||||
let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
|
||||
let no_newline = call.has_flag("no-newline");
|
||||
let to_stderr = call.has_flag("stderr");
|
||||
let head = call.head;
|
||||
|
||||
for arg in args {
|
||||
arg.into_pipeline_data()
|
||||
.print(engine_state, stack, no_newline, to_stderr)?;
|
||||
}
|
||||
|
||||
Ok(PipelineData::new(head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -4,7 +4,7 @@ use log::info;
|
||||
use nu_engine::eval_subexpression;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
Config, PipelineData, Span, Value,
|
||||
Config, PipelineData, Value,
|
||||
};
|
||||
use reedline::Prompt;
|
||||
|
||||
@ -37,12 +37,8 @@ fn get_prompt_string(
|
||||
let block = engine_state.get_block(block_id);
|
||||
let mut stack = stack.captures_to_stack(&captures);
|
||||
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
|
||||
let ret_val = eval_subexpression(
|
||||
engine_state,
|
||||
&mut stack,
|
||||
block,
|
||||
PipelineData::new(Span::new(0, 0)), // Don't try this at home, 0 span is ignored
|
||||
);
|
||||
let ret_val =
|
||||
eval_subexpression(engine_state, &mut stack, block, PipelineData::empty());
|
||||
info!(
|
||||
"get_prompt_string (block) {}:{}:{}",
|
||||
file!(),
|
||||
@ -62,12 +58,7 @@ fn get_prompt_string(
|
||||
Value::Block { val: block_id, .. } => {
|
||||
let block = engine_state.get_block(block_id);
|
||||
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
|
||||
let ret_val = eval_subexpression(
|
||||
engine_state,
|
||||
stack,
|
||||
block,
|
||||
PipelineData::new(Span::new(0, 0)), // Don't try this at home, 0 span is ignored
|
||||
);
|
||||
let ret_val = eval_subexpression(engine_state, stack, block, PipelineData::empty());
|
||||
info!(
|
||||
"get_prompt_string (block) {}:{}:{}",
|
||||
file!(),
|
||||
|
@ -1,11 +1,11 @@
|
||||
use super::DescriptionMenu;
|
||||
use crate::{menus::NuMenuCompleter, NuHelpCompleter};
|
||||
use crossterm::event::{KeyCode, KeyModifiers};
|
||||
use nu_color_config::lookup_ansi_color_style;
|
||||
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
||||
use nu_engine::eval_block;
|
||||
use nu_parser::parse;
|
||||
use nu_protocol::{
|
||||
color_value_string, create_menus,
|
||||
create_menus,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
extract_value, Config, IntoPipelineData, ParsedKeybinding, ParsedMenu, PipelineData,
|
||||
ShellError, Span, Value,
|
||||
@ -159,14 +159,11 @@ macro_rules! add_style {
|
||||
($name:expr, $cols: expr, $vals:expr, $span:expr, $config: expr, $menu:expr, $f:expr) => {
|
||||
$menu = match extract_value($name, $cols, $vals, $span) {
|
||||
Ok(text) => {
|
||||
let text = match text {
|
||||
Value::String { val, .. } => val.clone(),
|
||||
Value::Record { cols, vals, span } => {
|
||||
color_value_string(span, cols, vals, $config).into_string("", $config)
|
||||
}
|
||||
_ => "green".to_string(),
|
||||
let style = match text {
|
||||
Value::String { val, .. } => lookup_ansi_color_style(&val),
|
||||
Value::Record { .. } => color_record_to_nustyle(&text),
|
||||
_ => lookup_ansi_color_style("green"),
|
||||
};
|
||||
let style = lookup_ansi_color_style(&text);
|
||||
$f($menu, style)
|
||||
}
|
||||
Err(_) => $menu,
|
||||
@ -993,10 +990,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_send_event() {
|
||||
let cols = vec!["send".to_string()];
|
||||
let vals = vec![Value::String {
|
||||
val: "Enter".to_string(),
|
||||
span: Span::test_data(),
|
||||
}];
|
||||
let vals = vec![Value::string("Enter", Span::test_data())];
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
|
||||
@ -1016,10 +1010,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_edit_event() {
|
||||
let cols = vec!["edit".to_string()];
|
||||
let vals = vec![Value::String {
|
||||
val: "Clear".to_string(),
|
||||
span: Span::test_data(),
|
||||
}];
|
||||
let vals = vec![Value::string("Clear", Span::test_data())];
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, &span).unwrap();
|
||||
@ -1043,14 +1034,8 @@ mod test {
|
||||
fn test_send_menu() {
|
||||
let cols = vec!["send".to_string(), "name".to_string()];
|
||||
let vals = vec![
|
||||
Value::String {
|
||||
val: "Menu".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "history_menu".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("Menu", Span::test_data()),
|
||||
Value::string("history_menu", Span::test_data()),
|
||||
];
|
||||
|
||||
let span = Span::test_data();
|
||||
@ -1076,14 +1061,8 @@ mod test {
|
||||
// Menu event
|
||||
let cols = vec!["send".to_string(), "name".to_string()];
|
||||
let vals = vec![
|
||||
Value::String {
|
||||
val: "Menu".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "history_menu".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("Menu", Span::test_data()),
|
||||
Value::string("history_menu", Span::test_data()),
|
||||
];
|
||||
|
||||
let menu_event = Value::Record {
|
||||
@ -1094,10 +1073,7 @@ mod test {
|
||||
|
||||
// Enter event
|
||||
let cols = vec!["send".to_string()];
|
||||
let vals = vec![Value::String {
|
||||
val: "Enter".to_string(),
|
||||
span: Span::test_data(),
|
||||
}];
|
||||
let vals = vec![Value::string("Enter", Span::test_data())];
|
||||
|
||||
let enter_event = Value::Record {
|
||||
cols,
|
||||
@ -1138,14 +1114,8 @@ mod test {
|
||||
// Menu event
|
||||
let cols = vec!["send".to_string(), "name".to_string()];
|
||||
let vals = vec![
|
||||
Value::String {
|
||||
val: "Menu".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "history_menu".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("Menu", Span::test_data()),
|
||||
Value::string("history_menu", Span::test_data()),
|
||||
];
|
||||
|
||||
let menu_event = Value::Record {
|
||||
@ -1156,10 +1126,7 @@ mod test {
|
||||
|
||||
// Enter event
|
||||
let cols = vec!["send".to_string()];
|
||||
let vals = vec![Value::String {
|
||||
val: "Enter".to_string(),
|
||||
span: Span::test_data(),
|
||||
}];
|
||||
let vals = vec![Value::string("Enter", Span::test_data())];
|
||||
|
||||
let enter_event = Value::Record {
|
||||
cols,
|
||||
@ -1187,10 +1154,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_error() {
|
||||
let cols = vec!["not_exist".to_string()];
|
||||
let vals = vec![Value::String {
|
||||
val: "Enter".to_string(),
|
||||
span: Span::test_data(),
|
||||
}];
|
||||
let vals = vec![Value::string("Enter", Span::test_data())];
|
||||
|
||||
let span = Span::test_data();
|
||||
let b = EventType::try_from_columns(&cols, &vals, &span);
|
||||
|
@ -5,11 +5,9 @@ use crate::{
|
||||
util::{eval_source, get_guaranteed_cwd, report_error, report_error_new},
|
||||
NuHighlighter, NuValidator, NushellPrompt,
|
||||
};
|
||||
use fancy_regex::Regex;
|
||||
use lazy_static::lazy_static;
|
||||
use log::{info, trace, warn};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use nu_color_config::get_color_config;
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_engine::{convert_env_values, eval_block, eval_block_with_early_return};
|
||||
use nu_parser::{lex, parse, trim_quotes_str};
|
||||
use nu_protocol::{
|
||||
@ -74,19 +72,10 @@ pub fn evaluate_repl(
|
||||
// seed env vars
|
||||
stack.add_env_var(
|
||||
"CMD_DURATION_MS".into(),
|
||||
Value::String {
|
||||
val: "0823".to_string(),
|
||||
span: Span { start: 0, end: 0 },
|
||||
},
|
||||
Value::string("0823", Span::unknown()),
|
||||
);
|
||||
|
||||
stack.add_env_var(
|
||||
"LAST_EXIT_CODE".into(),
|
||||
Value::Int {
|
||||
val: 0,
|
||||
span: Span { start: 0, end: 0 },
|
||||
},
|
||||
);
|
||||
stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(0, Span::unknown()));
|
||||
|
||||
info!(
|
||||
"load config initially {}:{}:{}",
|
||||
@ -149,7 +138,7 @@ pub fn evaluate_repl(
|
||||
stack,
|
||||
s.item.as_bytes(),
|
||||
&format!("entry #{}", entry_num),
|
||||
PipelineData::new(Span::new(0, 0)),
|
||||
PipelineData::empty(),
|
||||
);
|
||||
engine_state.merge_env(stack, get_guaranteed_cwd(engine_state, stack))?;
|
||||
}
|
||||
@ -183,8 +172,6 @@ pub fn evaluate_repl(
|
||||
|
||||
info!("setup colors {}:{}:{}", file!(), line!(), column!());
|
||||
|
||||
let color_hm = get_color_config(config);
|
||||
|
||||
info!("update reedline {}:{}:{}", file!(), line!(), column!());
|
||||
let engine_reference = std::sync::Arc::new(engine_state.clone());
|
||||
line_editor = line_editor
|
||||
@ -203,10 +190,14 @@ pub fn evaluate_repl(
|
||||
.with_partial_completions(config.partial_completions)
|
||||
.with_ansi_colors(config.use_ansi_coloring);
|
||||
|
||||
let style_computer = StyleComputer::from_config(engine_state, stack);
|
||||
|
||||
line_editor = if config.use_ansi_coloring {
|
||||
line_editor.with_hinter(Box::new(
|
||||
DefaultHinter::default().with_style(color_hm["hints"]),
|
||||
))
|
||||
line_editor.with_hinter(Box::new({
|
||||
// As of Nov 2022, "hints" color_config closures only get `null` passed in.
|
||||
let style = style_computer.compute("hints", &Value::nothing(Span::unknown()));
|
||||
DefaultHinter::default().with_style(style)
|
||||
}))
|
||||
} else {
|
||||
line_editor.disable_hints()
|
||||
};
|
||||
@ -375,7 +366,7 @@ pub fn evaluate_repl(
|
||||
"OLDPWD".into(),
|
||||
Value::String {
|
||||
val: cwd.clone(),
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
|
||||
@ -385,7 +376,7 @@ pub fn evaluate_repl(
|
||||
"PWD".into(),
|
||||
Value::String {
|
||||
val: path.clone(),
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
let cwd = Value::String { val: cwd, span };
|
||||
@ -431,7 +422,7 @@ pub fn evaluate_repl(
|
||||
stack,
|
||||
s.as_bytes(),
|
||||
&format!("entry #{}", entry_num),
|
||||
PipelineData::new(Span::new(0, 0)),
|
||||
PipelineData::empty(),
|
||||
);
|
||||
}
|
||||
let cmd_duration = start_time.elapsed();
|
||||
@ -440,7 +431,7 @@ pub fn evaluate_repl(
|
||||
"CMD_DURATION_MS".into(),
|
||||
Value::String {
|
||||
val: format!("{}", cmd_duration.as_millis()),
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
},
|
||||
);
|
||||
|
||||
@ -637,7 +628,7 @@ pub fn eval_string_with_input(
|
||||
|
||||
let input_as_pipeline_data = match input {
|
||||
Some(input) => PipelineData::Value(input, None),
|
||||
None => PipelineData::new(Span::test_data()),
|
||||
None => PipelineData::empty(),
|
||||
};
|
||||
|
||||
eval_block(
|
||||
@ -718,11 +709,18 @@ pub fn eval_hook(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let value_span = value.span()?;
|
||||
|
||||
// Hooks can optionally be a record in this form:
|
||||
// {
|
||||
// condition: {|before, after| ... } # block that evaluates to true/false
|
||||
// code: # block or a string
|
||||
// }
|
||||
// The condition block will be run to check whether the main hook (in `code`) should be run.
|
||||
// If it returns true (the default if a condition block is not specified), the hook should be run.
|
||||
let condition_path = PathMember::String {
|
||||
val: "condition".to_string(),
|
||||
span: value_span,
|
||||
};
|
||||
let mut output = PipelineData::new(Span::new(0, 0));
|
||||
let mut output = PipelineData::empty();
|
||||
|
||||
let code_path = PathMember::String {
|
||||
val: "code".to_string(),
|
||||
@ -757,16 +755,19 @@ pub fn eval_hook(
|
||||
arguments.clone(),
|
||||
block_span,
|
||||
) {
|
||||
Ok(value) => match value {
|
||||
Value::Bool { val, .. } => val,
|
||||
other => {
|
||||
Ok(pipeline_data) => {
|
||||
if let PipelineData::Value(Value::Bool { val, .. }, ..) =
|
||||
pipeline_data
|
||||
{
|
||||
val
|
||||
} else {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"boolean output".to_string(),
|
||||
format!("{}", other.get_type()),
|
||||
other.span()?,
|
||||
"other PipelineData variant".to_string(),
|
||||
block_span,
|
||||
));
|
||||
}
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
@ -823,7 +824,7 @@ pub fn eval_hook(
|
||||
};
|
||||
|
||||
engine_state.merge_delta(delta)?;
|
||||
let input = PipelineData::new(value_span);
|
||||
let input = PipelineData::empty();
|
||||
|
||||
let var_ids: Vec<VarId> = vars
|
||||
.into_iter()
|
||||
@ -889,34 +890,28 @@ pub fn eval_hook(
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
output = PipelineData::Value(
|
||||
run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
*block_id,
|
||||
input,
|
||||
arguments,
|
||||
*block_span,
|
||||
)?,
|
||||
None,
|
||||
);
|
||||
output = run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
*block_id,
|
||||
input,
|
||||
arguments,
|
||||
*block_span,
|
||||
)?;
|
||||
}
|
||||
Value::Closure {
|
||||
val: block_id,
|
||||
span: block_span,
|
||||
..
|
||||
} => {
|
||||
output = PipelineData::Value(
|
||||
run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
*block_id,
|
||||
input,
|
||||
arguments,
|
||||
*block_span,
|
||||
)?,
|
||||
None,
|
||||
);
|
||||
output = run_hook_block(
|
||||
engine_state,
|
||||
stack,
|
||||
*block_id,
|
||||
input,
|
||||
arguments,
|
||||
*block_span,
|
||||
)?;
|
||||
}
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
@ -933,17 +928,17 @@ pub fn eval_hook(
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn run_hook_block(
|
||||
fn run_hook_block(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
block_id: BlockId,
|
||||
optional_input: Option<PipelineData>,
|
||||
arguments: Vec<(String, Value)>,
|
||||
span: Span,
|
||||
) -> Result<Value, ShellError> {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let block = engine_state.get_block(block_id);
|
||||
|
||||
let input = optional_input.unwrap_or_else(|| PipelineData::new(span));
|
||||
let input = optional_input.unwrap_or_else(PipelineData::empty);
|
||||
|
||||
let mut callee_stack = stack.gather_captures(&block.captures);
|
||||
|
||||
@ -964,28 +959,28 @@ pub fn run_hook_block(
|
||||
|
||||
match eval_block_with_early_return(engine_state, &mut callee_stack, block, input, false, false)
|
||||
{
|
||||
Ok(pipeline_data) => match pipeline_data.into_value(span) {
|
||||
Value::Error { error } => Err(error),
|
||||
val => {
|
||||
// If all went fine, preserve the environment of the called block
|
||||
let caller_env_vars = stack.get_env_var_names(engine_state);
|
||||
|
||||
// remove env vars that are present in the caller but not in the callee
|
||||
// (the callee hid them)
|
||||
for var in caller_env_vars.iter() {
|
||||
if !callee_stack.has_env_var(engine_state, var) {
|
||||
stack.remove_env_var(engine_state, var);
|
||||
}
|
||||
}
|
||||
|
||||
// add new env vars from callee to caller
|
||||
for (var, value) in callee_stack.get_stack_env_vars() {
|
||||
stack.add_env_var(var, value);
|
||||
}
|
||||
|
||||
Ok(val)
|
||||
Ok(pipeline_data) => {
|
||||
if let PipelineData::Value(Value::Error { error }, _) = pipeline_data {
|
||||
return Err(error);
|
||||
}
|
||||
},
|
||||
|
||||
// If all went fine, preserve the environment of the called block
|
||||
let caller_env_vars = stack.get_env_var_names(engine_state);
|
||||
|
||||
// remove env vars that are present in the caller but not in the callee
|
||||
// (the callee hid them)
|
||||
for var in caller_env_vars.iter() {
|
||||
if !callee_stack.has_env_var(engine_state, var) {
|
||||
stack.remove_env_var(engine_state, var);
|
||||
}
|
||||
}
|
||||
|
||||
// add new env vars from callee to caller
|
||||
for (var, value) in callee_stack.get_stack_env_vars() {
|
||||
stack.add_env_var(var, value);
|
||||
}
|
||||
Ok(pipeline_data)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
@ -997,7 +992,7 @@ fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> {
|
||||
return Err(ShellError::GenericError(
|
||||
"Error writing ansi sequence".into(),
|
||||
err.to_string(),
|
||||
Some(Span { start: 0, end: 0 }),
|
||||
Some(Span::unknown()),
|
||||
None,
|
||||
Vec::new(),
|
||||
));
|
||||
@ -1007,18 +1002,19 @@ fn run_ansi_sequence(seq: &str) -> Result<(), ShellError> {
|
||||
ShellError::GenericError(
|
||||
"Error flushing stdio".into(),
|
||||
e.to_string(),
|
||||
Some(Span { start: 0, end: 0 }),
|
||||
Some(Span::unknown()),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
// Absolute paths with a drive letter, like 'C:', 'D:\', 'E:\foo'
|
||||
static ref DRIVE_PATH_REGEX: Regex =
|
||||
Regex::new(r"^[a-zA-Z]:[/\\]?").expect("Internal error: regex creation");
|
||||
}
|
||||
// Absolute paths with a drive letter, like 'C:', 'D:\', 'E:\foo'
|
||||
#[cfg(windows)]
|
||||
static DRIVE_PATH_REGEX: once_cell::sync::Lazy<fancy_regex::Regex> =
|
||||
once_cell::sync::Lazy::new(|| {
|
||||
fancy_regex::Regex::new(r"^[a-zA-Z]:[/\\]?").expect("Internal error: regex creation")
|
||||
});
|
||||
|
||||
// A best-effort "does this string look kinda like a path?" function to determine whether to auto-cd
|
||||
fn looks_like_path(orig: &str) -> bool {
|
||||
|
@ -149,7 +149,7 @@ fn split_span_by_highlight_positions(
|
||||
for pos in highlight_positions {
|
||||
if start <= *pos && pos < &span.end {
|
||||
if start < *pos {
|
||||
result.push((Span { start, end: *pos }, false));
|
||||
result.push((Span::new(start, *pos), false));
|
||||
}
|
||||
let span_str = &line[pos - global_span_offset..span.end - global_span_offset];
|
||||
let end = span_str
|
||||
@ -157,18 +157,12 @@ fn split_span_by_highlight_positions(
|
||||
.next()
|
||||
.map(|c| pos + get_char_length(c))
|
||||
.unwrap_or(pos + 1);
|
||||
result.push((Span { start: *pos, end }, true));
|
||||
result.push((Span::new(*pos, end), true));
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
if start < span.end {
|
||||
result.push((
|
||||
Span {
|
||||
start,
|
||||
end: span.end,
|
||||
},
|
||||
false,
|
||||
));
|
||||
result.push((Span::new(start, span.end), false));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ pub fn eval_source(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = pipeline_data.print(engine_state, stack, false, false);
|
||||
result = pipeline_data.print(engine_state, stack, true, false);
|
||||
}
|
||||
|
||||
match result {
|
||||
@ -289,10 +289,7 @@ pub fn eval_source(
|
||||
fn set_last_exit_code(stack: &mut Stack, exit_code: i64) {
|
||||
stack.add_env_var(
|
||||
"LAST_EXIT_CODE".to_string(),
|
||||
Value::Int {
|
||||
val: exit_code,
|
||||
span: Span { start: 0, end: 0 },
|
||||
},
|
||||
Value::int(exit_code, Span::unknown()),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use nu_parser::parse;
|
||||
use nu_protocol::engine::StateWorkingSet;
|
||||
use reedline::{Completer, Suggestion};
|
||||
use rstest::{fixture, rstest};
|
||||
use support::{file, folder, match_suggestions, new_engine};
|
||||
use support::{completions_helpers::new_quote_engine, file, folder, match_suggestions, new_engine};
|
||||
|
||||
#[fixture]
|
||||
fn completer() -> NuCompleter {
|
||||
@ -411,6 +411,24 @@ fn command_watch_with_filecompletion() {
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_completion_quoted() {
|
||||
let (_, _, engine, stack) = new_quote_engine();
|
||||
|
||||
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
||||
|
||||
let target_dir = "open ";
|
||||
let suggestions = completer.complete(target_dir, target_dir.len());
|
||||
|
||||
let expected_paths: Vec<String> = vec![
|
||||
"`te st.txt`".to_string(),
|
||||
"`te#st.txt`".to_string(),
|
||||
"`te'st.txt`".to_string(),
|
||||
];
|
||||
|
||||
match_suggestions(expected_paths, suggestions)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_completions() {
|
||||
// Create a new engine
|
||||
|
@ -33,20 +33,53 @@ pub fn new_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
"PWD".to_string(),
|
||||
Value::String {
|
||||
val: dir_str.clone(),
|
||||
span: nu_protocol::Span {
|
||||
start: 0,
|
||||
end: dir_str.len(),
|
||||
},
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
);
|
||||
stack.add_env_var(
|
||||
"TEST".to_string(),
|
||||
Value::String {
|
||||
val: "NUSHELL".to_string(),
|
||||
span: nu_protocol::Span {
|
||||
start: 0,
|
||||
end: dir_str.len(),
|
||||
},
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
);
|
||||
|
||||
// Merge environment into the permanent state
|
||||
let merge_result = engine_state.merge_env(&mut stack, &dir);
|
||||
assert!(merge_result.is_ok());
|
||||
|
||||
(dir, dir_str, engine_state, stack)
|
||||
}
|
||||
|
||||
pub fn new_quote_engine() -> (PathBuf, String, EngineState, Stack) {
|
||||
// Target folder inside assets
|
||||
let dir = fs::fixtures().join("quoted_completions");
|
||||
let mut dir_str = dir
|
||||
.clone()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap_or_default();
|
||||
dir_str.push(SEP);
|
||||
|
||||
// Create a new engine with default context
|
||||
let mut engine_state = create_default_context();
|
||||
|
||||
// New stack
|
||||
let mut stack = Stack::new();
|
||||
|
||||
// Add pwd as env var
|
||||
stack.add_env_var(
|
||||
"PWD".to_string(),
|
||||
Value::String {
|
||||
val: dir_str.clone(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
);
|
||||
stack.add_env_var(
|
||||
"TEST".to_string(),
|
||||
Value::String {
|
||||
val: "NUSHELL".to_string(),
|
||||
span: nu_protocol::Span::new(0, dir_str.len()),
|
||||
},
|
||||
);
|
||||
|
||||
@ -112,7 +145,7 @@ pub fn merge_input(
|
||||
&block,
|
||||
PipelineData::Value(
|
||||
Value::Nothing {
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
},
|
||||
None
|
||||
),
|
||||
|
@ -5,11 +5,18 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-color-config"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.72.0" }
|
||||
nu-ansi-term = "0.46.0"
|
||||
nu-json = { path = "../nu-json", version = "0.72.0" }
|
||||
nu-table = { path = "../nu-table", version = "0.72.0" }
|
||||
serde = { version="1.0.123", features=["derive"] }
|
||||
# used only for text_style Alignments
|
||||
tabled = { version = "0.10.0", features = ["color"], default-features = false }
|
||||
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.73.0" }
|
||||
nu-ansi-term = "0.46.0"
|
||||
nu-utils = { path = "../nu-utils", version = "0.73.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.73.0" }
|
||||
nu-json = { path="../nu-json", version = "0.73.0" }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path="../nu-test-support", version = "0.73.0" }
|
||||
|
@ -1,413 +1,89 @@
|
||||
use crate::nu_style::{color_from_hex, color_string_to_nustyle};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_protocol::Config;
|
||||
use nu_table::{Alignment, TextStyle};
|
||||
use crate::{
|
||||
nu_style::{color_from_hex, lookup_style},
|
||||
parse_nustyle, NuStyle,
|
||||
};
|
||||
use nu_ansi_term::Style;
|
||||
use nu_protocol::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn lookup_ansi_color_style(s: &str) -> Style {
|
||||
if s.starts_with('#') {
|
||||
match color_from_hex(s) {
|
||||
Ok(c) => match c {
|
||||
Some(c) => c.normal(),
|
||||
None => Style::default(),
|
||||
},
|
||||
Err(_) => Style::default(),
|
||||
}
|
||||
color_from_hex(s)
|
||||
.ok()
|
||||
.and_then(|c| c.map(|c| c.normal()))
|
||||
.unwrap_or_default()
|
||||
} else if s.starts_with('{') {
|
||||
color_string_to_nustyle(s.to_string())
|
||||
} else {
|
||||
match s {
|
||||
"g" | "green" => Color::Green.normal(),
|
||||
"gb" | "green_bold" => Color::Green.bold(),
|
||||
"gu" | "green_underline" => Color::Green.underline(),
|
||||
"gi" | "green_italic" => Color::Green.italic(),
|
||||
"gd" | "green_dimmed" => Color::Green.dimmed(),
|
||||
"gr" | "green_reverse" => Color::Green.reverse(),
|
||||
"gbl" | "green_blink" => Color::Green.blink(),
|
||||
"gst" | "green_strike" => Color::Green.strikethrough(),
|
||||
|
||||
"lg" | "light_green" => Color::LightGreen.normal(),
|
||||
"lgb" | "light_green_bold" => Color::LightGreen.bold(),
|
||||
"lgu" | "light_green_underline" => Color::LightGreen.underline(),
|
||||
"lgi" | "light_green_italic" => Color::LightGreen.italic(),
|
||||
"lgd" | "light_green_dimmed" => Color::LightGreen.dimmed(),
|
||||
"lgr" | "light_green_reverse" => Color::LightGreen.reverse(),
|
||||
"lgbl" | "light_green_blink" => Color::LightGreen.blink(),
|
||||
"lgst" | "light_green_strike" => Color::LightGreen.strikethrough(),
|
||||
|
||||
"r" | "red" => Color::Red.normal(),
|
||||
"rb" | "red_bold" => Color::Red.bold(),
|
||||
"ru" | "red_underline" => Color::Red.underline(),
|
||||
"ri" | "red_italic" => Color::Red.italic(),
|
||||
"rd" | "red_dimmed" => Color::Red.dimmed(),
|
||||
"rr" | "red_reverse" => Color::Red.reverse(),
|
||||
"rbl" | "red_blink" => Color::Red.blink(),
|
||||
"rst" | "red_strike" => Color::Red.strikethrough(),
|
||||
|
||||
"lr" | "light_red" => Color::LightRed.normal(),
|
||||
"lrb" | "light_red_bold" => Color::LightRed.bold(),
|
||||
"lru" | "light_red_underline" => Color::LightRed.underline(),
|
||||
"lri" | "light_red_italic" => Color::LightRed.italic(),
|
||||
"lrd" | "light_red_dimmed" => Color::LightRed.dimmed(),
|
||||
"lrr" | "light_red_reverse" => Color::LightRed.reverse(),
|
||||
"lrbl" | "light_red_blink" => Color::LightRed.blink(),
|
||||
"lrst" | "light_red_strike" => Color::LightRed.strikethrough(),
|
||||
|
||||
"u" | "blue" => Color::Blue.normal(),
|
||||
"ub" | "blue_bold" => Color::Blue.bold(),
|
||||
"uu" | "blue_underline" => Color::Blue.underline(),
|
||||
"ui" | "blue_italic" => Color::Blue.italic(),
|
||||
"ud" | "blue_dimmed" => Color::Blue.dimmed(),
|
||||
"ur" | "blue_reverse" => Color::Blue.reverse(),
|
||||
"ubl" | "blue_blink" => Color::Blue.blink(),
|
||||
"ust" | "blue_strike" => Color::Blue.strikethrough(),
|
||||
|
||||
"lu" | "light_blue" => Color::LightBlue.normal(),
|
||||
"lub" | "light_blue_bold" => Color::LightBlue.bold(),
|
||||
"luu" | "light_blue_underline" => Color::LightBlue.underline(),
|
||||
"lui" | "light_blue_italic" => Color::LightBlue.italic(),
|
||||
"lud" | "light_blue_dimmed" => Color::LightBlue.dimmed(),
|
||||
"lur" | "light_blue_reverse" => Color::LightBlue.reverse(),
|
||||
"lubl" | "light_blue_blink" => Color::LightBlue.blink(),
|
||||
"lust" | "light_blue_strike" => Color::LightBlue.strikethrough(),
|
||||
|
||||
"b" | "black" => Color::Black.normal(),
|
||||
"bb" | "black_bold" => Color::Black.bold(),
|
||||
"bu" | "black_underline" => Color::Black.underline(),
|
||||
"bi" | "black_italic" => Color::Black.italic(),
|
||||
"bd" | "black_dimmed" => Color::Black.dimmed(),
|
||||
"br" | "black_reverse" => Color::Black.reverse(),
|
||||
"bbl" | "black_blink" => Color::Black.blink(),
|
||||
"bst" | "black_strike" => Color::Black.strikethrough(),
|
||||
|
||||
"ligr" | "light_gray" => Color::LightGray.normal(),
|
||||
"ligrb" | "light_gray_bold" => Color::LightGray.bold(),
|
||||
"ligru" | "light_gray_underline" => Color::LightGray.underline(),
|
||||
"ligri" | "light_gray_italic" => Color::LightGray.italic(),
|
||||
"ligrd" | "light_gray_dimmed" => Color::LightGray.dimmed(),
|
||||
"ligrr" | "light_gray_reverse" => Color::LightGray.reverse(),
|
||||
"ligrbl" | "light_gray_blink" => Color::LightGray.blink(),
|
||||
"ligrst" | "light_gray_strike" => Color::LightGray.strikethrough(),
|
||||
|
||||
"y" | "yellow" => Color::Yellow.normal(),
|
||||
"yb" | "yellow_bold" => Color::Yellow.bold(),
|
||||
"yu" | "yellow_underline" => Color::Yellow.underline(),
|
||||
"yi" | "yellow_italic" => Color::Yellow.italic(),
|
||||
"yd" | "yellow_dimmed" => Color::Yellow.dimmed(),
|
||||
"yr" | "yellow_reverse" => Color::Yellow.reverse(),
|
||||
"ybl" | "yellow_blink" => Color::Yellow.blink(),
|
||||
"yst" | "yellow_strike" => Color::Yellow.strikethrough(),
|
||||
|
||||
"ly" | "light_yellow" => Color::LightYellow.normal(),
|
||||
"lyb" | "light_yellow_bold" => Color::LightYellow.bold(),
|
||||
"lyu" | "light_yellow_underline" => Color::LightYellow.underline(),
|
||||
"lyi" | "light_yellow_italic" => Color::LightYellow.italic(),
|
||||
"lyd" | "light_yellow_dimmed" => Color::LightYellow.dimmed(),
|
||||
"lyr" | "light_yellow_reverse" => Color::LightYellow.reverse(),
|
||||
"lybl" | "light_yellow_blink" => Color::LightYellow.blink(),
|
||||
"lyst" | "light_yellow_strike" => Color::LightYellow.strikethrough(),
|
||||
|
||||
"p" | "purple" => Color::Purple.normal(),
|
||||
"pb" | "purple_bold" => Color::Purple.bold(),
|
||||
"pu" | "purple_underline" => Color::Purple.underline(),
|
||||
"pi" | "purple_italic" => Color::Purple.italic(),
|
||||
"pd" | "purple_dimmed" => Color::Purple.dimmed(),
|
||||
"pr" | "purple_reverse" => Color::Purple.reverse(),
|
||||
"pbl" | "purple_blink" => Color::Purple.blink(),
|
||||
"pst" | "purple_strike" => Color::Purple.strikethrough(),
|
||||
|
||||
"lp" | "light_purple" => Color::LightPurple.normal(),
|
||||
"lpb" | "light_purple_bold" => Color::LightPurple.bold(),
|
||||
"lpu" | "light_purple_underline" => Color::LightPurple.underline(),
|
||||
"lpi" | "light_purple_italic" => Color::LightPurple.italic(),
|
||||
"lpd" | "light_purple_dimmed" => Color::LightPurple.dimmed(),
|
||||
"lpr" | "light_purple_reverse" => Color::LightPurple.reverse(),
|
||||
"lpbl" | "light_purple_blink" => Color::LightPurple.blink(),
|
||||
"lpst" | "light_purple_strike" => Color::LightPurple.strikethrough(),
|
||||
|
||||
"c" | "cyan" => Color::Cyan.normal(),
|
||||
"cb" | "cyan_bold" => Color::Cyan.bold(),
|
||||
"cu" | "cyan_underline" => Color::Cyan.underline(),
|
||||
"ci" | "cyan_italic" => Color::Cyan.italic(),
|
||||
"cd" | "cyan_dimmed" => Color::Cyan.dimmed(),
|
||||
"cr" | "cyan_reverse" => Color::Cyan.reverse(),
|
||||
"cbl" | "cyan_blink" => Color::Cyan.blink(),
|
||||
"cst" | "cyan_strike" => Color::Cyan.strikethrough(),
|
||||
|
||||
"lc" | "light_cyan" => Color::LightCyan.normal(),
|
||||
"lcb" | "light_cyan_bold" => Color::LightCyan.bold(),
|
||||
"lcu" | "light_cyan_underline" => Color::LightCyan.underline(),
|
||||
"lci" | "light_cyan_italic" => Color::LightCyan.italic(),
|
||||
"lcd" | "light_cyan_dimmed" => Color::LightCyan.dimmed(),
|
||||
"lcr" | "light_cyan_reverse" => Color::LightCyan.reverse(),
|
||||
"lcbl" | "light_cyan_blink" => Color::LightCyan.blink(),
|
||||
"lcst" | "light_cyan_strike" => Color::LightCyan.strikethrough(),
|
||||
|
||||
"w" | "white" => Color::White.normal(),
|
||||
"wb" | "white_bold" => Color::White.bold(),
|
||||
"wu" | "white_underline" => Color::White.underline(),
|
||||
"wi" | "white_italic" => Color::White.italic(),
|
||||
"wd" | "white_dimmed" => Color::White.dimmed(),
|
||||
"wr" | "white_reverse" => Color::White.reverse(),
|
||||
"wbl" | "white_blink" => Color::White.blink(),
|
||||
"wst" | "white_strike" => Color::White.strikethrough(),
|
||||
|
||||
"dgr" | "dark_gray" => Color::DarkGray.normal(),
|
||||
"dgrb" | "dark_gray_bold" => Color::DarkGray.bold(),
|
||||
"dgru" | "dark_gray_underline" => Color::DarkGray.underline(),
|
||||
"dgri" | "dark_gray_italic" => Color::DarkGray.italic(),
|
||||
"dgrd" | "dark_gray_dimmed" => Color::DarkGray.dimmed(),
|
||||
"dgrr" | "dark_gray_reverse" => Color::DarkGray.reverse(),
|
||||
"dgrbl" | "dark_gray_blink" => Color::DarkGray.blink(),
|
||||
"dgrst" | "dark_gray_strike" => Color::DarkGray.strikethrough(),
|
||||
|
||||
"def" | "default" => Color::Default.normal(),
|
||||
"defb" | "default_bold" => Color::Default.bold(),
|
||||
"defu" | "default_underline" => Color::Default.underline(),
|
||||
"defi" | "default_italic" => Color::Default.italic(),
|
||||
"defd" | "default_dimmed" => Color::Default.dimmed(),
|
||||
"defr" | "default_reverse" => Color::Default.reverse(),
|
||||
|
||||
_ => Color::White.normal(),
|
||||
}
|
||||
lookup_style(s)
|
||||
}
|
||||
}
|
||||
|
||||
fn update_hashmap(key: &str, val: &str, hm: &mut HashMap<String, Style>) {
|
||||
// eprintln!("key: {}, val: {}", &key, &val);
|
||||
let color = lookup_ansi_color_style(val);
|
||||
if let Some(v) = hm.get_mut(key) {
|
||||
*v = color;
|
||||
} else {
|
||||
hm.insert(key.to_string(), color);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_color_config(config: &Config) -> HashMap<String, Style> {
|
||||
let config = config;
|
||||
|
||||
// create the hashmap
|
||||
pub fn get_color_map(colors: &HashMap<String, Value>) -> HashMap<String, Style> {
|
||||
let mut hm: HashMap<String, Style> = HashMap::new();
|
||||
// set some defaults
|
||||
// hm.insert("primitive_line".to_string(), Color::White.normal());
|
||||
// hm.insert("primitive_pattern".to_string(), Color::White.normal());
|
||||
// hm.insert("primitive_path".to_string(), Color::White.normal());
|
||||
hm.insert("separator".to_string(), Color::White.normal());
|
||||
hm.insert(
|
||||
"leading_trailing_space_bg".to_string(),
|
||||
Style::default().on(Color::Rgb(128, 128, 128)),
|
||||
);
|
||||
hm.insert("header".to_string(), Color::Green.bold());
|
||||
hm.insert("empty".to_string(), Color::Blue.normal());
|
||||
hm.insert("bool".to_string(), Color::White.normal());
|
||||
hm.insert("int".to_string(), Color::White.normal());
|
||||
hm.insert("filesize".to_string(), Color::White.normal());
|
||||
hm.insert("duration".to_string(), Color::White.normal());
|
||||
hm.insert("date".to_string(), Color::White.normal());
|
||||
hm.insert("range".to_string(), Color::White.normal());
|
||||
hm.insert("float".to_string(), Color::White.normal());
|
||||
hm.insert("string".to_string(), Color::White.normal());
|
||||
hm.insert("nothing".to_string(), Color::White.normal());
|
||||
hm.insert("binary".to_string(), Color::White.normal());
|
||||
hm.insert("cellpath".to_string(), Color::White.normal());
|
||||
hm.insert("row_index".to_string(), Color::Green.bold());
|
||||
hm.insert("record".to_string(), Color::White.normal());
|
||||
hm.insert("list".to_string(), Color::White.normal());
|
||||
hm.insert("block".to_string(), Color::White.normal());
|
||||
hm.insert("hints".to_string(), Color::DarkGray.normal());
|
||||
|
||||
for (key, value) in &config.color_config {
|
||||
match value.as_string() {
|
||||
Ok(value) => update_hashmap(key, &value, &mut hm),
|
||||
Err(_) => continue,
|
||||
}
|
||||
for (key, value) in colors {
|
||||
parse_map_entry(&mut hm, key, value);
|
||||
}
|
||||
|
||||
hm
|
||||
}
|
||||
|
||||
// This function will assign a text style to a primitive, or really any string that's
|
||||
// in the hashmap. The hashmap actually contains the style to be applied.
|
||||
pub fn style_primitive(primitive: &str, color_hm: &HashMap<String, Style>) -> TextStyle {
|
||||
match primitive {
|
||||
"bool" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"int" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Right, *s),
|
||||
None => TextStyle::basic_right(),
|
||||
}
|
||||
}
|
||||
|
||||
"filesize" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Right, *s),
|
||||
None => TextStyle::basic_right(),
|
||||
}
|
||||
}
|
||||
|
||||
"duration" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"date" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"range" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"float" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Right, *s),
|
||||
None => TextStyle::basic_right(),
|
||||
}
|
||||
}
|
||||
|
||||
"string" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"nothing" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
// not sure what to do with error
|
||||
// "error" => {}
|
||||
"binary" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"cellpath" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
"row_index" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Right, *s),
|
||||
None => TextStyle::new()
|
||||
.alignment(Alignment::Right)
|
||||
.fg(Color::Green)
|
||||
.bold(Some(true)),
|
||||
}
|
||||
}
|
||||
|
||||
"record" | "list" | "block" => {
|
||||
let style = color_hm.get(primitive);
|
||||
match style {
|
||||
Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
None => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
// types in nushell but not in engine-q
|
||||
// "Line" => {
|
||||
// let style = color_hm.get("Primitive::Line");
|
||||
// match style {
|
||||
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
// None => TextStyle::basic_left(),
|
||||
// }
|
||||
// }
|
||||
// "GlobPattern" => {
|
||||
// let style = color_hm.get("Primitive::GlobPattern");
|
||||
// match style {
|
||||
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
// None => TextStyle::basic_left(),
|
||||
// }
|
||||
// }
|
||||
// "FilePath" => {
|
||||
// let style = color_hm.get("Primitive::FilePath");
|
||||
// match style {
|
||||
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
// None => TextStyle::basic_left(),
|
||||
// }
|
||||
// }
|
||||
// "BeginningOfStream" => {
|
||||
// let style = color_hm.get("Primitive::BeginningOfStream");
|
||||
// match style {
|
||||
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
// None => TextStyle::basic_left(),
|
||||
// }
|
||||
// }
|
||||
// "EndOfStream" => {
|
||||
// let style = color_hm.get("Primitive::EndOfStream");
|
||||
// match style {
|
||||
// Some(s) => TextStyle::with_style(Alignment::Left, *s),
|
||||
// None => TextStyle::basic_left(),
|
||||
// }
|
||||
// }
|
||||
_ => TextStyle::basic_left(),
|
||||
fn parse_map_entry(hm: &mut HashMap<String, Style>, key: &str, value: &Value) {
|
||||
let value = match value {
|
||||
Value::String { val, .. } => Some(lookup_ansi_color_style(val)),
|
||||
Value::Record { cols, vals, .. } => get_style_from_value(cols, vals).map(parse_nustyle),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(value) = value {
|
||||
hm.entry(key.to_owned()).or_insert(value);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hm() {
|
||||
use nu_ansi_term::{Color, Style};
|
||||
fn get_style_from_value(cols: &[String], vals: &[Value]) -> Option<NuStyle> {
|
||||
let mut was_set = false;
|
||||
let mut style = NuStyle::from(Style::default());
|
||||
for (col, val) in cols.iter().zip(vals) {
|
||||
match col.as_str() {
|
||||
"bg" => {
|
||||
if let Value::String { val, .. } = val {
|
||||
style.bg = Some(val.clone());
|
||||
was_set = true;
|
||||
}
|
||||
}
|
||||
"fg" => {
|
||||
if let Value::String { val, .. } = val {
|
||||
style.fg = Some(val.clone());
|
||||
was_set = true;
|
||||
}
|
||||
}
|
||||
"attr" => {
|
||||
if let Value::String { val, .. } = val {
|
||||
style.attr = Some(val.clone());
|
||||
was_set = true;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
let mut hm: HashMap<String, Style> = HashMap::new();
|
||||
hm.insert("primitive_int".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_decimal".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_filesize".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_string".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_line".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_columnpath".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_pattern".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_boolean".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_date".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_duration".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_range".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_path".to_string(), Color::White.normal());
|
||||
hm.insert("primitive_binary".to_string(), Color::White.normal());
|
||||
hm.insert("separator".to_string(), Color::White.normal());
|
||||
hm.insert("header_align".to_string(), Color::Green.bold());
|
||||
hm.insert("header".to_string(), Color::Green.bold());
|
||||
hm.insert("header_style".to_string(), Style::default());
|
||||
hm.insert("row_index".to_string(), Color::Green.bold());
|
||||
hm.insert(
|
||||
"leading_trailing_space_bg".to_string(),
|
||||
Style::default().on(Color::Rgb(128, 128, 128)),
|
||||
);
|
||||
|
||||
update_hashmap("primitive_int", "green", &mut hm);
|
||||
|
||||
assert_eq!(hm["primitive_int"], Color::Green.normal());
|
||||
if was_set {
|
||||
Some(style)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn color_string_to_nustyle(color_string: String) -> Style {
|
||||
// eprintln!("color_string: {}", &color_string);
|
||||
if color_string.is_empty() {
|
||||
return Style::default();
|
||||
}
|
||||
|
||||
let nu_style = match nu_json::from_str::<NuStyle>(&color_string) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Style::default(),
|
||||
};
|
||||
|
||||
parse_nustyle(nu_style)
|
||||
}
|
||||
|
@ -2,8 +2,12 @@ mod color_config;
|
||||
mod matching_brackets_style;
|
||||
mod nu_style;
|
||||
mod shape_color;
|
||||
mod style_computer;
|
||||
mod text_style;
|
||||
|
||||
pub use color_config::*;
|
||||
pub use matching_brackets_style::*;
|
||||
pub use nu_style::*;
|
||||
pub use shape_color::*;
|
||||
pub use style_computer::*;
|
||||
pub use text_style::*;
|
||||
|
@ -1,88 +1,113 @@
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use serde::Deserialize;
|
||||
use nu_protocol::Value;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, PartialEq, Eq, Debug)]
|
||||
#[derive(Deserialize, Serialize, PartialEq, Eq, Debug)]
|
||||
pub struct NuStyle {
|
||||
pub fg: Option<String>,
|
||||
pub bg: Option<String>,
|
||||
pub attr: Option<String>,
|
||||
}
|
||||
|
||||
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
|
||||
// get the nu_ansi_term::Color foreground color
|
||||
let fg_color = match nu_style.fg {
|
||||
Some(fg) => color_from_hex(&fg).unwrap_or_default(),
|
||||
_ => None,
|
||||
};
|
||||
// get the nu_ansi_term::Color background color
|
||||
let bg_color = match nu_style.bg {
|
||||
Some(bg) => color_from_hex(&bg).unwrap_or_default(),
|
||||
_ => None,
|
||||
};
|
||||
// get the attributes
|
||||
let color_attr = match nu_style.attr {
|
||||
Some(attr) => attr,
|
||||
_ => "".to_string(),
|
||||
};
|
||||
|
||||
// setup the attributes available in nu_ansi_term::Style
|
||||
let mut bold = false;
|
||||
let mut dimmed = false;
|
||||
let mut italic = false;
|
||||
let mut underline = false;
|
||||
let mut blink = false;
|
||||
let mut reverse = false;
|
||||
let mut hidden = false;
|
||||
let mut strikethrough = false;
|
||||
|
||||
// since we can combine styles like bold-italic, iterate through the chars
|
||||
// and set the bools for later use in the nu_ansi_term::Style application
|
||||
for ch in color_attr.to_lowercase().chars() {
|
||||
match ch {
|
||||
'l' => blink = true,
|
||||
'b' => bold = true,
|
||||
'd' => dimmed = true,
|
||||
'h' => hidden = true,
|
||||
'i' => italic = true,
|
||||
'r' => reverse = true,
|
||||
's' => strikethrough = true,
|
||||
'u' => underline = true,
|
||||
'n' => (),
|
||||
_ => (),
|
||||
impl From<Style> for NuStyle {
|
||||
fn from(s: Style) -> Self {
|
||||
Self {
|
||||
bg: s.background.and_then(color_to_string),
|
||||
fg: s.foreground.and_then(color_to_string),
|
||||
attr: style_get_attr(s),
|
||||
}
|
||||
}
|
||||
|
||||
// here's where we build the nu_ansi_term::Style
|
||||
Style {
|
||||
foreground: fg_color,
|
||||
background: bg_color,
|
||||
is_blink: blink,
|
||||
is_bold: bold,
|
||||
is_dimmed: dimmed,
|
||||
is_hidden: hidden,
|
||||
is_italic: italic,
|
||||
is_reverse: reverse,
|
||||
is_strikethrough: strikethrough,
|
||||
is_underline: underline,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn color_string_to_nustyle(color_string: String) -> Style {
|
||||
// eprintln!("color_string: {}", &color_string);
|
||||
if color_string.chars().count() < 1 {
|
||||
Style::default()
|
||||
} else {
|
||||
let nu_style = match nu_json::from_str::<NuStyle>(&color_string) {
|
||||
Ok(s) => s,
|
||||
Err(_) => NuStyle {
|
||||
fg: None,
|
||||
bg: None,
|
||||
attr: None,
|
||||
},
|
||||
fn style_get_attr(s: Style) -> Option<String> {
|
||||
macro_rules! check {
|
||||
($attrs:expr, $b:expr, $c:expr) => {
|
||||
if $b {
|
||||
$attrs.push($c);
|
||||
}
|
||||
};
|
||||
|
||||
parse_nustyle(nu_style)
|
||||
}
|
||||
|
||||
let mut attrs = String::new();
|
||||
|
||||
check!(attrs, s.is_blink, 'l');
|
||||
check!(attrs, s.is_bold, 'b');
|
||||
check!(attrs, s.is_dimmed, 'd');
|
||||
check!(attrs, s.is_reverse, 'r');
|
||||
check!(attrs, s.is_strikethrough, 's');
|
||||
check!(attrs, s.is_underline, 'u');
|
||||
|
||||
if attrs.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(attrs)
|
||||
}
|
||||
}
|
||||
|
||||
fn color_to_string(color: Color) -> Option<String> {
|
||||
match color {
|
||||
Color::Black => Some(String::from("black")),
|
||||
Color::DarkGray => Some(String::from("dark_gray")),
|
||||
Color::Red => Some(String::from("red")),
|
||||
Color::LightRed => Some(String::from("light_red")),
|
||||
Color::Green => Some(String::from("green")),
|
||||
Color::LightGreen => Some(String::from("light_green")),
|
||||
Color::Yellow => Some(String::from("yellow")),
|
||||
Color::LightYellow => Some(String::from("light_yellow")),
|
||||
Color::Blue => Some(String::from("blue")),
|
||||
Color::LightBlue => Some(String::from("light_blue")),
|
||||
Color::Purple => Some(String::from("purple")),
|
||||
Color::LightPurple => Some(String::from("light_purple")),
|
||||
Color::Magenta => Some(String::from("magenta")),
|
||||
Color::LightMagenta => Some(String::from("light_magenta")),
|
||||
Color::Cyan => Some(String::from("cyan")),
|
||||
Color::LightCyan => Some(String::from("light_cyan")),
|
||||
Color::White => Some(String::from("white")),
|
||||
Color::LightGray => Some(String::from("light_gray")),
|
||||
Color::Default => Some(String::from("default")),
|
||||
Color::Rgb(r, g, b) => Some(format!("#{:X}{:X}{:X}", r, g, b)),
|
||||
Color::Fixed(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_nustyle(nu_style: NuStyle) -> Style {
|
||||
let mut style = Style {
|
||||
foreground: nu_style.fg.and_then(|fg| lookup_color_str(&fg)),
|
||||
background: nu_style.bg.and_then(|bg| lookup_color_str(&bg)),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(attrs) = nu_style.attr {
|
||||
fill_modifiers(&attrs, &mut style)
|
||||
}
|
||||
|
||||
style
|
||||
}
|
||||
|
||||
// Converts the color_config records, { fg, bg, attr }, into a Style.
|
||||
pub fn color_record_to_nustyle(value: &Value) -> Style {
|
||||
let mut fg = None;
|
||||
let mut bg = None;
|
||||
let mut attr = None;
|
||||
let v = value.as_record();
|
||||
if let Ok((cols, inner_vals)) = v {
|
||||
for (k, v) in cols.iter().zip(inner_vals) {
|
||||
// Because config already type-checked the color_config records, this doesn't bother giving errors
|
||||
// if there are unrecognised keys or bad values.
|
||||
if let Ok(v) = v.as_string() {
|
||||
match k.as_str() {
|
||||
"fg" => fg = Some(v),
|
||||
|
||||
"bg" => bg = Some(v),
|
||||
|
||||
"attr" => attr = Some(v),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parse_nustyle(NuStyle { fg, bg, attr })
|
||||
}
|
||||
|
||||
pub fn color_from_hex(
|
||||
@ -101,3 +126,471 @@ pub fn color_from_hex(
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_style(s: &str) -> Style {
|
||||
match s {
|
||||
"g" | "green" => Color::Green.normal(),
|
||||
"gb" | "green_bold" => Color::Green.bold(),
|
||||
"gu" | "green_underline" => Color::Green.underline(),
|
||||
"gi" | "green_italic" => Color::Green.italic(),
|
||||
"gd" | "green_dimmed" => Color::Green.dimmed(),
|
||||
"gr" | "green_reverse" => Color::Green.reverse(),
|
||||
"gbl" | "green_blink" => Color::Green.blink(),
|
||||
"gst" | "green_strike" => Color::Green.strikethrough(),
|
||||
|
||||
"lg" | "light_green" => Color::LightGreen.normal(),
|
||||
"lgb" | "light_green_bold" => Color::LightGreen.bold(),
|
||||
"lgu" | "light_green_underline" => Color::LightGreen.underline(),
|
||||
"lgi" | "light_green_italic" => Color::LightGreen.italic(),
|
||||
"lgd" | "light_green_dimmed" => Color::LightGreen.dimmed(),
|
||||
"lgr" | "light_green_reverse" => Color::LightGreen.reverse(),
|
||||
"lgbl" | "light_green_blink" => Color::LightGreen.blink(),
|
||||
"lgst" | "light_green_strike" => Color::LightGreen.strikethrough(),
|
||||
|
||||
"r" | "red" => Color::Red.normal(),
|
||||
"rb" | "red_bold" => Color::Red.bold(),
|
||||
"ru" | "red_underline" => Color::Red.underline(),
|
||||
"ri" | "red_italic" => Color::Red.italic(),
|
||||
"rd" | "red_dimmed" => Color::Red.dimmed(),
|
||||
"rr" | "red_reverse" => Color::Red.reverse(),
|
||||
"rbl" | "red_blink" => Color::Red.blink(),
|
||||
"rst" | "red_strike" => Color::Red.strikethrough(),
|
||||
|
||||
"lr" | "light_red" => Color::LightRed.normal(),
|
||||
"lrb" | "light_red_bold" => Color::LightRed.bold(),
|
||||
"lru" | "light_red_underline" => Color::LightRed.underline(),
|
||||
"lri" | "light_red_italic" => Color::LightRed.italic(),
|
||||
"lrd" | "light_red_dimmed" => Color::LightRed.dimmed(),
|
||||
"lrr" | "light_red_reverse" => Color::LightRed.reverse(),
|
||||
"lrbl" | "light_red_blink" => Color::LightRed.blink(),
|
||||
"lrst" | "light_red_strike" => Color::LightRed.strikethrough(),
|
||||
|
||||
"u" | "blue" => Color::Blue.normal(),
|
||||
"ub" | "blue_bold" => Color::Blue.bold(),
|
||||
"uu" | "blue_underline" => Color::Blue.underline(),
|
||||
"ui" | "blue_italic" => Color::Blue.italic(),
|
||||
"ud" | "blue_dimmed" => Color::Blue.dimmed(),
|
||||
"ur" | "blue_reverse" => Color::Blue.reverse(),
|
||||
"ubl" | "blue_blink" => Color::Blue.blink(),
|
||||
"ust" | "blue_strike" => Color::Blue.strikethrough(),
|
||||
|
||||
"lu" | "light_blue" => Color::LightBlue.normal(),
|
||||
"lub" | "light_blue_bold" => Color::LightBlue.bold(),
|
||||
"luu" | "light_blue_underline" => Color::LightBlue.underline(),
|
||||
"lui" | "light_blue_italic" => Color::LightBlue.italic(),
|
||||
"lud" | "light_blue_dimmed" => Color::LightBlue.dimmed(),
|
||||
"lur" | "light_blue_reverse" => Color::LightBlue.reverse(),
|
||||
"lubl" | "light_blue_blink" => Color::LightBlue.blink(),
|
||||
"lust" | "light_blue_strike" => Color::LightBlue.strikethrough(),
|
||||
|
||||
"b" | "black" => Color::Black.normal(),
|
||||
"bb" | "black_bold" => Color::Black.bold(),
|
||||
"bu" | "black_underline" => Color::Black.underline(),
|
||||
"bi" | "black_italic" => Color::Black.italic(),
|
||||
"bd" | "black_dimmed" => Color::Black.dimmed(),
|
||||
"br" | "black_reverse" => Color::Black.reverse(),
|
||||
"bbl" | "black_blink" => Color::Black.blink(),
|
||||
"bst" | "black_strike" => Color::Black.strikethrough(),
|
||||
|
||||
"ligr" | "light_gray" => Color::LightGray.normal(),
|
||||
"ligrb" | "light_gray_bold" => Color::LightGray.bold(),
|
||||
"ligru" | "light_gray_underline" => Color::LightGray.underline(),
|
||||
"ligri" | "light_gray_italic" => Color::LightGray.italic(),
|
||||
"ligrd" | "light_gray_dimmed" => Color::LightGray.dimmed(),
|
||||
"ligrr" | "light_gray_reverse" => Color::LightGray.reverse(),
|
||||
"ligrbl" | "light_gray_blink" => Color::LightGray.blink(),
|
||||
"ligrst" | "light_gray_strike" => Color::LightGray.strikethrough(),
|
||||
|
||||
"y" | "yellow" => Color::Yellow.normal(),
|
||||
"yb" | "yellow_bold" => Color::Yellow.bold(),
|
||||
"yu" | "yellow_underline" => Color::Yellow.underline(),
|
||||
"yi" | "yellow_italic" => Color::Yellow.italic(),
|
||||
"yd" | "yellow_dimmed" => Color::Yellow.dimmed(),
|
||||
"yr" | "yellow_reverse" => Color::Yellow.reverse(),
|
||||
"ybl" | "yellow_blink" => Color::Yellow.blink(),
|
||||
"yst" | "yellow_strike" => Color::Yellow.strikethrough(),
|
||||
|
||||
"ly" | "light_yellow" => Color::LightYellow.normal(),
|
||||
"lyb" | "light_yellow_bold" => Color::LightYellow.bold(),
|
||||
"lyu" | "light_yellow_underline" => Color::LightYellow.underline(),
|
||||
"lyi" | "light_yellow_italic" => Color::LightYellow.italic(),
|
||||
"lyd" | "light_yellow_dimmed" => Color::LightYellow.dimmed(),
|
||||
"lyr" | "light_yellow_reverse" => Color::LightYellow.reverse(),
|
||||
"lybl" | "light_yellow_blink" => Color::LightYellow.blink(),
|
||||
"lyst" | "light_yellow_strike" => Color::LightYellow.strikethrough(),
|
||||
|
||||
"p" | "purple" => Color::Purple.normal(),
|
||||
"pb" | "purple_bold" => Color::Purple.bold(),
|
||||
"pu" | "purple_underline" => Color::Purple.underline(),
|
||||
"pi" | "purple_italic" => Color::Purple.italic(),
|
||||
"pd" | "purple_dimmed" => Color::Purple.dimmed(),
|
||||
"pr" | "purple_reverse" => Color::Purple.reverse(),
|
||||
"pbl" | "purple_blink" => Color::Purple.blink(),
|
||||
"pst" | "purple_strike" => Color::Purple.strikethrough(),
|
||||
|
||||
"lp" | "light_purple" => Color::LightPurple.normal(),
|
||||
"lpb" | "light_purple_bold" => Color::LightPurple.bold(),
|
||||
"lpu" | "light_purple_underline" => Color::LightPurple.underline(),
|
||||
"lpi" | "light_purple_italic" => Color::LightPurple.italic(),
|
||||
"lpd" | "light_purple_dimmed" => Color::LightPurple.dimmed(),
|
||||
"lpr" | "light_purple_reverse" => Color::LightPurple.reverse(),
|
||||
"lpbl" | "light_purple_blink" => Color::LightPurple.blink(),
|
||||
"lpst" | "light_purple_strike" => Color::LightPurple.strikethrough(),
|
||||
|
||||
"c" | "cyan" => Color::Cyan.normal(),
|
||||
"cb" | "cyan_bold" => Color::Cyan.bold(),
|
||||
"cu" | "cyan_underline" => Color::Cyan.underline(),
|
||||
"ci" | "cyan_italic" => Color::Cyan.italic(),
|
||||
"cd" | "cyan_dimmed" => Color::Cyan.dimmed(),
|
||||
"cr" | "cyan_reverse" => Color::Cyan.reverse(),
|
||||
"cbl" | "cyan_blink" => Color::Cyan.blink(),
|
||||
"cst" | "cyan_strike" => Color::Cyan.strikethrough(),
|
||||
|
||||
"lc" | "light_cyan" => Color::LightCyan.normal(),
|
||||
"lcb" | "light_cyan_bold" => Color::LightCyan.bold(),
|
||||
"lcu" | "light_cyan_underline" => Color::LightCyan.underline(),
|
||||
"lci" | "light_cyan_italic" => Color::LightCyan.italic(),
|
||||
"lcd" | "light_cyan_dimmed" => Color::LightCyan.dimmed(),
|
||||
"lcr" | "light_cyan_reverse" => Color::LightCyan.reverse(),
|
||||
"lcbl" | "light_cyan_blink" => Color::LightCyan.blink(),
|
||||
"lcst" | "light_cyan_strike" => Color::LightCyan.strikethrough(),
|
||||
|
||||
"w" | "white" => Color::White.normal(),
|
||||
"wb" | "white_bold" => Color::White.bold(),
|
||||
"wu" | "white_underline" => Color::White.underline(),
|
||||
"wi" | "white_italic" => Color::White.italic(),
|
||||
"wd" | "white_dimmed" => Color::White.dimmed(),
|
||||
"wr" | "white_reverse" => Color::White.reverse(),
|
||||
"wbl" | "white_blink" => Color::White.blink(),
|
||||
"wst" | "white_strike" => Color::White.strikethrough(),
|
||||
|
||||
"dgr" | "dark_gray" => Color::DarkGray.normal(),
|
||||
"dgrb" | "dark_gray_bold" => Color::DarkGray.bold(),
|
||||
"dgru" | "dark_gray_underline" => Color::DarkGray.underline(),
|
||||
"dgri" | "dark_gray_italic" => Color::DarkGray.italic(),
|
||||
"dgrd" | "dark_gray_dimmed" => Color::DarkGray.dimmed(),
|
||||
"dgrr" | "dark_gray_reverse" => Color::DarkGray.reverse(),
|
||||
"dgrbl" | "dark_gray_blink" => Color::DarkGray.blink(),
|
||||
"dgrst" | "dark_gray_strike" => Color::DarkGray.strikethrough(),
|
||||
|
||||
"def" | "default" => Color::Default.normal(),
|
||||
"defb" | "default_bold" => Color::Default.bold(),
|
||||
"defu" | "default_underline" => Color::Default.underline(),
|
||||
"defi" | "default_italic" => Color::Default.italic(),
|
||||
"defd" | "default_dimmed" => Color::Default.dimmed(),
|
||||
"defr" | "default_reverse" => Color::Default.reverse(),
|
||||
|
||||
// Add xterm 256 colors adding an x prefix where the name conflicts
|
||||
"xblack" | "xterm_black" => Color::Fixed(0).normal(),
|
||||
"maroon" | "xterm_maroon" => Color::Fixed(1).normal(),
|
||||
"xgreen" | "xterm_green" => Color::Fixed(2).normal(),
|
||||
"olive" | "xterm_olive" => Color::Fixed(3).normal(),
|
||||
"navy" | "xterm_navy" => Color::Fixed(4).normal(),
|
||||
"xpurplea" | "xterm_purplea" => Color::Fixed(5).normal(),
|
||||
"teal" | "xterm_teal" => Color::Fixed(6).normal(),
|
||||
"silver" | "xterm_silver" => Color::Fixed(7).normal(),
|
||||
"grey" | "xterm_grey" => Color::Fixed(8).normal(),
|
||||
"xred" | "xterm_red" => Color::Fixed(9).normal(),
|
||||
"lime" | "xterm_lime" => Color::Fixed(10).normal(),
|
||||
"xyellow" | "xterm_yellow" => Color::Fixed(11).normal(),
|
||||
"xblue" | "xterm_blue" => Color::Fixed(12).normal(),
|
||||
"fuchsia" | "xterm_fuchsia" => Color::Fixed(13).normal(),
|
||||
"aqua" | "xterm_aqua" => Color::Fixed(14).normal(),
|
||||
"xwhite" | "xterm_white" => Color::Fixed(15).normal(),
|
||||
"grey0" | "xterm_grey0" => Color::Fixed(16).normal(),
|
||||
"navyblue" | "xterm_navyblue" => Color::Fixed(17).normal(),
|
||||
"darkblue" | "xterm_darkblue" => Color::Fixed(18).normal(),
|
||||
"blue3a" | "xterm_blue3a" => Color::Fixed(19).normal(),
|
||||
"blue3b" | "xterm_blue3b" => Color::Fixed(20).normal(),
|
||||
"blue1" | "xterm_blue1" => Color::Fixed(21).normal(),
|
||||
"darkgreen" | "xterm_darkgreen" => Color::Fixed(22).normal(),
|
||||
"deepskyblue4a" | "xterm_deepskyblue4a" => Color::Fixed(23).normal(),
|
||||
"deepskyblue4b" | "xterm_deepskyblue4b" => Color::Fixed(24).normal(),
|
||||
"deepskyblue4c" | "xterm_deepskyblue4c" => Color::Fixed(25).normal(),
|
||||
"dodgerblue3" | "xterm_dodgerblue3" => Color::Fixed(26).normal(),
|
||||
"dodgerblue2" | "xterm_dodgerblue2" => Color::Fixed(27).normal(),
|
||||
"green4" | "xterm_green4" => Color::Fixed(28).normal(),
|
||||
"springgreen4" | "xterm_springgreen4" => Color::Fixed(29).normal(),
|
||||
"turquoise4" | "xterm_turquoise4" => Color::Fixed(30).normal(),
|
||||
"deepskyblue3a" | "xterm_deepskyblue3a" => Color::Fixed(31).normal(),
|
||||
"deepskyblue3b" | "xterm_deepskyblue3b" => Color::Fixed(32).normal(),
|
||||
"dodgerblue1" | "xterm_dodgerblue1" => Color::Fixed(33).normal(),
|
||||
"green3a" | "xterm_green3a" => Color::Fixed(34).normal(),
|
||||
"springgreen3a" | "xterm_springgreen3a" => Color::Fixed(35).normal(),
|
||||
"darkcyan" | "xterm_darkcyan" => Color::Fixed(36).normal(),
|
||||
"lightseagreen" | "xterm_lightseagreen" => Color::Fixed(37).normal(),
|
||||
"deepskyblue2" | "xterm_deepskyblue2" => Color::Fixed(38).normal(),
|
||||
"deepskyblue1" | "xterm_deepskyblue1" => Color::Fixed(39).normal(),
|
||||
"green3b" | "xterm_green3b" => Color::Fixed(40).normal(),
|
||||
"springgreen3b" | "xterm_springgreen3b" => Color::Fixed(41).normal(),
|
||||
"springgreen2a" | "xterm_springgreen2a" => Color::Fixed(42).normal(),
|
||||
"cyan3" | "xterm_cyan3" => Color::Fixed(43).normal(),
|
||||
"darkturquoise" | "xterm_darkturquoise" => Color::Fixed(44).normal(),
|
||||
"turquoise2" | "xterm_turquoise2" => Color::Fixed(45).normal(),
|
||||
"green1" | "xterm_green1" => Color::Fixed(46).normal(),
|
||||
"springgreen2b" | "xterm_springgreen2b" => Color::Fixed(47).normal(),
|
||||
"springgreen1" | "xterm_springgreen1" => Color::Fixed(48).normal(),
|
||||
"mediumspringgreen" | "xterm_mediumspringgreen" => Color::Fixed(49).normal(),
|
||||
"cyan2" | "xterm_cyan2" => Color::Fixed(50).normal(),
|
||||
"cyan1" | "xterm_cyan1" => Color::Fixed(51).normal(),
|
||||
"darkreda" | "xterm_darkreda" => Color::Fixed(52).normal(),
|
||||
"deeppink4a" | "xterm_deeppink4a" => Color::Fixed(53).normal(),
|
||||
"purple4a" | "xterm_purple4a" => Color::Fixed(54).normal(),
|
||||
"purple4b" | "xterm_purple4b" => Color::Fixed(55).normal(),
|
||||
"purple3" | "xterm_purple3" => Color::Fixed(56).normal(),
|
||||
"blueviolet" | "xterm_blueviolet" => Color::Fixed(57).normal(),
|
||||
"orange4a" | "xterm_orange4a" => Color::Fixed(58).normal(),
|
||||
"grey37" | "xterm_grey37" => Color::Fixed(59).normal(),
|
||||
"mediumpurple4" | "xterm_mediumpurple4" => Color::Fixed(60).normal(),
|
||||
"slateblue3a" | "xterm_slateblue3a" => Color::Fixed(61).normal(),
|
||||
"slateblue3b" | "xterm_slateblue3b" => Color::Fixed(62).normal(),
|
||||
"royalblue1" | "xterm_royalblue1" => Color::Fixed(63).normal(),
|
||||
"chartreuse4" | "xterm_chartreuse4" => Color::Fixed(64).normal(),
|
||||
"darkseagreen4a" | "xterm_darkseagreen4a" => Color::Fixed(65).normal(),
|
||||
"paleturquoise4" | "xterm_paleturquoise4" => Color::Fixed(66).normal(),
|
||||
"steelblue" | "xterm_steelblue" => Color::Fixed(67).normal(),
|
||||
"steelblue3" | "xterm_steelblue3" => Color::Fixed(68).normal(),
|
||||
"cornflowerblue" | "xterm_cornflowerblue" => Color::Fixed(69).normal(),
|
||||
"chartreuse3a" | "xterm_chartreuse3a" => Color::Fixed(70).normal(),
|
||||
"darkseagreen4b" | "xterm_darkseagreen4b" => Color::Fixed(71).normal(),
|
||||
"cadetbluea" | "xterm_cadetbluea" => Color::Fixed(72).normal(),
|
||||
"cadetblueb" | "xterm_cadetblueb" => Color::Fixed(73).normal(),
|
||||
"skyblue3" | "xterm_skyblue3" => Color::Fixed(74).normal(),
|
||||
"steelblue1a" | "xterm_steelblue1a" => Color::Fixed(75).normal(),
|
||||
"chartreuse3b" | "xterm_chartreuse3b" => Color::Fixed(76).normal(),
|
||||
"palegreen3a" | "xterm_palegreen3a" => Color::Fixed(77).normal(),
|
||||
"seagreen3" | "xterm_seagreen3" => Color::Fixed(78).normal(),
|
||||
"aquamarine3" | "xterm_aquamarine3" => Color::Fixed(79).normal(),
|
||||
"mediumturquoise" | "xterm_mediumturquoise" => Color::Fixed(80).normal(),
|
||||
"steelblue1b" | "xterm_steelblue1b" => Color::Fixed(81).normal(),
|
||||
"chartreuse2a" | "xterm_chartreuse2a" => Color::Fixed(82).normal(),
|
||||
"seagreen2" | "xterm_seagreen2" => Color::Fixed(83).normal(),
|
||||
"seagreen1a" | "xterm_seagreen1a" => Color::Fixed(84).normal(),
|
||||
"seagreen1b" | "xterm_seagreen1b" => Color::Fixed(85).normal(),
|
||||
"aquamarine1a" | "xterm_aquamarine1a" => Color::Fixed(86).normal(),
|
||||
"darkslategray2" | "xterm_darkslategray2" => Color::Fixed(87).normal(),
|
||||
"darkredb" | "xterm_darkredb" => Color::Fixed(88).normal(),
|
||||
"deeppink4b" | "xterm_deeppink4b" => Color::Fixed(89).normal(),
|
||||
"darkmagentaa" | "xterm_darkmagentaa" => Color::Fixed(90).normal(),
|
||||
"darkmagentab" | "xterm_darkmagentab" => Color::Fixed(91).normal(),
|
||||
"darkvioleta" | "xterm_darkvioleta" => Color::Fixed(92).normal(),
|
||||
"xpurpleb" | "xterm_purpleb" => Color::Fixed(93).normal(),
|
||||
"orange4b" | "xterm_orange4b" => Color::Fixed(94).normal(),
|
||||
"lightpink4" | "xterm_lightpink4" => Color::Fixed(95).normal(),
|
||||
"plum4" | "xterm_plum4" => Color::Fixed(96).normal(),
|
||||
"mediumpurple3a" | "xterm_mediumpurple3a" => Color::Fixed(97).normal(),
|
||||
"mediumpurple3b" | "xterm_mediumpurple3b" => Color::Fixed(98).normal(),
|
||||
"slateblue1" | "xterm_slateblue1" => Color::Fixed(99).normal(),
|
||||
"yellow4a" | "xterm_yellow4a" => Color::Fixed(100).normal(),
|
||||
"wheat4" | "xterm_wheat4" => Color::Fixed(101).normal(),
|
||||
"grey53" | "xterm_grey53" => Color::Fixed(102).normal(),
|
||||
"lightslategrey" | "xterm_lightslategrey" => Color::Fixed(103).normal(),
|
||||
"mediumpurple" | "xterm_mediumpurple" => Color::Fixed(104).normal(),
|
||||
"lightslateblue" | "xterm_lightslateblue" => Color::Fixed(105).normal(),
|
||||
"yellow4b" | "xterm_yellow4b" => Color::Fixed(106).normal(),
|
||||
"darkolivegreen3a" | "xterm_darkolivegreen3a" => Color::Fixed(107).normal(),
|
||||
"darkseagreen" | "xterm_darkseagreen" => Color::Fixed(108).normal(),
|
||||
"lightskyblue3a" | "xterm_lightskyblue3a" => Color::Fixed(109).normal(),
|
||||
"lightskyblue3b" | "xterm_lightskyblue3b" => Color::Fixed(110).normal(),
|
||||
"skyblue2" | "xterm_skyblue2" => Color::Fixed(111).normal(),
|
||||
"chartreuse2b" | "xterm_chartreuse2b" => Color::Fixed(112).normal(),
|
||||
"darkolivegreen3b" | "xterm_darkolivegreen3b" => Color::Fixed(113).normal(),
|
||||
"palegreen3b" | "xterm_palegreen3b" => Color::Fixed(114).normal(),
|
||||
"darkseagreen3a" | "xterm_darkseagreen3a" => Color::Fixed(115).normal(),
|
||||
"darkslategray3" | "xterm_darkslategray3" => Color::Fixed(116).normal(),
|
||||
"skyblue1" | "xterm_skyblue1" => Color::Fixed(117).normal(),
|
||||
"chartreuse1" | "xterm_chartreuse1" => Color::Fixed(118).normal(),
|
||||
"lightgreena" | "xterm_lightgreena" => Color::Fixed(119).normal(),
|
||||
"lightgreenb" | "xterm_lightgreenb" => Color::Fixed(120).normal(),
|
||||
"palegreen1a" | "xterm_palegreen1a" => Color::Fixed(121).normal(),
|
||||
"aquamarine1b" | "xterm_aquamarine1b" => Color::Fixed(122).normal(),
|
||||
"darkslategray1" | "xterm_darkslategray1" => Color::Fixed(123).normal(),
|
||||
"red3a" | "xterm_red3a" => Color::Fixed(124).normal(),
|
||||
"deeppink4c" | "xterm_deeppink4c" => Color::Fixed(125).normal(),
|
||||
"mediumvioletred" | "xterm_mediumvioletred" => Color::Fixed(126).normal(),
|
||||
"magenta3" | "xterm_magenta3" => Color::Fixed(127).normal(),
|
||||
"darkvioletb" | "xterm_darkvioletb" => Color::Fixed(128).normal(),
|
||||
"purplec" | "xterm_purplec" => Color::Fixed(129).normal(),
|
||||
"darkorange3a" | "xterm_darkorange3a" => Color::Fixed(130).normal(),
|
||||
"indianreda" | "xterm_indianreda" => Color::Fixed(131).normal(),
|
||||
"hotpink3a" | "xterm_hotpink3a" => Color::Fixed(132).normal(),
|
||||
"mediumorchid3" | "xterm_mediumorchid3" => Color::Fixed(133).normal(),
|
||||
"mediumorchid" | "xterm_mediumorchid" => Color::Fixed(134).normal(),
|
||||
"mediumpurple2a" | "xterm_mediumpurple2a" => Color::Fixed(135).normal(),
|
||||
"darkgoldenrod" | "xterm_darkgoldenrod" => Color::Fixed(136).normal(),
|
||||
"lightsalmon3a" | "xterm_lightsalmon3a" => Color::Fixed(137).normal(),
|
||||
"rosybrown" | "xterm_rosybrown" => Color::Fixed(138).normal(),
|
||||
"grey63" | "xterm_grey63" => Color::Fixed(139).normal(),
|
||||
"mediumpurple2b" | "xterm_mediumpurple2b" => Color::Fixed(140).normal(),
|
||||
"mediumpurple1" | "xterm_mediumpurple1" => Color::Fixed(141).normal(),
|
||||
"gold3a" | "xterm_gold3a" => Color::Fixed(142).normal(),
|
||||
"darkkhaki" | "xterm_darkkhaki" => Color::Fixed(143).normal(),
|
||||
"navajowhite3" | "xterm_navajowhite3" => Color::Fixed(144).normal(),
|
||||
"grey69" | "xterm_grey69" => Color::Fixed(145).normal(),
|
||||
"lightsteelblue3" | "xterm_lightsteelblue3" => Color::Fixed(146).normal(),
|
||||
"lightsteelblue" | "xterm_lightsteelblue" => Color::Fixed(147).normal(),
|
||||
"yellow3a" | "xterm_yellow3a" => Color::Fixed(148).normal(),
|
||||
"darkolivegreen3c" | "xterm_darkolivegreen3c" => Color::Fixed(149).normal(),
|
||||
"darkseagreen3b" | "xterm_darkseagreen3b" => Color::Fixed(150).normal(),
|
||||
"darkseagreen2a" | "xterm_darkseagreen2a" => Color::Fixed(151).normal(),
|
||||
"lightcyan3" | "xterm_lightcyan3" => Color::Fixed(152).normal(),
|
||||
"lightskyblue1" | "xterm_lightskyblue1" => Color::Fixed(153).normal(),
|
||||
"greenyellow" | "xterm_greenyellow" => Color::Fixed(154).normal(),
|
||||
"darkolivegreen2" | "xterm_darkolivegreen2" => Color::Fixed(155).normal(),
|
||||
"palegreen1b" | "xterm_palegreen1b" => Color::Fixed(156).normal(),
|
||||
"darkseagreen2b" | "xterm_darkseagreen2b" => Color::Fixed(157).normal(),
|
||||
"darkseagreen1a" | "xterm_darkseagreen1a" => Color::Fixed(158).normal(),
|
||||
"paleturquoise1" | "xterm_paleturquoise1" => Color::Fixed(159).normal(),
|
||||
"red3b" | "xterm_red3b" => Color::Fixed(160).normal(),
|
||||
"deeppink3a" | "xterm_deeppink3a" => Color::Fixed(161).normal(),
|
||||
"deeppink3b" | "xterm_deeppink3b" => Color::Fixed(162).normal(),
|
||||
"magenta3a" | "xterm_magenta3a" => Color::Fixed(163).normal(),
|
||||
"magenta3b" | "xterm_magenta3b" => Color::Fixed(164).normal(),
|
||||
"magenta2a" | "xterm_magenta2a" => Color::Fixed(165).normal(),
|
||||
"darkorange3b" | "xterm_darkorange3b" => Color::Fixed(166).normal(),
|
||||
"indianredb" | "xterm_indianredb" => Color::Fixed(167).normal(),
|
||||
"hotpink3b" | "xterm_hotpink3b" => Color::Fixed(168).normal(),
|
||||
"hotpink2" | "xterm_hotpink2" => Color::Fixed(169).normal(),
|
||||
"orchid" | "xterm_orchid" => Color::Fixed(170).normal(),
|
||||
"mediumorchid1a" | "xterm_mediumorchid1a" => Color::Fixed(171).normal(),
|
||||
"orange3" | "xterm_orange3" => Color::Fixed(172).normal(),
|
||||
"lightsalmon3b" | "xterm_lightsalmon3b" => Color::Fixed(173).normal(),
|
||||
"lightpink3" | "xterm_lightpink3" => Color::Fixed(174).normal(),
|
||||
"pink3" | "xterm_pink3" => Color::Fixed(175).normal(),
|
||||
"plum3" | "xterm_plum3" => Color::Fixed(176).normal(),
|
||||
"violet" | "xterm_violet" => Color::Fixed(177).normal(),
|
||||
"gold3b" | "xterm_gold3b" => Color::Fixed(178).normal(),
|
||||
"lightgoldenrod3" | "xterm_lightgoldenrod3" => Color::Fixed(179).normal(),
|
||||
"tan" | "xterm_tan" => Color::Fixed(180).normal(),
|
||||
"mistyrose3" | "xterm_mistyrose3" => Color::Fixed(181).normal(),
|
||||
"thistle3" | "xterm_thistle3" => Color::Fixed(182).normal(),
|
||||
"plum2" | "xterm_plum2" => Color::Fixed(183).normal(),
|
||||
"yellow3b" | "xterm_yellow3b" => Color::Fixed(184).normal(),
|
||||
"khaki3" | "xterm_khaki3" => Color::Fixed(185).normal(),
|
||||
"lightgoldenrod2" | "xterm_lightgoldenrod2" => Color::Fixed(186).normal(),
|
||||
"lightyellow3" | "xterm_lightyellow3" => Color::Fixed(187).normal(),
|
||||
"grey84" | "xterm_grey84" => Color::Fixed(188).normal(),
|
||||
"lightsteelblue1" | "xterm_lightsteelblue1" => Color::Fixed(189).normal(),
|
||||
"yellow2" | "xterm_yellow2" => Color::Fixed(190).normal(),
|
||||
"darkolivegreen1a" | "xterm_darkolivegreen1a" => Color::Fixed(191).normal(),
|
||||
"darkolivegreen1b" | "xterm_darkolivegreen1b" => Color::Fixed(192).normal(),
|
||||
"darkseagreen1b" | "xterm_darkseagreen1b" => Color::Fixed(193).normal(),
|
||||
"honeydew2" | "xterm_honeydew2" => Color::Fixed(194).normal(),
|
||||
"lightcyan1" | "xterm_lightcyan1" => Color::Fixed(195).normal(),
|
||||
"red1" | "xterm_red1" => Color::Fixed(196).normal(),
|
||||
"deeppink2" | "xterm_deeppink2" => Color::Fixed(197).normal(),
|
||||
"deeppink1a" | "xterm_deeppink1a" => Color::Fixed(198).normal(),
|
||||
"deeppink1b" | "xterm_deeppink1b" => Color::Fixed(199).normal(),
|
||||
"magenta2b" | "xterm_magenta2b" => Color::Fixed(200).normal(),
|
||||
"magenta1" | "xterm_magenta1" => Color::Fixed(201).normal(),
|
||||
"orangered1" | "xterm_orangered1" => Color::Fixed(202).normal(),
|
||||
"indianred1a" | "xterm_indianred1a" => Color::Fixed(203).normal(),
|
||||
"indianred1b" | "xterm_indianred1b" => Color::Fixed(204).normal(),
|
||||
"hotpinka" | "xterm_hotpinka" => Color::Fixed(205).normal(),
|
||||
"hotpinkb" | "xterm_hotpinkb" => Color::Fixed(206).normal(),
|
||||
"mediumorchid1b" | "xterm_mediumorchid1b" => Color::Fixed(207).normal(),
|
||||
"darkorange" | "xterm_darkorange" => Color::Fixed(208).normal(),
|
||||
"salmon1" | "xterm_salmon1" => Color::Fixed(209).normal(),
|
||||
"lightcoral" | "xterm_lightcoral" => Color::Fixed(210).normal(),
|
||||
"palevioletred1" | "xterm_palevioletred1" => Color::Fixed(211).normal(),
|
||||
"orchid2" | "xterm_orchid2" => Color::Fixed(212).normal(),
|
||||
"orchid1" | "xterm_orchid1" => Color::Fixed(213).normal(),
|
||||
"orange1" | "xterm_orange1" => Color::Fixed(214).normal(),
|
||||
"sandybrown" | "xterm_sandybrown" => Color::Fixed(215).normal(),
|
||||
"lightsalmon1" | "xterm_lightsalmon1" => Color::Fixed(216).normal(),
|
||||
"lightpink1" | "xterm_lightpink1" => Color::Fixed(217).normal(),
|
||||
"pink1" | "xterm_pink1" => Color::Fixed(218).normal(),
|
||||
"plum1" | "xterm_plum1" => Color::Fixed(219).normal(),
|
||||
"gold1" | "xterm_gold1" => Color::Fixed(220).normal(),
|
||||
"lightgoldenrod2a" | "xterm_lightgoldenrod2a" => Color::Fixed(221).normal(),
|
||||
"lightgoldenrod2b" | "xterm_lightgoldenrod2b" => Color::Fixed(222).normal(),
|
||||
"navajowhite1" | "xterm_navajowhite1" => Color::Fixed(223).normal(),
|
||||
"mistyrose1" | "xterm_mistyrose1" => Color::Fixed(224).normal(),
|
||||
"thistle1" | "xterm_thistle1" => Color::Fixed(225).normal(),
|
||||
"yellow1" | "xterm_yellow1" => Color::Fixed(226).normal(),
|
||||
"lightgoldenrod1" | "xterm_lightgoldenrod1" => Color::Fixed(227).normal(),
|
||||
"khaki1" | "xterm_khaki1" => Color::Fixed(228).normal(),
|
||||
"wheat1" | "xterm_wheat1" => Color::Fixed(229).normal(),
|
||||
"cornsilk1" | "xterm_cornsilk1" => Color::Fixed(230).normal(),
|
||||
"grey100" | "xterm_grey100" => Color::Fixed(231).normal(),
|
||||
"grey3" | "xterm_grey3" => Color::Fixed(232).normal(),
|
||||
"grey7" | "xterm_grey7" => Color::Fixed(233).normal(),
|
||||
"grey11" | "xterm_grey11" => Color::Fixed(234).normal(),
|
||||
"grey15" | "xterm_grey15" => Color::Fixed(235).normal(),
|
||||
"grey19" | "xterm_grey19" => Color::Fixed(236).normal(),
|
||||
"grey23" | "xterm_grey23" => Color::Fixed(237).normal(),
|
||||
"grey27" | "xterm_grey27" => Color::Fixed(238).normal(),
|
||||
"grey30" | "xterm_grey30" => Color::Fixed(239).normal(),
|
||||
"grey35" | "xterm_grey35" => Color::Fixed(240).normal(),
|
||||
"grey39" | "xterm_grey39" => Color::Fixed(241).normal(),
|
||||
"grey42" | "xterm_grey42" => Color::Fixed(242).normal(),
|
||||
"grey46" | "xterm_grey46" => Color::Fixed(243).normal(),
|
||||
"grey50" | "xterm_grey50" => Color::Fixed(244).normal(),
|
||||
"grey54" | "xterm_grey54" => Color::Fixed(245).normal(),
|
||||
"grey58" | "xterm_grey58" => Color::Fixed(246).normal(),
|
||||
"grey62" | "xterm_grey62" => Color::Fixed(247).normal(),
|
||||
"grey66" | "xterm_grey66" => Color::Fixed(248).normal(),
|
||||
"grey70" | "xterm_grey70" => Color::Fixed(249).normal(),
|
||||
"grey74" | "xterm_grey74" => Color::Fixed(250).normal(),
|
||||
"grey78" | "xterm_grey78" => Color::Fixed(251).normal(),
|
||||
"grey82" | "xterm_grey82" => Color::Fixed(252).normal(),
|
||||
"grey85" | "xterm_grey85" => Color::Fixed(253).normal(),
|
||||
"grey89" | "xterm_grey89" => Color::Fixed(254).normal(),
|
||||
"grey93" | "xterm_grey93" => Color::Fixed(255).normal(),
|
||||
_ => Color::White.normal(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_color(s: &str) -> Option<Color> {
|
||||
let color = match s {
|
||||
"g" | "green" => Color::Green,
|
||||
"lg" | "light_green" => Color::LightGreen,
|
||||
"r" | "red" => Color::Red,
|
||||
"lr" | "light_red" => Color::LightRed,
|
||||
"u" | "blue" => Color::Blue,
|
||||
"lu" | "light_blue" => Color::LightBlue,
|
||||
"b" | "black" => Color::Black,
|
||||
"ligr" | "light_gray" => Color::LightGray,
|
||||
"y" | "yellow" => Color::Yellow,
|
||||
"ly" | "light_yellow" => Color::LightYellow,
|
||||
"p" | "purple" => Color::Purple,
|
||||
"lp" | "light_purple" => Color::LightPurple,
|
||||
"c" | "cyan" => Color::Cyan,
|
||||
"lc" | "light_cyan" => Color::LightCyan,
|
||||
"w" | "white" => Color::White,
|
||||
"dgr" | "dark_gray" => Color::DarkGray,
|
||||
"def" | "default" => Color::Default,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some(color)
|
||||
}
|
||||
|
||||
fn fill_modifiers(attrs: &str, style: &mut Style) {
|
||||
// setup the attributes available in nu_ansi_term::Style
|
||||
//
|
||||
// since we can combine styles like bold-italic, iterate through the chars
|
||||
// and set the bools for later use in the nu_ansi_term::Style application
|
||||
for ch in attrs.to_lowercase().chars() {
|
||||
match ch {
|
||||
'l' => style.is_blink = true,
|
||||
'b' => style.is_bold = true,
|
||||
'd' => style.is_dimmed = true,
|
||||
'h' => style.is_hidden = true,
|
||||
'i' => style.is_italic = true,
|
||||
'r' => style.is_reverse = true,
|
||||
's' => style.is_strikethrough = true,
|
||||
'u' => style.is_underline = true,
|
||||
'n' => (),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_color_str(s: &str) -> Option<Color> {
|
||||
if s.starts_with('#') {
|
||||
color_from_hex(s).ok().and_then(|c| c)
|
||||
} else {
|
||||
lookup_color(s)
|
||||
}
|
||||
}
|
||||
|
@ -9,36 +9,36 @@ pub fn get_shape_color(shape: String, conf: &Config) -> Style {
|
||||
Err(_) => Style::default(),
|
||||
},
|
||||
None => match shape.as_ref() {
|
||||
"shape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
|
||||
"shape_and" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_binary" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_block" => Style::new().fg(Color::Blue).bold(),
|
||||
"shape_bool" => Style::new().fg(Color::LightCyan),
|
||||
"shape_int" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_float" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_range" => Style::new().fg(Color::Yellow).bold(),
|
||||
"shape_internalcall" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_custom" => Style::new().fg(Color::Green),
|
||||
"shape_datetime" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_directory" => Style::new().fg(Color::Cyan),
|
||||
"shape_external" => Style::new().fg(Color::Cyan),
|
||||
"shape_externalarg" => Style::new().fg(Color::Green).bold(),
|
||||
"shape_filepath" => Style::new().fg(Color::Cyan),
|
||||
"shape_flag" => Style::new().fg(Color::Blue).bold(),
|
||||
"shape_float" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_garbage" => Style::new().fg(Color::White).on(Color::Red).bold(),
|
||||
"shape_globpattern" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_int" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_internalcall" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_list" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_literal" => Style::new().fg(Color::Blue),
|
||||
"shape_nothing" => Style::new().fg(Color::LightCyan),
|
||||
"shape_operator" => Style::new().fg(Color::Yellow),
|
||||
"shape_or" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_pipe" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_range" => Style::new().fg(Color::Yellow).bold(),
|
||||
"shape_record" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_redirection" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_signature" => Style::new().fg(Color::Green).bold(),
|
||||
"shape_string" => Style::new().fg(Color::Green),
|
||||
"shape_string_interpolation" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_datetime" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_list" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_table" => Style::new().fg(Color::Blue).bold(),
|
||||
"shape_record" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_block" => Style::new().fg(Color::Blue).bold(),
|
||||
"shape_filepath" => Style::new().fg(Color::Cyan),
|
||||
"shape_directory" => Style::new().fg(Color::Cyan),
|
||||
"shape_globpattern" => Style::new().fg(Color::Cyan).bold(),
|
||||
"shape_variable" => Style::new().fg(Color::Purple),
|
||||
"shape_flag" => Style::new().fg(Color::Blue).bold(),
|
||||
"shape_custom" => Style::new().fg(Color::Green),
|
||||
"shape_pipe" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_redirection" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_and" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_or" => Style::new().fg(Color::Purple).bold(),
|
||||
"shape_nothing" => Style::new().fg(Color::LightCyan),
|
||||
_ => Style::default(),
|
||||
},
|
||||
}
|
||||
|
285
crates/nu-color-config/src/style_computer.rs
Normal file
285
crates/nu-color-config/src/style_computer.rs
Normal file
@ -0,0 +1,285 @@
|
||||
use crate::{color_record_to_nustyle, lookup_ansi_color_style, TextStyle};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_engine::eval_block;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
CliError, IntoPipelineData, Value,
|
||||
};
|
||||
use tabled::alignment::AlignmentHorizontal;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{Debug, Formatter, Result},
|
||||
};
|
||||
|
||||
// ComputableStyle represents the valid user style types: a single color value, or a closure which
|
||||
// takes an input value and produces a color value. The latter represents a value which
|
||||
// is computed at use-time.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ComputableStyle {
|
||||
Static(Style),
|
||||
Closure(Value),
|
||||
}
|
||||
|
||||
// macro used for adding initial values to the style hashmap
|
||||
macro_rules! initial {
|
||||
($a:expr, $b:expr) => {
|
||||
($a.to_string(), ComputableStyle::Static($b))
|
||||
};
|
||||
}
|
||||
|
||||
// An alias for the mapping used internally by StyleComputer.
|
||||
pub type StyleMapping = HashMap<String, ComputableStyle>;
|
||||
//
|
||||
// A StyleComputer is an all-in-one way to compute styles. A nu command can
|
||||
// simply create it with from_config(), and then use it with compute().
|
||||
// It stores the engine state and stack needed to run closures that
|
||||
// may be defined as a user style.
|
||||
//
|
||||
pub struct StyleComputer<'a> {
|
||||
engine_state: &'a EngineState,
|
||||
stack: &'a Stack,
|
||||
map: StyleMapping,
|
||||
}
|
||||
|
||||
impl<'a> StyleComputer<'a> {
|
||||
// This is NOT meant to be used in most cases - please use from_config() instead.
|
||||
// This only exists for testing purposes.
|
||||
pub fn new(
|
||||
engine_state: &'a EngineState,
|
||||
stack: &'a Stack,
|
||||
map: StyleMapping,
|
||||
) -> StyleComputer<'a> {
|
||||
StyleComputer {
|
||||
engine_state,
|
||||
stack,
|
||||
map,
|
||||
}
|
||||
}
|
||||
// The main method. Takes a string name which maps to a color_config style name,
|
||||
// and a Nu value to pipe into any closures that may have been defined there.
|
||||
pub fn compute(&self, style_name: &str, value: &Value) -> Style {
|
||||
match self.map.get(style_name) {
|
||||
// Static values require no computation.
|
||||
Some(ComputableStyle::Static(s)) => *s,
|
||||
// Closures are run here.
|
||||
Some(ComputableStyle::Closure(Value::Closure {
|
||||
val: block_id,
|
||||
captures,
|
||||
span,
|
||||
})) => {
|
||||
let block = self.engine_state.get_block(*block_id).clone();
|
||||
// Because captures_to_stack() clones, we don't need to use with_env() here
|
||||
// (contrast with_env() usage in `each` or `do`).
|
||||
let mut stack = self.stack.captures_to_stack(captures);
|
||||
|
||||
// Support 1-argument blocks as well as 0-argument blocks.
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
if let Some(var_id) = &var.var_id {
|
||||
stack.add_var(*var_id, value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// Run the block.
|
||||
match eval_block(
|
||||
self.engine_state,
|
||||
&mut stack,
|
||||
&block,
|
||||
value.clone().into_pipeline_data(),
|
||||
false,
|
||||
false,
|
||||
) {
|
||||
Ok(v) => {
|
||||
let value = v.into_value(*span);
|
||||
// These should be the same color data forms supported by color_config.
|
||||
match value {
|
||||
Value::Record { .. } => color_record_to_nustyle(&value),
|
||||
Value::String { val, .. } => lookup_ansi_color_style(&val),
|
||||
_ => Style::default(),
|
||||
}
|
||||
}
|
||||
// This is basically a copy of nu_cli::report_error(), but that isn't usable due to
|
||||
// dependencies. While crudely spitting out a bunch of errors like this is not ideal,
|
||||
// currently hook closure errors behave roughly the same.
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"Error: {:?}",
|
||||
CliError(&e, &StateWorkingSet::new(self.engine_state))
|
||||
);
|
||||
Style::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
// There should be no other kinds of values (due to create_map() in config.rs filtering them out)
|
||||
// so this is just a fallback.
|
||||
_ => Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// Used only by the `table` command.
|
||||
pub fn style_primitive(&self, value: &Value) -> TextStyle {
|
||||
let s = self.compute(&value.get_type().to_string(), value);
|
||||
match *value {
|
||||
Value::Bool { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Int { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
|
||||
|
||||
Value::Filesize { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
|
||||
|
||||
Value::Duration { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Date { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Range { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Float { .. } => TextStyle::with_style(AlignmentHorizontal::Right, s),
|
||||
|
||||
Value::String { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Nothing { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Binary { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::CellPath { .. } => TextStyle::with_style(AlignmentHorizontal::Left, s),
|
||||
|
||||
Value::Record { .. } | Value::List { .. } | Value::Block { .. } => {
|
||||
TextStyle::with_style(AlignmentHorizontal::Left, s)
|
||||
}
|
||||
_ => TextStyle::basic_left(),
|
||||
}
|
||||
}
|
||||
|
||||
// The main constructor.
|
||||
pub fn from_config(engine_state: &'a EngineState, stack: &'a Stack) -> StyleComputer<'a> {
|
||||
let config = engine_state.get_config();
|
||||
|
||||
// Create the hashmap
|
||||
let mut map: StyleMapping = HashMap::from([
|
||||
initial!("separator", Color::White.normal()),
|
||||
initial!(
|
||||
"leading_trailing_space_bg",
|
||||
Style::default().on(Color::Rgb(128, 128, 128))
|
||||
),
|
||||
initial!("header", Color::White.normal()),
|
||||
initial!("empty", Color::White.normal()),
|
||||
initial!("bool", Color::White.normal()),
|
||||
initial!("int", Color::White.normal()),
|
||||
initial!("filesize", Color::White.normal()),
|
||||
initial!("duration", Color::White.normal()),
|
||||
initial!("date", Color::White.normal()),
|
||||
initial!("range", Color::White.normal()),
|
||||
initial!("float", Color::White.normal()),
|
||||
initial!("string", Color::White.normal()),
|
||||
initial!("nothing", Color::White.normal()),
|
||||
initial!("binary", Color::White.normal()),
|
||||
initial!("cellpath", Color::White.normal()),
|
||||
initial!("row_index", Color::Green.bold()),
|
||||
initial!("record", Color::White.normal()),
|
||||
initial!("list", Color::White.normal()),
|
||||
initial!("block", Color::White.normal()),
|
||||
initial!("hints", Color::DarkGray.normal()),
|
||||
]);
|
||||
|
||||
for (key, value) in &config.color_config {
|
||||
match value {
|
||||
Value::Closure { .. } => {
|
||||
map.insert(key.to_string(), ComputableStyle::Closure(value.clone()));
|
||||
}
|
||||
Value::Record { .. } => {
|
||||
map.insert(
|
||||
key.to_string(),
|
||||
ComputableStyle::Static(color_record_to_nustyle(value)),
|
||||
);
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
// update the stylemap with the found key
|
||||
let color = lookup_ansi_color_style(val.as_str());
|
||||
if let Some(v) = map.get_mut(key) {
|
||||
*v = ComputableStyle::Static(color);
|
||||
} else {
|
||||
map.insert(key.to_string(), ComputableStyle::Static(color));
|
||||
}
|
||||
}
|
||||
// This should never occur.
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
StyleComputer::new(engine_state, stack, map)
|
||||
}
|
||||
}
|
||||
|
||||
// Because EngineState doesn't have Debug (Dec 2022),
|
||||
// this incomplete representation must be used.
|
||||
impl<'a> Debug for StyleComputer<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
|
||||
f.debug_struct("StyleComputer")
|
||||
.field("map", &self.map)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_computable_style_static() {
|
||||
use nu_protocol::Span;
|
||||
|
||||
let style1 = Style::default().italic();
|
||||
let style2 = Style::default().underline();
|
||||
// Create a "dummy" style_computer for this test.
|
||||
let dummy_engine_state = EngineState::new();
|
||||
let mut dummy_stack = Stack::new();
|
||||
let style_computer = StyleComputer::new(
|
||||
&dummy_engine_state,
|
||||
&mut dummy_stack,
|
||||
HashMap::from([
|
||||
("string".into(), ComputableStyle::Static(style1)),
|
||||
("row_index".into(), ComputableStyle::Static(style2)),
|
||||
]),
|
||||
);
|
||||
assert_eq!(
|
||||
style_computer.compute("string", &Value::nothing(Span::unknown())),
|
||||
style1
|
||||
);
|
||||
assert_eq!(
|
||||
style_computer.compute("row_index", &Value::nothing(Span::unknown())),
|
||||
style2
|
||||
);
|
||||
}
|
||||
|
||||
// Because each closure currently runs in a separate environment, checks that the closures have run
|
||||
// must use the filesystem.
|
||||
#[test]
|
||||
fn test_computable_style_closure_basic() {
|
||||
use nu_test_support::{nu, nu_repl_code, playground::Playground};
|
||||
Playground::setup("computable_style_closure_basic", |dirs, _| {
|
||||
let inp = [
|
||||
r#"let-env config = {
|
||||
color_config: {
|
||||
string: {|e| touch ($e + '.obj'); 'red' }
|
||||
}
|
||||
};"#,
|
||||
"[bell book candle] | table | ignore",
|
||||
"ls | get name | to nuon",
|
||||
];
|
||||
let actual_repl = nu!(cwd: dirs.test(), nu_repl_code(&inp));
|
||||
assert_eq!(actual_repl.err, "");
|
||||
assert_eq!(actual_repl.out, "[bell.obj, book.obj, candle.obj]");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_computable_style_closure_errors() {
|
||||
use nu_test_support::{nu, nu_repl_code};
|
||||
let inp = [
|
||||
r#"let-env config = {
|
||||
color_config: {
|
||||
string: {|e| $e + 2 }
|
||||
}
|
||||
};"#,
|
||||
"[bell] | table",
|
||||
];
|
||||
let actual_repl = nu!(cwd: ".", nu_repl_code(&inp));
|
||||
// Check that the error was printed
|
||||
assert!(actual_repl.err.contains("type mismatch for operator"));
|
||||
// Check that the value was printed
|
||||
assert!(actual_repl.out.contains("bell"));
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use std::fmt::Display;
|
||||
|
||||
pub type Alignment = tabled::alignment::AlignmentHorizontal;
|
||||
|
||||
@ -239,3 +240,23 @@ impl Default for TextStyle {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl tabled::papergrid::Color for TextStyle {
|
||||
fn fmt_prefix(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(color) = &self.color_style {
|
||||
color.prefix().fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fmt_suffix(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
if let Some(color) = &self.color_style {
|
||||
if !color.is_plain() {
|
||||
f.write_str("\u{1b}[0m")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -5,33 +5,35 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-command"
|
||||
version = "0.72.0"
|
||||
version = "0.73.0"
|
||||
build = "build.rs"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.72.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.72.0" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.72.0" }
|
||||
nu-json = { path = "../nu-json", version = "0.72.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.72.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.72.0" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.72.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.72.0" }
|
||||
nu-system = { path = "../nu-system", version = "0.72.0" }
|
||||
nu-table = { path = "../nu-table", version = "0.72.0" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.72.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.72.0" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.73.0" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.73.0" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.73.0" }
|
||||
nu-json = { path = "../nu-json", version = "0.73.0" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.73.0" }
|
||||
nu-path = { path = "../nu-path", version = "0.73.0" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.73.0" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.73.0" }
|
||||
nu-system = { path = "../nu-system", version = "0.73.0" }
|
||||
nu-table = { path = "../nu-table", version = "0.73.0" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.73.0" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.73.0" }
|
||||
nu-explore = { path = "../nu-explore", version = "0.73.0" }
|
||||
nu-ansi-term = "0.46.0"
|
||||
num-format = { version = "0.4.3" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
alphanumeric-sort = "1.4.4"
|
||||
atty = "0.2.14"
|
||||
base64 = "0.13.0"
|
||||
byteorder = "1.4.3"
|
||||
bytesize = "1.1.0"
|
||||
calamine = "0.18.0"
|
||||
calamine = "0.19.1"
|
||||
chrono = { version = "0.4.23", features = ["unstable-locales", "std"], default-features = false }
|
||||
chrono-humanize = "0.2.1"
|
||||
chrono-tz = "0.6.3"
|
||||
@ -52,7 +54,6 @@ indexmap = { version="1.7", features=["serde-1"] }
|
||||
Inflector = "0.11"
|
||||
is-root = "0.1.2"
|
||||
itertools = "0.10.0"
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.14"
|
||||
lscolors = { version = "0.12.0", features = ["crossterm"], default-features = false }
|
||||
md5 = { package = "md-5", version = "0.10.0" }
|
||||
@ -64,11 +65,12 @@ num-traits = "0.2.14"
|
||||
once_cell = "1.0"
|
||||
pathdiff = "0.2.1"
|
||||
powierza-coefficient = "1.0.1"
|
||||
quick-xml = "0.23.0"
|
||||
quick-xml = "0.25"
|
||||
rand = "0.8"
|
||||
rayon = "1.5.1"
|
||||
regex = "1.6.0"
|
||||
reqwest = {version = "0.11", features = ["blocking", "json"] }
|
||||
roxmltree = "0.14.0"
|
||||
roxmltree = "0.16.0"
|
||||
rust-embed = "6.3.0"
|
||||
same-file = "1.0.6"
|
||||
serde = { version="1.0.123", features=["derive"] }
|
||||
@ -101,7 +103,7 @@ users = "0.11.0"
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies.trash]
|
||||
version = "2.1.3"
|
||||
version = "3.0.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.polars]
|
||||
@ -136,7 +138,7 @@ features = [
|
||||
]
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.42.0"
|
||||
version = "0.43.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Storage_FileSystem",
|
||||
@ -154,7 +156,7 @@ sqlite = ["rusqlite"] # TODO: given that rusqlite is included in reedline, shoul
|
||||
shadow-rs = { version = "0.16.1", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.72.0" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.73.0" }
|
||||
|
||||
hamcrest2 = "0.3.0"
|
||||
dirs-next = "2.0.0"
|
||||
|
@ -54,10 +54,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Apply bits and to two numbers",
|
||||
example: "2 | bits and 2",
|
||||
result: Some(Value::Int {
|
||||
val: 2,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(2, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Apply logical and to a list of numbers",
|
||||
|
@ -54,10 +54,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Apply bits or to two numbers",
|
||||
example: "2 | bits or 6",
|
||||
result: Some(Value::Int {
|
||||
val: 6,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(6, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Apply logical or to a list of numbers",
|
||||
|
@ -76,10 +76,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Rotate left a number with 2 bits",
|
||||
example: "17 | bits rol 2",
|
||||
result: Some(Value::Int {
|
||||
val: 68,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(68, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate left a list of numbers with 2 bits",
|
||||
|
@ -76,10 +76,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Rotate right a number with 60 bits",
|
||||
example: "17 | bits ror 60",
|
||||
result: Some(Value::Int {
|
||||
val: 272,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(272, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Rotate right a list of numbers of one byte",
|
||||
|
@ -76,26 +76,17 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Shift left a number by 7 bits",
|
||||
example: "2 | bits shl 7",
|
||||
result: Some(Value::Int {
|
||||
val: 256,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(256, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Shift left a number with 1 byte by 7 bits",
|
||||
example: "2 | bits shl 7 -n 1",
|
||||
result: Some(Value::Int {
|
||||
val: 0,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(0, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Shift left a signed number by 1 bit",
|
||||
example: "0x7F | bits shl 1 -s",
|
||||
result: Some(Value::Int {
|
||||
val: 254,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(254, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Shift left a list of numbers",
|
||||
|
@ -76,10 +76,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Shift right a number with 2 bits",
|
||||
example: "8 | bits shr 2",
|
||||
result: Some(Value::Int {
|
||||
val: 2,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(2, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Shift right a list of numbers",
|
||||
|
@ -54,10 +54,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Apply bits xor to two numbers",
|
||||
example: "2 | bits xor 2",
|
||||
result: Some(Value::Int {
|
||||
val: 0,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(0, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Apply logical xor to a list of numbers",
|
||||
|
@ -68,26 +68,17 @@ impl Command for BytesEndsWith {
|
||||
Example {
|
||||
description: "Checks if binary ends with `0x[AA]`",
|
||||
example: "0x[1F FF AA AA] | bytes ends-with 0x[AA]",
|
||||
result: Some(Value::Bool {
|
||||
val: true,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::boolean(true, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Checks if binary ends with `0x[FF AA AA]`",
|
||||
example: "0x[1F FF AA AA] | bytes ends-with 0x[FF AA AA]",
|
||||
result: Some(Value::Bool {
|
||||
val: true,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::boolean(true, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Checks if binary ends with `0x[11]`",
|
||||
example: "0x[1F FF AA AA] | bytes ends-with 0x[11]",
|
||||
result: Some(Value::Bool {
|
||||
val: false,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::boolean(false, Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -98,10 +89,7 @@ fn ends_with(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => Value::Bool {
|
||||
val: val.ends_with(&args.pattern),
|
||||
span: *val_span,
|
||||
},
|
||||
} => Value::boolean(val.ends_with(&args.pattern), *val_span),
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
format!(
|
||||
|
@ -70,10 +70,7 @@ fn length(val: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => Value::Int {
|
||||
val: val.len() as i64,
|
||||
span: *val_span,
|
||||
},
|
||||
} => Value::int(val.len() as i64, *val_span),
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
format!(
|
||||
|
@ -74,26 +74,17 @@ impl Command for BytesStartsWith {
|
||||
Example {
|
||||
description: "Checks if binary starts with `0x[1F FF AA]`",
|
||||
example: "0x[1F FF AA AA] | bytes starts-with 0x[1F FF AA]",
|
||||
result: Some(Value::Bool {
|
||||
val: true,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::boolean(true, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Checks if binary starts with `0x[1F]`",
|
||||
example: "0x[1F FF AA AA] | bytes starts-with 0x[1F]",
|
||||
result: Some(Value::Bool {
|
||||
val: true,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::boolean(true, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Checks if binary starts with `0x[1F]`",
|
||||
example: "0x[1F FF AA AA] | bytes starts-with 0x[11]",
|
||||
result: Some(Value::Bool {
|
||||
val: false,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::boolean(false, Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -104,10 +95,7 @@ fn starts_with(val: &Value, args: &Arguments, span: Span) -> Value {
|
||||
Value::Binary {
|
||||
val,
|
||||
span: val_span,
|
||||
} => Value::Bool {
|
||||
val: val.starts_with(&args.pattern),
|
||||
span: *val_span,
|
||||
},
|
||||
} => Value::boolean(val.starts_with(&args.pattern), *val_span),
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
format!(
|
||||
|
@ -53,7 +53,7 @@ impl Default for HashableValue {
|
||||
fn default() -> Self {
|
||||
HashableValue::Bool {
|
||||
val: false,
|
||||
span: Span { start: 0, end: 0 },
|
||||
span: Span::unknown(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -214,7 +214,7 @@ mod test {
|
||||
];
|
||||
for (val, expect_hashable_val) in values.into_iter() {
|
||||
assert_eq!(
|
||||
HashableValue::from_value(val, Span { start: 0, end: 0 }).unwrap(),
|
||||
HashableValue::from_value(val, Span::unknown()).unwrap(),
|
||||
expect_hashable_val
|
||||
);
|
||||
}
|
||||
@ -245,7 +245,7 @@ mod test {
|
||||
},
|
||||
];
|
||||
for v in values {
|
||||
assert!(HashableValue::from_value(v, Span { start: 0, end: 0 }).is_err())
|
||||
assert!(HashableValue::from_value(v, Span::unknown()).is_err())
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +266,7 @@ mod test {
|
||||
for val in values.into_iter() {
|
||||
let expected_val = val.clone();
|
||||
assert_eq!(
|
||||
HashableValue::from_value(val, Span { start: 0, end: 0 })
|
||||
HashableValue::from_value(val, Span::unknown())
|
||||
.unwrap()
|
||||
.into_value(),
|
||||
expected_val
|
||||
@ -279,14 +279,11 @@ mod test {
|
||||
assert_eq!(
|
||||
HashableValue::Bool {
|
||||
val: true,
|
||||
span: Span { start: 0, end: 1 }
|
||||
span: Span::new(0, 1)
|
||||
},
|
||||
HashableValue::Bool {
|
||||
val: true,
|
||||
span: Span {
|
||||
start: 90,
|
||||
end: 1000
|
||||
}
|
||||
span: Span::new(90, 1000)
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -299,7 +296,7 @@ mod test {
|
||||
assert!(set.contains(&HashableValue::Bool { val: true, span }));
|
||||
|
||||
// hashable value doesn't care about span.
|
||||
let diff_span = Span { start: 1, end: 2 };
|
||||
let diff_span = Span::new(1, 2);
|
||||
set.insert(HashableValue::Bool {
|
||||
val: true,
|
||||
span: diff_span,
|
||||
|
@ -50,7 +50,7 @@ impl Command for Histogram {
|
||||
},
|
||||
Example {
|
||||
description: "Compute a histogram for a list of numbers",
|
||||
example: "echo [1 2 1] | histogram",
|
||||
example: "[1 2 1] | histogram",
|
||||
result: Some(Value::List {
|
||||
vals: vec![Value::Record {
|
||||
cols: vec!["value".to_string(), "count".to_string(), "quantile".to_string(), "percentage".to_string(), "frequency".to_string()],
|
||||
@ -80,7 +80,7 @@ impl Command for Histogram {
|
||||
},
|
||||
Example {
|
||||
description: "Compute a histogram for a list of numbers, and percentage is based on the maximum value",
|
||||
example: "echo [1 2 3 1 1 1 2 2 1 1] | histogram --percentage-type relative",
|
||||
example: "[1 2 3 1 1 1 2 2 1 1] | histogram --percentage-type relative",
|
||||
result: None,
|
||||
}
|
||||
]
|
||||
@ -249,25 +249,33 @@ fn histogram_impl(
|
||||
let percentage = format!("{:.2}%", quantile * 100_f64);
|
||||
let freq = "*".repeat((MAX_FREQ_COUNT * quantile).floor() as usize);
|
||||
|
||||
result.push(Value::Record {
|
||||
cols: result_cols.clone(),
|
||||
vals: vec![
|
||||
val.into_value(),
|
||||
Value::Int { val: count, span },
|
||||
Value::Float {
|
||||
val: quantile,
|
||||
span,
|
||||
},
|
||||
Value::String {
|
||||
val: percentage,
|
||||
span,
|
||||
},
|
||||
Value::String { val: freq, span },
|
||||
],
|
||||
span,
|
||||
});
|
||||
result.push((
|
||||
count, // attach count first for easily sorting.
|
||||
Value::Record {
|
||||
cols: result_cols.clone(),
|
||||
vals: vec![
|
||||
val.into_value(),
|
||||
Value::Int { val: count, span },
|
||||
Value::Float {
|
||||
val: quantile,
|
||||
span,
|
||||
},
|
||||
Value::String {
|
||||
val: percentage,
|
||||
span,
|
||||
},
|
||||
Value::String { val: freq, span },
|
||||
],
|
||||
span,
|
||||
},
|
||||
));
|
||||
}
|
||||
Value::List { vals: result, span }.into_pipeline_data()
|
||||
result.sort_by(|a, b| b.0.cmp(&a.0));
|
||||
Value::List {
|
||||
vals: result.into_iter().map(|x| x.1).collect(),
|
||||
span,
|
||||
}
|
||||
.into_pipeline_data()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -44,38 +44,14 @@ impl Command for Fmt {
|
||||
"upperhex".into(),
|
||||
],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "0b101010".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "42".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "42".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "4.2e1".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "0x2a".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "0o52".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "4.2E1".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "0x2A".to_string(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("0b101010", Span::test_data()),
|
||||
Value::string("42", Span::test_data()),
|
||||
Value::string("42", Span::test_data()),
|
||||
Value::string("4.2e1", Span::test_data()),
|
||||
Value::string("0x2a", Span::test_data()),
|
||||
Value::string("0o52", Span::test_data()),
|
||||
Value::string("4.2E1", Span::test_data()),
|
||||
Value::string("0x2A", Span::test_data()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
|
@ -54,7 +54,7 @@ impl Command for SubCommand {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert value to boolean in table",
|
||||
example: "echo [[value]; ['false'] ['1'] [0] [1.0] [true]] | into bool value",
|
||||
example: "[[value]; ['false'] ['1'] [0] [1.0] [true]] | into bool value",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
Value::Record {
|
||||
|
@ -86,7 +86,7 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
|
||||
let other = s.trim();
|
||||
|
||||
match other.parse::<f64>() {
|
||||
Ok(x) => Value::Float { val: x, span: head },
|
||||
Ok(x) => Value::float(x, head),
|
||||
Err(reason) => Value::Error {
|
||||
error: ShellError::CantConvert(
|
||||
"float".to_string(),
|
||||
@ -97,10 +97,7 @@ fn action(input: &Value, _args: &CellPathOnlyArgs, head: Span) -> Value {
|
||||
},
|
||||
}
|
||||
}
|
||||
Value::Int { val: v, span } => Value::Float {
|
||||
val: *v as f64,
|
||||
span: *span,
|
||||
},
|
||||
Value::Int { val: v, span } => Value::float(*v as f64, *span),
|
||||
Value::Bool { val: b, span } => Value::Float {
|
||||
val: match b {
|
||||
true => 1.0,
|
||||
|
@ -65,7 +65,8 @@ impl Command for SubCommand {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert string to duration in table",
|
||||
example: "echo [[value]; ['1sec'] ['2min'] ['3hr'] ['4day'] ['5wk']] | into duration value",
|
||||
example:
|
||||
"[[value]; ['1sec'] ['2min'] ['3hr'] ['4day'] ['5wk']] | into duration value",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
Value::Record {
|
||||
@ -502,7 +503,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_ns_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 2);
|
||||
let word = Value::test_string("3ns");
|
||||
let expected = Value::Duration { val: 3, span };
|
||||
let convert_duration = None;
|
||||
@ -513,7 +514,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_us_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 2);
|
||||
let word = Value::test_string("4us");
|
||||
let expected = Value::Duration {
|
||||
val: 4 * 1000,
|
||||
@ -527,7 +528,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_ms_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 2);
|
||||
let word = Value::test_string("5ms");
|
||||
let expected = Value::Duration {
|
||||
val: 5 * 1000 * 1000,
|
||||
@ -541,7 +542,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_sec_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 3);
|
||||
let word = Value::test_string("1sec");
|
||||
let expected = Value::Duration {
|
||||
val: 1000 * 1000 * 1000,
|
||||
@ -555,7 +556,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_min_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 3);
|
||||
let word = Value::test_string("7min");
|
||||
let expected = Value::Duration {
|
||||
val: 7 * 60 * 1000 * 1000 * 1000,
|
||||
@ -569,7 +570,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_hr_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 3);
|
||||
let word = Value::test_string("42hr");
|
||||
let expected = Value::Duration {
|
||||
val: 42 * 60 * 60 * 1000 * 1000 * 1000,
|
||||
@ -583,7 +584,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_day_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 5);
|
||||
let word = Value::test_string("123day");
|
||||
let expected = Value::Duration {
|
||||
val: 123 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
||||
@ -597,7 +598,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn turns_wk_to_duration() {
|
||||
let span = Span::test_data();
|
||||
let span = Span::new(0, 2);
|
||||
let word = Value::test_string("3wk");
|
||||
let expected = Value::Duration {
|
||||
val: 3 * 7 * 24 * 60 * 60 * 1000 * 1000 * 1000,
|
||||
|
@ -92,7 +92,7 @@ impl Command for SubCommand {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert string to integer in table",
|
||||
example: "echo [[num]; ['-5'] [4] [1.5]] | into int num",
|
||||
example: "[[num]; ['-5'] [4] [1.5]] | into int num",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
@ -113,10 +113,7 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "Convert file size to integer",
|
||||
example: "4KB | into int",
|
||||
result: Some(Value::Int {
|
||||
val: 4000,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(4000, Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Convert bool to integer",
|
||||
@ -233,20 +230,14 @@ fn action(input: &Value, args: &Arguments, span: Span) -> Value {
|
||||
}
|
||||
val.resize(8, 0);
|
||||
|
||||
Value::Int {
|
||||
val: LittleEndian::read_i64(&val),
|
||||
span: *span,
|
||||
}
|
||||
Value::int(LittleEndian::read_i64(&val), *span)
|
||||
} else {
|
||||
while val.len() < 8 {
|
||||
val.insert(0, 0);
|
||||
}
|
||||
val.resize(8, 0);
|
||||
|
||||
Value::Int {
|
||||
val: BigEndian::read_i64(&val),
|
||||
span: *span,
|
||||
}
|
||||
Value::int(BigEndian::read_i64(&val), *span)
|
||||
}
|
||||
}
|
||||
_ => Value::Error {
|
||||
@ -269,13 +260,13 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
|
||||
// octal
|
||||
{
|
||||
match int_from_string(val, head) {
|
||||
Ok(x) => return Value::Int { val: x, span: head },
|
||||
Ok(x) => return Value::int(x, head),
|
||||
Err(e) => return Value::Error { error: e },
|
||||
}
|
||||
} else if val.starts_with("00") {
|
||||
// It's a padded string
|
||||
match i64::from_str_radix(val, radix) {
|
||||
Ok(n) => return Value::Int { val: n, span: head },
|
||||
Ok(n) => return Value::int(n, head),
|
||||
Err(e) => {
|
||||
return Value::Error {
|
||||
error: ShellError::CantConvert(
|
||||
@ -300,7 +291,7 @@ fn convert_int(input: &Value, head: Span, radix: u32) -> Value {
|
||||
}
|
||||
};
|
||||
match i64::from_str_radix(i.trim(), radix) {
|
||||
Ok(n) => Value::Int { val: n, span: head },
|
||||
Ok(n) => Value::int(n, head),
|
||||
Err(_reason) => Value::Error {
|
||||
error: ShellError::CantConvert("string".to_string(), "int".to_string(), head, None),
|
||||
},
|
||||
|
@ -49,7 +49,7 @@ impl Command for SubCommand {
|
||||
vec![
|
||||
Example {
|
||||
description: "Convert from one row table to record",
|
||||
example: "echo [[value]; [false]] | into record",
|
||||
example: "[[value]; [false]] | into record",
|
||||
result: Some(Value::Record {
|
||||
cols: vec!["value".to_string()],
|
||||
vals: vec![Value::boolean(false, span)],
|
||||
@ -183,12 +183,12 @@ fn into_record(
|
||||
Value::Record { cols, vals, span }
|
||||
}
|
||||
Value::Record { cols, vals, span } => Value::Record { cols, vals, span },
|
||||
other => Value::Error {
|
||||
error: ShellError::UnsupportedInput(
|
||||
other => {
|
||||
return Err(ShellError::UnsupportedInput(
|
||||
"'into record' does not support this input".into(),
|
||||
other.span().unwrap_or(call.head),
|
||||
),
|
||||
},
|
||||
))
|
||||
}
|
||||
};
|
||||
Ok(res.into_pipeline_data())
|
||||
}
|
||||
|
@ -79,34 +79,22 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "convert integer to string and append three decimal places",
|
||||
example: "5 | into string -d 3",
|
||||
result: Some(Value::String {
|
||||
val: "5.000".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("5.000", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "convert decimal to string and round to nearest integer",
|
||||
example: "1.7 | into string -d 0",
|
||||
result: Some(Value::String {
|
||||
val: "2".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("2", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "convert decimal to string",
|
||||
example: "1.7 | into string -d 1",
|
||||
result: Some(Value::String {
|
||||
val: "1.7".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("1.7", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "convert decimal to string and limit to 2 decimals",
|
||||
example: "1.734 | into string -d 2",
|
||||
result: Some(Value::String {
|
||||
val: "1.73".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("1.73", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "try to convert decimal to string and provide negative decimal points",
|
||||
@ -123,26 +111,17 @@ impl Command for SubCommand {
|
||||
Example {
|
||||
description: "convert decimal to string",
|
||||
example: "4.3 | into string",
|
||||
result: Some(Value::String {
|
||||
val: "4.3".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("4.3", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "convert string to string",
|
||||
example: "'1234' | into string",
|
||||
result: Some(Value::String {
|
||||
val: "1234".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("1234", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "convert boolean to string",
|
||||
example: "true | into string",
|
||||
result: Some(Value::String {
|
||||
val: "true".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("true", Span::test_data())),
|
||||
},
|
||||
// TODO: This should work but does not; see https://github.com/nushell/nushell/issues/7032
|
||||
// Example {
|
||||
|
@ -43,10 +43,10 @@ impl Command for Alias {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -37,14 +37,13 @@ impl Command for Ast {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let pipeline: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
let (output, err) = parse(&mut working_set, None, pipeline.item.as_bytes(), false, &[]);
|
||||
eprintln!("output: {:#?}\nerror: {:#?}", output, err);
|
||||
|
||||
Ok(PipelineData::new(head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -74,7 +74,7 @@ impl Command for Debug {
|
||||
},
|
||||
Example {
|
||||
description: "Debug print a table",
|
||||
example: "echo [[version patch]; [0.1.0 false] [0.1.1 true] [0.2.0 false]] | debug",
|
||||
example: "[[version patch]; [0.1.0 false] [0.1.1 true] [0.2.0 false]] | debug",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
Value::test_string("{version: 0.1.0, patch: false}"),
|
||||
|
@ -36,10 +36,10 @@ impl Command for Def {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -62,20 +62,17 @@ def-env cd_with_fallback [arg = ""] {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Set environment variable by call a custom command",
|
||||
example: r#"def-env foo [] { let-env BAR = "BAZ" }; foo; $env.BAR"#,
|
||||
result: Some(Value::String {
|
||||
val: "BAZ".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("BAZ", Span::test_data())),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ impl Command for Do {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Run a block"
|
||||
"Run a closure, providing it with the pipeline input"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
@ -23,25 +23,25 @@ impl Command for Do {
|
||||
.input_output_types(vec![(Type::Any, Type::Any)])
|
||||
.switch(
|
||||
"ignore-errors",
|
||||
"ignore errors as the block runs",
|
||||
"ignore errors as the closure runs",
|
||||
Some('i'),
|
||||
)
|
||||
.switch(
|
||||
"ignore-shell-errors",
|
||||
"ignore shell errors as the block runs",
|
||||
"ignore shell errors as the closure runs",
|
||||
Some('s'),
|
||||
)
|
||||
.switch(
|
||||
"ignore-program-errors",
|
||||
"ignore program errors as the block runs",
|
||||
"ignore external program errors as the closure runs",
|
||||
Some('p'),
|
||||
)
|
||||
.switch(
|
||||
"capture-errors",
|
||||
"capture errors as the block runs and return it",
|
||||
"catch errors as the closure runs, and return them",
|
||||
Some('c'),
|
||||
)
|
||||
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
||||
.rest("rest", SyntaxShape::Any, "the parameter(s) for the closure")
|
||||
.category(Category::Core)
|
||||
}
|
||||
|
||||
@ -169,9 +169,9 @@ impl Command for Do {
|
||||
trim_end_newline,
|
||||
}),
|
||||
Ok(PipelineData::Value(Value::Error { .. }, ..)) if ignore_shell_errors => {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
Err(_) if ignore_shell_errors => Ok(PipelineData::new(call.head)),
|
||||
Err(_) if ignore_shell_errors => Ok(PipelineData::empty()),
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
@ -179,22 +179,27 @@ impl Command for Do {
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Run the block",
|
||||
description: "Run the closure",
|
||||
example: r#"do { echo hello }"#,
|
||||
result: Some(Value::test_string("hello")),
|
||||
},
|
||||
Example {
|
||||
description: "Run the block and ignore both shell and program errors",
|
||||
description: "Run a stored first-class closure",
|
||||
example: r#"let text = "I am enclosed"; let hello = {|| echo $text}; do $hello"#,
|
||||
result: Some(Value::test_string("I am enclosed")),
|
||||
},
|
||||
Example {
|
||||
description: "Run the closure and ignore both shell and external program errors",
|
||||
example: r#"do -i { thisisnotarealcommand }"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Run the block and ignore shell errors",
|
||||
description: "Run the closure and ignore shell errors",
|
||||
example: r#"do -s { thisisnotarealcommand }"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Run the block and ignore program errors",
|
||||
description: "Run the closure and ignore external program errors",
|
||||
example: r#"do -p { nu -c 'exit 1' }; echo "I'll still run""#,
|
||||
result: None,
|
||||
},
|
||||
@ -204,12 +209,12 @@ impl Command for Do {
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Run the block, with a positional parameter",
|
||||
description: "Run the closure, with a positional parameter",
|
||||
example: r#"do {|x| 100 + $x } 77"#,
|
||||
result: Some(Value::test_int(177)),
|
||||
},
|
||||
Example {
|
||||
description: "Run the block, with input",
|
||||
description: "Run the closure, with input",
|
||||
example: r#"77 | do {|x| 100 + $in }"#,
|
||||
result: None, // TODO: returns 177
|
||||
},
|
||||
|
@ -51,13 +51,7 @@ little reason to use this over just writing the values as-is."#
|
||||
std::cmp::Ordering::Equal => PipelineData::Value(to_be_echoed[0].clone(), None),
|
||||
|
||||
// When there are no elements, we echo the empty string
|
||||
std::cmp::Ordering::Less => PipelineData::Value(
|
||||
Value::String {
|
||||
val: "".to_string(),
|
||||
span: call.head,
|
||||
},
|
||||
None,
|
||||
),
|
||||
std::cmp::Ordering::Less => PipelineData::Value(Value::string("", call.head), None),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -108,10 +108,7 @@ fn make_error(value: &Value, throw_span: Option<Span>) -> Option<ShellError> {
|
||||
) => Some(ShellError::GenericError(
|
||||
message,
|
||||
label_text,
|
||||
Some(Span {
|
||||
start: start as usize,
|
||||
end: end as usize,
|
||||
}),
|
||||
Some(Span::new(start as usize, end as usize)),
|
||||
None,
|
||||
Vec::new(),
|
||||
)),
|
||||
|
@ -56,10 +56,7 @@ impl Command for ExportCommand {
|
||||
vec![Example {
|
||||
description: "Export a definition from a module",
|
||||
example: r#"module utils { export def my-command [] { "hello" } }; use utils my-command; my-command"#,
|
||||
result: Some(Value::String {
|
||||
val: "hello".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("hello", Span::test_data())),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -39,10 +39,10 @@ impl Command for ExportAlias {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -36,20 +36,17 @@ impl Command for ExportDef {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Define a custom command in a module and call it",
|
||||
example: r#"module spam { export def foo [] { "foo" } }; use spam foo; foo"#,
|
||||
result: Some(Value::String {
|
||||
val: "foo".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("foo", Span::test_data())),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -62,20 +62,17 @@ export def-env cd_with_fallback [arg = ""] {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Define a custom command that participates in the environment in a module and call it",
|
||||
example: r#"module foo { export def-env bar [] { let-env FOO_BAR = "BAZ" } }; use foo bar; bar; $env.FOO_BAR"#,
|
||||
result: Some(Value::String {
|
||||
val: "BAZ".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("BAZ", Span::test_data())),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,10 @@ impl Command for ExportExtern {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -34,10 +34,10 @@ impl Command for ExportUse {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -48,10 +48,7 @@ impl Command for ExportUse {
|
||||
use eggs foo
|
||||
foo
|
||||
"#,
|
||||
result: Some(Value::String {
|
||||
val: "foo".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("foo", Span::test_data())),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,10 @@ impl Command for Extern {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -91,13 +91,7 @@ impl Command for For {
|
||||
if numbered {
|
||||
Value::Record {
|
||||
cols: vec!["index".into(), "item".into()],
|
||||
vals: vec![
|
||||
Value::Int {
|
||||
val: idx as i64,
|
||||
span: head,
|
||||
},
|
||||
x,
|
||||
],
|
||||
vals: vec![Value::int(idx as i64, head), x],
|
||||
span: head,
|
||||
}
|
||||
} else {
|
||||
@ -110,7 +104,7 @@ impl Command for For {
|
||||
&engine_state,
|
||||
stack,
|
||||
&block,
|
||||
PipelineData::new(head),
|
||||
PipelineData::empty(),
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
) {
|
||||
@ -124,7 +118,10 @@ impl Command for For {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(pipeline) => {
|
||||
pipeline.into_value(head);
|
||||
let exit_code = pipeline.print(&engine_state, stack, false, false)?;
|
||||
if exit_code != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -136,13 +133,7 @@ impl Command for For {
|
||||
if numbered {
|
||||
Value::Record {
|
||||
cols: vec!["index".into(), "item".into()],
|
||||
vals: vec![
|
||||
Value::Int {
|
||||
val: idx as i64,
|
||||
span: head,
|
||||
},
|
||||
x,
|
||||
],
|
||||
vals: vec![Value::int(idx as i64, head), x],
|
||||
span: head,
|
||||
}
|
||||
} else {
|
||||
@ -155,7 +146,7 @@ impl Command for For {
|
||||
&engine_state,
|
||||
stack,
|
||||
&block,
|
||||
PipelineData::new(head),
|
||||
PipelineData::empty(),
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
) {
|
||||
@ -169,7 +160,10 @@ impl Command for For {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(pipeline) => {
|
||||
pipeline.into_value(head);
|
||||
let exit_code = pipeline.print(&engine_state, stack, false, false)?;
|
||||
if exit_code != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,14 +175,14 @@ impl Command for For {
|
||||
&engine_state,
|
||||
stack,
|
||||
&block,
|
||||
PipelineData::new(head),
|
||||
PipelineData::empty(),
|
||||
redirect_stdout,
|
||||
redirect_stderr,
|
||||
)?
|
||||
.into_value(head);
|
||||
}
|
||||
}
|
||||
Ok(PipelineData::new(head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use fancy_regex::Regex;
|
||||
use nu_ansi_term::{
|
||||
Color::{Default, Red, White},
|
||||
Color::{Red, White},
|
||||
Style,
|
||||
};
|
||||
use nu_color_config::get_color_config;
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_engine::{get_full_help, CallExt};
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
@ -86,13 +86,13 @@ fn help(
|
||||
let find: Option<Spanned<String>> = call.get_flag(engine_state, stack, "find")?;
|
||||
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?;
|
||||
let commands = engine_state.get_decl_ids_sorted(false);
|
||||
let config = engine_state.get_config();
|
||||
let color_hm = get_color_config(config);
|
||||
let default_style = Style::new().fg(Default).on(Default);
|
||||
let string_style = match color_hm.get("string") {
|
||||
Some(style) => style,
|
||||
None => &default_style,
|
||||
};
|
||||
|
||||
// 🚩The following two-lines are copied from filters/find.rs:
|
||||
let style_computer = StyleComputer::from_config(engine_state, stack);
|
||||
// Currently, search results all use the same style.
|
||||
// Also note that this sample string is passed into user-written code (the closure that may or may not be
|
||||
// defined for "string").
|
||||
let string_style = style_computer.compute("string", &Value::string("search result", head));
|
||||
|
||||
if let Some(f) = find {
|
||||
let org_search_string = f.item.clone();
|
||||
@ -123,7 +123,7 @@ fn help(
|
||||
cols.push("name".into());
|
||||
vals.push(Value::String {
|
||||
val: if key_match {
|
||||
highlight_search_string(&key, &org_search_string, string_style)?
|
||||
highlight_search_string(&key, &org_search_string, &string_style)?
|
||||
} else {
|
||||
key
|
||||
},
|
||||
@ -131,10 +131,7 @@ fn help(
|
||||
});
|
||||
|
||||
cols.push("category".into());
|
||||
vals.push(Value::String {
|
||||
val: sig.category.to_string(),
|
||||
span: head,
|
||||
});
|
||||
vals.push(Value::string(sig.category.to_string(), head));
|
||||
|
||||
cols.push("command_type".into());
|
||||
vals.push(Value::String {
|
||||
@ -145,7 +142,7 @@ fn help(
|
||||
cols.push("usage".into());
|
||||
vals.push(Value::String {
|
||||
val: if usage_match {
|
||||
highlight_search_string(&usage, &org_search_string, string_style)?
|
||||
highlight_search_string(&usage, &org_search_string, &string_style)?
|
||||
} else {
|
||||
usage
|
||||
},
|
||||
@ -175,7 +172,7 @@ fn help(
|
||||
match highlight_search_string(
|
||||
term,
|
||||
&org_search_string,
|
||||
string_style,
|
||||
&string_style,
|
||||
) {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
@ -231,10 +228,7 @@ fn help(
|
||||
});
|
||||
|
||||
cols.push("category".into());
|
||||
vals.push(Value::String {
|
||||
val: sig.category.to_string(),
|
||||
span: head,
|
||||
});
|
||||
vals.push(Value::string(sig.category.to_string(), head));
|
||||
|
||||
cols.push("command_type".into());
|
||||
vals.push(Value::String {
|
||||
@ -334,11 +328,7 @@ Get the processes on your system actively using CPU:
|
||||
|
||||
You can also learn more at https://www.nushell.sh/book/"#;
|
||||
|
||||
Ok(Value::String {
|
||||
val: msg.into(),
|
||||
span: head,
|
||||
}
|
||||
.into_pipeline_data())
|
||||
Ok(Value::string(msg, head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,13 @@ fn generate_operator_info() -> Vec<OperatorInfo> {
|
||||
description: "Adds a value to a variable.".into(),
|
||||
precedence: 10,
|
||||
},
|
||||
OperatorInfo {
|
||||
op_type: "Assignment".into(),
|
||||
operator: "++=".into(),
|
||||
name: "AppendAssign".into(),
|
||||
description: "Appends a list or a value to a variable.".into(),
|
||||
precedence: 10,
|
||||
},
|
||||
OperatorInfo {
|
||||
op_type: "Assignment".into(),
|
||||
operator: "-=".into(),
|
||||
@ -284,13 +291,6 @@ fn generate_operator_info() -> Vec<OperatorInfo> {
|
||||
description: "Shifts a value right by another.".into(),
|
||||
precedence: 85,
|
||||
},
|
||||
OperatorInfo {
|
||||
op_type: "Boolean".into(),
|
||||
operator: "&&".into(),
|
||||
name: "And".into(),
|
||||
description: "Deprecated. Checks if two values are true.".into(),
|
||||
precedence: 50,
|
||||
},
|
||||
OperatorInfo {
|
||||
op_type: "Boolean".into(),
|
||||
operator: "and".into(),
|
||||
@ -298,13 +298,6 @@ fn generate_operator_info() -> Vec<OperatorInfo> {
|
||||
description: "Checks if two values are true.".into(),
|
||||
precedence: 50,
|
||||
},
|
||||
OperatorInfo {
|
||||
op_type: "Boolean".into(),
|
||||
operator: "||".into(),
|
||||
name: "Or".into(),
|
||||
description: "Deprecated. Checks if either value is true.".into(),
|
||||
precedence: 40,
|
||||
},
|
||||
OperatorInfo {
|
||||
op_type: "Boolean".into(),
|
||||
operator: "or".into(),
|
||||
|
@ -62,7 +62,7 @@ This command is a parser keyword. For details, check:
|
||||
|
||||
stack.remove_env_var(engine_state, &env_var_name.item);
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -63,7 +63,7 @@ impl Command for HideEnv {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -28,7 +28,13 @@ impl Command for If {
|
||||
)
|
||||
.optional(
|
||||
"else_expression",
|
||||
SyntaxShape::Keyword(b"else".to_vec(), Box::new(SyntaxShape::Expression)),
|
||||
SyntaxShape::Keyword(
|
||||
b"else".to_vec(),
|
||||
Box::new(SyntaxShape::OneOf(vec![
|
||||
SyntaxShape::Block,
|
||||
SyntaxShape::Expression,
|
||||
])),
|
||||
),
|
||||
"expression or block to run if check fails",
|
||||
)
|
||||
.category(Category::Core)
|
||||
@ -102,7 +108,7 @@ impl Command for If {
|
||||
.map(|res| res.0)
|
||||
}
|
||||
} else {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
}
|
||||
x => Err(ShellError::CantConvert(
|
||||
|
@ -32,7 +32,7 @@ impl Command for Ignore {
|
||||
input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
input.into_value(call.head);
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -73,7 +73,7 @@ impl Command for Let {
|
||||
//println!("Adding: {:?} to {}", rhs, var_id);
|
||||
|
||||
stack.add_var(var_id, rhs.into_value(call.head));
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use nu_engine::{eval_block, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Block, Command, EngineState, Stack};
|
||||
@ -44,10 +42,8 @@ impl Command for Loop {
|
||||
let block: Block = call.req(engine_state, stack, 0)?;
|
||||
|
||||
loop {
|
||||
if let Some(ctrlc) = &engine_state.ctrlc {
|
||||
if ctrlc.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
if nu_utils::ctrl_c::was_pressed(&engine_state.ctrlc) {
|
||||
break;
|
||||
}
|
||||
|
||||
let block = engine_state.get_block(block.block_id);
|
||||
@ -55,7 +51,7 @@ impl Command for Loop {
|
||||
engine_state,
|
||||
stack,
|
||||
block,
|
||||
PipelineData::new(call.head),
|
||||
PipelineData::empty(),
|
||||
call.redirect_stdout,
|
||||
call.redirect_stderr,
|
||||
) {
|
||||
@ -69,21 +65,21 @@ impl Command for Loop {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(pipeline) => {
|
||||
pipeline.into_value(call.head);
|
||||
let exit_code = pipeline.print(engine_state, stack, false, false)?;
|
||||
if exit_code != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Loop while a condition is true",
|
||||
example: "mut x = 0; loop { if $x > 10 { break }; $x = $x + 1 }; $x",
|
||||
result: Some(Value::Int {
|
||||
val: 11,
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::int(11, Span::test_data())),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
@ -81,19 +81,13 @@ impl Command for Metadata {
|
||||
data_source: DataSource::Ls,
|
||||
} => {
|
||||
cols.push("source".into());
|
||||
vals.push(Value::String {
|
||||
val: "ls".into(),
|
||||
span: head,
|
||||
})
|
||||
vals.push(Value::string("ls", head))
|
||||
}
|
||||
PipelineMetadata {
|
||||
data_source: DataSource::HtmlThemes,
|
||||
} => {
|
||||
cols.push("source".into());
|
||||
vals.push(Value::String {
|
||||
val: "into html --list".into(),
|
||||
span: head,
|
||||
})
|
||||
vals.push(Value::string("into html --list", head))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,19 +146,13 @@ fn build_metadata_record(arg: &Value, metadata: &Option<PipelineMetadata>, head:
|
||||
data_source: DataSource::Ls,
|
||||
} => {
|
||||
cols.push("source".into());
|
||||
vals.push(Value::String {
|
||||
val: "ls".into(),
|
||||
span: head,
|
||||
})
|
||||
vals.push(Value::string("ls", head))
|
||||
}
|
||||
PipelineMetadata {
|
||||
data_source: DataSource::HtmlThemes,
|
||||
} => {
|
||||
cols.push("source".into());
|
||||
vals.push(Value::String {
|
||||
val: "into html --list".into(),
|
||||
span: head,
|
||||
})
|
||||
vals.push(Value::string("into html --list", head))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,10 @@ impl Command for Module {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -46,26 +46,17 @@ impl Command for Module {
|
||||
Example {
|
||||
description: "Define a custom command in a module and call it",
|
||||
example: r#"module spam { export def foo [] { "foo" } }; use spam foo; foo"#,
|
||||
result: Some(Value::String {
|
||||
val: "foo".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("foo", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Define an environment variable in a module",
|
||||
example: r#"module foo { export-env { let-env FOO = "BAZ" } }; use foo; $env.FOO"#,
|
||||
result: Some(Value::String {
|
||||
val: "BAZ".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("BAZ", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Define a custom command that participates in the environment in a module and call it",
|
||||
example: r#"module foo { export def-env bar [] { let-env FOO_BAR = "BAZ" } }; use foo bar; bar; $env.FOO_BAR"#,
|
||||
result: Some(Value::String {
|
||||
val: "BAZ".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("BAZ", Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ impl Command for Mut {
|
||||
//println!("Adding: {:?} to {}", rhs, var_id);
|
||||
|
||||
stack.add_var(var_id, rhs.into_value(call.head));
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -83,6 +83,11 @@ impl Command for Mut {
|
||||
example: "mut x = 10; $x = 12",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Upsert a value inside a mutable data structure",
|
||||
example: "mut a = {b:{c:1}}; $a.b.c = 2",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Set a mutable variable to the result of an expression",
|
||||
example: "mut x = 10 + 100",
|
||||
|
@ -88,7 +88,7 @@ impl Command for OverlayHide {
|
||||
stack.add_env_var(name, val);
|
||||
}
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -50,10 +50,7 @@ impl Command for OverlayList {
|
||||
example: r#"module spam { export def foo [] { "foo" } }
|
||||
overlay use spam
|
||||
overlay list | last"#,
|
||||
result: Some(Value::String {
|
||||
val: "spam".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("spam", Span::test_data())),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ This command is a parser keyword. For details, check:
|
||||
|
||||
stack.add_overlay(name_arg.item);
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -130,22 +130,19 @@ impl Command for OverlayUse {
|
||||
if let Some(block_id) = module.env_block {
|
||||
let maybe_path = find_in_dirs_env(&name_arg.item, engine_state, caller_stack)?;
|
||||
|
||||
let block = engine_state.get_block(block_id);
|
||||
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
||||
|
||||
if let Some(path) = &maybe_path {
|
||||
// Set the currently evaluated directory, if the argument is a valid path
|
||||
let mut parent = path.clone();
|
||||
parent.pop();
|
||||
|
||||
let file_pwd = Value::String {
|
||||
val: parent.to_string_lossy().to_string(),
|
||||
span: call.head,
|
||||
};
|
||||
let file_pwd = Value::string(parent.to_string_lossy(), call.head);
|
||||
|
||||
caller_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||
callee_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||
}
|
||||
|
||||
let block = engine_state.get_block(block_id);
|
||||
let mut callee_stack = caller_stack.gather_captures(&block.captures);
|
||||
|
||||
let _ = eval_block(
|
||||
engine_state,
|
||||
&mut callee_stack,
|
||||
@ -160,11 +157,6 @@ impl Command for OverlayUse {
|
||||
|
||||
// Merge the block's environment to the current stack
|
||||
redirect_env(engine_state, caller_stack, &callee_stack);
|
||||
|
||||
if maybe_path.is_some() {
|
||||
// Remove the file-relative PWD, if the argument is a valid path
|
||||
caller_stack.remove_env_var(engine_state, "FILE_PWD");
|
||||
}
|
||||
} else {
|
||||
caller_stack.add_overlay(overlay_name);
|
||||
}
|
||||
@ -172,7 +164,7 @@ impl Command for OverlayUse {
|
||||
caller_stack.add_overlay(overlay_name);
|
||||
}
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -49,10 +49,10 @@ impl Command for Register {
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -69,15 +69,43 @@ impl Command for Try {
|
||||
engine_state,
|
||||
stack,
|
||||
catch_block,
|
||||
PipelineData::new(call.head),
|
||||
PipelineData::empty(),
|
||||
false,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
}
|
||||
// external command may fail to run
|
||||
Ok(pipeline) => {
|
||||
let (pipeline, external_failed) = pipeline.is_external_failed();
|
||||
if external_failed {
|
||||
if let Some(catch_block) = catch_block {
|
||||
let catch_block = engine_state.get_block(catch_block.block_id);
|
||||
|
||||
if let Some(var) = catch_block.signature.get_positional(0) {
|
||||
if let Some(var_id) = &var.var_id {
|
||||
let err_value = Value::nothing(call.head);
|
||||
stack.add_var(*var_id, err_value);
|
||||
}
|
||||
}
|
||||
|
||||
eval_block(
|
||||
engine_state,
|
||||
stack,
|
||||
catch_block,
|
||||
PipelineData::empty(),
|
||||
false,
|
||||
false,
|
||||
)
|
||||
} else {
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
} else {
|
||||
Ok(pipeline)
|
||||
}
|
||||
}
|
||||
Ok(output) => Ok(output),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,10 +79,7 @@ impl Command for Use {
|
||||
|
||||
// If so, set the currently evaluated directory (file-relative PWD)
|
||||
if let Some(parent) = maybe_parent {
|
||||
let file_pwd = Value::String {
|
||||
val: parent.to_string_lossy().to_string(),
|
||||
span: call.head,
|
||||
};
|
||||
let file_pwd = Value::string(parent.to_string_lossy(), call.head);
|
||||
callee_stack.add_env_var("FILE_PWD".to_string(), file_pwd);
|
||||
}
|
||||
|
||||
@ -112,7 +109,7 @@ impl Command for Use {
|
||||
));
|
||||
}
|
||||
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -120,18 +117,12 @@ impl Command for Use {
|
||||
Example {
|
||||
description: "Define a custom command in a module and call it",
|
||||
example: r#"module spam { export def foo [] { "foo" } }; use spam foo; foo"#,
|
||||
result: Some(Value::String {
|
||||
val: "foo".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("foo", Span::test_data())),
|
||||
},
|
||||
Example {
|
||||
description: "Define a custom command that participates in the environment in a module and call it",
|
||||
example: r#"module foo { export def-env bar [] { let-env FOO_BAR = "BAZ" } }; use foo bar; bar; $env.FOO_BAR"#,
|
||||
result: Some(Value::String {
|
||||
val: "BAZ".to_string(),
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
result: Some(Value::string("BAZ", Span::test_data())),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -54,97 +54,64 @@ pub fn version(
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("version".to_string());
|
||||
vals.push(Value::String {
|
||||
val: env!("CARGO_PKG_VERSION").to_string(),
|
||||
span: tag,
|
||||
});
|
||||
vals.push(Value::string(env!("CARGO_PKG_VERSION"), tag));
|
||||
|
||||
cols.push("branch".to_string());
|
||||
vals.push(Value::String {
|
||||
val: shadow::BRANCH.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(shadow::BRANCH, call.head));
|
||||
|
||||
let commit_hash: Option<&str> = option_env!("NU_COMMIT_HASH");
|
||||
if let Some(commit_hash) = commit_hash {
|
||||
cols.push("commit_hash".to_string());
|
||||
vals.push(Value::String {
|
||||
val: commit_hash.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(commit_hash, call.head));
|
||||
}
|
||||
|
||||
let build_os: Option<&str> = Some(shadow::BUILD_OS).filter(|x| !x.is_empty());
|
||||
if let Some(build_os) = build_os {
|
||||
cols.push("build_os".to_string());
|
||||
vals.push(Value::String {
|
||||
val: build_os.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(build_os, call.head));
|
||||
}
|
||||
|
||||
let build_target: Option<&str> = Some(shadow::BUILD_TARGET).filter(|x| !x.is_empty());
|
||||
if let Some(build_target) = build_target {
|
||||
cols.push("build_target".to_string());
|
||||
vals.push(Value::String {
|
||||
val: build_target.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(build_target, call.head));
|
||||
}
|
||||
|
||||
let rust_version: Option<&str> = Some(shadow::RUST_VERSION).filter(|x| !x.is_empty());
|
||||
if let Some(rust_version) = rust_version {
|
||||
cols.push("rust_version".to_string());
|
||||
vals.push(Value::String {
|
||||
val: rust_version.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(rust_version, call.head));
|
||||
}
|
||||
|
||||
let rust_channel: Option<&str> = Some(shadow::RUST_CHANNEL).filter(|x| !x.is_empty());
|
||||
if let Some(rust_channel) = rust_channel {
|
||||
cols.push("rust_channel".to_string());
|
||||
vals.push(Value::String {
|
||||
val: rust_channel.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(rust_channel, call.head));
|
||||
}
|
||||
|
||||
let cargo_version: Option<&str> = Some(shadow::CARGO_VERSION).filter(|x| !x.is_empty());
|
||||
if let Some(cargo_version) = cargo_version {
|
||||
cols.push("cargo_version".to_string());
|
||||
vals.push(Value::String {
|
||||
val: cargo_version.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(cargo_version, call.head));
|
||||
}
|
||||
|
||||
let pkg_version: Option<&str> = Some(shadow::PKG_VERSION).filter(|x| !x.is_empty());
|
||||
if let Some(pkg_version) = pkg_version {
|
||||
cols.push("pkg_version".to_string());
|
||||
vals.push(Value::String {
|
||||
val: pkg_version.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(pkg_version, call.head));
|
||||
}
|
||||
|
||||
let build_time: Option<&str> = Some(shadow::BUILD_TIME).filter(|x| !x.is_empty());
|
||||
if let Some(build_time) = build_time {
|
||||
cols.push("build_time".to_string());
|
||||
vals.push(Value::String {
|
||||
val: build_time.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(build_time, call.head));
|
||||
}
|
||||
|
||||
let build_rust_channel: Option<&str> =
|
||||
Some(shadow::BUILD_RUST_CHANNEL).filter(|x| !x.is_empty());
|
||||
if let Some(build_rust_channel) = build_rust_channel {
|
||||
cols.push("build_rust_channel".to_string());
|
||||
vals.push(Value::String {
|
||||
val: build_rust_channel.to_string(),
|
||||
span: call.head,
|
||||
});
|
||||
vals.push(Value::string(build_rust_channel, call.head));
|
||||
}
|
||||
|
||||
cols.push("features".to_string());
|
||||
|
@ -1,5 +1,3 @@
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use nu_engine::{eval_block, eval_expression, CallExt};
|
||||
use nu_protocol::ast::Call;
|
||||
use nu_protocol::engine::{Block, Command, EngineState, Stack};
|
||||
@ -48,10 +46,8 @@ impl Command for While {
|
||||
let block: Block = call.req(engine_state, stack, 1)?;
|
||||
|
||||
loop {
|
||||
if let Some(ctrlc) = &engine_state.ctrlc {
|
||||
if ctrlc.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
if nu_utils::ctrl_c::was_pressed(&engine_state.ctrlc) {
|
||||
break;
|
||||
}
|
||||
|
||||
let result = eval_expression(engine_state, stack, cond)?;
|
||||
@ -63,7 +59,7 @@ impl Command for While {
|
||||
engine_state,
|
||||
stack,
|
||||
block,
|
||||
PipelineData::new(call.head),
|
||||
PipelineData::empty(),
|
||||
call.redirect_stdout,
|
||||
call.redirect_stderr,
|
||||
) {
|
||||
@ -77,7 +73,11 @@ impl Command for While {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(pipeline) => {
|
||||
pipeline.into_value(call.head);
|
||||
let exit_code =
|
||||
pipeline.print(engine_state, stack, false, false)?;
|
||||
if exit_code != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -94,7 +94,7 @@ impl Command for While {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(PipelineData::new(call.head))
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::super::SQLiteDatabase;
|
||||
use crate::database::values::definitions::{db::Db, db_row::DbRow, db_table::DbTable};
|
||||
use crate::database::values::definitions::{db_row::DbRow, db_table::DbTable};
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
engine::{Command, EngineState, Stack},
|
||||
@ -22,7 +22,7 @@ impl Command for SchemaDb {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Show SQLite database information, including its schema."
|
||||
"Show the schema of a SQLite database."
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -50,76 +50,63 @@ impl Command for SchemaDb {
|
||||
|
||||
let sqlite_db = SQLiteDatabase::try_from_pipeline(input, span)?;
|
||||
let conn = open_sqlite_db_connection(&sqlite_db, span)?;
|
||||
let dbs = get_databases_and_tables(&sqlite_db, &conn, span)?;
|
||||
let tables = sqlite_db.get_tables(&conn).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error reading tables".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})?;
|
||||
|
||||
cols.push("db_filename".into());
|
||||
vals.push(Value::String {
|
||||
val: sqlite_db.path.to_string_lossy().into(),
|
||||
let mut table_names = vec![];
|
||||
let mut table_values = vec![];
|
||||
for table in tables {
|
||||
let column_info = get_table_columns(&sqlite_db, &conn, &table, span)?;
|
||||
let constraint_info = get_table_constraints(&sqlite_db, &conn, &table, span)?;
|
||||
let foreign_key_info = get_table_foreign_keys(&sqlite_db, &conn, &table, span)?;
|
||||
let index_info = get_table_indexes(&sqlite_db, &conn, &table, span)?;
|
||||
|
||||
let mut cols = vec![];
|
||||
let mut vals = vec![];
|
||||
|
||||
cols.push("columns".into());
|
||||
vals.push(Value::List {
|
||||
vals: column_info,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("constraints".into());
|
||||
vals.push(Value::List {
|
||||
vals: constraint_info,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("foreign_keys".into());
|
||||
vals.push(Value::List {
|
||||
vals: foreign_key_info,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("indexes".into());
|
||||
vals.push(Value::List {
|
||||
vals: index_info,
|
||||
span,
|
||||
});
|
||||
|
||||
table_names.push(table.name);
|
||||
table_values.push(Value::Record { cols, vals, span });
|
||||
}
|
||||
|
||||
cols.push("tables".into());
|
||||
vals.push(Value::Record {
|
||||
cols: table_names,
|
||||
vals: table_values,
|
||||
span,
|
||||
});
|
||||
|
||||
for db in dbs {
|
||||
let tables = get_database_tables(&db);
|
||||
let mut table_list: Vec<Value> = vec![];
|
||||
let mut table_names = vec![];
|
||||
let mut table_values = vec![];
|
||||
for table in tables {
|
||||
let column_info = get_table_columns(&sqlite_db, &conn, &table, span)?;
|
||||
let constraint_info = get_table_constraints(&sqlite_db, &conn, &table, span)?;
|
||||
let foreign_key_info = get_table_foreign_keys(&sqlite_db, &conn, &table, span)?;
|
||||
let index_info = get_table_indexes(&sqlite_db, &conn, &table, span)?;
|
||||
|
||||
table_names.push(table.name);
|
||||
table_values.push(Value::Record {
|
||||
cols: vec![
|
||||
"columns".into(),
|
||||
"constraints".into(),
|
||||
"foreign_keys".into(),
|
||||
"indexes".into(),
|
||||
],
|
||||
vals: vec![
|
||||
Value::List {
|
||||
vals: column_info,
|
||||
span,
|
||||
},
|
||||
Value::List {
|
||||
vals: constraint_info,
|
||||
span,
|
||||
},
|
||||
Value::List {
|
||||
vals: foreign_key_info,
|
||||
span,
|
||||
},
|
||||
Value::List {
|
||||
vals: index_info,
|
||||
span,
|
||||
},
|
||||
],
|
||||
span,
|
||||
});
|
||||
}
|
||||
table_list.push(Value::Record {
|
||||
cols: table_names,
|
||||
vals: table_values,
|
||||
span,
|
||||
});
|
||||
|
||||
cols.push("databases".into());
|
||||
|
||||
let mut rcols = vec![];
|
||||
let mut rvals = vec![];
|
||||
rcols.push("name".into());
|
||||
rvals.push(Value::string(db.name().to_string(), span));
|
||||
|
||||
rcols.push("tables".into());
|
||||
rvals.append(&mut table_list);
|
||||
|
||||
vals.push(Value::Record {
|
||||
cols: rcols,
|
||||
vals: rvals,
|
||||
span,
|
||||
});
|
||||
}
|
||||
// TODO: add views and triggers
|
||||
|
||||
Ok(PipelineData::Value(
|
||||
Value::Record { cols, vals, span },
|
||||
@ -140,26 +127,6 @@ fn open_sqlite_db_connection(db: &SQLiteDatabase, span: Span) -> Result<Connecti
|
||||
})
|
||||
}
|
||||
|
||||
fn get_databases_and_tables(
|
||||
db: &SQLiteDatabase,
|
||||
conn: &Connection,
|
||||
span: Span,
|
||||
) -> Result<Vec<Db>, ShellError> {
|
||||
db.get_databases_and_tables(conn).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Error getting databases and tables".into(),
|
||||
e.to_string(),
|
||||
Some(span),
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_database_tables(db: &Db) -> Vec<DbTable> {
|
||||
db.tables()
|
||||
}
|
||||
|
||||
fn get_table_columns(
|
||||
db: &SQLiteDatabase,
|
||||
conn: &Connection,
|
||||
|
@ -1,27 +0,0 @@
|
||||
use super::db_table::DbTable;
|
||||
|
||||
// Thank you gobang
|
||||
// https://github.com/TaKO8Ki/gobang/blob/main/database-tree/src/lib.rs
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Db {
|
||||
pub name: String,
|
||||
pub tables: Vec<DbTable>,
|
||||
}
|
||||
|
||||
impl Db {
|
||||
pub fn new(database: String, tables: Vec<DbTable>) -> Self {
|
||||
Self {
|
||||
name: database,
|
||||
tables,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
pub fn tables(&self) -> Vec<DbTable> {
|
||||
self.tables.clone()
|
||||
}
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
pub mod db;
|
||||
pub mod db_column;
|
||||
pub mod db_constraint;
|
||||
pub mod db_foreignkey;
|
||||
|
@ -1,5 +1,5 @@
|
||||
use super::definitions::{
|
||||
db::Db, db_column::DbColumn, db_constraint::DbConstraint, db_foreignkey::DbForeignKey,
|
||||
db_column::DbColumn, db_constraint::DbConstraint, db_foreignkey::DbForeignKey,
|
||||
db_index::DbIndex, db_table::DbTable,
|
||||
};
|
||||
|
||||
@ -10,6 +10,7 @@ use std::{
|
||||
fs::File,
|
||||
io::Read,
|
||||
path::{Path, PathBuf},
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
};
|
||||
|
||||
const SQLITE_MAGIC_BYTES: &[u8] = "SQLite format 3\0".as_bytes();
|
||||
@ -20,16 +21,25 @@ pub struct SQLiteDatabase {
|
||||
// 1) YAGNI, 2) it's not obvious how cloning a connection could work, 3) state
|
||||
// management gets tricky quick. Revisit this approach if we find a compelling use case.
|
||||
pub path: PathBuf,
|
||||
#[serde(skip)]
|
||||
// this understandably can't be serialized. think that's OK, I'm not aware of a
|
||||
// reason why a CustomValue would be serialized outside of a plugin
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
impl SQLiteDatabase {
|
||||
pub fn new(path: &Path) -> Self {
|
||||
pub fn new(path: &Path, ctrlc: Option<Arc<AtomicBool>>) -> Self {
|
||||
Self {
|
||||
path: PathBuf::from(path),
|
||||
ctrlc,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_from_path(path: &Path, span: Span) -> Result<Self, ShellError> {
|
||||
pub fn try_from_path(
|
||||
path: &Path,
|
||||
span: Span,
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
) -> Result<Self, ShellError> {
|
||||
let mut file =
|
||||
File::open(path).map_err(|e| ShellError::ReadingFile(e.to_string(), span))?;
|
||||
|
||||
@ -38,7 +48,7 @@ impl SQLiteDatabase {
|
||||
.map_err(|e| ShellError::ReadingFile(e.to_string(), span))
|
||||
.and_then(|_| {
|
||||
if buf == SQLITE_MAGIC_BYTES {
|
||||
Ok(SQLiteDatabase::new(path))
|
||||
Ok(SQLiteDatabase::new(path, ctrlc))
|
||||
} else {
|
||||
Err(ShellError::ReadingFile("Not a SQLite file".into(), span))
|
||||
}
|
||||
@ -50,6 +60,7 @@ impl SQLiteDatabase {
|
||||
Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
|
||||
Some(db) => Ok(Self {
|
||||
path: db.path.clone(),
|
||||
ctrlc: db.ctrlc.clone(),
|
||||
}),
|
||||
None => Err(ShellError::CantConvert(
|
||||
"database".into(),
|
||||
@ -81,7 +92,8 @@ impl SQLiteDatabase {
|
||||
|
||||
pub fn query(&self, sql: &Spanned<String>, call_span: Span) -> Result<Value, ShellError> {
|
||||
let db = open_sqlite_db(&self.path, call_span)?;
|
||||
run_sql_query(db, sql).map_err(|e| {
|
||||
|
||||
let stream = run_sql_query(db, sql, self.ctrlc.clone()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Failed to query SQLite database".into(),
|
||||
e.to_string(),
|
||||
@ -89,7 +101,9 @@ impl SQLiteDatabase {
|
||||
None,
|
||||
Vec::new(),
|
||||
)
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(stream)
|
||||
}
|
||||
|
||||
pub fn open_connection(&self) -> Result<Connection, rusqlite::Error> {
|
||||
@ -101,35 +115,6 @@ impl SQLiteDatabase {
|
||||
Ok(conn)
|
||||
}
|
||||
|
||||
pub fn get_databases_and_tables(&self, conn: &Connection) -> Result<Vec<Db>, rusqlite::Error> {
|
||||
let mut db_query = conn.prepare("SELECT name FROM pragma_database_list")?;
|
||||
|
||||
let databases = db_query.query_map([], |row| {
|
||||
let name: String = row.get(0)?;
|
||||
Ok(Db::new(name, self.get_tables(conn)?))
|
||||
})?;
|
||||
|
||||
let mut db_list = vec![];
|
||||
for db in databases {
|
||||
db_list.push(db?);
|
||||
}
|
||||
|
||||
Ok(db_list)
|
||||
}
|
||||
|
||||
pub fn get_databases(&self, conn: &Connection) -> Result<Vec<String>, rusqlite::Error> {
|
||||
let mut db_query = conn.prepare("SELECT name FROM pragma_database_list")?;
|
||||
|
||||
let mut db_list = vec![];
|
||||
let _ = db_query.query_map([], |row| {
|
||||
let name: String = row.get(0)?;
|
||||
db_list.push(name);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(db_list)
|
||||
}
|
||||
|
||||
pub fn get_tables(&self, conn: &Connection) -> Result<Vec<DbTable>, rusqlite::Error> {
|
||||
let mut table_names =
|
||||
conn.prepare("SELECT name FROM sqlite_master WHERE type = 'table'")?;
|
||||
@ -297,6 +282,7 @@ impl CustomValue for SQLiteDatabase {
|
||||
fn clone_value(&self, span: Span) -> Value {
|
||||
let cloned = SQLiteDatabase {
|
||||
path: self.path.clone(),
|
||||
ctrlc: self.ctrlc.clone(),
|
||||
};
|
||||
|
||||
Value::CustomValue {
|
||||
@ -311,7 +297,7 @@ impl CustomValue for SQLiteDatabase {
|
||||
|
||||
fn to_base_value(&self, span: Span) -> Result<Value, ShellError> {
|
||||
let db = open_sqlite_db(&self.path, span)?;
|
||||
read_entire_sqlite_db(db, span).map_err(|e| {
|
||||
read_entire_sqlite_db(db, span, self.ctrlc.clone()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Failed to read from SQLite database".into(),
|
||||
e.to_string(),
|
||||
@ -334,7 +320,7 @@ impl CustomValue for SQLiteDatabase {
|
||||
fn follow_path_string(&self, _column_name: String, span: Span) -> Result<Value, ShellError> {
|
||||
let db = open_sqlite_db(&self.path, span)?;
|
||||
|
||||
read_single_table(db, _column_name, span).map_err(|e| {
|
||||
read_single_table(db, _column_name, span, self.ctrlc.clone()).map_err(|e| {
|
||||
ShellError::GenericError(
|
||||
"Failed to read from SQLite database".into(),
|
||||
e.to_string(),
|
||||
@ -368,47 +354,72 @@ pub fn open_sqlite_db(path: &Path, call_span: Span) -> Result<Connection, nu_pro
|
||||
})
|
||||
}
|
||||
|
||||
fn run_sql_query(conn: Connection, sql: &Spanned<String>) -> Result<Value, rusqlite::Error> {
|
||||
fn run_sql_query(
|
||||
conn: Connection,
|
||||
sql: &Spanned<String>,
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
) -> Result<Value, rusqlite::Error> {
|
||||
let stmt = conn.prepare(&sql.item)?;
|
||||
prepared_statement_to_nu_list(stmt, sql.span)
|
||||
prepared_statement_to_nu_list(stmt, sql.span, ctrlc)
|
||||
}
|
||||
|
||||
fn read_single_table(
|
||||
conn: Connection,
|
||||
table_name: String,
|
||||
call_span: Span,
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
) -> Result<Value, rusqlite::Error> {
|
||||
let stmt = conn.prepare(&format!("SELECT * FROM {}", table_name))?;
|
||||
prepared_statement_to_nu_list(stmt, call_span)
|
||||
prepared_statement_to_nu_list(stmt, call_span, ctrlc)
|
||||
}
|
||||
|
||||
fn prepared_statement_to_nu_list(
|
||||
mut stmt: rusqlite::Statement,
|
||||
call_span: Span,
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
) -> Result<Value, rusqlite::Error> {
|
||||
let column_names = stmt
|
||||
.column_names()
|
||||
.iter()
|
||||
.map(|c| c.to_string())
|
||||
.collect::<Vec<String>>();
|
||||
let results = stmt.query([])?;
|
||||
let nu_records = results
|
||||
.mapped(|row| {
|
||||
Result::Ok(convert_sqlite_row_to_nu_value(
|
||||
row,
|
||||
call_span,
|
||||
column_names.clone(),
|
||||
))
|
||||
})
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<Value>, rusqlite::Error>>()?;
|
||||
|
||||
let row_results = stmt.query_map([], |row| {
|
||||
Ok(convert_sqlite_row_to_nu_value(
|
||||
row,
|
||||
call_span,
|
||||
column_names.clone(),
|
||||
))
|
||||
})?;
|
||||
|
||||
// we collect all rows before returning them. Not ideal but it's hard/impossible to return a stream from a CustomValue
|
||||
let mut row_values = vec![];
|
||||
|
||||
for row_result in row_results {
|
||||
if nu_utils::ctrl_c::was_pressed(&ctrlc) {
|
||||
// return whatever we have so far, let the caller decide whether to use it
|
||||
return Ok(Value::List {
|
||||
vals: row_values,
|
||||
span: call_span,
|
||||
});
|
||||
}
|
||||
|
||||
if let Ok(row_value) = row_result {
|
||||
row_values.push(row_value);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Value::List {
|
||||
vals: nu_records,
|
||||
vals: row_values,
|
||||
span: call_span,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_entire_sqlite_db(conn: Connection, call_span: Span) -> Result<Value, rusqlite::Error> {
|
||||
fn read_entire_sqlite_db(
|
||||
conn: Connection,
|
||||
call_span: Span,
|
||||
ctrlc: Option<Arc<AtomicBool>>,
|
||||
) -> Result<Value, rusqlite::Error> {
|
||||
let mut table_names: Vec<String> = Vec::new();
|
||||
let mut tables: Vec<Value> = Vec::new();
|
||||
|
||||
@ -421,7 +432,7 @@ fn read_entire_sqlite_db(conn: Connection, call_span: Span) -> Result<Value, rus
|
||||
table_names.push(table_name.clone());
|
||||
|
||||
let table_stmt = conn.prepare(&format!("select * from [{}]", table_name))?;
|
||||
let rows = prepared_statement_to_nu_list(table_stmt, call_span)?;
|
||||
let rows = prepared_statement_to_nu_list(table_stmt, call_span, ctrlc.clone())?;
|
||||
tables.push(rows);
|
||||
}
|
||||
|
||||
@ -480,7 +491,7 @@ mod test {
|
||||
#[test]
|
||||
fn can_read_empty_db() {
|
||||
let db = open_connection_in_memory().unwrap();
|
||||
let converted_db = read_entire_sqlite_db(db, Span::test_data()).unwrap();
|
||||
let converted_db = read_entire_sqlite_db(db, Span::test_data(), None).unwrap();
|
||||
|
||||
let expected = Value::Record {
|
||||
cols: vec![],
|
||||
@ -504,7 +515,7 @@ mod test {
|
||||
[],
|
||||
)
|
||||
.unwrap();
|
||||
let converted_db = read_entire_sqlite_db(db, Span::test_data()).unwrap();
|
||||
let converted_db = read_entire_sqlite_db(db, Span::test_data(), None).unwrap();
|
||||
|
||||
let expected = Value::Record {
|
||||
cols: vec!["person".to_string()],
|
||||
@ -538,7 +549,7 @@ mod test {
|
||||
db.execute("INSERT INTO item (id, name) VALUES (456, 'foo bar')", [])
|
||||
.unwrap();
|
||||
|
||||
let converted_db = read_entire_sqlite_db(db, span).unwrap();
|
||||
let converted_db = read_entire_sqlite_db(db, span, None).unwrap();
|
||||
|
||||
let expected = Value::Record {
|
||||
cols: vec!["item".to_string()],
|
||||
|
@ -30,14 +30,8 @@ impl Command for ColumnsDF {
|
||||
example: "[[a b]; [1 2] [3 4]] | into df | columns",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "a".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "b".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("a", Span::test_data()),
|
||||
Value::string("b", Span::test_data()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
@ -67,10 +61,7 @@ fn command(
|
||||
.as_ref()
|
||||
.get_column_names()
|
||||
.iter()
|
||||
.map(|v| Value::String {
|
||||
val: v.to_string(),
|
||||
span: call.head,
|
||||
})
|
||||
.map(|v| Value::string(*v, call.head))
|
||||
.collect();
|
||||
|
||||
let names = Value::List {
|
||||
|
@ -82,10 +82,7 @@ fn command(
|
||||
span: call.head,
|
||||
});
|
||||
|
||||
Value::String {
|
||||
val: v.to_string(),
|
||||
span: call.head,
|
||||
}
|
||||
Value::string(*v, call.head)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -61,15 +61,9 @@ impl Command for ListDF {
|
||||
span: call.head,
|
||||
};
|
||||
|
||||
let columns = Value::Int {
|
||||
val: df.as_ref().width() as i64,
|
||||
span: call.head,
|
||||
};
|
||||
let columns = Value::int(df.as_ref().width() as i64, call.head);
|
||||
|
||||
let rows = Value::Int {
|
||||
val: df.as_ref().height() as i64,
|
||||
span: call.head,
|
||||
};
|
||||
let rows = Value::int(df.as_ref().height() as i64, call.head);
|
||||
|
||||
let cols = vec![
|
||||
"name".to_string(),
|
||||
|
@ -61,15 +61,9 @@ fn command(
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let df = NuDataFrame::try_from_pipeline(input, call.head)?;
|
||||
|
||||
let rows = Value::Int {
|
||||
val: df.as_ref().height() as i64,
|
||||
span: call.head,
|
||||
};
|
||||
let rows = Value::int(df.as_ref().height() as i64, call.head);
|
||||
|
||||
let cols = Value::Int {
|
||||
val: df.as_ref().width() as i64,
|
||||
span: call.head,
|
||||
};
|
||||
let cols = Value::int(df.as_ref().width() as i64, call.head);
|
||||
|
||||
let rows_col = Column::new("rows".to_string(), vec![rows]);
|
||||
let cols_col = Column::new("columns".to_string(), vec![cols]);
|
||||
|
@ -32,14 +32,8 @@ impl Command for ExprAsNu {
|
||||
result: Some(Value::Record {
|
||||
cols: vec!["expr".into(), "value".into()],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "column".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "a".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("column", Span::test_data()),
|
||||
Value::string("a", Span::test_data()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
|
@ -38,14 +38,8 @@ impl Command for ExprCol {
|
||||
result: Some(Value::Record {
|
||||
cols: vec!["expr".into(), "value".into()],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "column".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "a".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("column", Span::test_data()),
|
||||
Value::string("a", Span::test_data()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
|
@ -37,14 +37,8 @@ impl Command for ExprLit {
|
||||
result: Some(Value::Record {
|
||||
cols: vec!["expr".into(), "value".into()],
|
||||
vals: vec![
|
||||
Value::String {
|
||||
val: "literal".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::String {
|
||||
val: "2i64".into(),
|
||||
span: Span::test_data(),
|
||||
},
|
||||
Value::string("literal", Span::test_data()),
|
||||
Value::string("2i64", Span::test_data()),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
|
@ -86,10 +86,7 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let value = Value::Bool {
|
||||
val: !bool.any(),
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::boolean(!bool.any(), call.head);
|
||||
|
||||
NuDataFrame::try_from_columns(vec![Column::new("all_false".to_string(), vec![value])])
|
||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||
|
@ -86,10 +86,7 @@ fn command(
|
||||
)
|
||||
})?;
|
||||
|
||||
let value = Value::Bool {
|
||||
val: bool.all(),
|
||||
span: call.head,
|
||||
};
|
||||
let value = Value::boolean(bool.all(), call.head);
|
||||
|
||||
NuDataFrame::try_from_columns(vec![Column::new("all_true".to_string(), vec![value])])
|
||||
.map(|df| PipelineData::Value(NuDataFrame::into_value(df, call.head), None))
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user