Merge branch 'main' into derive-value
This commit is contained in:
commit
5542545222
6
.github/workflows/nightly-build.yml
vendored
6
.github/workflows/nightly-build.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
|||
token: ${{ secrets.WORKFLOW_TOKEN }}
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3.10
|
||||
uses: hustcer/setup-nu@v3.11
|
||||
if: github.repository == 'nushell/nightly'
|
||||
with:
|
||||
version: 0.93.0
|
||||
|
@ -128,7 +128,7 @@ jobs:
|
|||
rustflags: ''
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3.10
|
||||
uses: hustcer/setup-nu@v3.11
|
||||
with:
|
||||
version: 0.93.0
|
||||
|
||||
|
@ -186,7 +186,7 @@ jobs:
|
|||
ref: main
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3.10
|
||||
uses: hustcer/setup-nu@v3.11
|
||||
with:
|
||||
version: 0.93.0
|
||||
|
||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -76,7 +76,7 @@ jobs:
|
|||
rustflags: ''
|
||||
|
||||
- name: Setup Nushell
|
||||
uses: hustcer/setup-nu@v3.10
|
||||
uses: hustcer/setup-nu@v3.11
|
||||
with:
|
||||
version: 0.93.0
|
||||
|
||||
|
|
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
|
@ -10,4 +10,4 @@ jobs:
|
|||
uses: actions/checkout@v4.1.6
|
||||
|
||||
- name: Check spelling
|
||||
uses: crate-ci/typos@v1.21.0
|
||||
uses: crate-ci/typos@v1.22.0
|
||||
|
|
26
CITATION.cff
Normal file
26
CITATION.cff
Normal file
|
@ -0,0 +1,26 @@
|
|||
cff-version: 1.2.0
|
||||
title: 'Nushell'
|
||||
message: >-
|
||||
If you use this software and wish to cite it,
|
||||
you can use the metadata from this file.
|
||||
type: software
|
||||
authors:
|
||||
- name: "The Nushell Project Team"
|
||||
identifiers:
|
||||
- type: url
|
||||
value: 'https://github.com/nushell/nushell'
|
||||
description: Repository
|
||||
repository-code: 'https://github.com/nushell/nushell'
|
||||
url: 'https://www.nushell.sh/'
|
||||
abstract: >-
|
||||
The goal of the Nushell project is to take the Unix
|
||||
philosophy of shells, where pipes connect simple commands
|
||||
together, and bring it to the modern style of development.
|
||||
Thus, rather than being either a shell, or a programming
|
||||
language, Nushell connects both by bringing a rich
|
||||
programming language and a full-featured shell together
|
||||
into one package.
|
||||
keywords:
|
||||
- nushell
|
||||
- shell
|
||||
license: MIT
|
232
Cargo.lock
generated
232
Cargo.lock
generated
|
@ -478,17 +478,6 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ada7f35ca622a86a4d6c27be2633fc6c243ecc834859628fcce0681d8e76e1c8"
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d640d25bc63c50fb1f0b545ffd80207d2e10a4c965530809b40ba3386825c391"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor 2.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli"
|
||||
version = "5.0.0"
|
||||
|
@ -497,17 +486,7 @@ checksum = "19483b140a7ac7174d34b5a581b406c64f84da5409d3e09cf4fff604f9270e67"
|
|||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor 4.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "brotli-decompressor"
|
||||
version = "2.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f"
|
||||
dependencies = [
|
||||
"alloc-no-stdlib",
|
||||
"alloc-stdlib",
|
||||
"brotli-decompressor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -871,7 +850,7 @@ checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7"
|
|||
dependencies = [
|
||||
"crossterm",
|
||||
"strum",
|
||||
"strum_macros 0.26.2",
|
||||
"strum_macros",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
|
@ -1304,6 +1283,9 @@ name = "either"
|
|||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eml-parser"
|
||||
|
@ -1803,6 +1785,7 @@ dependencies = [
|
|||
"ahash 0.8.11",
|
||||
"allocator-api2",
|
||||
"rayon",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2779,7 +2762,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"crossterm",
|
||||
|
@ -2832,7 +2815,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cli"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossterm",
|
||||
|
@ -2867,7 +2850,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-base"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"miette",
|
||||
|
@ -2879,7 +2862,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-extra"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"heck 0.5.0",
|
||||
|
@ -2904,7 +2887,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nu-engine",
|
||||
|
@ -2916,7 +2899,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-plugin"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nu-engine",
|
||||
|
@ -2927,7 +2910,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-color-config"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-engine",
|
||||
|
@ -2939,12 +2922,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-command"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"alphanumeric-sort",
|
||||
"base64 0.22.1",
|
||||
"bracoxide",
|
||||
"brotli 5.0.0",
|
||||
"brotli",
|
||||
"byteorder",
|
||||
"bytesize",
|
||||
"calamine",
|
||||
|
@ -3048,7 +3031,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-derive-value"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"proc-macro-error",
|
||||
|
@ -3059,7 +3042,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
|
@ -3069,7 +3052,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-explore"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"anyhow",
|
||||
|
@ -3094,14 +3077,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"doc-comment",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-json"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
"num-traits",
|
||||
|
@ -3111,7 +3094,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-lsp"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"crossbeam-channel",
|
||||
|
@ -3132,7 +3115,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-parser"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"chrono",
|
||||
|
@ -3148,7 +3131,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"dirs-next",
|
||||
"omnipath",
|
||||
|
@ -3157,7 +3140,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix",
|
||||
|
@ -3172,7 +3155,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-core"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"log",
|
||||
|
@ -3186,7 +3169,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-engine"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nu-engine",
|
||||
|
@ -3201,7 +3184,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"nu-protocol",
|
||||
|
@ -3213,7 +3196,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-test-support"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-cmd-lang",
|
||||
|
@ -3231,7 +3214,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"nu-ansi-term",
|
||||
|
@ -3240,9 +3223,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"brotli 5.0.0",
|
||||
"brotli",
|
||||
"byte-unit",
|
||||
"chrono",
|
||||
"chrono-humanize",
|
||||
|
@ -3264,7 +3247,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum_macros 0.26.2",
|
||||
"strum_macros",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"typetag",
|
||||
|
@ -3272,7 +3255,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-std"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"miette",
|
||||
|
@ -3283,7 +3266,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.12.1",
|
||||
|
@ -3301,7 +3284,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-table"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"nu-ansi-term",
|
||||
|
@ -3315,7 +3298,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-term-grid"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-utils",
|
||||
"unicode-width",
|
||||
|
@ -3323,7 +3306,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-test-support"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
|
@ -3335,7 +3318,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"crossterm_winapi",
|
||||
"log",
|
||||
|
@ -3361,7 +3344,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_example"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-cmd-lang",
|
||||
"nu-plugin",
|
||||
|
@ -3371,7 +3354,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_formats"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"eml-parser",
|
||||
"ical",
|
||||
|
@ -3384,7 +3367,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_gstat"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"nu-plugin",
|
||||
|
@ -3393,7 +3376,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_inc"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
|
@ -3402,7 +3385,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_polars"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz 0.9.0",
|
||||
|
@ -3425,7 +3408,7 @@ dependencies = [
|
|||
"polars-plan",
|
||||
"polars-utils",
|
||||
"serde",
|
||||
"sqlparser 0.45.0",
|
||||
"sqlparser 0.47.0",
|
||||
"tempfile",
|
||||
"typetag",
|
||||
"uuid",
|
||||
|
@ -3433,7 +3416,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_query"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"gjson",
|
||||
"nu-plugin",
|
||||
|
@ -3445,7 +3428,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_stress_internals"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"serde",
|
||||
|
@ -3571,7 +3554,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|||
|
||||
[[package]]
|
||||
name = "nuon"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fancy-regex",
|
||||
|
@ -4035,9 +4018,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ea21b858b16b9c0e17a12db2800d11aa5b4bd182be6b3022eb537bbfc1f2db5"
|
||||
checksum = "e148396dca5496566880fa19374f3f789a29db94e3eb458afac1497b4bac5442"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"polars-arrow",
|
||||
|
@ -4055,9 +4038,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-arrow"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "725b09f2b5ef31279b66e27bbab63c58d49d8f6696b66b1f46c7eaab95e80f75"
|
||||
checksum = "1cb5e11cd0752ae022fa6ca3afa50a14b0301b7ce53c0135828fbb0f4fa8303e"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"atoi",
|
||||
|
@ -4103,9 +4086,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-compute"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a796945b14b14fbb79b91ef0406e6fddca2be636e889f81ea5d6ee7d36efb4fe"
|
||||
checksum = "89fc4578f826234cdecb782952aa9c479dc49373f81694a7b439c70b6f609ba0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"either",
|
||||
|
@ -4119,9 +4102,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-core"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "465f70d3e96b6d0b1a43c358ba451286b8c8bd56696feff020d65702aa33e35c"
|
||||
checksum = "e490c6bace1366a558feea33d1846f749a8ca90bd72a6748752bc65bb4710b2a"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"bitflags 2.5.0",
|
||||
|
@ -4153,9 +4136,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-error"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5224d5d05e6b8a6f78b75951ae1b5f82c8ab1979e11ffaf5fd41941e3d5b0757"
|
||||
checksum = "08888f58e61599b00f5ea0c2ccdc796b54b9859559cc0d4582733509451fa01a"
|
||||
dependencies = [
|
||||
"avro-schema",
|
||||
"polars-arrow-format",
|
||||
|
@ -4165,10 +4148,30 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "polars-io"
|
||||
version = "0.39.2"
|
||||
name = "polars-expr"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2c8589e418cbe4a48228d64b2a8a40284a82ec3c98817c0c2bcc0267701338b"
|
||||
checksum = "4173591920fe56ad55af025f92eb0d08421ca85705c326a640c43856094e3484"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"bitflags 2.5.0",
|
||||
"once_cell",
|
||||
"polars-arrow",
|
||||
"polars-core",
|
||||
"polars-io",
|
||||
"polars-ops",
|
||||
"polars-plan",
|
||||
"polars-time",
|
||||
"polars-utils",
|
||||
"rayon",
|
||||
"smartstring",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polars-io"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5842896aea46d975b425d63f156f412aed3cfde4c257b64fb1f43ceea288074e"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"async-trait",
|
||||
|
@ -4207,9 +4210,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-json"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81224492a649a12b668480c0cf219d703f432509765d2717e72fe32ad16fc701"
|
||||
checksum = "160cbad0145b93ac6a88639aadfa6f7d7c769d05a8674f9b7e895b398cae9901"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"chrono",
|
||||
|
@ -4228,9 +4231,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-lazy"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2632b1af668e2058d5f8f916d8fbde3cac63d03ae29a705f598e41dcfeb7f"
|
||||
checksum = "e805ea2ebbc6b7749b0afb31b7fc5d32b42b57ba29b984549d43d3a16114c4a5"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"bitflags 2.5.0",
|
||||
|
@ -4238,6 +4241,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"polars-arrow",
|
||||
"polars-core",
|
||||
"polars-expr",
|
||||
"polars-io",
|
||||
"polars-json",
|
||||
"polars-ops",
|
||||
|
@ -4252,13 +4256,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-ops"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efdbdb4d9a92109bc2e0ce8e17af5ae8ab643bb5b7ee9d1d74f0aeffd1fbc95f"
|
||||
checksum = "7b0aed7e169c81b98457641cf82b251f52239a668916c2e683abd1f38df00d58"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"argminmax",
|
||||
"base64 0.21.7",
|
||||
"base64 0.22.1",
|
||||
"bytemuck",
|
||||
"chrono",
|
||||
"chrono-tz 0.8.6",
|
||||
|
@ -4288,14 +4292,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-parquet"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b421d2196f786fdfe162db614c8485f8308fe41575d4de634a39bbe460d1eb6a"
|
||||
checksum = "c70670a9e51cac66d0e77fd20b5cc957dbcf9f2660d410633862bb72f846d5b8"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"async-stream",
|
||||
"base64 0.21.7",
|
||||
"brotli 3.5.0",
|
||||
"base64 0.22.1",
|
||||
"brotli",
|
||||
"ethnum",
|
||||
"flate2",
|
||||
"futures",
|
||||
|
@ -4314,9 +4318,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-pipe"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48700f1d5bd56a15451e581f465c09541492750360f18637b196f995470a015c"
|
||||
checksum = "0a40ae1b3c74ee07e2d1f7cbf56c5d6e15969e45d9b6f0903bd2acaf783ba436"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-queue",
|
||||
|
@ -4326,6 +4330,7 @@ dependencies = [
|
|||
"polars-arrow",
|
||||
"polars-compute",
|
||||
"polars-core",
|
||||
"polars-expr",
|
||||
"polars-io",
|
||||
"polars-ops",
|
||||
"polars-plan",
|
||||
|
@ -4339,13 +4344,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-plan"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fb8e2302e20c44defd5be8cad9c96e75face63c3a5f609aced8c4ec3b3ac97d"
|
||||
checksum = "8daa3541ae7e9af311a4389bc2b21f83349c34c723cc67fa524cdefdaa172d90"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"bytemuck",
|
||||
"chrono-tz 0.8.6",
|
||||
"either",
|
||||
"hashbrown 0.14.5",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
|
@ -4362,15 +4368,15 @@ dependencies = [
|
|||
"regex",
|
||||
"serde",
|
||||
"smartstring",
|
||||
"strum_macros 0.25.3",
|
||||
"strum_macros",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polars-row"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a515bdc68c2ae3702e3de70d89601f3b71ca8137e282a226dddb53ee4bacfa2e"
|
||||
checksum = "deb285f2f3a65b00dd06bef16bb9f712dbb5478f941dab5cf74f9f016d382e40"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"polars-arrow",
|
||||
|
@ -4380,11 +4386,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-sql"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4bb7cc1c04c3023d1953b2f1dec50515e8fd8169a5a2bf4967b3b082232db7"
|
||||
checksum = "a724f699d194cb02c25124d3832f7d4d77f387f1a89ee42f6b9e88ec561d4ad9"
|
||||
dependencies = [
|
||||
"hex",
|
||||
"once_cell",
|
||||
"polars-arrow",
|
||||
"polars-core",
|
||||
"polars-error",
|
||||
|
@ -4398,11 +4405,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-time"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efc18e3ad92eec55db89d88f16c22d436559ba7030cf76f86f6ed7a754b673f1"
|
||||
checksum = "87ebec238d8b6200d9f0c3ce411c8441e950bd5a7df7806b8172d06c1d5a4b97"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"bytemuck",
|
||||
"chrono",
|
||||
"chrono-tz 0.8.6",
|
||||
"now",
|
||||
|
@ -4419,9 +4427,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "polars-utils"
|
||||
version = "0.39.2"
|
||||
version = "0.40.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c760b6c698cfe2fbbbd93d6cfb408db14ececfe1d92445dae2229ce1b5b21ae8"
|
||||
checksum = "34e1a907c63abf71e5f21467e2e4ff748896c28196746f631c6c25512ec6102c"
|
||||
dependencies = [
|
||||
"ahash 0.8.11",
|
||||
"bytemuck",
|
||||
|
@ -4856,7 +4864,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"strip-ansi-escapes",
|
||||
"strum",
|
||||
"strum_macros 0.26.2",
|
||||
"strum_macros",
|
||||
"thiserror",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
|
@ -5584,9 +5592,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlparser"
|
||||
version = "0.45.0"
|
||||
version = "0.47.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7bbffee862a796d67959a89859d6b1046bb5016d63e23835ad0da182777bbe0"
|
||||
checksum = "295e9930cd7a97e58ca2a070541a3ca502b17f5d1fa7157376d0fabd85324f25"
|
||||
dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
@ -5700,20 +5708,7 @@ version = "0.26.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
|
||||
dependencies = [
|
||||
"strum_macros 0.26.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.25.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.60",
|
||||
"strum_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -6090,6 +6085,7 @@ version = "0.8.12"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
|
|
42
Cargo.toml
42
Cargo.toml
|
@ -11,7 +11,7 @@ license = "MIT"
|
|||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.77.2"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -180,22 +180,22 @@ windows = "0.54"
|
|||
winreg = "0.52"
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.94.2" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.94.2" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.94.2" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.94.2", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.94.2" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.94.2" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.94.2" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.94.2" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.94.2" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.94.2" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.94.2" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.94.2" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.94.2" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.94.2" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.94.2" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.94.2" }
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.94.3" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.94.3" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.94.3" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.94.3", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.94.3" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.94.3" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.94.3" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.94.3" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.94.3" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.94.3" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.94.3" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.94.3" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.94.3" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.94.3" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.94.3" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.94.3" }
|
||||
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
|
@ -224,9 +224,9 @@ nix = { workspace = true, default-features = false, features = [
|
|||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.94.2" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.94.2" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.94.2" }
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.94.3" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.94.3" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.94.3" }
|
||||
assert_cmd = "2.0"
|
||||
dirs-next = { workspace = true }
|
||||
tango-bench = "0.5"
|
||||
|
@ -311,4 +311,4 @@ bench = false
|
|||
# Run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`
|
||||
[[bench]]
|
||||
name = "benchmarks"
|
||||
harness = false
|
||||
harness = false
|
||||
|
|
|
@ -5,27 +5,27 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.3" }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.2", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.3", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.3" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
|
@ -46,4 +46,4 @@ which = { workspace = true }
|
|||
|
||||
[features]
|
||||
plugin = ["nu-plugin-engine"]
|
||||
system-clipboard = ["reedline/system_clipboard"]
|
||||
system-clipboard = ["reedline/system_clipboard"]
|
||||
|
|
|
@ -52,18 +52,16 @@ impl Completer for CustomCompletion {
|
|||
decl_id: self.decl_id,
|
||||
head: span,
|
||||
arguments: vec![
|
||||
Argument::Positional(Expression {
|
||||
span: Span::unknown(),
|
||||
ty: Type::String,
|
||||
expr: Expr::String(self.line.clone()),
|
||||
custom_completion: None,
|
||||
}),
|
||||
Argument::Positional(Expression {
|
||||
span: Span::unknown(),
|
||||
ty: Type::Int,
|
||||
expr: Expr::Int(line_pos as i64),
|
||||
custom_completion: None,
|
||||
}),
|
||||
Argument::Positional(Expression::new_unknown(
|
||||
Expr::String(self.line.clone()),
|
||||
Span::unknown(),
|
||||
Type::String,
|
||||
)),
|
||||
Argument::Positional(Expression::new_unknown(
|
||||
Expr::Int(line_pos as i64),
|
||||
Span::unknown(),
|
||||
Type::Int,
|
||||
)),
|
||||
],
|
||||
parser_info: HashMap::new(),
|
||||
},
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::{menus::NuMenuCompleter, NuHelpCompleter};
|
||||
use crossterm::event::{KeyCode, KeyModifiers};
|
||||
use log::trace;
|
||||
use nu_ansi_term::Style;
|
||||
use nu_color_config::{color_record_to_nustyle, lookup_ansi_color_style};
|
||||
use nu_engine::eval_block;
|
||||
|
@ -80,7 +79,7 @@ pub(crate) fn add_menus(
|
|||
stack: &Stack,
|
||||
config: &Config,
|
||||
) -> Result<Reedline, ShellError> {
|
||||
trace!("add_menus: config: {:#?}", &config);
|
||||
//log::trace!("add_menus: config: {:#?}", &config);
|
||||
line_editor = line_editor.clear_menus();
|
||||
|
||||
for menu in &config.menus {
|
||||
|
|
|
@ -5,17 +5,17 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-cmd-base"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
|
||||
indexmap = { workspace = true }
|
||||
miette = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-cmd-extra"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -13,13 +13,13 @@ version = "0.94.2"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-json = { version = "0.94.2", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-pretty-hex = { version = "0.94.2", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-json = { version = "0.94.3", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-pretty-hex = { version = "0.94.3", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
heck = { workspace = true }
|
||||
|
@ -37,6 +37,6 @@ extra = ["default"]
|
|||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.3" }
|
||||
|
|
|
@ -6,16 +6,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
|
||||
itertools = { workspace = true }
|
||||
shadow-rs = { version = "0.28", default-features = false }
|
||||
|
@ -29,4 +29,4 @@ which-support = []
|
|||
trash-support = []
|
||||
sqlite = []
|
||||
static-link-openssl = []
|
||||
system-clipboard = []
|
||||
system-clipboard = []
|
||||
|
|
|
@ -60,6 +60,11 @@ impl Command for Def {
|
|||
example: r#"def --env foo [] { $env.BAR = "BAZ" }; foo; $env.BAR"#,
|
||||
result: Some(Value::test_string("BAZ")),
|
||||
},
|
||||
Example {
|
||||
description: "cd affects the environment, so '--env' is required to change directory from within a command",
|
||||
example: r#"def --env gohome [] { cd ~ }; gohome; $env.PWD == ('~' | path expand)"#,
|
||||
result: Some(Value::test_string("true")),
|
||||
},
|
||||
Example {
|
||||
description: "Define a custom wrapper for an external command",
|
||||
example: r#"def --wrapped my-echo [...rest] { echo $rest }; my-echo spam"#,
|
||||
|
|
|
@ -5,16 +5,16 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-cmd-plugin"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-plugin"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.3" }
|
||||
|
||||
itertools = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -5,18 +5,18 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-color-config"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.3" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.3" }
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-command"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -13,21 +13,21 @@ version = "0.94.2"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.2" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.2" }
|
||||
nu-table = { path = "../nu-table", version = "0.94.2" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.3" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.3" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.3" }
|
||||
nu-table = { path = "../nu-table", version = "0.94.3" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
nuon = { path = "../nuon", version = "0.94.2" }
|
||||
nuon = { path = "../nuon", version = "0.94.3" }
|
||||
|
||||
alphanumeric-sort = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
|
@ -86,7 +86,7 @@ sysinfo = { workspace = true }
|
|||
tabled = { workspace = true, features = ["color"], default-features = false }
|
||||
terminal_size = { workspace = true }
|
||||
titlecase = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
toml = { workspace = true, features = ["preserve_order"]}
|
||||
unicode-segmentation = { workspace = true }
|
||||
ureq = { workspace = true, default-features = false, features = ["charset", "gzip", "json", "native-tls"] }
|
||||
url = { workspace = true }
|
||||
|
@ -137,8 +137,8 @@ trash-support = ["trash"]
|
|||
which-support = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.3" }
|
||||
|
||||
dirs-next = { workspace = true }
|
||||
mockito = { workspace = true, default-features = false }
|
||||
|
@ -146,4 +146,4 @@ quickcheck = { workspace = true }
|
|||
quickcheck_macros = { workspace = true }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
pretty_assertions = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
|
|
|
@ -138,6 +138,7 @@ pub fn action(input: &Value, _args: &CellPathOnlyArgs, span: Span) -> Value {
|
|||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
|
||||
// Get the Locale so we know what the thousands separator is
|
||||
let locale = get_system_locale();
|
||||
|
@ -148,29 +149,35 @@ fn int_from_string(a_string: &str, span: Span) -> Result<i64, ShellError> {
|
|||
let clean_string = no_comma_string.trim();
|
||||
|
||||
// Hadle negative file size
|
||||
if let Some(stripped_string) = clean_string.strip_prefix('-') {
|
||||
match stripped_string.parse::<bytesize::ByteSize>() {
|
||||
if let Some(stripped_negative_string) = clean_string.strip_prefix('-') {
|
||||
match stripped_negative_string.parse::<bytesize::ByteSize>() {
|
||||
Ok(n) => Ok(-(n.as_u64() as i64)),
|
||||
Err(_) => Err(ShellError::CantConvert {
|
||||
to_type: "int".into(),
|
||||
from_type: "string".into(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
Err(_) => Err(string_convert_error(span)),
|
||||
}
|
||||
} else if let Some(stripped_positive_string) = clean_string.strip_prefix('+') {
|
||||
match stripped_positive_string.parse::<bytesize::ByteSize>() {
|
||||
Ok(n) if stripped_positive_string.starts_with(|c: char| c.is_ascii_digit()) => {
|
||||
Ok(n.as_u64() as i64)
|
||||
}
|
||||
_ => Err(string_convert_error(span)),
|
||||
}
|
||||
} else {
|
||||
match clean_string.parse::<bytesize::ByteSize>() {
|
||||
Ok(n) => Ok(n.0 as i64),
|
||||
Err(_) => Err(ShellError::CantConvert {
|
||||
to_type: "int".into(),
|
||||
from_type: "string".into(),
|
||||
span,
|
||||
help: None,
|
||||
}),
|
||||
Ok(n) => Ok(n.as_u64() as i64),
|
||||
Err(_) => Err(string_convert_error(span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn string_convert_error(span: Span) -> ShellError {
|
||||
ShellError::CantConvert {
|
||||
to_type: "filesize".into(),
|
||||
from_type: "string".into(),
|
||||
span,
|
||||
help: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -135,6 +135,11 @@ impl Command for Cd {
|
|||
example: r#"cd -"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Changing directory with a custom command requires 'def --env'",
|
||||
example: r#"def --env gohome [] { cd ~ }"#,
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use nu_engine::command_prelude::*;
|
|||
use super::msgpack::write_value;
|
||||
|
||||
const BUFFER_SIZE: usize = 65536;
|
||||
const DEFAULT_QUALITY: u32 = 1;
|
||||
const DEFAULT_QUALITY: u32 = 3; // 1 can be very bad
|
||||
const DEFAULT_WINDOW_SIZE: u32 = 20;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -22,7 +22,7 @@ impl Command for ToMsgpackz {
|
|||
.named(
|
||||
"quality",
|
||||
SyntaxShape::Int,
|
||||
"Quality of brotli compression (default 1)",
|
||||
"Quality of brotli compression (default 3)",
|
||||
Some('q'),
|
||||
)
|
||||
.named(
|
||||
|
|
|
@ -24,7 +24,7 @@ impl Command for ToToml {
|
|||
vec![Example {
|
||||
description: "Outputs an TOML string representing the contents of this record",
|
||||
example: r#"{foo: 1 bar: 'qwe'} | to toml"#,
|
||||
result: Some(Value::test_string("bar = \"qwe\"\nfoo = 1\n")),
|
||||
result: Some(Value::test_string("foo = 1\nbar = \"qwe\"\n")),
|
||||
}]
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ fn toml_into_pipeline_data(
|
|||
value_type: Type,
|
||||
span: Span,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
match toml::to_string(&toml_value) {
|
||||
match toml::to_string_pretty(&toml_value) {
|
||||
Ok(serde_toml_string) => Ok(Value::string(serde_toml_string, span).into_pipeline_data()),
|
||||
_ => Ok(Value::error(
|
||||
ShellError::CantConvert {
|
||||
|
|
|
@ -12,14 +12,17 @@ impl Command for StorInsert {
|
|||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("stor insert")
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
.input_output_types(vec![
|
||||
(Type::Nothing, Type::table()),
|
||||
(Type::record(), Type::table()),
|
||||
])
|
||||
.required_named(
|
||||
"table-name",
|
||||
SyntaxShape::String,
|
||||
"name of the table you want to insert into",
|
||||
Some('t'),
|
||||
)
|
||||
.required_named(
|
||||
.named(
|
||||
"data-record",
|
||||
SyntaxShape::Record(vec![]),
|
||||
"a record of column names and column values to insert into the specified table",
|
||||
|
@ -39,10 +42,16 @@ impl Command for StorInsert {
|
|||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "Insert data the in-memory sqlite database using a data-record of column-name and column-value pairs",
|
||||
example: "stor insert --table-name nudb --data-record {bool1: true, int1: 5, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}",
|
||||
result: None,
|
||||
}]
|
||||
description: "Insert data the in-memory sqlite database using a data-record of column-name and column-value pairs",
|
||||
example: "stor insert --table-name nudb --data-record {bool1: true, int1: 5, float1: 1.1, str1: fdncred, datetime1: 2023-04-17}",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Insert data through pipeline input as a record of column-name and column-value pairs",
|
||||
example: "{bool1: true, int1: 5, float1: 1.1, str1: fdncred, datetime1: 2023-04-17} | stor insert --table-name nudb",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
|
@ -50,25 +59,79 @@ impl Command for StorInsert {
|
|||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.head;
|
||||
let table_name: Option<String> = call.get_flag(engine_state, stack, "table-name")?;
|
||||
let columns: Option<Record> = call.get_flag(engine_state, stack, "data-record")?;
|
||||
let data_record: Option<Record> = call.get_flag(engine_state, stack, "data-record")?;
|
||||
// let config = engine_state.get_config();
|
||||
let db = Box::new(SQLiteDatabase::new(std::path::Path::new(MEMORY_DB), None));
|
||||
|
||||
// Check if the record is being passed as input or using the data record parameter
|
||||
let columns = handle(span, data_record, input)?;
|
||||
|
||||
process(table_name, span, &db, columns)?;
|
||||
|
||||
Ok(Value::custom(db, span).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(
|
||||
span: Span,
|
||||
data_record: Option<Record>,
|
||||
input: PipelineData,
|
||||
) -> Result<Record, ShellError> {
|
||||
match input {
|
||||
PipelineData::Empty => data_record.ok_or_else(|| ShellError::MissingParameter {
|
||||
param_name: "requires a record".into(),
|
||||
span,
|
||||
}),
|
||||
PipelineData::Value(value, ..) => {
|
||||
// Since input is being used, check if the data record parameter is used too
|
||||
if data_record.is_some() {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Pipeline and Flag both being used".into(),
|
||||
msg: "Use either pipeline input or '--data-record' parameter".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
match value {
|
||||
Value::Record { val, .. } => Ok(val.into_owned()),
|
||||
val => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: val.get_type().to_string(),
|
||||
dst_span: Span::unknown(),
|
||||
src_span: val.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if data_record.is_some() {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Pipeline and Flag both being used".into(),
|
||||
msg: "Use either pipeline input or '--data-record' parameter".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: "".into(),
|
||||
dst_span: span,
|
||||
src_span: span,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process(
|
||||
table_name: Option<String>,
|
||||
span: Span,
|
||||
db: &SQLiteDatabase,
|
||||
columns: Option<Record>,
|
||||
record: Record,
|
||||
) -> Result<(), ShellError> {
|
||||
if table_name.is_none() {
|
||||
return Err(ShellError::MissingParameter {
|
||||
|
@ -77,54 +140,45 @@ fn process(
|
|||
});
|
||||
}
|
||||
let new_table_name = table_name.unwrap_or("table".into());
|
||||
|
||||
if let Ok(conn) = db.open_connection() {
|
||||
match columns {
|
||||
Some(record) => {
|
||||
let mut create_stmt = format!("INSERT INTO {} ( ", new_table_name);
|
||||
let cols = record.columns();
|
||||
cols.for_each(|col| {
|
||||
create_stmt.push_str(&format!("{}, ", col));
|
||||
});
|
||||
if create_stmt.ends_with(", ") {
|
||||
create_stmt.pop();
|
||||
create_stmt.pop();
|
||||
}
|
||||
let mut create_stmt = format!("INSERT INTO {} ( ", new_table_name);
|
||||
let cols = record.columns();
|
||||
cols.for_each(|col| {
|
||||
create_stmt.push_str(&format!("{}, ", col));
|
||||
});
|
||||
if create_stmt.ends_with(", ") {
|
||||
create_stmt.pop();
|
||||
create_stmt.pop();
|
||||
}
|
||||
|
||||
// Values are set as placeholders.
|
||||
create_stmt.push_str(") VALUES ( ");
|
||||
for (index, _) in record.columns().enumerate() {
|
||||
create_stmt.push_str(&format!("?{}, ", index + 1));
|
||||
}
|
||||
// Values are set as placeholders.
|
||||
create_stmt.push_str(") VALUES ( ");
|
||||
for (index, _) in record.columns().enumerate() {
|
||||
create_stmt.push_str(&format!("?{}, ", index + 1));
|
||||
}
|
||||
|
||||
if create_stmt.ends_with(", ") {
|
||||
create_stmt.pop();
|
||||
create_stmt.pop();
|
||||
}
|
||||
if create_stmt.ends_with(", ") {
|
||||
create_stmt.pop();
|
||||
create_stmt.pop();
|
||||
}
|
||||
|
||||
create_stmt.push(')');
|
||||
create_stmt.push(')');
|
||||
|
||||
// dbg!(&create_stmt);
|
||||
// dbg!(&create_stmt);
|
||||
|
||||
// Get the params from the passed values
|
||||
let params = values_to_sql(record.values().cloned())?;
|
||||
// Get the params from the passed values
|
||||
let params = values_to_sql(record.values().cloned())?;
|
||||
|
||||
conn.execute(&create_stmt, params_from_iter(params))
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Failed to open SQLite connection in memory from insert".into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
}
|
||||
None => {
|
||||
return Err(ShellError::MissingParameter {
|
||||
param_name: "requires at least one column".into(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
conn.execute(&create_stmt, params_from_iter(params))
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Failed to open SQLite connection in memory from insert".into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
};
|
||||
// dbg!(db.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
@ -176,7 +230,7 @@ mod test {
|
|||
),
|
||||
);
|
||||
|
||||
let result = process(table_name, span, &db, Some(columns));
|
||||
let result = process(table_name, span, &db, columns);
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
@ -201,7 +255,7 @@ mod test {
|
|||
Value::test_string("String With Spaces".to_string()),
|
||||
);
|
||||
|
||||
let result = process(table_name, span, &db, Some(columns));
|
||||
let result = process(table_name, span, &db, columns);
|
||||
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
@ -226,7 +280,7 @@ mod test {
|
|||
Value::test_string("ThisIsALongString".to_string()),
|
||||
);
|
||||
|
||||
let result = process(table_name, span, &db, Some(columns));
|
||||
let result = process(table_name, span, &db, columns);
|
||||
// SQLite uses dynamic typing, making any length acceptable for a varchar column
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
@ -251,7 +305,7 @@ mod test {
|
|||
Value::test_string("ThisIsTheWrongType".to_string()),
|
||||
);
|
||||
|
||||
let result = process(table_name, span, &db, Some(columns));
|
||||
let result = process(table_name, span, &db, columns);
|
||||
// SQLite uses dynamic typing, making any type acceptable for a column
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
@ -276,7 +330,7 @@ mod test {
|
|||
Value::test_string("ThisIsALongString".to_string()),
|
||||
);
|
||||
|
||||
let result = process(table_name, span, &db, Some(columns));
|
||||
let result = process(table_name, span, &db, columns);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
@ -293,7 +347,7 @@ mod test {
|
|||
Value::test_string("ThisIsALongString".to_string()),
|
||||
);
|
||||
|
||||
let result = process(table_name, span, &db, Some(columns));
|
||||
let result = process(table_name, span, &db, columns);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
|
|
@ -11,14 +11,17 @@ impl Command for StorUpdate {
|
|||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("stor update")
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
.input_output_types(vec![
|
||||
(Type::Nothing, Type::table()),
|
||||
(Type::record(), Type::table()),
|
||||
])
|
||||
.required_named(
|
||||
"table-name",
|
||||
SyntaxShape::String,
|
||||
"name of the table you want to insert into",
|
||||
Some('t'),
|
||||
)
|
||||
.required_named(
|
||||
.named(
|
||||
"update-record",
|
||||
SyntaxShape::Record(vec![]),
|
||||
"a record of column names and column values to update in the specified table",
|
||||
|
@ -54,6 +57,11 @@ impl Command for StorUpdate {
|
|||
example: "stor update --table-name nudb --update-record {str1: nushell datetime1: 2020-04-17} --where-clause \"bool1 = 1\"",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Update the in-memory sqlite database through pipeline input",
|
||||
example: "{str1: nushell datetime1: 2020-04-17} | stor update --table-name nudb",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -62,91 +70,147 @@ impl Command for StorUpdate {
|
|||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.head;
|
||||
let table_name: Option<String> = call.get_flag(engine_state, stack, "table-name")?;
|
||||
let columns: Option<Record> = call.get_flag(engine_state, stack, "update-record")?;
|
||||
let update_record: Option<Record> = call.get_flag(engine_state, stack, "update-record")?;
|
||||
let where_clause_opt: Option<Spanned<String>> =
|
||||
call.get_flag(engine_state, stack, "where-clause")?;
|
||||
|
||||
// Open the in-mem database
|
||||
let db = Box::new(SQLiteDatabase::new(std::path::Path::new(MEMORY_DB), None));
|
||||
|
||||
if table_name.is_none() {
|
||||
return Err(ShellError::MissingParameter {
|
||||
param_name: "requires at table name".into(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
let new_table_name = table_name.unwrap_or("table".into());
|
||||
if let Ok(conn) = db.open_connection() {
|
||||
match columns {
|
||||
Some(record) => {
|
||||
let mut update_stmt = format!("UPDATE {} ", new_table_name);
|
||||
// Check if the record is being passed as input or using the update record parameter
|
||||
let columns = handle(span, update_record, input)?;
|
||||
|
||||
update_stmt.push_str("SET ");
|
||||
let vals = record.iter();
|
||||
vals.for_each(|(key, val)| match val {
|
||||
Value::Int { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = {}, ", key, val));
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = {}, ", key, val));
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = '{}', ", key, val));
|
||||
}
|
||||
Value::Date { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = '{}', ", key, val));
|
||||
}
|
||||
Value::Bool { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = {}, ", key, val));
|
||||
}
|
||||
_ => {
|
||||
// return Err(ShellError::UnsupportedInput {
|
||||
// msg: format!("{} is not a valid datepart, expected one of year, month, day, hour, minute, second, millisecond, microsecond, nanosecond", part.item),
|
||||
// input: "value originates from here".to_string(),
|
||||
// msg_span: span,
|
||||
// input_span: val.span(),
|
||||
// });
|
||||
}
|
||||
});
|
||||
if update_stmt.ends_with(", ") {
|
||||
update_stmt.pop();
|
||||
update_stmt.pop();
|
||||
}
|
||||
process(table_name, span, &db, columns, where_clause_opt)?;
|
||||
|
||||
// Yup, this is a bit janky, but I'm not sure a better way to do this without having
|
||||
// --and and --or flags as well as supporting ==, !=, <>, is null, is not null, etc.
|
||||
// and other sql syntax. So, for now, just type a sql where clause as a string.
|
||||
if let Some(where_clause) = where_clause_opt {
|
||||
update_stmt.push_str(&format!(" WHERE {}", where_clause.item));
|
||||
}
|
||||
// dbg!(&update_stmt);
|
||||
|
||||
conn.execute(&update_stmt, [])
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Failed to open SQLite connection in memory from update".into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
}
|
||||
None => {
|
||||
return Err(ShellError::MissingParameter {
|
||||
param_name: "requires at least one column".into(),
|
||||
span: call.head,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
// dbg!(db.clone());
|
||||
Ok(Value::custom(db, span).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
fn handle(
|
||||
span: Span,
|
||||
update_record: Option<Record>,
|
||||
input: PipelineData,
|
||||
) -> Result<Record, ShellError> {
|
||||
match input {
|
||||
PipelineData::Empty => update_record.ok_or_else(|| ShellError::MissingParameter {
|
||||
param_name: "requires a record".into(),
|
||||
span,
|
||||
}),
|
||||
PipelineData::Value(value, ..) => {
|
||||
// Since input is being used, check if the data record parameter is used too
|
||||
if update_record.is_some() {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Pipeline and Flag both being used".into(),
|
||||
msg: "Use either pipeline input or '--update-record' parameter".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
match value {
|
||||
Value::Record { val, .. } => Ok(val.into_owned()),
|
||||
val => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: val.get_type().to_string(),
|
||||
dst_span: Span::unknown(),
|
||||
src_span: val.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if update_record.is_some() {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Pipeline and Flag both being used".into(),
|
||||
msg: "Use either pipeline input or '--update-record' parameter".into(),
|
||||
span: Some(span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "record".into(),
|
||||
wrong_type: "".into(),
|
||||
dst_span: span,
|
||||
src_span: span,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process(
|
||||
table_name: Option<String>,
|
||||
span: Span,
|
||||
db: &SQLiteDatabase,
|
||||
record: Record,
|
||||
where_clause_opt: Option<Spanned<String>>,
|
||||
) -> Result<(), ShellError> {
|
||||
if table_name.is_none() {
|
||||
return Err(ShellError::MissingParameter {
|
||||
param_name: "requires at table name".into(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
let new_table_name = table_name.unwrap_or("table".into());
|
||||
if let Ok(conn) = db.open_connection() {
|
||||
let mut update_stmt = format!("UPDATE {} ", new_table_name);
|
||||
|
||||
update_stmt.push_str("SET ");
|
||||
let vals = record.iter();
|
||||
vals.for_each(|(key, val)| match val {
|
||||
Value::Int { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = {}, ", key, val));
|
||||
}
|
||||
Value::Float { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = {}, ", key, val));
|
||||
}
|
||||
Value::String { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = '{}', ", key, val));
|
||||
}
|
||||
Value::Date { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = '{}', ", key, val));
|
||||
}
|
||||
Value::Bool { val, .. } => {
|
||||
update_stmt.push_str(&format!("{} = {}, ", key, val));
|
||||
}
|
||||
_ => {
|
||||
// return Err(ShellError::UnsupportedInput {
|
||||
// msg: format!("{} is not a valid datepart, expected one of year, month, day, hour, minute, second, millisecond, microsecond, nanosecond", part.item),
|
||||
// input: "value originates from here".to_string(),
|
||||
// msg_span: span,
|
||||
// input_span: val.span(),
|
||||
// });
|
||||
}
|
||||
});
|
||||
if update_stmt.ends_with(", ") {
|
||||
update_stmt.pop();
|
||||
update_stmt.pop();
|
||||
}
|
||||
|
||||
// Yup, this is a bit janky, but I'm not sure a better way to do this without having
|
||||
// --and and --or flags as well as supporting ==, !=, <>, is null, is not null, etc.
|
||||
// and other sql syntax. So, for now, just type a sql where clause as a string.
|
||||
if let Some(where_clause) = where_clause_opt {
|
||||
update_stmt.push_str(&format!(" WHERE {}", where_clause.item));
|
||||
}
|
||||
// dbg!(&update_stmt);
|
||||
|
||||
conn.execute(&update_stmt, [])
|
||||
.map_err(|err| ShellError::GenericError {
|
||||
error: "Failed to open SQLite connection in memory from update".into(),
|
||||
msg: err.to_string(),
|
||||
span: Some(Span::test_data()),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
}
|
||||
// dbg!(db.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use indexmap::{indexmap, IndexMap};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::engine::StateWorkingSet;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
|
||||
|
|
|
@ -45,20 +45,6 @@ impl Command for DetectColumns {
|
|||
vec!["split", "tabular"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
if call.has_flag(engine_state, stack, "guess")? {
|
||||
guess_width(engine_state, stack, call, input)
|
||||
} else {
|
||||
detect_columns(engine_state, stack, call, input)
|
||||
}
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
@ -109,33 +95,87 @@ none 8150224 4 8150220 1% /mnt/c' | detect columns --gue
|
|||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let num_rows_to_skip: Option<usize> = call.get_flag(engine_state, stack, "skip")?;
|
||||
let noheader = call.has_flag(engine_state, stack, "no-headers")?;
|
||||
let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?;
|
||||
|
||||
let args = Arguments {
|
||||
noheader,
|
||||
num_rows_to_skip,
|
||||
range,
|
||||
};
|
||||
|
||||
if call.has_flag(engine_state, stack, "guess")? {
|
||||
guess_width(engine_state, call, input, args)
|
||||
} else {
|
||||
detect_columns(engine_state, call, input, args)
|
||||
}
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let num_rows_to_skip: Option<usize> = call.get_flag_const(working_set, "skip")?;
|
||||
let noheader = call.has_flag_const(working_set, "no-headers")?;
|
||||
let range: Option<Range> = call.get_flag_const(working_set, "combine-columns")?;
|
||||
|
||||
let args = Arguments {
|
||||
noheader,
|
||||
num_rows_to_skip,
|
||||
range,
|
||||
};
|
||||
|
||||
if call.has_flag_const(working_set, "guess")? {
|
||||
guess_width(working_set.permanent(), call, input, args)
|
||||
} else {
|
||||
detect_columns(working_set.permanent(), call, input, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
num_rows_to_skip: Option<usize>,
|
||||
noheader: bool,
|
||||
range: Option<Range>,
|
||||
}
|
||||
|
||||
fn guess_width(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
args: Arguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
use super::guess_width::GuessWidth;
|
||||
let input_span = input.span().unwrap_or(call.head);
|
||||
|
||||
let mut input = input.collect_string("", engine_state.get_config())?;
|
||||
let num_rows_to_skip: Option<usize> = call.get_flag(engine_state, stack, "skip")?;
|
||||
if let Some(rows) = num_rows_to_skip {
|
||||
if let Some(rows) = args.num_rows_to_skip {
|
||||
input = input.lines().skip(rows).map(|x| x.to_string()).join("\n");
|
||||
}
|
||||
|
||||
let mut guess_width = GuessWidth::new_reader(Box::new(Cursor::new(input)));
|
||||
let noheader = call.has_flag(engine_state, stack, "no-headers")?;
|
||||
|
||||
let result = guess_width.read_all();
|
||||
|
||||
if result.is_empty() {
|
||||
return Ok(Value::nothing(input_span).into_pipeline_data());
|
||||
}
|
||||
let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?;
|
||||
if !noheader {
|
||||
if !args.noheader {
|
||||
let columns = result[0].clone();
|
||||
Ok(result
|
||||
.into_iter()
|
||||
|
@ -152,7 +192,7 @@ fn guess_width(
|
|||
let record =
|
||||
Record::from_raw_cols_vals(columns.clone(), values, input_span, input_span);
|
||||
match record {
|
||||
Ok(r) => match &range {
|
||||
Ok(r) => match &args.range {
|
||||
Some(range) => merge_record(r, range, input_span),
|
||||
None => Value::record(r, input_span),
|
||||
},
|
||||
|
@ -177,7 +217,7 @@ fn guess_width(
|
|||
let record =
|
||||
Record::from_raw_cols_vals(columns.clone(), values, input_span, input_span);
|
||||
match record {
|
||||
Ok(r) => match &range {
|
||||
Ok(r) => match &args.range {
|
||||
Some(range) => merge_record(r, range, input_span),
|
||||
None => Value::record(r, input_span),
|
||||
},
|
||||
|
@ -190,21 +230,18 @@ fn guess_width(
|
|||
|
||||
fn detect_columns(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
args: Arguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name_span = call.head;
|
||||
let num_rows_to_skip: Option<usize> = call.get_flag(engine_state, stack, "skip")?;
|
||||
let noheader = call.has_flag(engine_state, stack, "no-headers")?;
|
||||
let range: Option<Range> = call.get_flag(engine_state, stack, "combine-columns")?;
|
||||
let ctrlc = engine_state.ctrlc.clone();
|
||||
let config = engine_state.get_config();
|
||||
let input = input.collect_string("", config)?;
|
||||
|
||||
let input: Vec<_> = input
|
||||
.lines()
|
||||
.skip(num_rows_to_skip.unwrap_or_default())
|
||||
.skip(args.num_rows_to_skip.unwrap_or_default())
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
|
||||
|
@ -214,13 +251,14 @@ fn detect_columns(
|
|||
if let Some(orig_headers) = headers {
|
||||
let mut headers = find_columns(&orig_headers);
|
||||
|
||||
if noheader {
|
||||
if args.noheader {
|
||||
for header in headers.iter_mut().enumerate() {
|
||||
header.1.item = format!("column{}", header.0);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(noheader
|
||||
Ok(args
|
||||
.noheader
|
||||
.then_some(orig_headers)
|
||||
.into_iter()
|
||||
.chain(input)
|
||||
|
@ -273,7 +311,7 @@ fn detect_columns(
|
|||
}
|
||||
}
|
||||
|
||||
match &range {
|
||||
match &args.range {
|
||||
Some(range) => merge_record(record, range, name_span),
|
||||
None => Value::record(record, name_span),
|
||||
}
|
||||
|
|
|
@ -7,10 +7,9 @@ use base64::{
|
|||
Engine,
|
||||
};
|
||||
use nu_cmd_base::input_handler::{operate as general_operate, CmdArgument};
|
||||
use nu_engine::CallExt;
|
||||
use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
engine::{EngineState, Stack},
|
||||
engine::EngineState,
|
||||
PipelineData, ShellError, Span, Spanned, Value,
|
||||
};
|
||||
|
||||
|
@ -42,22 +41,24 @@ impl CmdArgument for Arguments {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) struct Base64CommandArguments {
|
||||
pub(super) character_set: Option<Spanned<String>>,
|
||||
pub(super) action_type: ActionType,
|
||||
pub(super) binary: bool,
|
||||
}
|
||||
|
||||
pub fn operate(
|
||||
action_type: ActionType,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
cell_paths: Vec<CellPath>,
|
||||
args: Base64CommandArguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let character_set: Option<Spanned<String>> =
|
||||
call.get_flag(engine_state, stack, "character-set")?;
|
||||
let binary = call.has_flag(engine_state, stack, "binary")?;
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
|
||||
// Default the character set to standard if the argument is not specified.
|
||||
let character_set = match character_set {
|
||||
let character_set = match args.character_set {
|
||||
Some(inner_tag) => inner_tag,
|
||||
None => Spanned {
|
||||
item: "standard".to_string(),
|
||||
|
@ -68,9 +69,9 @@ pub fn operate(
|
|||
let args = Arguments {
|
||||
encoding_config: Base64Config {
|
||||
character_set,
|
||||
action_type,
|
||||
action_type: args.action_type,
|
||||
},
|
||||
binary,
|
||||
binary: args.binary,
|
||||
cell_paths,
|
||||
};
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -53,49 +57,67 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let encoding: Option<Spanned<String>> = call.opt(engine_state, stack, 0)?;
|
||||
run(call, input, encoding)
|
||||
}
|
||||
|
||||
match input {
|
||||
PipelineData::ByteStream(stream, ..) => {
|
||||
let span = stream.span();
|
||||
let bytes = stream.into_bytes()?;
|
||||
match encoding {
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let encoding: Option<Spanned<String>> = call.opt_const(working_set, 0)?;
|
||||
run(call, input, encoding)
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
encoding: Option<Spanned<String>>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
|
||||
match input {
|
||||
PipelineData::ByteStream(stream, ..) => {
|
||||
let span = stream.span();
|
||||
let bytes = stream.into_bytes()?;
|
||||
match encoding {
|
||||
Some(encoding_name) => super::encoding::decode(head, encoding_name, &bytes),
|
||||
None => super::encoding::detect_encoding_name(head, span, &bytes)
|
||||
.map(|encoding| encoding.decode(&bytes).0.into_owned())
|
||||
.map(|s| Value::string(s, head)),
|
||||
}
|
||||
.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
PipelineData::Value(v, ..) => {
|
||||
let input_span = v.span();
|
||||
match v {
|
||||
Value::Binary { val: bytes, .. } => match encoding {
|
||||
Some(encoding_name) => super::encoding::decode(head, encoding_name, &bytes),
|
||||
None => super::encoding::detect_encoding_name(head, span, &bytes)
|
||||
None => super::encoding::detect_encoding_name(head, input_span, &bytes)
|
||||
.map(|encoding| encoding.decode(&bytes).0.into_owned())
|
||||
.map(|s| Value::string(s, head)),
|
||||
}
|
||||
.map(|val| val.into_pipeline_data())
|
||||
.map(|val| val.into_pipeline_data()),
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: v.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: v.span(),
|
||||
}),
|
||||
}
|
||||
PipelineData::Value(v, ..) => {
|
||||
let input_span = v.span();
|
||||
match v {
|
||||
Value::Binary { val: bytes, .. } => match encoding {
|
||||
Some(encoding_name) => super::encoding::decode(head, encoding_name, &bytes),
|
||||
None => super::encoding::detect_encoding_name(head, input_span, &bytes)
|
||||
.map(|encoding| encoding.decode(&bytes).0.into_owned())
|
||||
.map(|s| Value::string(s, head)),
|
||||
}
|
||||
.map(|val| val.into_pipeline_data()),
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "binary".into(),
|
||||
wrong_type: v.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: v.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
// This should be more precise, but due to difficulties in getting spans
|
||||
// from PipelineData::ListData, this is as it is.
|
||||
_ => Err(ShellError::UnsupportedInput {
|
||||
msg: "non-binary input".into(),
|
||||
input: "value originates from here".into(),
|
||||
msg_span: head,
|
||||
input_span: input.span().unwrap_or(head),
|
||||
}),
|
||||
}
|
||||
// This should be more precise, but due to difficulties in getting spans
|
||||
// from PipelineData::ListData, this is as it is.
|
||||
_ => Err(ShellError::UnsupportedInput {
|
||||
msg: "non-binary input".into(),
|
||||
input: "value originates from here".into(),
|
||||
msg_span: head,
|
||||
input_span: input.span().unwrap_or(head),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::base64::{operate, ActionType, CHARACTER_SET_DESC};
|
||||
use super::base64::{operate, ActionType, Base64CommandArguments, CHARACTER_SET_DESC};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -66,6 +66,10 @@ impl Command for DecodeBase64 {
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -73,7 +77,34 @@ impl Command for DecodeBase64 {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(ActionType::Decode, engine_state, stack, call, input)
|
||||
let character_set: Option<Spanned<String>> =
|
||||
call.get_flag(engine_state, stack, "character-set")?;
|
||||
let binary = call.has_flag(engine_state, stack, "binary")?;
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let args = Base64CommandArguments {
|
||||
action_type: ActionType::Decode,
|
||||
binary,
|
||||
character_set,
|
||||
};
|
||||
operate(engine_state, call, input, cell_paths, args)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let character_set: Option<Spanned<String>> =
|
||||
call.get_flag_const(working_set, "character-set")?;
|
||||
let binary = call.has_flag_const(working_set, "binary")?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
let args = Base64CommandArguments {
|
||||
action_type: ActionType::Decode,
|
||||
binary,
|
||||
character_set,
|
||||
};
|
||||
operate(working_set.permanent(), call, input, cell_paths, args)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,10 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -76,42 +80,62 @@ documentation link at https://docs.rs/encoding_rs/latest/encoding_rs/#statics"#
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let encoding: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let ignore_errors = call.has_flag(engine_state, stack, "ignore-errors")?;
|
||||
run(call, input, encoding, ignore_errors)
|
||||
}
|
||||
|
||||
match input {
|
||||
PipelineData::ByteStream(stream, ..) => {
|
||||
let span = stream.span();
|
||||
let s = stream.into_string()?;
|
||||
super::encoding::encode(head, encoding, &s, span, ignore_errors)
|
||||
.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
PipelineData::Value(v, ..) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::String { val: s, .. } => {
|
||||
super::encoding::encode(head, encoding, &s, span, ignore_errors)
|
||||
.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: v.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: v.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
// This should be more precise, but due to difficulties in getting spans
|
||||
// from PipelineData::ListStream, this is as it is.
|
||||
_ => Err(ShellError::UnsupportedInput {
|
||||
msg: "non-string input".into(),
|
||||
input: "value originates from here".into(),
|
||||
msg_span: head,
|
||||
input_span: input.span().unwrap_or(head),
|
||||
}),
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let encoding: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let ignore_errors = call.has_flag_const(working_set, "ignore-errors")?;
|
||||
run(call, input, encoding, ignore_errors)
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
encoding: Spanned<String>,
|
||||
ignore_errors: bool,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
|
||||
match input {
|
||||
PipelineData::ByteStream(stream, ..) => {
|
||||
let span = stream.span();
|
||||
let s = stream.into_string()?;
|
||||
super::encoding::encode(head, encoding, &s, span, ignore_errors)
|
||||
.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
PipelineData::Value(v, ..) => {
|
||||
let span = v.span();
|
||||
match v {
|
||||
Value::String { val: s, .. } => {
|
||||
super::encoding::encode(head, encoding, &s, span, ignore_errors)
|
||||
.map(|val| val.into_pipeline_data())
|
||||
}
|
||||
Value::Error { error, .. } => Err(*error),
|
||||
_ => Err(ShellError::OnlySupportsThisInputType {
|
||||
exp_input_type: "string".into(),
|
||||
wrong_type: v.get_type().to_string(),
|
||||
dst_span: head,
|
||||
src_span: v.span(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
// This should be more precise, but due to difficulties in getting spans
|
||||
// from PipelineData::ListStream, this is as it is.
|
||||
_ => Err(ShellError::UnsupportedInput {
|
||||
msg: "non-string input".into(),
|
||||
input: "value originates from here".into(),
|
||||
msg_span: head,
|
||||
input_span: input.span().unwrap_or(head),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::base64::{operate, ActionType, CHARACTER_SET_DESC};
|
||||
use super::base64::{operate, ActionType, Base64CommandArguments, CHARACTER_SET_DESC};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -70,6 +70,10 @@ impl Command for EncodeBase64 {
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -77,7 +81,34 @@ impl Command for EncodeBase64 {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(ActionType::Encode, engine_state, stack, call, input)
|
||||
let character_set: Option<Spanned<String>> =
|
||||
call.get_flag(engine_state, stack, "character-set")?;
|
||||
let binary = call.has_flag(engine_state, stack, "binary")?;
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let args = Base64CommandArguments {
|
||||
action_type: ActionType::Encode,
|
||||
binary,
|
||||
character_set,
|
||||
};
|
||||
operate(engine_state, call, input, cell_paths, args)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let character_set: Option<Spanned<String>> =
|
||||
call.get_flag_const(working_set, "character-set")?;
|
||||
let binary = call.has_flag_const(working_set, "binary")?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
let args = Base64CommandArguments {
|
||||
action_type: ActionType::Encode,
|
||||
binary,
|
||||
character_set,
|
||||
};
|
||||
operate(working_set.permanent(), call, input, cell_paths, args)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,36 +38,6 @@ impl Command for FormatDate {
|
|||
vec!["fmt", "strftime"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
if call.has_flag(engine_state, stack, "list")? {
|
||||
return Ok(PipelineData::Value(
|
||||
generate_strftime_list(head, false),
|
||||
None,
|
||||
));
|
||||
}
|
||||
|
||||
let format = call.opt::<Spanned<String>>(engine_state, stack, 0)?;
|
||||
|
||||
// This doesn't match explicit nulls
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
input.map(
|
||||
move |value| match &format {
|
||||
Some(format) => format_helper(value, format.item.as_str(), format.span, head),
|
||||
None => format_helper_rfc2822(value, head),
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
@ -104,6 +74,61 @@ impl Command for FormatDate {
|
|||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let list = call.has_flag(engine_state, stack, "list")?;
|
||||
let format = call.opt::<Spanned<String>>(engine_state, stack, 0)?;
|
||||
run(engine_state, call, input, list, format)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let list = call.has_flag_const(working_set, "list")?;
|
||||
let format = call.opt_const::<Spanned<String>>(working_set, 0)?;
|
||||
run(working_set.permanent(), call, input, list, format)
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
engine_state: &EngineState,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
list: bool,
|
||||
format: Option<Spanned<String>>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
if list {
|
||||
return Ok(PipelineData::Value(
|
||||
generate_strftime_list(head, false),
|
||||
None,
|
||||
));
|
||||
}
|
||||
|
||||
// This doesn't match explicit nulls
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: head });
|
||||
}
|
||||
input.map(
|
||||
move |value| match &format {
|
||||
Some(format) => format_helper(value, format.item.as_str(), format.span, head),
|
||||
None => format_helper_rfc2822(value, head),
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn format_from<Tz: TimeZone>(date_time: DateTime<Tz>, formatter: &str, span: Span) -> Value
|
||||
|
|
|
@ -53,6 +53,10 @@ impl Command for FormatDuration {
|
|||
vec!["convert", "display", "pattern", "human readable"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -81,6 +85,33 @@ impl Command for FormatDuration {
|
|||
)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let format_value = call
|
||||
.req_const::<Value>(working_set, 0)?
|
||||
.coerce_into_string()?
|
||||
.to_ascii_lowercase();
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let float_precision = working_set.permanent().config.float_precision as usize;
|
||||
let arg = Arguments {
|
||||
format_value,
|
||||
float_precision,
|
||||
cell_paths,
|
||||
};
|
||||
operate(
|
||||
format_value_impl,
|
||||
arg,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::format_filesize;
|
||||
use nu_protocol::{engine::StateWorkingSet, format_filesize};
|
||||
|
||||
struct Arguments {
|
||||
format_value: String,
|
||||
|
@ -50,6 +50,10 @@ impl Command for FormatFilesize {
|
|||
vec!["convert", "display", "pattern", "human readable"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -76,6 +80,31 @@ impl Command for FormatFilesize {
|
|||
)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let format_value = call
|
||||
.req_const::<Value>(working_set, 0)?
|
||||
.coerce_into_string()?
|
||||
.to_ascii_lowercase();
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let arg = Arguments {
|
||||
format_value,
|
||||
cell_paths,
|
||||
};
|
||||
operate(
|
||||
format_value_impl,
|
||||
arg,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use fancy_regex::{Captures, Regex};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::ListStream;
|
||||
use nu_protocol::{engine::StateWorkingSet, ListStream};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
|
@ -99,6 +99,10 @@ impl Command for Parse {
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -106,19 +110,31 @@ impl Command for Parse {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(engine_state, stack, call, input)
|
||||
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let regex: bool = call.has_flag(engine_state, stack, "regex")?;
|
||||
operate(engine_state, pattern, regex, call, input)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let pattern: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let regex: bool = call.has_flag_const(working_set, "regex")?;
|
||||
operate(working_set.permanent(), pattern, regex, call, input)
|
||||
}
|
||||
}
|
||||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
pattern: Spanned<String>,
|
||||
regex: bool,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let regex: bool = call.has_flag(engine_state, stack, "regex")?;
|
||||
|
||||
let pattern_item = pattern.item;
|
||||
let pattern_span = pattern.span;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::grapheme_flags;
|
||||
use crate::{grapheme_flags, grapheme_flags_const};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -88,6 +89,10 @@ impl Command for SubCommand {
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -95,19 +100,28 @@ impl Command for SubCommand {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
split_chars(engine_state, stack, call, input)
|
||||
let graphemes = grapheme_flags(engine_state, stack, call)?;
|
||||
split_chars(engine_state, call, input, graphemes)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let graphemes = grapheme_flags_const(working_set, call)?;
|
||||
split_chars(working_set.permanent(), call, input, graphemes)
|
||||
}
|
||||
}
|
||||
|
||||
fn split_chars(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
graphemes: bool,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.head;
|
||||
|
||||
let graphemes = grapheme_flags(engine_state, stack, call)?;
|
||||
input.map(
|
||||
move |x| split_chars_helper(&x, span, graphemes),
|
||||
engine_state.ctrlc.clone(),
|
||||
|
|
|
@ -43,16 +43,6 @@ impl Command for SubCommand {
|
|||
vec!["separate", "divide", "regex"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
split_column(engine_state, stack, call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
@ -103,35 +93,83 @@ impl Command for SubCommand {
|
|||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 1)?;
|
||||
let collapse_empty = call.has_flag(engine_state, stack, "collapse-empty")?;
|
||||
let has_regex = call.has_flag(engine_state, stack, "regex")?;
|
||||
|
||||
let args = Arguments {
|
||||
separator,
|
||||
rest,
|
||||
collapse_empty,
|
||||
has_regex,
|
||||
};
|
||||
split_column(engine_state, call, input, args)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let rest: Vec<Spanned<String>> = call.rest_const(working_set, 1)?;
|
||||
let collapse_empty = call.has_flag_const(working_set, "collapse-empty")?;
|
||||
let has_regex = call.has_flag_const(working_set, "regex")?;
|
||||
|
||||
let args = Arguments {
|
||||
separator,
|
||||
rest,
|
||||
collapse_empty,
|
||||
has_regex,
|
||||
};
|
||||
split_column(working_set.permanent(), call, input, args)
|
||||
}
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
separator: Spanned<String>,
|
||||
rest: Vec<Spanned<String>>,
|
||||
collapse_empty: bool,
|
||||
has_regex: bool,
|
||||
}
|
||||
|
||||
fn split_column(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
args: Arguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name_span = call.head;
|
||||
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 1)?;
|
||||
let collapse_empty = call.has_flag(engine_state, stack, "collapse-empty")?;
|
||||
|
||||
let regex = if call.has_flag(engine_state, stack, "regex")? {
|
||||
Regex::new(&separator.item)
|
||||
let regex = if args.has_regex {
|
||||
Regex::new(&args.separator.item)
|
||||
} else {
|
||||
let escaped = regex::escape(&separator.item);
|
||||
let escaped = regex::escape(&args.separator.item);
|
||||
Regex::new(&escaped)
|
||||
}
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error with regular expression".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(separator.span),
|
||||
span: Some(args.separator.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
|
||||
input.flat_map(
|
||||
move |x| split_column_helper(&x, ®ex, &rest, collapse_empty, name_span),
|
||||
move |x| split_column_helper(&x, ®ex, &args.rest, args.collapse_empty, name_span),
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -36,16 +36,6 @@ impl Command for SubCommand {
|
|||
vec!["separate", "divide", "regex"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
split_list(engine_state, stack, call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
@ -145,6 +135,33 @@ impl Command for SubCommand {
|
|||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let has_regex = call.has_flag(engine_state, stack, "regex")?;
|
||||
let separator: Value = call.req(engine_state, stack, 0)?;
|
||||
split_list(engine_state, call, input, has_regex, separator)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let has_regex = call.has_flag_const(working_set, "regex")?;
|
||||
let separator: Value = call.req_const(working_set, 0)?;
|
||||
split_list(working_set.permanent(), call, input, has_regex, separator)
|
||||
}
|
||||
}
|
||||
|
||||
enum Matcher {
|
||||
|
@ -188,15 +205,15 @@ impl Matcher {
|
|||
|
||||
fn split_list(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
has_regex: bool,
|
||||
separator: Value,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Value = call.req(engine_state, stack, 0)?;
|
||||
let mut temp_list = Vec::new();
|
||||
let mut returned_list = Vec::new();
|
||||
|
||||
let matcher = Matcher::new(call.has_flag(engine_state, stack, "regex")?, separator)?;
|
||||
let matcher = Matcher::new(has_regex, separator)?;
|
||||
for val in input {
|
||||
if nu_utils::ctrl_c::was_pressed(&engine_state.ctrlc) {
|
||||
break;
|
||||
|
|
|
@ -43,16 +43,6 @@ impl Command for SubCommand {
|
|||
vec!["separate", "divide", "regex"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
split_row(engine_state, stack, call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
@ -109,32 +99,77 @@ impl Command for SubCommand {
|
|||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let max_split: Option<usize> = call.get_flag(engine_state, stack, "number")?;
|
||||
let has_regex = call.has_flag(engine_state, stack, "regex")?;
|
||||
|
||||
let args = Arguments {
|
||||
separator,
|
||||
max_split,
|
||||
has_regex,
|
||||
};
|
||||
split_row(engine_state, call, input, args)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let max_split: Option<usize> = call.get_flag_const(working_set, "number")?;
|
||||
let has_regex = call.has_flag_const(working_set, "regex")?;
|
||||
|
||||
let args = Arguments {
|
||||
separator,
|
||||
max_split,
|
||||
has_regex,
|
||||
};
|
||||
split_row(working_set.permanent(), call, input, args)
|
||||
}
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
has_regex: bool,
|
||||
separator: Spanned<String>,
|
||||
max_split: Option<usize>,
|
||||
}
|
||||
|
||||
fn split_row(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
args: Arguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name_span = call.head;
|
||||
let separator: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let regex = if call.has_flag(engine_state, stack, "regex")? {
|
||||
Regex::new(&separator.item)
|
||||
let regex = if args.has_regex {
|
||||
Regex::new(&args.separator.item)
|
||||
} else {
|
||||
let escaped = regex::escape(&separator.item);
|
||||
let escaped = regex::escape(&args.separator.item);
|
||||
Regex::new(&escaped)
|
||||
}
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Error with regular expression".into(),
|
||||
msg: e.to_string(),
|
||||
span: Some(separator.span),
|
||||
span: Some(args.separator.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?;
|
||||
let max_split: Option<usize> = call.get_flag(engine_state, stack, "number")?;
|
||||
input.flat_map(
|
||||
move |x| split_row_helper(&x, ®ex, max_split, name_span),
|
||||
move |x| split_row_helper(&x, ®ex, args.max_split, name_span),
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::grapheme_flags;
|
||||
use crate::{grapheme_flags, grapheme_flags_const};
|
||||
use fancy_regex::Regex;
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
|
@ -96,6 +96,10 @@ impl Command for SubCommand {
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -103,40 +107,76 @@ impl Command for SubCommand {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
split_words(engine_state, stack, call, input)
|
||||
let word_length: Option<usize> = call.get_flag(engine_state, stack, "min-word-length")?;
|
||||
let has_grapheme = call.has_flag(engine_state, stack, "grapheme-clusters")?;
|
||||
let has_utf8 = call.has_flag(engine_state, stack, "utf-8-bytes")?;
|
||||
let graphemes = grapheme_flags(engine_state, stack, call)?;
|
||||
|
||||
let args = Arguments {
|
||||
word_length,
|
||||
has_grapheme,
|
||||
has_utf8,
|
||||
graphemes,
|
||||
};
|
||||
split_words(engine_state, call, input, args)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let word_length: Option<usize> = call.get_flag_const(working_set, "min-word-length")?;
|
||||
let has_grapheme = call.has_flag_const(working_set, "grapheme-clusters")?;
|
||||
let has_utf8 = call.has_flag_const(working_set, "utf-8-bytes")?;
|
||||
let graphemes = grapheme_flags_const(working_set, call)?;
|
||||
|
||||
let args = Arguments {
|
||||
word_length,
|
||||
has_grapheme,
|
||||
has_utf8,
|
||||
graphemes,
|
||||
};
|
||||
split_words(working_set.permanent(), call, input, args)
|
||||
}
|
||||
}
|
||||
|
||||
struct Arguments {
|
||||
word_length: Option<usize>,
|
||||
has_grapheme: bool,
|
||||
has_utf8: bool,
|
||||
graphemes: bool,
|
||||
}
|
||||
|
||||
fn split_words(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
args: Arguments,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.head;
|
||||
// let ignore_hyphenated = call.has_flag(engine_state, stack, "ignore-hyphenated")?;
|
||||
// let ignore_apostrophes = call.has_flag(engine_state, stack, "ignore-apostrophes")?;
|
||||
// let ignore_punctuation = call.has_flag(engine_state, stack, "ignore-punctuation")?;
|
||||
let word_length: Option<usize> = call.get_flag(engine_state, stack, "min-word-length")?;
|
||||
|
||||
if word_length.is_none() {
|
||||
if call.has_flag(engine_state, stack, "grapheme-clusters")? {
|
||||
if args.word_length.is_none() {
|
||||
if args.has_grapheme {
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "--grapheme-clusters (-g) requires --min-word-length (-l)".to_string(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
if call.has_flag(engine_state, stack, "utf-8-bytes")? {
|
||||
if args.has_utf8 {
|
||||
return Err(ShellError::IncompatibleParametersSingle {
|
||||
msg: "--utf-8-bytes (-b) requires --min-word-length (-l)".to_string(),
|
||||
span,
|
||||
});
|
||||
}
|
||||
}
|
||||
let graphemes = grapheme_flags(engine_state, stack, call)?;
|
||||
|
||||
input.map(
|
||||
move |x| split_words_helper(&x, word_length, span, graphemes),
|
||||
move |x| split_words_helper(&x, args.word_length, span, args.graphemes),
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -36,6 +36,10 @@ impl Command for SubCommand {
|
|||
vec!["convert", "style", "caps", "upper"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -43,7 +47,18 @@ impl Command for SubCommand {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(engine_state, stack, call, input)
|
||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
operate(engine_state, call, input, column_paths)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
operate(working_set.permanent(), call, input, column_paths)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -72,12 +87,11 @@ impl Command for SubCommand {
|
|||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
column_paths: Vec<CellPath>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
input.map(
|
||||
move |v| {
|
||||
if column_paths.is_empty() {
|
||||
|
|
|
@ -36,6 +36,10 @@ impl Command for SubCommand {
|
|||
vec!["lower case", "lowercase"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -43,7 +47,18 @@ impl Command for SubCommand {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(engine_state, stack, call, input)
|
||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
operate(engine_state, call, input, column_paths)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
operate(working_set.permanent(), call, input, column_paths)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -80,12 +95,11 @@ impl Command for SubCommand {
|
|||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
column_paths: Vec<CellPath>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
input.map(
|
||||
move |v| {
|
||||
if column_paths.is_empty() {
|
||||
|
|
|
@ -36,6 +36,10 @@ impl Command for SubCommand {
|
|||
vec!["uppercase", "upper case"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -43,7 +47,18 @@ impl Command for SubCommand {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
operate(engine_state, stack, call, input)
|
||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
operate(engine_state, call, input, column_paths)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let column_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
operate(working_set.permanent(), call, input, column_paths)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -57,12 +72,11 @@ impl Command for SubCommand {
|
|||
|
||||
fn operate(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
column_paths: Vec<CellPath>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let head = call.head;
|
||||
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
input.map(
|
||||
move |v| {
|
||||
if column_paths.is_empty() {
|
||||
|
|
|
@ -52,6 +52,10 @@ impl Command for SubCommand {
|
|||
vec!["substring", "match", "find", "search"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -84,6 +88,43 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
if call.has_flag_const(working_set, "not")? {
|
||||
nu_protocol::report_error_new(
|
||||
working_set.permanent(),
|
||||
&ShellError::GenericError {
|
||||
error: "Deprecated option".into(),
|
||||
msg: "`str contains --not {string}` is deprecated and will be removed in 0.95."
|
||||
.into(),
|
||||
span: Some(call.head),
|
||||
help: Some("Please use the `not` operator instead.".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let args = Arguments {
|
||||
substring: call.req_const::<String>(working_set, 0)?,
|
||||
cell_paths,
|
||||
case_insensitive: call.has_flag_const(working_set, "ignore-case")?,
|
||||
not_contain: call.has_flag_const(working_set, "not")?,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::levenshtein_distance;
|
||||
use nu_protocol::{engine::StateWorkingSet, levenshtein_distance};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SubCommand;
|
||||
|
@ -49,6 +49,10 @@ impl Command for SubCommand {
|
|||
vec!["edit", "levenshtein"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -66,6 +70,28 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let compare_string: String = call.req_const(working_set, 0)?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let args = Arguments {
|
||||
compare_string,
|
||||
cell_paths,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
description: "get the edit distance between two strings",
|
||||
|
|
|
@ -50,6 +50,10 @@ impl Command for SubCommand {
|
|||
vec!["suffix", "match", "find", "search"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -67,6 +71,28 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let args = Arguments {
|
||||
substring: call.req_const::<String>(working_set, 0)?,
|
||||
cell_paths,
|
||||
case_insensitive: call.has_flag_const(working_set, "ignore-case")?,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -179,6 +179,10 @@ impl Command for SubCommand {
|
|||
]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -186,32 +190,51 @@ impl Command for SubCommand {
|
|||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.head;
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: span });
|
||||
}
|
||||
let is_path = call.has_flag(engine_state, stack, "path")?;
|
||||
input.map(
|
||||
move |v| {
|
||||
let value_span = v.span();
|
||||
match v.coerce_into_string() {
|
||||
Ok(s) => {
|
||||
let contents = if is_path { s.replace('\\', "\\\\") } else { s };
|
||||
str_expand(&contents, span, value_span)
|
||||
}
|
||||
Err(_) => Value::error(
|
||||
ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: span,
|
||||
src_span: value_span,
|
||||
},
|
||||
span,
|
||||
),
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
run(call, input, is_path, engine_state)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let is_path = call.has_flag_const(working_set, "path")?;
|
||||
run(call, input, is_path, working_set.permanent())
|
||||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
is_path: bool,
|
||||
engine_state: &EngineState,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let span = call.head;
|
||||
if matches!(input, PipelineData::Empty) {
|
||||
return Err(ShellError::PipelineEmpty { dst_span: span });
|
||||
}
|
||||
input.map(
|
||||
move |v| {
|
||||
let value_span = v.span();
|
||||
match v.coerce_into_string() {
|
||||
Ok(s) => {
|
||||
let contents = if is_path { s.replace('\\', "\\\\") } else { s };
|
||||
str_expand(&contents, span, value_span)
|
||||
}
|
||||
Err(_) => Value::error(
|
||||
ShellError::PipelineMismatch {
|
||||
exp_input_type: "string".into(),
|
||||
dst_span: span,
|
||||
src_span: value_span,
|
||||
},
|
||||
span,
|
||||
),
|
||||
}
|
||||
},
|
||||
engine_state.ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn str_expand(contents: &str, span: Span, value_span: Span) -> Value {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::grapheme_flags;
|
||||
use crate::{grapheme_flags, grapheme_flags_const};
|
||||
use nu_cmd_base::{
|
||||
input_handler::{operate, CmdArgument},
|
||||
util,
|
||||
};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
use nu_protocol::{engine::StateWorkingSet, Range};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
struct Arguments {
|
||||
|
@ -72,6 +72,10 @@ impl Command for SubCommand {
|
|||
vec!["match", "find", "search"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -92,6 +96,31 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let substring: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let args = Arguments {
|
||||
substring: substring.item,
|
||||
range: call.get_flag_const(working_set, "range")?,
|
||||
end: call.has_flag_const(working_set, "end")?,
|
||||
cell_paths,
|
||||
graphemes: grapheme_flags_const(working_set, call)?,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use nu_engine::command_prelude::*;
|
||||
|
||||
use std::io::Write;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -32,6 +33,10 @@ impl Command for StrJoin {
|
|||
vec!["collect", "concatenate"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -40,41 +45,17 @@ impl Command for StrJoin {
|
|||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Option<String> = call.opt(engine_state, stack, 0)?;
|
||||
run(engine_state, call, input, separator)
|
||||
}
|
||||
|
||||
let config = engine_state.config.clone();
|
||||
|
||||
let span = call.head;
|
||||
|
||||
let metadata = input.metadata();
|
||||
let mut iter = input.into_iter();
|
||||
let mut first = true;
|
||||
|
||||
let output = ByteStream::from_fn(span, None, ByteStreamType::String, move |buffer| {
|
||||
// Write each input to the buffer
|
||||
if let Some(value) = iter.next() {
|
||||
// Write the separator if this is not the first
|
||||
if first {
|
||||
first = false;
|
||||
} else if let Some(separator) = &separator {
|
||||
write!(buffer, "{}", separator)?;
|
||||
}
|
||||
|
||||
match value {
|
||||
Value::Error { error, .. } => {
|
||||
return Err(*error);
|
||||
}
|
||||
// Hmm, not sure what we actually want.
|
||||
// `to_expanded_string` formats dates as human readable which feels funny.
|
||||
Value::Date { val, .. } => write!(buffer, "{val:?}")?,
|
||||
value => write!(buffer, "{}", value.to_expanded_string("\n", &config))?,
|
||||
}
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
});
|
||||
|
||||
Ok(PipelineData::ByteStream(output, metadata))
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let separator: Option<String> = call.opt_const(working_set, 0)?;
|
||||
run(working_set.permanent(), call, input, separator)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -93,6 +74,48 @@ impl Command for StrJoin {
|
|||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
engine_state: &EngineState,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
separator: Option<String>,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let config = engine_state.config.clone();
|
||||
|
||||
let span = call.head;
|
||||
|
||||
let metadata = input.metadata();
|
||||
let mut iter = input.into_iter();
|
||||
let mut first = true;
|
||||
|
||||
let output = ByteStream::from_fn(span, None, ByteStreamType::String, move |buffer| {
|
||||
// Write each input to the buffer
|
||||
if let Some(value) = iter.next() {
|
||||
// Write the separator if this is not the first
|
||||
if first {
|
||||
first = false;
|
||||
} else if let Some(separator) = &separator {
|
||||
write!(buffer, "{}", separator)?;
|
||||
}
|
||||
|
||||
match value {
|
||||
Value::Error { error, .. } => {
|
||||
return Err(*error);
|
||||
}
|
||||
// Hmm, not sure what we actually want.
|
||||
// `to_expanded_string` formats dates as human readable which feels funny.
|
||||
Value::Date { val, .. } => write!(buffer, "{val:?}")?,
|
||||
value => write!(buffer, "{}", value.to_expanded_string("\n", &config))?,
|
||||
}
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
});
|
||||
|
||||
Ok(PipelineData::ByteStream(output, metadata))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{grapheme_flags, grapheme_flags_const};
|
||||
use nu_cmd_base::input_handler::{operate, CmdArgument};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::engine::StateWorkingSet;
|
||||
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
struct Arguments {
|
||||
|
|
|
@ -73,6 +73,10 @@ impl Command for SubCommand {
|
|||
vec!["search", "shift", "switch", "regex"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -101,6 +105,39 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let find: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let replace: Spanned<String> = call.req_const(working_set, 1)?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 2)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let literal_replace = call.has_flag_const(working_set, "no-expand")?;
|
||||
let no_regex = !call.has_flag_const(working_set, "regex")?
|
||||
&& !call.has_flag_const(working_set, "multiline")?;
|
||||
let multiline = call.has_flag_const(working_set, "multiline")?;
|
||||
|
||||
let args = Arguments {
|
||||
all: call.has_flag_const(working_set, "all")?,
|
||||
find,
|
||||
replace,
|
||||
cell_paths,
|
||||
literal_replace,
|
||||
no_regex,
|
||||
multiline,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -37,6 +37,10 @@ impl Command for SubCommand {
|
|||
vec!["convert", "inverse", "flip"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -49,6 +53,23 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
let args = CellPathOnlyArgs::from(cell_paths);
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -51,6 +51,10 @@ impl Command for SubCommand {
|
|||
vec!["prefix", "match", "find", "search"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -69,6 +73,29 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let substring: Spanned<String> = call.req_const(working_set, 0)?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let args = Arguments {
|
||||
substring: substring.item,
|
||||
cell_paths,
|
||||
case_insensitive: call.has_flag_const(working_set, "ignore-case")?,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use fancy_regex::Regex;
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::{fmt, str};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
@ -29,6 +30,10 @@ impl Command for SubCommand {
|
|||
vec!["count", "word", "character", "unicode", "wc"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -39,6 +44,15 @@ impl Command for SubCommand {
|
|||
stats(engine_state, call, input)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
stats(working_set.permanent(), call, input)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::grapheme_flags;
|
||||
use crate::{grapheme_flags, grapheme_flags_const};
|
||||
use nu_cmd_base::{
|
||||
input_handler::{operate, CmdArgument},
|
||||
util,
|
||||
};
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::Range;
|
||||
use nu_protocol::{engine::StateWorkingSet, Range};
|
||||
use std::cmp::Ordering;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
|
@ -77,6 +77,10 @@ impl Command for SubCommand {
|
|||
vec!["slice"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -103,6 +107,37 @@ impl Command for SubCommand {
|
|||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let range: Range = call.req_const(working_set, 0)?;
|
||||
|
||||
let indexes = match util::process_range(&range) {
|
||||
Ok(idxs) => idxs.into(),
|
||||
Err(processing_error) => {
|
||||
return Err(processing_error("could not perform substring", call.head))
|
||||
}
|
||||
};
|
||||
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 1)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let args = Arguments {
|
||||
indexes,
|
||||
cell_paths,
|
||||
graphemes: grapheme_flags_const(working_set, call)?,
|
||||
};
|
||||
operate(
|
||||
action,
|
||||
args,
|
||||
input,
|
||||
call.head,
|
||||
working_set.permanent().ctrlc.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
|
|
@ -71,6 +71,10 @@ impl Command for SubCommand {
|
|||
vec!["whitespace", "strip", "lstrip", "rstrip"]
|
||||
}
|
||||
|
||||
fn is_const(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -79,44 +83,37 @@ impl Command for SubCommand {
|
|||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let character = call.get_flag::<Spanned<String>>(engine_state, stack, "char")?;
|
||||
let to_trim = match character.as_ref() {
|
||||
Some(v) => {
|
||||
if v.item.chars().count() > 1 {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Trim only works with single character".into(),
|
||||
msg: "needs single character".into(),
|
||||
span: Some(v.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
v.item.chars().next()
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let cell_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let mode = match cell_paths {
|
||||
None => ActionMode::Global,
|
||||
Some(_) => ActionMode::Local,
|
||||
};
|
||||
|
||||
let left = call.has_flag(engine_state, stack, "left")?;
|
||||
let right = call.has_flag(engine_state, stack, "right")?;
|
||||
let trim_side = match (left, right) {
|
||||
(true, true) => TrimSide::Both,
|
||||
(true, false) => TrimSide::Left,
|
||||
(false, true) => TrimSide::Right,
|
||||
(false, false) => TrimSide::Both,
|
||||
};
|
||||
|
||||
let args = Arguments {
|
||||
to_trim,
|
||||
trim_side,
|
||||
run(
|
||||
character,
|
||||
cell_paths,
|
||||
mode,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
(left, right),
|
||||
call,
|
||||
input,
|
||||
engine_state,
|
||||
)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
&self,
|
||||
working_set: &StateWorkingSet,
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let character = call.get_flag_const::<Spanned<String>>(working_set, "char")?;
|
||||
let cell_paths: Vec<CellPath> = call.rest_const(working_set, 0)?;
|
||||
let left = call.has_flag_const(working_set, "left")?;
|
||||
let right = call.has_flag_const(working_set, "right")?;
|
||||
run(
|
||||
character,
|
||||
cell_paths,
|
||||
(left, right),
|
||||
call,
|
||||
input,
|
||||
working_set.permanent(),
|
||||
)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -150,6 +147,52 @@ impl Command for SubCommand {
|
|||
}
|
||||
}
|
||||
|
||||
fn run(
|
||||
character: Option<Spanned<String>>,
|
||||
cell_paths: Vec<CellPath>,
|
||||
(left, right): (bool, bool),
|
||||
call: &Call,
|
||||
input: PipelineData,
|
||||
engine_state: &EngineState,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let to_trim = match character.as_ref() {
|
||||
Some(v) => {
|
||||
if v.item.chars().count() > 1 {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "Trim only works with single character".into(),
|
||||
msg: "needs single character".into(),
|
||||
span: Some(v.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
});
|
||||
}
|
||||
v.item.chars().next()
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let cell_paths = (!cell_paths.is_empty()).then_some(cell_paths);
|
||||
let mode = match cell_paths {
|
||||
None => ActionMode::Global,
|
||||
Some(_) => ActionMode::Local,
|
||||
};
|
||||
|
||||
let trim_side = match (left, right) {
|
||||
(true, true) => TrimSide::Both,
|
||||
(true, false) => TrimSide::Left,
|
||||
(false, true) => TrimSide::Right,
|
||||
(false, false) => TrimSide::Both,
|
||||
};
|
||||
|
||||
let args = Arguments {
|
||||
to_trim,
|
||||
trim_side,
|
||||
cell_paths,
|
||||
mode,
|
||||
};
|
||||
operate(action, args, input, call.head, engine_state.ctrlc.clone())
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ActionMode {
|
||||
Local,
|
||||
|
|
|
@ -218,14 +218,16 @@ impl Command for External {
|
|||
|
||||
/// Removes surrounding quotes from a string. Doesn't remove quotes from raw
|
||||
/// strings. Returns the original string if it doesn't have matching quotes.
|
||||
fn remove_quotes(s: &str) -> &str {
|
||||
fn remove_quotes(s: &str) -> Cow<'_, str> {
|
||||
let quoted_by_double_quotes = s.len() >= 2 && s.starts_with('"') && s.ends_with('"');
|
||||
let quoted_by_single_quotes = s.len() >= 2 && s.starts_with('\'') && s.ends_with('\'');
|
||||
let quoted_by_backticks = s.len() >= 2 && s.starts_with('`') && s.ends_with('`');
|
||||
if quoted_by_double_quotes || quoted_by_single_quotes || quoted_by_backticks {
|
||||
&s[1..s.len() - 1]
|
||||
if quoted_by_double_quotes {
|
||||
Cow::Owned(s[1..s.len() - 1].to_string().replace(r#"\""#, "\""))
|
||||
} else if quoted_by_single_quotes || quoted_by_backticks {
|
||||
Cow::Borrowed(&s[1..s.len() - 1])
|
||||
} else {
|
||||
s
|
||||
Cow::Borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,10 +402,6 @@ fn expand_glob(
|
|||
/// with double quotes, single quotes, or backticks. Only removes the outermost
|
||||
/// pair of quotes after the equal sign.
|
||||
fn remove_inner_quotes(arg: &str) -> Cow<'_, str> {
|
||||
// Check that `arg` is a long option.
|
||||
if !arg.starts_with("--") {
|
||||
return Cow::Borrowed(arg);
|
||||
}
|
||||
// Split `arg` on the first `=`.
|
||||
let Some((option, value)) = arg.split_once('=') else {
|
||||
return Cow::Borrowed(arg);
|
||||
|
@ -660,17 +658,13 @@ mod test {
|
|||
assert_eq!(remove_quotes(r#"`foo '"' bar`"#), r#"foo '"' bar"#);
|
||||
assert_eq!(remove_quotes(r#"'foo' bar"#), r#"'foo' bar"#);
|
||||
assert_eq!(remove_quotes(r#"r#'foo'#"#), r#"r#'foo'#"#);
|
||||
assert_eq!(remove_quotes(r#""foo\" bar""#), r#"foo" bar"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_eval_argument() {
|
||||
fn expression(expr: Expr) -> Expression {
|
||||
Expression {
|
||||
expr,
|
||||
span: Span::unknown(),
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
}
|
||||
Expression::new_unknown(expr, Span::unknown(), Type::Any)
|
||||
}
|
||||
|
||||
fn eval(expr: Expr, spread: bool) -> Result<Vec<String>, ShellError> {
|
||||
|
@ -763,6 +757,18 @@ mod test {
|
|||
let actual = remove_inner_quotes(r#"--option "value""#);
|
||||
let expected = r#"--option "value""#;
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = remove_inner_quotes(r#"-option="value""#);
|
||||
let expected = r#"-option=value"#;
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = remove_inner_quotes(r#"option="value""#);
|
||||
let expected = r#"option=value"#;
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = remove_inner_quotes(r#"option="v\"value""#);
|
||||
let expected = r#"option=v"value"#;
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -63,8 +63,57 @@ fn into_filesize_negative_filesize() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn into_negative_filesize() {
|
||||
fn into_filesize_negative_str_filesize() {
|
||||
let actual = nu!("'-3kib' | into filesize");
|
||||
|
||||
assert!(actual.out.contains("-3.0 KiB"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_wrong_negative_str_filesize() {
|
||||
let actual = nu!("'--3kib' | into filesize");
|
||||
|
||||
assert!(actual.err.contains("can't convert string to filesize"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_negative_str() {
|
||||
let actual = nu!("'-1' | into filesize");
|
||||
|
||||
assert!(actual.out.contains("-1 B"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_wrong_negative_str() {
|
||||
let actual = nu!("'--1' | into filesize");
|
||||
|
||||
assert!(actual.err.contains("can't convert string to filesize"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_positive_str_filesize() {
|
||||
let actual = nu!("'+1Kib' | into filesize");
|
||||
|
||||
assert!(actual.out.contains("1.0 KiB"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_wrong_positive_str_filesize() {
|
||||
let actual = nu!("'++1Kib' | into filesize");
|
||||
|
||||
assert!(actual.err.contains("can't convert string to filesize"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_positive_str() {
|
||||
let actual = nu!("'+1' | into filesize");
|
||||
|
||||
assert!(actual.out.contains("1 B"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn into_filesize_wrong_positive_str() {
|
||||
let actual = nu!("'++1' | into filesize");
|
||||
|
||||
assert!(actual.err.contains("can't convert string to filesize"));
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-derive-value"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-derive-value"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
|
|
@ -5,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-engine"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-engine"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", features = ["plugin"], version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", features = ["plugin"], version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
|
||||
[features]
|
||||
plugin = []
|
||||
plugin = []
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
pub use crate::CallExt;
|
||||
pub use nu_protocol::{
|
||||
ast::{Call, CellPath},
|
||||
engine::{Command, EngineState, Stack},
|
||||
engine::{Command, EngineState, Stack, StateWorkingSet},
|
||||
record, ByteStream, ByteStreamType, Category, ErrSpan, Example, IntoInterruptiblePipelineData,
|
||||
IntoPipelineData, IntoSpanned, PipelineData, Record, ShellError, Signature, Span, Spanned,
|
||||
SyntaxShape, Type, Value,
|
||||
|
|
|
@ -2,9 +2,9 @@ use crate::eval_call;
|
|||
use nu_protocol::{
|
||||
ast::{Argument, Call, Expr, Expression, RecordItem},
|
||||
debugger::WithoutDebug,
|
||||
engine::{Command, EngineState, Stack},
|
||||
record, Category, Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Type,
|
||||
Value,
|
||||
engine::{Command, EngineState, Stack, UNKNOWN_SPAN_ID},
|
||||
record, Category, Example, IntoPipelineData, PipelineData, Signature, Span, SpanId,
|
||||
SyntaxShape, Type, Value,
|
||||
};
|
||||
use std::{collections::HashMap, fmt::Write};
|
||||
|
||||
|
@ -339,8 +339,9 @@ fn get_ansi_color_for_component_or_default(
|
|||
if let Some(color) = &engine_state.get_config().color_config.get(theme_component) {
|
||||
let caller_stack = &mut Stack::new().capture();
|
||||
let span = Span::unknown();
|
||||
let span_id = UNKNOWN_SPAN_ID;
|
||||
|
||||
let argument_opt = get_argument_for_color_value(engine_state, color, span);
|
||||
let argument_opt = get_argument_for_color_value(engine_state, color, span, span_id);
|
||||
|
||||
// Call ansi command using argument
|
||||
if let Some(argument) = argument_opt {
|
||||
|
@ -371,6 +372,7 @@ fn get_argument_for_color_value(
|
|||
engine_state: &EngineState,
|
||||
color: &&Value,
|
||||
span: Span,
|
||||
span_id: SpanId,
|
||||
) -> Option<Argument> {
|
||||
match color {
|
||||
Value::Record { val, .. } => {
|
||||
|
@ -378,43 +380,43 @@ fn get_argument_for_color_value(
|
|||
.iter()
|
||||
.map(|(k, v)| {
|
||||
RecordItem::Pair(
|
||||
Expression {
|
||||
expr: Expr::String(k.clone()),
|
||||
Expression::new_existing(
|
||||
Expr::String(k.clone()),
|
||||
span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
},
|
||||
Expression {
|
||||
expr: Expr::String(
|
||||
span_id,
|
||||
Type::String,
|
||||
),
|
||||
Expression::new_existing(
|
||||
Expr::String(
|
||||
v.clone().to_expanded_string("", engine_state.get_config()),
|
||||
),
|
||||
span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
},
|
||||
span_id,
|
||||
Type::String,
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(Argument::Positional(Expression {
|
||||
span: Span::unknown(),
|
||||
ty: Type::Record(
|
||||
Some(Argument::Positional(Expression::new_existing(
|
||||
Expr::Record(record_exp),
|
||||
Span::unknown(),
|
||||
UNKNOWN_SPAN_ID,
|
||||
Type::Record(
|
||||
[
|
||||
("fg".to_string(), Type::String),
|
||||
("attr".to_string(), Type::String),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
expr: Expr::Record(record_exp),
|
||||
custom_completion: None,
|
||||
}))
|
||||
)))
|
||||
}
|
||||
Value::String { val, .. } => Some(Argument::Positional(Expression {
|
||||
span: Span::unknown(),
|
||||
ty: Type::String,
|
||||
expr: Expr::String(val.clone()),
|
||||
custom_completion: None,
|
||||
})),
|
||||
Value::String { val, .. } => Some(Argument::Positional(Expression::new_existing(
|
||||
Expr::String(val.clone()),
|
||||
Span::unknown(),
|
||||
UNKNOWN_SPAN_ID,
|
||||
Type::String,
|
||||
))),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,21 +5,21 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-explore"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-explore"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-table = { path = "../nu-table", version = "0.94.2" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-table = { path = "../nu-table", version = "0.94.3" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.2" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.3" }
|
||||
|
||||
anyhow = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
@ -32,4 +32,4 @@ ansi-str = { workspace = true }
|
|||
unicode-width = { workspace = true }
|
||||
lscolors = { workspace = true, default-features = false, features = [
|
||||
"nu-ansi-term",
|
||||
] }
|
||||
] }
|
||||
|
|
|
@ -4,7 +4,6 @@ use crate::{
|
|||
views::{Orientation, RecordView},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use nu_ansi_term::Style;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Value,
|
||||
|
@ -19,12 +18,6 @@ pub struct TableCmd {
|
|||
#[derive(Debug, Default, Clone)]
|
||||
struct TableSettings {
|
||||
orientation: Option<Orientation>,
|
||||
split_line_s: Option<Style>,
|
||||
selected_cell_s: Option<Style>,
|
||||
selected_row_s: Option<Style>,
|
||||
selected_column_s: Option<Style>,
|
||||
padding_column_left: Option<usize>,
|
||||
padding_column_right: Option<usize>,
|
||||
turn_on_cursor_mode: bool,
|
||||
}
|
||||
|
||||
|
@ -64,8 +57,6 @@ impl ViewCommand for TableCmd {
|
|||
|
||||
let mut view = RecordView::new(columns, data);
|
||||
|
||||
// todo: use setup instead ????
|
||||
|
||||
if is_record {
|
||||
view.set_orientation_current(Orientation::Left);
|
||||
}
|
||||
|
@ -74,32 +65,6 @@ impl ViewCommand for TableCmd {
|
|||
view.set_orientation_current(o);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.selected_cell_s {
|
||||
view.set_style_selected_cell(style);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.selected_column_s {
|
||||
view.set_style_selected_column(style);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.selected_row_s {
|
||||
view.set_style_selected_row(style);
|
||||
}
|
||||
|
||||
if let Some(style) = self.settings.split_line_s {
|
||||
view.set_style_split_line(style);
|
||||
}
|
||||
|
||||
if let Some(p) = self.settings.padding_column_left {
|
||||
let c = view.get_padding_column();
|
||||
view.set_padding_column((p, c.1))
|
||||
}
|
||||
|
||||
if let Some(p) = self.settings.padding_column_right {
|
||||
let c = view.get_padding_column();
|
||||
view.set_padding_column((c.0, p))
|
||||
}
|
||||
|
||||
if self.settings.turn_on_cursor_mode {
|
||||
view.set_cursor_mode();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::ViewCommand;
|
||||
use crate::views::InteractiveView;
|
||||
use crate::views::TryView;
|
||||
use anyhow::Result;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
|
@ -22,7 +22,7 @@ impl TryCmd {
|
|||
}
|
||||
|
||||
impl ViewCommand for TryCmd {
|
||||
type View = InteractiveView<'static>;
|
||||
type View = TryView<'static>;
|
||||
|
||||
fn name(&self) -> &'static str {
|
||||
Self::NAME
|
||||
|
@ -45,7 +45,7 @@ impl ViewCommand for TryCmd {
|
|||
value: Option<Value>,
|
||||
) -> Result<Self::View> {
|
||||
let value = value.unwrap_or_default();
|
||||
let mut view = InteractiveView::new(value);
|
||||
let mut view = TryView::new(value);
|
||||
view.init(self.command.clone());
|
||||
view.try_run(engine_state, stack)?;
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use crate::{
|
||||
run_pager,
|
||||
util::{create_lscolors, create_map, map_into_value},
|
||||
PagerConfig, StyleConfig,
|
||||
util::{create_lscolors, create_map},
|
||||
PagerConfig,
|
||||
};
|
||||
use nu_ansi_term::{Color, Style};
|
||||
use nu_color_config::{get_color_map, StyleComputer};
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use nu_protocol::Config;
|
||||
|
||||
/// A `less` like program to render a [`Value`] as a table.
|
||||
#[derive(Clone)]
|
||||
|
@ -68,19 +67,21 @@ impl Command for Explore {
|
|||
let nu_config = engine_state.get_config();
|
||||
let style_computer = StyleComputer::from_config(engine_state, stack);
|
||||
|
||||
let mut config = nu_config.explore.clone();
|
||||
include_nu_config(&mut config, &style_computer);
|
||||
update_config(&mut config, show_index, show_head);
|
||||
prepare_default_config(&mut config);
|
||||
|
||||
let style = style_from_config(&config);
|
||||
let mut explore_config = ExploreConfig::from_nu_config(nu_config);
|
||||
explore_config.table.show_header = show_head;
|
||||
explore_config.table.show_index = show_index;
|
||||
explore_config.table.separator_style = lookup_color(&style_computer, "separator");
|
||||
|
||||
let lscolors = create_lscolors(engine_state, stack);
|
||||
|
||||
let mut config = PagerConfig::new(nu_config, &style_computer, &lscolors, config);
|
||||
config.style = style;
|
||||
config.peek_value = peek_value;
|
||||
config.tail = tail;
|
||||
let config = PagerConfig::new(
|
||||
nu_config,
|
||||
&explore_config,
|
||||
&style_computer,
|
||||
&lscolors,
|
||||
peek_value,
|
||||
tail,
|
||||
);
|
||||
|
||||
let result = run_pager(engine_state, &mut stack.clone(), ctrlc, input, config);
|
||||
|
||||
|
@ -134,153 +135,118 @@ impl Command for Explore {
|
|||
}
|
||||
}
|
||||
|
||||
fn update_config(config: &mut HashMap<String, Value>, show_index: bool, show_head: bool) {
|
||||
let mut hm = config.get("table").and_then(create_map).unwrap_or_default();
|
||||
if show_index {
|
||||
insert_bool(&mut hm, "show_index", show_index);
|
||||
}
|
||||
|
||||
if show_head {
|
||||
insert_bool(&mut hm, "show_head", show_head);
|
||||
}
|
||||
|
||||
config.insert(String::from("table"), map_into_value(hm));
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExploreConfig {
|
||||
pub table: TableConfig,
|
||||
pub selected_cell: Style,
|
||||
pub status_info: Style,
|
||||
pub status_success: Style,
|
||||
pub status_warn: Style,
|
||||
pub status_error: Style,
|
||||
pub status_bar_background: Style,
|
||||
pub status_bar_text: Style,
|
||||
pub cmd_bar_text: Style,
|
||||
pub cmd_bar_background: Style,
|
||||
pub highlight: Style,
|
||||
/// if true, the explore view will immediately try to run the command as it is typed
|
||||
pub try_reactive: bool,
|
||||
}
|
||||
|
||||
fn style_from_config(config: &HashMap<String, Value>) -> StyleConfig {
|
||||
let mut style = StyleConfig::default();
|
||||
|
||||
let colors = get_color_map(config);
|
||||
|
||||
if let Some(s) = colors.get("status_bar_text") {
|
||||
style.status_bar_text = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("status_bar_background") {
|
||||
style.status_bar_background = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("command_bar_text") {
|
||||
style.cmd_bar_text = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("command_bar_background") {
|
||||
style.cmd_bar_background = *s;
|
||||
}
|
||||
|
||||
if let Some(hm) = config.get("status").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
if let Some(s) = colors.get("info") {
|
||||
style.status_info = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("success") {
|
||||
style.status_success = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("warn") {
|
||||
style.status_warn = *s;
|
||||
}
|
||||
|
||||
if let Some(s) = colors.get("error") {
|
||||
style.status_error = *s;
|
||||
impl Default for ExploreConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
table: TableConfig::default(),
|
||||
selected_cell: color(None, Some(Color::LightBlue)),
|
||||
status_info: color(None, None),
|
||||
status_success: color(Some(Color::Black), Some(Color::Green)),
|
||||
status_warn: color(None, None),
|
||||
status_error: color(Some(Color::White), Some(Color::Red)),
|
||||
status_bar_background: color(
|
||||
Some(Color::Rgb(29, 31, 33)),
|
||||
Some(Color::Rgb(196, 201, 198)),
|
||||
),
|
||||
status_bar_text: color(None, None),
|
||||
cmd_bar_text: color(Some(Color::Rgb(196, 201, 198)), None),
|
||||
cmd_bar_background: color(None, None),
|
||||
highlight: color(Some(Color::Black), Some(Color::Yellow)),
|
||||
try_reactive: false,
|
||||
}
|
||||
}
|
||||
|
||||
style
|
||||
}
|
||||
impl ExploreConfig {
|
||||
/// take the default explore config and update it with relevant values from the nu config
|
||||
pub fn from_nu_config(config: &Config) -> Self {
|
||||
let mut ret = Self::default();
|
||||
|
||||
fn prepare_default_config(config: &mut HashMap<String, Value>) {
|
||||
const STATUS_BAR: Style = color(
|
||||
Some(Color::Rgb(29, 31, 33)),
|
||||
Some(Color::Rgb(196, 201, 198)),
|
||||
);
|
||||
const INPUT_BAR: Style = color(Some(Color::Rgb(196, 201, 198)), None);
|
||||
ret.table.column_padding_left = config.table_indent.left;
|
||||
ret.table.column_padding_right = config.table_indent.right;
|
||||
|
||||
const HIGHLIGHT: Style = color(Some(Color::Black), Some(Color::Yellow));
|
||||
let explore_cfg_hash_map = config.explore.clone();
|
||||
let colors = get_color_map(&explore_cfg_hash_map);
|
||||
|
||||
const STATUS_ERROR: Style = color(Some(Color::White), Some(Color::Red));
|
||||
const STATUS_INFO: Style = color(None, None);
|
||||
const STATUS_SUCCESS: Style = color(Some(Color::Black), Some(Color::Green));
|
||||
const STATUS_WARN: Style = color(None, None);
|
||||
if let Some(s) = colors.get("status_bar_text") {
|
||||
ret.status_bar_text = *s;
|
||||
}
|
||||
|
||||
const TABLE_SPLIT_LINE: Style = color(Some(Color::Rgb(64, 64, 64)), None);
|
||||
const TABLE_SELECT_CELL: Style = color(None, None);
|
||||
const TABLE_SELECT_ROW: Style = color(None, None);
|
||||
const TABLE_SELECT_COLUMN: Style = color(None, None);
|
||||
if let Some(s) = colors.get("status_bar_background") {
|
||||
ret.status_bar_background = *s;
|
||||
}
|
||||
|
||||
const HEXDUMP_INDEX: Style = color(Some(Color::Cyan), None);
|
||||
const HEXDUMP_SEGMENT: Style = color(Some(Color::Cyan), None).bold();
|
||||
const HEXDUMP_SEGMENT_ZERO: Style = color(Some(Color::Purple), None).bold();
|
||||
const HEXDUMP_SEGMENT_UNKNOWN: Style = color(Some(Color::Green), None).bold();
|
||||
const HEXDUMP_ASCII: Style = color(Some(Color::Cyan), None).bold();
|
||||
const HEXDUMP_ASCII_ZERO: Style = color(Some(Color::Purple), None).bold();
|
||||
const HEXDUMP_ASCII_UNKNOWN: Style = color(Some(Color::Green), None).bold();
|
||||
if let Some(s) = colors.get("command_bar_text") {
|
||||
ret.cmd_bar_text = *s;
|
||||
}
|
||||
|
||||
insert_style(config, "status_bar_background", STATUS_BAR);
|
||||
insert_style(config, "command_bar_text", INPUT_BAR);
|
||||
insert_style(config, "highlight", HIGHLIGHT);
|
||||
if let Some(s) = colors.get("command_bar_background") {
|
||||
ret.cmd_bar_background = *s;
|
||||
}
|
||||
|
||||
// because how config works we need to parse a string into Value::Record
|
||||
if let Some(s) = colors.get("command_bar_background") {
|
||||
ret.cmd_bar_background = *s;
|
||||
}
|
||||
|
||||
{
|
||||
let mut hm = config
|
||||
.get("status")
|
||||
.and_then(parse_hash_map)
|
||||
.unwrap_or_default();
|
||||
if let Some(s) = colors.get("selected_cell") {
|
||||
ret.selected_cell = *s;
|
||||
}
|
||||
|
||||
insert_style(&mut hm, "info", STATUS_INFO);
|
||||
insert_style(&mut hm, "success", STATUS_SUCCESS);
|
||||
insert_style(&mut hm, "warn", STATUS_WARN);
|
||||
insert_style(&mut hm, "error", STATUS_ERROR);
|
||||
if let Some(hm) = explore_cfg_hash_map.get("status").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
config.insert(String::from("status"), map_into_value(hm));
|
||||
}
|
||||
if let Some(s) = colors.get("info") {
|
||||
ret.status_info = *s;
|
||||
}
|
||||
|
||||
{
|
||||
let mut hm = config
|
||||
.get("table")
|
||||
.and_then(parse_hash_map)
|
||||
.unwrap_or_default();
|
||||
if let Some(s) = colors.get("success") {
|
||||
ret.status_success = *s;
|
||||
}
|
||||
|
||||
insert_style(&mut hm, "split_line", TABLE_SPLIT_LINE);
|
||||
insert_style(&mut hm, "selected_cell", TABLE_SELECT_CELL);
|
||||
insert_style(&mut hm, "selected_row", TABLE_SELECT_ROW);
|
||||
insert_style(&mut hm, "selected_column", TABLE_SELECT_COLUMN);
|
||||
if let Some(s) = colors.get("warn") {
|
||||
ret.status_warn = *s;
|
||||
}
|
||||
|
||||
config.insert(String::from("table"), map_into_value(hm));
|
||||
}
|
||||
if let Some(s) = colors.get("error") {
|
||||
ret.status_error = *s;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut hm = config
|
||||
.get("hex-dump")
|
||||
.and_then(create_map)
|
||||
.unwrap_or_default();
|
||||
if let Some(hm) = explore_cfg_hash_map.get("try").and_then(create_map) {
|
||||
if let Some(reactive) = hm.get("reactive") {
|
||||
if let Ok(b) = reactive.as_bool() {
|
||||
ret.try_reactive = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
insert_style(&mut hm, "color_index", HEXDUMP_INDEX);
|
||||
insert_style(&mut hm, "color_segment", HEXDUMP_SEGMENT);
|
||||
insert_style(&mut hm, "color_segment_zero", HEXDUMP_SEGMENT_ZERO);
|
||||
insert_style(&mut hm, "color_segment_unknown", HEXDUMP_SEGMENT_UNKNOWN);
|
||||
insert_style(&mut hm, "color_ascii", HEXDUMP_ASCII);
|
||||
insert_style(&mut hm, "color_ascii_zero", HEXDUMP_ASCII_ZERO);
|
||||
insert_style(&mut hm, "color_ascii_unknown", HEXDUMP_ASCII_UNKNOWN);
|
||||
|
||||
insert_int(&mut hm, "segment_size", 2);
|
||||
insert_int(&mut hm, "count_segments", 8);
|
||||
|
||||
insert_bool(&mut hm, "split", true);
|
||||
|
||||
config.insert(String::from("hex-dump"), map_into_value(hm));
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_hash_map(value: &Value) -> Option<HashMap<String, Value>> {
|
||||
value.as_record().ok().map(|val| {
|
||||
val.iter()
|
||||
.map(|(col, val)| (col.clone(), val.clone()))
|
||||
.collect::<HashMap<_, _>>()
|
||||
})
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct TableConfig {
|
||||
pub separator_style: Style,
|
||||
pub show_index: bool,
|
||||
pub show_header: bool,
|
||||
pub column_padding_left: usize,
|
||||
pub column_padding_right: usize,
|
||||
}
|
||||
|
||||
const fn color(foreground: Option<Color>, background: Option<Color>) -> Style {
|
||||
|
@ -299,49 +265,6 @@ const fn color(foreground: Option<Color>, background: Option<Color>) -> Style {
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_style(map: &mut HashMap<String, Value>, key: &str, value: Style) {
|
||||
if map.contains_key(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if value == Style::default() {
|
||||
return;
|
||||
}
|
||||
|
||||
let value = nu_color_config::NuStyle::from(value);
|
||||
if let Ok(val) = nu_json::to_string_raw(&value) {
|
||||
map.insert(String::from(key), Value::string(val, Span::unknown()));
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_bool(map: &mut HashMap<String, Value>, key: &str, value: bool) {
|
||||
if map.contains_key(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.insert(String::from(key), Value::bool(value, Span::unknown()));
|
||||
}
|
||||
|
||||
fn insert_int(map: &mut HashMap<String, Value>, key: &str, value: i64) {
|
||||
if map.contains_key(key) {
|
||||
return;
|
||||
}
|
||||
|
||||
map.insert(String::from(key), Value::int(value, Span::unknown()));
|
||||
}
|
||||
|
||||
fn include_nu_config(config: &mut HashMap<String, Value>, style_computer: &StyleComputer) {
|
||||
let line_color = lookup_color(style_computer, "separator");
|
||||
if line_color != nu_ansi_term::Style::default() {
|
||||
let mut map = config
|
||||
.get("table")
|
||||
.and_then(parse_hash_map)
|
||||
.unwrap_or_default();
|
||||
insert_style(&mut map, "split_line", line_color);
|
||||
config.insert(String::from("table"), map_into_value(map));
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_color(style_computer: &StyleComputer, key: &str) -> nu_ansi_term::Style {
|
||||
style_computer.compute(key, &Value::nothing(Span::unknown()))
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@ use nu_protocol::{
|
|||
engine::{EngineState, Stack},
|
||||
PipelineData, Value,
|
||||
};
|
||||
use pager::{Page, Pager, PagerConfig, StyleConfig};
|
||||
use pager::{Page, Pager, PagerConfig};
|
||||
use registry::CommandRegistry;
|
||||
use terminal_size::{Height, Width};
|
||||
use views::{BinaryView, Orientation, Preview, RecordView};
|
||||
|
||||
mod util {
|
||||
pub use super::nu_common::{create_lscolors, create_map, map_into_value};
|
||||
pub use super::nu_common::{create_lscolors, create_map};
|
||||
}
|
||||
|
||||
fn run_pager(
|
||||
|
|
|
@ -4,7 +4,6 @@ use nu_ansi_term::{Color, Style};
|
|||
use nu_engine::env_to_string;
|
||||
use nu_protocol::engine::{EngineState, Stack};
|
||||
use nu_utils::get_ls_colors;
|
||||
use std::fs::symlink_metadata;
|
||||
|
||||
pub fn create_lscolors(engine_state: &EngineState, stack: &Stack) -> LsColors {
|
||||
let colors = stack
|
||||
|
@ -14,6 +13,7 @@ pub fn create_lscolors(engine_state: &EngineState, stack: &Stack) -> LsColors {
|
|||
get_ls_colors(colors)
|
||||
}
|
||||
|
||||
/// Colorizes any columns named "name" in the table using LS_COLORS
|
||||
pub fn lscolorize(header: &[String], data: &mut [Vec<NuText>], lscolors: &LsColors) {
|
||||
for (col, col_name) in header.iter().enumerate() {
|
||||
if col_name != "name" {
|
||||
|
@ -33,14 +33,7 @@ pub fn lscolorize(header: &[String], data: &mut [Vec<NuText>], lscolors: &LsColo
|
|||
|
||||
fn get_path_style(path: &str, ls_colors: &LsColors) -> Option<Style> {
|
||||
let stripped_path = nu_utils::strip_ansi_unlikely(path);
|
||||
|
||||
let style = match symlink_metadata(stripped_path.as_ref()) {
|
||||
Ok(metadata) => {
|
||||
ls_colors.style_for_path_with_metadata(stripped_path.as_ref(), Some(&metadata))
|
||||
}
|
||||
Err(_) => ls_colors.style_for_path(stripped_path.as_ref()),
|
||||
};
|
||||
|
||||
let style = ls_colors.style_for_str(stripped_path.as_ref());
|
||||
style.map(lsstyle_to_nu_style)
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ pub use command::run_command_with_value;
|
|||
pub use lscolor::{create_lscolors, lscolorize};
|
||||
pub use string::{string_width, truncate_str};
|
||||
pub use table::try_build_table;
|
||||
pub use value::{collect_input, collect_pipeline, create_map, map_into_value};
|
||||
pub use value::{collect_input, collect_pipeline, create_map};
|
||||
|
||||
pub fn has_simple_value(data: &[Vec<Value>]) -> Option<&Value> {
|
||||
if data.len() == 1
|
||||
|
|
|
@ -176,10 +176,6 @@ pub fn create_map(value: &Value) -> Option<HashMap<String, Value>> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn map_into_value(hm: HashMap<String, Value>) -> Value {
|
||||
Value::record(hm.into_iter().collect(), NuSpan::unknown())
|
||||
}
|
||||
|
||||
fn unknown_error_value() -> Value {
|
||||
Value::string(String::from("❎"), NuSpan::unknown())
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ use self::{
|
|||
};
|
||||
use super::views::{Layout, View};
|
||||
use crate::{
|
||||
nu_common::{CtrlC, NuColor, NuConfig, NuSpan, NuStyle},
|
||||
explore::ExploreConfig,
|
||||
nu_common::{CtrlC, NuColor, NuConfig, NuStyle},
|
||||
registry::{Command, CommandRegistry},
|
||||
util::map_into_value,
|
||||
views::{util::nu_style_to_tui, ViewConfig},
|
||||
};
|
||||
use anyhow::Result;
|
||||
|
@ -26,15 +26,14 @@ use crossterm::{
|
|||
};
|
||||
use events::UIEvents;
|
||||
use lscolors::LsColors;
|
||||
use nu_color_config::{lookup_ansi_color_style, StyleComputer};
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Record, Value,
|
||||
Value,
|
||||
};
|
||||
use ratatui::{backend::CrosstermBackend, layout::Rect, widgets::Block};
|
||||
use std::{
|
||||
cmp::min,
|
||||
collections::HashMap,
|
||||
io::{self, Stdout},
|
||||
result,
|
||||
sync::atomic::Ordering,
|
||||
|
@ -42,7 +41,6 @@ use std::{
|
|||
|
||||
pub type Frame<'a> = ratatui::Frame<'a>;
|
||||
pub type Terminal = ratatui::Terminal<CrosstermBackend<Stdout>>;
|
||||
pub type ConfigMap = HashMap<String, Value>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Pager<'a> {
|
||||
|
@ -73,19 +71,6 @@ struct CommandBuf {
|
|||
cmd_exec_info: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct StyleConfig {
|
||||
pub status_info: NuStyle,
|
||||
pub status_success: NuStyle,
|
||||
pub status_warn: NuStyle,
|
||||
pub status_error: NuStyle,
|
||||
pub status_bar_background: NuStyle,
|
||||
pub status_bar_text: NuStyle,
|
||||
pub cmd_bar_text: NuStyle,
|
||||
pub cmd_bar_background: NuStyle,
|
||||
pub highlight: NuStyle,
|
||||
}
|
||||
|
||||
impl<'a> Pager<'a> {
|
||||
pub fn new(config: PagerConfig<'a>) -> Self {
|
||||
Self {
|
||||
|
@ -100,27 +85,6 @@ impl<'a> Pager<'a> {
|
|||
self.message = Some(text.into());
|
||||
}
|
||||
|
||||
pub fn set_config(&mut self, path: &[String], value: Value) -> bool {
|
||||
let path = path.iter().map(|s| s.as_str()).collect::<Vec<_>>();
|
||||
|
||||
match &path[..] {
|
||||
["status_bar_text"] => value_as_style(&mut self.config.style.status_bar_text, &value),
|
||||
["status_bar_background"] => {
|
||||
value_as_style(&mut self.config.style.status_bar_background, &value)
|
||||
}
|
||||
["command_bar_text"] => value_as_style(&mut self.config.style.cmd_bar_text, &value),
|
||||
["command_bar_background"] => {
|
||||
value_as_style(&mut self.config.style.cmd_bar_background, &value)
|
||||
}
|
||||
["highlight"] => value_as_style(&mut self.config.style.highlight, &value),
|
||||
["status", "info"] => value_as_style(&mut self.config.style.status_info, &value),
|
||||
["status", "success"] => value_as_style(&mut self.config.style.status_success, &value),
|
||||
["status", "warn"] => value_as_style(&mut self.config.style.status_warn, &value),
|
||||
["status", "error"] => value_as_style(&mut self.config.style.status_error, &value),
|
||||
path => set_config(&mut self.config.config, path, value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
&mut self,
|
||||
engine_state: &EngineState,
|
||||
|
@ -132,8 +96,8 @@ impl<'a> Pager<'a> {
|
|||
if let Some(page) = &mut view {
|
||||
page.view.setup(ViewConfig::new(
|
||||
self.config.nu_config,
|
||||
self.config.explore_config,
|
||||
self.config.style_computer,
|
||||
&self.config.config,
|
||||
self.config.lscolors,
|
||||
))
|
||||
}
|
||||
|
@ -153,10 +117,9 @@ pub enum Transition {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct PagerConfig<'a> {
|
||||
pub nu_config: &'a NuConfig,
|
||||
pub explore_config: &'a ExploreConfig,
|
||||
pub style_computer: &'a StyleComputer<'a>,
|
||||
pub lscolors: &'a LsColors,
|
||||
pub config: ConfigMap,
|
||||
pub style: StyleConfig,
|
||||
// If true, when quitting output the value of the cell the cursor was on
|
||||
pub peek_value: bool,
|
||||
pub tail: bool,
|
||||
|
@ -165,18 +128,19 @@ pub struct PagerConfig<'a> {
|
|||
impl<'a> PagerConfig<'a> {
|
||||
pub fn new(
|
||||
nu_config: &'a NuConfig,
|
||||
explore_config: &'a ExploreConfig,
|
||||
style_computer: &'a StyleComputer,
|
||||
lscolors: &'a LsColors,
|
||||
config: ConfigMap,
|
||||
peek_value: bool,
|
||||
tail: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
nu_config,
|
||||
explore_config,
|
||||
style_computer,
|
||||
config,
|
||||
lscolors,
|
||||
peek_value: false,
|
||||
tail: false,
|
||||
style: StyleConfig::default(),
|
||||
peek_value,
|
||||
tail,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -401,7 +365,7 @@ fn draw_frame(
|
|||
|
||||
draw_info(f, pager, info);
|
||||
|
||||
highlight_search_results(f, pager, layout, pager.config.style.highlight);
|
||||
highlight_search_results(f, pager, layout, pager.config.explore_config.highlight);
|
||||
set_cursor_cmd_bar(f, area, pager);
|
||||
}
|
||||
|
||||
|
@ -411,19 +375,24 @@ fn draw_info(f: &mut Frame, pager: &mut Pager<'_>, info: ViewInfo) {
|
|||
if let Some(report) = info.status {
|
||||
let last_2nd_line = area.bottom().saturating_sub(2);
|
||||
let area = Rect::new(area.left(), last_2nd_line, area.width, 1);
|
||||
render_status_bar(f, area, report, &pager.config.style);
|
||||
render_status_bar(f, area, report, pager.config.explore_config);
|
||||
}
|
||||
|
||||
{
|
||||
let last_line = area.bottom().saturating_sub(1);
|
||||
let area = Rect::new(area.left(), last_line, area.width, 1);
|
||||
render_cmd_bar(f, area, pager, info.report, &pager.config.style);
|
||||
render_cmd_bar(f, area, pager, info.report, pager.config.explore_config);
|
||||
}
|
||||
}
|
||||
|
||||
fn create_view_config<'a>(pager: &'a Pager<'_>) -> ViewConfig<'a> {
|
||||
let cfg = &pager.config;
|
||||
ViewConfig::new(cfg.nu_config, cfg.style_computer, &cfg.config, cfg.lscolors)
|
||||
ViewConfig::new(
|
||||
cfg.nu_config,
|
||||
cfg.explore_config,
|
||||
cfg.style_computer,
|
||||
cfg.lscolors,
|
||||
)
|
||||
}
|
||||
|
||||
fn pager_run_command(
|
||||
|
@ -463,16 +432,7 @@ fn run_command(
|
|||
let value = view_stack.curr_view.as_mut().and_then(|p| p.view.exit());
|
||||
let transition = command.react(engine_state, stack, pager, value)?;
|
||||
match transition {
|
||||
Transition::Ok => {
|
||||
// so we basically allow a change of a config inside a command,
|
||||
// and cause of this we wanna update all of our views.
|
||||
//
|
||||
// THOUGH: MOST LIKELY IT WON'T BE CHANGED AND WE DO A WASTE.......
|
||||
|
||||
update_view_stack_setup(view_stack, &pager.config);
|
||||
|
||||
Ok(CmdResult::new(false, false, String::new()))
|
||||
}
|
||||
Transition::Ok => Ok(CmdResult::new(false, false, String::new())),
|
||||
Transition::Exit => Ok(CmdResult::new(true, false, String::new())),
|
||||
Transition::Cmd { .. } => todo!("not used so far"),
|
||||
}
|
||||
|
@ -487,7 +447,8 @@ fn run_command(
|
|||
}
|
||||
}
|
||||
|
||||
update_view_setup(&mut new_view, &pager.config);
|
||||
setup_view(&mut new_view, &pager.config);
|
||||
|
||||
view_stack.curr_view = Some(Page::raw(new_view, stackable));
|
||||
|
||||
Ok(CmdResult::new(false, true, cmd.name().to_owned()))
|
||||
|
@ -495,18 +456,13 @@ fn run_command(
|
|||
}
|
||||
}
|
||||
|
||||
fn update_view_stack_setup(view_stack: &mut ViewStack, cfg: &PagerConfig<'_>) {
|
||||
if let Some(page) = view_stack.curr_view.as_mut() {
|
||||
update_view_setup(&mut page.view, cfg);
|
||||
}
|
||||
|
||||
for page in &mut view_stack.stack {
|
||||
update_view_setup(&mut page.view, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_view_setup(view: &mut Box<dyn View>, cfg: &PagerConfig<'_>) {
|
||||
let cfg = ViewConfig::new(cfg.nu_config, cfg.style_computer, &cfg.config, cfg.lscolors);
|
||||
fn setup_view(view: &mut Box<dyn View>, cfg: &PagerConfig<'_>) {
|
||||
let cfg = ViewConfig::new(
|
||||
cfg.nu_config,
|
||||
cfg.explore_config,
|
||||
cfg.style_computer,
|
||||
cfg.lscolors,
|
||||
);
|
||||
view.setup(cfg);
|
||||
}
|
||||
|
||||
|
@ -528,7 +484,7 @@ fn set_cursor_cmd_bar(f: &mut Frame, area: Rect, pager: &Pager) {
|
|||
}
|
||||
}
|
||||
|
||||
fn render_status_bar(f: &mut Frame, area: Rect, report: Report, theme: &StyleConfig) {
|
||||
fn render_status_bar(f: &mut Frame, area: Rect, report: Report, theme: &ExploreConfig) {
|
||||
let msg_style = report_msg_style(&report, theme, theme.status_bar_text);
|
||||
let mut status_bar = create_status_bar(report);
|
||||
status_bar.set_background_style(theme.status_bar_background);
|
||||
|
@ -549,11 +505,11 @@ fn create_status_bar(report: Report) -> StatusBar {
|
|||
)
|
||||
}
|
||||
|
||||
fn report_msg_style(report: &Report, theme: &StyleConfig, style: NuStyle) -> NuStyle {
|
||||
fn report_msg_style(report: &Report, config: &ExploreConfig, style: NuStyle) -> NuStyle {
|
||||
if matches!(report.level, Severity::Info) {
|
||||
style
|
||||
} else {
|
||||
report_level_style(report.level, theme)
|
||||
report_level_style(report.level, config)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,15 +518,15 @@ fn render_cmd_bar(
|
|||
area: Rect,
|
||||
pager: &Pager,
|
||||
report: Option<Report>,
|
||||
theme: &StyleConfig,
|
||||
config: &ExploreConfig,
|
||||
) {
|
||||
if let Some(report) = report {
|
||||
let style = report_msg_style(&report, theme, theme.cmd_bar_text);
|
||||
let style = report_msg_style(&report, config, config.cmd_bar_text);
|
||||
let bar = CommandBar::new(
|
||||
&report.message,
|
||||
&report.context1,
|
||||
style,
|
||||
theme.cmd_bar_background,
|
||||
config.cmd_bar_background,
|
||||
);
|
||||
|
||||
f.render_widget(bar, area);
|
||||
|
@ -578,16 +534,16 @@ fn render_cmd_bar(
|
|||
}
|
||||
|
||||
if pager.cmd_buf.is_cmd_input {
|
||||
render_cmd_bar_cmd(f, area, pager, theme);
|
||||
render_cmd_bar_cmd(f, area, pager, config);
|
||||
return;
|
||||
}
|
||||
|
||||
if pager.search_buf.is_search_input || !pager.search_buf.buf_cmd_input.is_empty() {
|
||||
render_cmd_bar_search(f, area, pager, theme);
|
||||
render_cmd_bar_search(f, area, pager, config);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, theme: &StyleConfig) {
|
||||
fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, config: &ExploreConfig) {
|
||||
if pager.search_buf.search_results.is_empty() && !pager.search_buf.is_search_input {
|
||||
let message = format!("Pattern not found: {}", pager.search_buf.buf_cmd_input);
|
||||
let style = NuStyle {
|
||||
|
@ -596,7 +552,7 @@ fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, theme: &S
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let bar = CommandBar::new(&message, "", style, theme.cmd_bar_background);
|
||||
let bar = CommandBar::new(&message, "", style, config.cmd_bar_background);
|
||||
f.render_widget(bar, area);
|
||||
return;
|
||||
}
|
||||
|
@ -615,11 +571,11 @@ fn render_cmd_bar_search(f: &mut Frame, area: Rect, pager: &Pager<'_>, theme: &S
|
|||
format!("[{index}/{total}]")
|
||||
};
|
||||
|
||||
let bar = CommandBar::new(&text, &info, theme.cmd_bar_text, theme.cmd_bar_background);
|
||||
let bar = CommandBar::new(&text, &info, config.cmd_bar_text, config.cmd_bar_background);
|
||||
f.render_widget(bar, area);
|
||||
}
|
||||
|
||||
fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, theme: &StyleConfig) {
|
||||
fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, config: &ExploreConfig) {
|
||||
let mut input = pager.cmd_buf.buf_cmd2.as_str();
|
||||
if input.len() > area.width as usize + 1 {
|
||||
// in such case we take last max_cmd_len chars
|
||||
|
@ -637,7 +593,7 @@ fn render_cmd_bar_cmd(f: &mut Frame, area: Rect, pager: &Pager, theme: &StyleCon
|
|||
let prefix = ':';
|
||||
let text = format!("{prefix}{input}");
|
||||
|
||||
let bar = CommandBar::new(&text, "", theme.cmd_bar_text, theme.cmd_bar_background);
|
||||
let bar = CommandBar::new(&text, "", config.cmd_bar_text, config.cmd_bar_background);
|
||||
f.render_widget(bar, area);
|
||||
}
|
||||
|
||||
|
@ -998,72 +954,12 @@ fn cmd_input_key_event(buf: &mut CommandBuf, key: &KeyEvent) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn value_as_style(style: &mut nu_ansi_term::Style, value: &Value) -> bool {
|
||||
match value.coerce_str() {
|
||||
Ok(s) => {
|
||||
*style = lookup_ansi_color_style(&s);
|
||||
true
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_config(hm: &mut HashMap<String, Value>, path: &[&str], value: Value) -> bool {
|
||||
if path.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let key = path[0];
|
||||
|
||||
if !hm.contains_key(key) {
|
||||
hm.insert(
|
||||
key.to_string(),
|
||||
Value::record(Record::new(), NuSpan::unknown()),
|
||||
);
|
||||
}
|
||||
|
||||
let val = hm.get_mut(key).expect("...");
|
||||
|
||||
if path.len() == 1 {
|
||||
*val = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
match val {
|
||||
Value::Record { val: record, .. } => {
|
||||
if path.len() == 2 {
|
||||
let key = path[1];
|
||||
|
||||
record.to_mut().insert(key, value);
|
||||
} else {
|
||||
let mut hm2: HashMap<String, Value> = HashMap::new();
|
||||
for (k, v) in record.iter() {
|
||||
hm2.insert(k.to_string(), v.clone());
|
||||
}
|
||||
|
||||
let result = set_config(&mut hm2, &path[1..], value);
|
||||
if !result {
|
||||
*val = map_into_value(hm2);
|
||||
}
|
||||
|
||||
if path.len() == 2 {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn report_level_style(level: Severity, theme: &StyleConfig) -> NuStyle {
|
||||
fn report_level_style(level: Severity, config: &ExploreConfig) -> NuStyle {
|
||||
match level {
|
||||
Severity::Info => theme.status_info,
|
||||
Severity::Success => theme.status_success,
|
||||
Severity::Warn => theme.status_warn,
|
||||
Severity::Err => theme.status_error,
|
||||
Severity::Info => config.status_info,
|
||||
Severity::Success => config.status_success,
|
||||
Severity::Warn => config.status_warn,
|
||||
Severity::Err => config.status_error,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
mod binary_widget;
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use nu_color_config::get_color_map;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Value,
|
||||
|
@ -11,22 +10,26 @@ use nu_protocol::{
|
|||
use ratatui::layout::Rect;
|
||||
|
||||
use crate::{
|
||||
explore::ExploreConfig,
|
||||
nu_common::NuText,
|
||||
pager::{
|
||||
report::{Report, Severity},
|
||||
ConfigMap, Frame, Transition, ViewInfo,
|
||||
Frame, Transition, ViewInfo,
|
||||
},
|
||||
util::create_map,
|
||||
views::cursor::Position,
|
||||
};
|
||||
|
||||
use self::binary_widget::{BinarySettings, BinaryStyle, BinaryWidget};
|
||||
|
||||
use super::{cursor::XYCursor, Layout, View, ViewConfig};
|
||||
use super::{cursor::WindowCursor2D, Layout, View, ViewConfig};
|
||||
|
||||
/// An interactive view that displays binary data in a hex dump format.
|
||||
/// Not finished; many aspects are still WIP.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BinaryView {
|
||||
data: Vec<u8>,
|
||||
cursor: XYCursor,
|
||||
// HACK: we are only using the vertical dimension of the cursor, should we use a plain old WindowCursor?
|
||||
cursor: WindowCursor2D,
|
||||
settings: Settings,
|
||||
}
|
||||
|
||||
|
@ -40,7 +43,7 @@ impl BinaryView {
|
|||
pub fn new(data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
data,
|
||||
cursor: XYCursor::default(),
|
||||
cursor: WindowCursor2D::default(),
|
||||
settings: Settings::default(),
|
||||
}
|
||||
}
|
||||
|
@ -86,21 +89,17 @@ impl View for BinaryView {
|
|||
}
|
||||
|
||||
fn setup(&mut self, cfg: ViewConfig<'_>) {
|
||||
let hm = match cfg.config.get("hex-dump").and_then(create_map) {
|
||||
Some(hm) => hm,
|
||||
None => return,
|
||||
};
|
||||
|
||||
self.settings = settings_from_config(&hm);
|
||||
self.settings = settings_from_config(cfg.explore_config);
|
||||
|
||||
let count_rows =
|
||||
BinaryWidget::new(&self.data, self.settings.opts, Default::default()).count_lines();
|
||||
self.cursor = XYCursor::new(count_rows, 0);
|
||||
// TODO: refactor View so setup() is fallible and we don't have to panic here
|
||||
self.cursor = WindowCursor2D::new(count_rows, 1).expect("Failed to create XYCursor");
|
||||
}
|
||||
}
|
||||
|
||||
fn create_binary_widget(v: &BinaryView) -> BinaryWidget<'_> {
|
||||
let start_line = v.cursor.row_starts_at();
|
||||
let start_line = v.cursor.window_origin().row;
|
||||
let count_elements =
|
||||
BinaryWidget::new(&[], v.settings.opts, Default::default()).count_elements();
|
||||
let index = start_line * count_elements;
|
||||
|
@ -179,31 +178,19 @@ fn handle_event_view_mode(view: &mut BinaryView, key: &KeyEvent) -> Option<Trans
|
|||
}
|
||||
}
|
||||
|
||||
fn settings_from_config(config: &ConfigMap) -> Settings {
|
||||
let colors = get_color_map(config);
|
||||
|
||||
fn settings_from_config(config: &ExploreConfig) -> Settings {
|
||||
// Most of this is hardcoded for now, add it to the config later if needed
|
||||
Settings {
|
||||
opts: BinarySettings::new(
|
||||
config_get_usize(config, "segment_size", 2),
|
||||
config_get_usize(config, "count_segments", 8),
|
||||
),
|
||||
opts: BinarySettings::new(2, 8),
|
||||
style: BinaryStyle::new(
|
||||
colors.get("color_index").cloned(),
|
||||
config_get_usize(config, "column_padding_left", 1) as u16,
|
||||
config_get_usize(config, "column_padding_right", 1) as u16,
|
||||
None,
|
||||
config.table.column_padding_left as u16,
|
||||
config.table.column_padding_right as u16,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize {
|
||||
config
|
||||
.get(key)
|
||||
.and_then(|v| v.coerce_str().ok())
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn create_report(cursor: XYCursor) -> Report {
|
||||
fn create_report(cursor: WindowCursor2D) -> Report {
|
||||
let covered_percent = report_row_position(cursor);
|
||||
let cursor = report_cursor_position(cursor);
|
||||
let mode = report_mode_name();
|
||||
|
@ -216,8 +203,8 @@ fn report_mode_name() -> String {
|
|||
String::from("VIEW")
|
||||
}
|
||||
|
||||
fn report_row_position(cursor: XYCursor) -> String {
|
||||
if cursor.row_starts_at() == 0 {
|
||||
fn report_row_position(cursor: WindowCursor2D) -> String {
|
||||
if cursor.window_origin().row == 0 {
|
||||
return String::from("Top");
|
||||
}
|
||||
|
||||
|
@ -233,10 +220,9 @@ fn report_row_position(cursor: XYCursor) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn report_cursor_position(cursor: XYCursor) -> String {
|
||||
let rows_seen = cursor.row_starts_at();
|
||||
let columns_seen = cursor.column_starts_at();
|
||||
format!("{rows_seen},{columns_seen}")
|
||||
fn report_cursor_position(cursor: WindowCursor2D) -> String {
|
||||
let Position { row, column } = cursor.window_origin();
|
||||
format!("{row},{column}")
|
||||
}
|
||||
|
||||
fn get_percentage(value: usize, max: usize) -> usize {
|
||||
|
|
|
@ -1,71 +1,124 @@
|
|||
mod windowcursor;
|
||||
mod xycursor;
|
||||
mod window_cursor;
|
||||
mod window_cursor_2d;
|
||||
|
||||
pub use windowcursor::WindowCursor;
|
||||
pub use xycursor::XYCursor;
|
||||
use anyhow::{bail, Result};
|
||||
pub use window_cursor::WindowCursor;
|
||||
pub use window_cursor_2d::{Position, WindowCursor2D};
|
||||
|
||||
/// A 1-dimensional cursor to track a position from 0 to N
|
||||
///
|
||||
/// Say we have a cursor with size=9, at position 3:
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// | | | C | | | | | |
|
||||
///
|
||||
/// After moving forward by 2 steps:
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// | | | | | C | | | |
|
||||
///
|
||||
/// After moving backward by 6 steps (clamped to 0):
|
||||
/// 0 1 2 3 4 5 6 7 8 9
|
||||
/// C | | | | | | | | |
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Cursor {
|
||||
index: usize,
|
||||
limit: usize,
|
||||
struct Cursor {
|
||||
/// The current position of the cursor
|
||||
position: usize,
|
||||
/// The number of distinct positions the cursor can be at
|
||||
size: usize,
|
||||
}
|
||||
|
||||
impl Cursor {
|
||||
pub fn new(limit: usize) -> Self {
|
||||
Self { index: 0, limit }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_index(&self) -> usize {
|
||||
self.index
|
||||
}
|
||||
|
||||
pub fn cap(&self) -> usize {
|
||||
self.limit - self.index
|
||||
}
|
||||
|
||||
pub fn set(&mut self, i: usize) -> bool {
|
||||
if i >= self.limit {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.index = i;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn limit(&mut self, i: usize) -> bool {
|
||||
if self.index > self.limit {
|
||||
self.index = self.limit.saturating_sub(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
self.limit = i;
|
||||
if self.index >= self.limit {
|
||||
self.index = self.limit.saturating_sub(1);
|
||||
}
|
||||
|
||||
true
|
||||
/// Constructor to create a new Cursor
|
||||
pub fn new(size: usize) -> Self {
|
||||
// In theory we should not be able to create a cursor with size 0, but in practice
|
||||
// it's easier to allow that for empty lists etc. instead of propagating errors
|
||||
Cursor { position: 0, size }
|
||||
}
|
||||
|
||||
/// The max position the cursor can be at
|
||||
pub fn end(&self) -> usize {
|
||||
self.limit
|
||||
self.size - 1
|
||||
}
|
||||
|
||||
pub fn next(&mut self, i: usize) -> bool {
|
||||
if self.index + i == self.limit {
|
||||
return false;
|
||||
/// Set the position to a specific value within the bounds [0, end]
|
||||
pub fn set_position(&mut self, pos: usize) {
|
||||
if pos <= self.end() {
|
||||
self.position = pos;
|
||||
} else {
|
||||
// Clamp the position to end if out of bounds
|
||||
self.position = self.end();
|
||||
}
|
||||
|
||||
self.index += i;
|
||||
true
|
||||
}
|
||||
|
||||
pub fn prev(&mut self, i: usize) -> bool {
|
||||
if self.index < i {
|
||||
return false;
|
||||
/// Set the size of the cursor. The position is clamped if it exceeds the new size
|
||||
pub fn set_size(&mut self, size: usize) -> Result<()> {
|
||||
if size == 0 {
|
||||
bail!("Size cannot be zero");
|
||||
}
|
||||
self.size = size;
|
||||
if self.position > self.end() {
|
||||
self.position = self.end();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
self.index -= i;
|
||||
true
|
||||
/// Move the cursor forward by a specified number of steps
|
||||
pub fn move_forward(&mut self, steps: usize) {
|
||||
if self.position + steps <= self.end() {
|
||||
self.position += steps;
|
||||
} else {
|
||||
self.position = self.end();
|
||||
}
|
||||
}
|
||||
|
||||
/// Move the cursor backward by a specified number of steps
|
||||
pub fn move_backward(&mut self, steps: usize) {
|
||||
if self.position >= steps {
|
||||
self.position -= steps;
|
||||
} else {
|
||||
self.position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cursor_set_position() {
|
||||
// from 0 to 9
|
||||
let mut cursor = Cursor::new(10);
|
||||
cursor.set_position(5);
|
||||
assert_eq!(cursor.position, 5);
|
||||
|
||||
cursor.set_position(15);
|
||||
assert_eq!(cursor.position, 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cursor_move_forward() {
|
||||
// from 0 to 9
|
||||
let mut cursor = Cursor::new(10);
|
||||
assert_eq!(cursor.position, 0);
|
||||
cursor.move_forward(3);
|
||||
assert_eq!(cursor.position, 3);
|
||||
|
||||
cursor.move_forward(10);
|
||||
assert_eq!(cursor.position, 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cursor_move_backward() {
|
||||
// from 0 to 9
|
||||
let mut cursor = Cursor::new(10);
|
||||
cursor.move_backward(3);
|
||||
assert_eq!(cursor.position, 0);
|
||||
|
||||
cursor.move_forward(5);
|
||||
assert_eq!(cursor.position, 5);
|
||||
cursor.move_backward(3);
|
||||
assert_eq!(cursor.position, 2);
|
||||
cursor.move_backward(3);
|
||||
assert_eq!(cursor.position, 0);
|
||||
}
|
||||
}
|
||||
|
|
146
crates/nu-explore/src/views/cursor/window_cursor.rs
Normal file
146
crates/nu-explore/src/views/cursor/window_cursor.rs
Normal file
|
@ -0,0 +1,146 @@
|
|||
use std::cmp::min;
|
||||
|
||||
use super::Cursor;
|
||||
use anyhow::{bail, Ok, Result};
|
||||
|
||||
/// WindowCursor provides a mechanism to navigate through a 1-dimensional range
|
||||
/// using a smaller movable window within the view.
|
||||
///
|
||||
/// View: The larger context or total allowable range for navigation.
|
||||
/// Window: The smaller, focused subset of the view.
|
||||
///
|
||||
/// Example:
|
||||
/// ```plaintext
|
||||
/// 1. Initial view of size 20 with a window of size 5. The absolute cursor position starts at 0.
|
||||
/// View :
|
||||
/// |--------------------|
|
||||
/// Window :
|
||||
/// |X====|
|
||||
///
|
||||
/// 2. After advancing the window by 3, the absolute cursor position becomes 3.
|
||||
/// View :
|
||||
/// |--------------------|
|
||||
/// Window :
|
||||
/// |X====|
|
||||
///
|
||||
/// 3. After advancing the cursor inside the window by 2, the absolute cursor position becomes 5.
|
||||
/// View :
|
||||
/// |--------------------|
|
||||
/// Window :
|
||||
/// |==X==|
|
||||
/// ```
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct WindowCursor {
|
||||
view: Cursor,
|
||||
window: Cursor,
|
||||
}
|
||||
|
||||
impl WindowCursor {
|
||||
pub fn new(view_size: usize, window_size: usize) -> Result<Self> {
|
||||
if window_size > view_size {
|
||||
bail!("Window size cannot be greater than view size");
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
view: Cursor::new(view_size),
|
||||
window: Cursor::new(window_size),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn absolute_position(&self) -> usize {
|
||||
self.window_starts_at() + self.window.position
|
||||
}
|
||||
|
||||
pub fn window_relative_position(&self) -> usize {
|
||||
self.window.position
|
||||
}
|
||||
|
||||
pub fn window_starts_at(&self) -> usize {
|
||||
self.view.position
|
||||
}
|
||||
|
||||
pub fn window_size(&self) -> usize {
|
||||
self.window.size
|
||||
}
|
||||
|
||||
pub fn end(&self) -> usize {
|
||||
self.view.end()
|
||||
}
|
||||
|
||||
pub fn set_window_start_position(&mut self, i: usize) {
|
||||
self.view.set_position(i)
|
||||
}
|
||||
|
||||
pub fn move_window_to_end(&mut self) {
|
||||
self.view.set_position(self.end() - self.window_size() + 1);
|
||||
}
|
||||
|
||||
pub fn set_window_size(&mut self, new_size: usize) -> Result<()> {
|
||||
if new_size > self.view.size {
|
||||
// TODO: should we return an error here or clamp? the Ok is copying existing behavior
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.window.set_size(new_size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn next_n(&mut self, n: usize) {
|
||||
for _ in 0..n {
|
||||
self.next();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next(&mut self) {
|
||||
if self.absolute_position() >= self.end() {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.window_relative_position() == self.window.end() {
|
||||
self.view.move_forward(1);
|
||||
} else {
|
||||
self.window.move_forward(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_window(&mut self) {
|
||||
self.move_cursor_to_end_of_window();
|
||||
|
||||
// move window forward by window size, or less if that would send it off the end of the view
|
||||
let window_end = self.window_starts_at() + self.window_size() - 1;
|
||||
let distance_from_window_end_to_view_end = self.end() - window_end;
|
||||
self.view.move_forward(min(
|
||||
distance_from_window_end_to_view_end,
|
||||
self.window_size(),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn prev_n(&mut self, n: usize) {
|
||||
for _ in 0..n {
|
||||
self.prev();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev(&mut self) {
|
||||
if self.window_relative_position() == 0 {
|
||||
self.view.move_backward(1);
|
||||
} else {
|
||||
self.window.move_backward(1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prev_window(&mut self) {
|
||||
self.move_cursor_to_start_of_window();
|
||||
|
||||
// move the whole window back
|
||||
self.view.move_backward(self.window_size());
|
||||
}
|
||||
|
||||
pub fn move_cursor_to_start_of_window(&mut self) {
|
||||
self.window.move_backward(self.window_size());
|
||||
}
|
||||
|
||||
pub fn move_cursor_to_end_of_window(&mut self) {
|
||||
self.window.move_forward(self.window_size());
|
||||
}
|
||||
}
|
172
crates/nu-explore/src/views/cursor/window_cursor_2d.rs
Normal file
172
crates/nu-explore/src/views/cursor/window_cursor_2d.rs
Normal file
|
@ -0,0 +1,172 @@
|
|||
use super::WindowCursor;
|
||||
use anyhow::Result;
|
||||
|
||||
/// `WindowCursor2D` manages a 2-dimensional "window" onto a grid of cells, with a cursor that can point to a specific cell.
|
||||
/// For example, consider a 3x3 grid of cells:
|
||||
///
|
||||
/// +---+---+---+
|
||||
/// | a | b | c |
|
||||
/// |---|---|---|
|
||||
/// | d | e | f |
|
||||
/// |---|---|---|
|
||||
/// | g | h | i |
|
||||
/// +---+---+---+
|
||||
///
|
||||
/// A `WindowCursor2D` can be used to track the currently visible section of this grid.
|
||||
/// For example, a 2x2 window onto this grid could initially show the top left 2x2 section:
|
||||
///
|
||||
/// +---+---+
|
||||
/// | a | b |
|
||||
/// |---|---|
|
||||
/// | d | e |
|
||||
/// +---+---+
|
||||
///
|
||||
/// Moving the window down 1 row:
|
||||
///
|
||||
/// +---+---+
|
||||
/// | d | e |
|
||||
/// |---|---|
|
||||
/// | g | h |
|
||||
/// +---+---+
|
||||
///
|
||||
/// Inside the window, the cursor can point to a specific cell.
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct WindowCursor2D {
|
||||
x: WindowCursor,
|
||||
y: WindowCursor,
|
||||
}
|
||||
|
||||
pub struct Position {
|
||||
pub row: usize,
|
||||
pub column: usize,
|
||||
}
|
||||
|
||||
impl WindowCursor2D {
|
||||
pub fn new(count_rows: usize, count_columns: usize) -> Result<Self> {
|
||||
Ok(Self {
|
||||
x: WindowCursor::new(count_columns, count_columns)?,
|
||||
y: WindowCursor::new(count_rows, count_rows)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_window_size(&mut self, count_rows: usize, count_columns: usize) -> Result<()> {
|
||||
self.x.set_window_size(count_columns)?;
|
||||
self.y.set_window_size(count_rows)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_window_start_position(&mut self, row: usize, col: usize) {
|
||||
self.x.set_window_start_position(col);
|
||||
self.y.set_window_start_position(row);
|
||||
}
|
||||
|
||||
/// The absolute position of the cursor in the grid (0-indexed, row only)
|
||||
pub fn row(&self) -> usize {
|
||||
self.y.absolute_position()
|
||||
}
|
||||
|
||||
/// The absolute position of the cursor in the grid (0-indexed, column only)
|
||||
pub fn column(&self) -> usize {
|
||||
self.x.absolute_position()
|
||||
}
|
||||
|
||||
/// The absolute position of the cursor in the grid (0-indexed)
|
||||
pub fn position(&self) -> Position {
|
||||
Position {
|
||||
row: self.row(),
|
||||
column: self.column(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn row_limit(&self) -> usize {
|
||||
self.y.end()
|
||||
}
|
||||
|
||||
pub fn window_origin(&self) -> Position {
|
||||
Position {
|
||||
row: self.y.window_starts_at(),
|
||||
column: self.x.window_starts_at(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn window_relative_position(&self) -> Position {
|
||||
Position {
|
||||
row: self.y.window_relative_position(),
|
||||
column: self.x.window_relative_position(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn window_width_in_columns(&self) -> usize {
|
||||
self.x.window_size()
|
||||
}
|
||||
|
||||
pub fn next_row(&mut self) {
|
||||
self.y.next_n(1)
|
||||
}
|
||||
|
||||
pub fn next_row_page(&mut self) {
|
||||
self.y.next_window()
|
||||
}
|
||||
|
||||
pub fn row_move_to_end(&mut self) {
|
||||
self.y.move_window_to_end();
|
||||
self.y.move_cursor_to_end_of_window();
|
||||
}
|
||||
|
||||
pub fn row_move_to_start(&mut self) {
|
||||
self.y.move_cursor_to_start_of_window();
|
||||
self.y.set_window_start_position(0);
|
||||
}
|
||||
|
||||
pub fn prev_row(&mut self) {
|
||||
self.y.prev()
|
||||
}
|
||||
|
||||
pub fn prev_row_page(&mut self) {
|
||||
self.y.prev_window()
|
||||
}
|
||||
|
||||
pub fn next_column(&mut self) {
|
||||
self.x.next()
|
||||
}
|
||||
|
||||
pub fn next_column_by(&mut self, i: usize) {
|
||||
self.x.next_n(i)
|
||||
}
|
||||
|
||||
pub fn prev_column(&mut self) {
|
||||
self.x.prev()
|
||||
}
|
||||
|
||||
pub fn prev_column_by(&mut self, i: usize) {
|
||||
self.x.prev_n(i)
|
||||
}
|
||||
|
||||
pub fn next_column_i(&mut self) {
|
||||
self.x
|
||||
.set_window_start_position(self.x.window_starts_at() + 1)
|
||||
}
|
||||
|
||||
pub fn prev_column_i(&mut self) {
|
||||
if self.x.window_starts_at() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.x
|
||||
.set_window_start_position(self.x.window_starts_at() - 1)
|
||||
}
|
||||
|
||||
pub fn next_row_i(&mut self) {
|
||||
self.y
|
||||
.set_window_start_position(self.y.window_starts_at() + 1)
|
||||
}
|
||||
|
||||
pub fn prev_row_i(&mut self) {
|
||||
if self.y.window_starts_at() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.y
|
||||
.set_window_start_position(self.y.window_starts_at() - 1)
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
use super::Cursor;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct WindowCursor {
|
||||
view: Cursor,
|
||||
window: Cursor,
|
||||
}
|
||||
|
||||
impl WindowCursor {
|
||||
pub fn new(limit: usize, window: usize) -> Option<Self> {
|
||||
if window > limit {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
view: Cursor::new(limit),
|
||||
window: Cursor::new(window),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn index(&self) -> usize {
|
||||
self.view.index + self.window.index
|
||||
}
|
||||
|
||||
pub fn offset(&self) -> usize {
|
||||
self.window.index
|
||||
}
|
||||
|
||||
pub fn starts_at(&self) -> usize {
|
||||
self.view.index
|
||||
}
|
||||
|
||||
pub fn cap(&self) -> usize {
|
||||
self.view.cap()
|
||||
}
|
||||
|
||||
pub fn window(&self) -> usize {
|
||||
self.window.end()
|
||||
}
|
||||
|
||||
pub fn end(&self) -> usize {
|
||||
self.view.end()
|
||||
}
|
||||
|
||||
pub fn set_window_at(&mut self, i: usize) -> bool {
|
||||
self.view.set(i)
|
||||
}
|
||||
|
||||
pub fn set_window(&mut self, i: usize) -> bool {
|
||||
if i > self.view.end() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.window.limit(i)
|
||||
}
|
||||
|
||||
pub fn next(&mut self, i: usize) -> bool {
|
||||
if i > self.cap() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut rest = 0;
|
||||
for y in 0..i {
|
||||
if !self.window.next(1) {
|
||||
rest = i - y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..rest {
|
||||
if self.index() + 1 == self.end() {
|
||||
return rest != i;
|
||||
}
|
||||
|
||||
self.view.next(1);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn next_window(&mut self) -> bool {
|
||||
let end_cursor = self.window() - self.offset();
|
||||
self.next(end_cursor);
|
||||
|
||||
let mut index_move = self.window();
|
||||
if index_move + self.starts_at() >= self.end() {
|
||||
index_move = self.end() - self.starts_at();
|
||||
}
|
||||
|
||||
self.next(index_move)
|
||||
}
|
||||
|
||||
pub fn prev(&mut self, i: usize) -> bool {
|
||||
for _ in 0..i {
|
||||
if !self.window.prev(1) {
|
||||
self.view.prev(1);
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
pub fn prev_window(&mut self) -> bool {
|
||||
self.prev(self.window() + self.offset())
|
||||
}
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
use super::WindowCursor;
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct XYCursor {
|
||||
x: WindowCursor,
|
||||
y: WindowCursor,
|
||||
}
|
||||
|
||||
impl XYCursor {
|
||||
pub fn new(count_rows: usize, count_columns: usize) -> Self {
|
||||
Self {
|
||||
x: WindowCursor::new(count_columns, count_columns).expect("..."),
|
||||
y: WindowCursor::new(count_rows, count_rows).expect("..."),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_window(&mut self, count_rows: usize, count_columns: usize) {
|
||||
self.x.set_window(count_columns);
|
||||
self.y.set_window(count_rows);
|
||||
}
|
||||
|
||||
pub fn set_position(&mut self, row: usize, col: usize) {
|
||||
self.x.set_window_at(col);
|
||||
self.y.set_window_at(row);
|
||||
}
|
||||
|
||||
pub fn row(&self) -> usize {
|
||||
self.y.index()
|
||||
}
|
||||
|
||||
pub fn column(&self) -> usize {
|
||||
self.x.index()
|
||||
}
|
||||
|
||||
pub fn row_limit(&self) -> usize {
|
||||
self.y.end()
|
||||
}
|
||||
|
||||
pub fn row_starts_at(&self) -> usize {
|
||||
self.y.starts_at()
|
||||
}
|
||||
|
||||
pub fn column_starts_at(&self) -> usize {
|
||||
self.x.starts_at()
|
||||
}
|
||||
|
||||
pub fn row_window(&self) -> usize {
|
||||
self.y.offset()
|
||||
}
|
||||
|
||||
pub fn column_window(&self) -> usize {
|
||||
self.x.offset()
|
||||
}
|
||||
|
||||
pub fn column_window_size(&self) -> usize {
|
||||
self.x.window()
|
||||
}
|
||||
|
||||
pub fn next_row(&mut self) -> bool {
|
||||
self.y.next(1)
|
||||
}
|
||||
|
||||
pub fn next_row_page(&mut self) -> bool {
|
||||
self.y.next_window()
|
||||
}
|
||||
|
||||
pub fn row_move_to_end(&mut self) -> bool {
|
||||
self.y.next(self.y.cap())
|
||||
}
|
||||
|
||||
pub fn row_move_to_start(&mut self) -> bool {
|
||||
self.y.prev(self.y.index())
|
||||
}
|
||||
|
||||
pub fn prev_row(&mut self) -> bool {
|
||||
self.y.prev(1)
|
||||
}
|
||||
|
||||
pub fn prev_row_page(&mut self) -> bool {
|
||||
self.y.prev_window()
|
||||
}
|
||||
|
||||
pub fn next_column(&mut self) -> bool {
|
||||
self.x.next(1)
|
||||
}
|
||||
|
||||
pub fn next_column_by(&mut self, i: usize) -> bool {
|
||||
self.x.next(i)
|
||||
}
|
||||
|
||||
pub fn prev_column(&mut self) -> bool {
|
||||
self.x.prev(1)
|
||||
}
|
||||
|
||||
pub fn prev_column_by(&mut self, i: usize) -> bool {
|
||||
self.x.prev(i)
|
||||
}
|
||||
|
||||
pub fn next_column_i(&mut self) -> bool {
|
||||
self.x.set_window_at(self.x.starts_at() + 1)
|
||||
}
|
||||
|
||||
pub fn prev_column_i(&mut self) -> bool {
|
||||
if self.x.starts_at() == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.x.set_window_at(self.x.starts_at() - 1)
|
||||
}
|
||||
|
||||
pub fn next_row_i(&mut self) -> bool {
|
||||
self.y.set_window_at(self.y.starts_at() + 1)
|
||||
}
|
||||
|
||||
pub fn prev_row_i(&mut self) -> bool {
|
||||
if self.y.starts_at() == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.y.set_window_at(self.y.starts_at() - 1)
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
mod binary;
|
||||
mod colored_text_widget;
|
||||
mod cursor;
|
||||
mod interactive;
|
||||
mod preview;
|
||||
mod record;
|
||||
mod r#try;
|
||||
pub mod util;
|
||||
|
||||
use super::{
|
||||
nu_common::NuText,
|
||||
pager::{Frame, Transition, ViewInfo},
|
||||
};
|
||||
use crate::{nu_common::NuConfig, pager::ConfigMap};
|
||||
use crate::{explore::ExploreConfig, nu_common::NuConfig};
|
||||
use crossterm::event::KeyEvent;
|
||||
use lscolors::LsColors;
|
||||
use nu_color_config::StyleComputer;
|
||||
|
@ -21,8 +21,8 @@ use nu_protocol::{
|
|||
use ratatui::layout::Rect;
|
||||
|
||||
pub use binary::BinaryView;
|
||||
pub use interactive::InteractiveView;
|
||||
pub use preview::Preview;
|
||||
pub use r#try::TryView;
|
||||
pub use record::{Orientation, RecordView};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
@ -55,22 +55,22 @@ impl ElementInfo {
|
|||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ViewConfig<'a> {
|
||||
pub nu_config: &'a NuConfig,
|
||||
pub explore_config: &'a ExploreConfig,
|
||||
pub style_computer: &'a StyleComputer<'a>,
|
||||
pub config: &'a ConfigMap,
|
||||
pub lscolors: &'a LsColors,
|
||||
}
|
||||
|
||||
impl<'a> ViewConfig<'a> {
|
||||
pub fn new(
|
||||
nu_config: &'a NuConfig,
|
||||
explore_config: &'a ExploreConfig,
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
config: &'a ConfigMap,
|
||||
lscolors: &'a LsColors,
|
||||
) -> Self {
|
||||
Self {
|
||||
nu_config,
|
||||
explore_config,
|
||||
style_computer,
|
||||
config,
|
||||
lscolors,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use super::{colored_text_widget::ColoredTextWidget, cursor::XYCursor, Layout, View, ViewConfig};
|
||||
use super::{
|
||||
colored_text_widget::ColoredTextWidget, cursor::WindowCursor2D, Layout, View, ViewConfig,
|
||||
};
|
||||
use crate::{
|
||||
nu_common::{NuSpan, NuText},
|
||||
pager::{report::Report, Frame, Transition, ViewInfo},
|
||||
|
@ -17,7 +19,7 @@ use std::cmp::max;
|
|||
pub struct Preview {
|
||||
underlying_value: Option<Value>,
|
||||
lines: Vec<String>,
|
||||
cursor: XYCursor,
|
||||
cursor: WindowCursor2D,
|
||||
}
|
||||
|
||||
impl Preview {
|
||||
|
@ -26,8 +28,9 @@ impl Preview {
|
|||
.lines()
|
||||
.map(|line| line.replace('\t', " ")) // tui: doesn't support TAB
|
||||
.collect();
|
||||
let cursor = XYCursor::new(lines.len(), usize::MAX);
|
||||
|
||||
// TODO: refactor so this is fallible and returns a Result instead of panicking
|
||||
let cursor = WindowCursor2D::new(lines.len(), usize::MAX).expect("Failed to create cursor");
|
||||
Self {
|
||||
lines,
|
||||
cursor,
|
||||
|
@ -38,10 +41,11 @@ impl Preview {
|
|||
|
||||
impl View for Preview {
|
||||
fn draw(&mut self, f: &mut Frame, area: Rect, _: ViewConfig<'_>, layout: &mut Layout) {
|
||||
self.cursor
|
||||
.set_window(area.height as usize, area.width as usize);
|
||||
let _ = self
|
||||
.cursor
|
||||
.set_window_size(area.height as usize, area.width as usize);
|
||||
|
||||
let lines = &self.lines[self.cursor.row_starts_at()..];
|
||||
let lines = &self.lines[self.cursor.window_origin().row..];
|
||||
for (i, line) in lines.iter().enumerate().take(area.height as usize) {
|
||||
let text_widget = ColoredTextWidget::new(line, self.cursor.column());
|
||||
let plain_text = text_widget.get_plain_text(area.width as usize);
|
||||
|
@ -65,13 +69,13 @@ impl View for Preview {
|
|||
match key.code {
|
||||
KeyCode::Left => {
|
||||
self.cursor
|
||||
.prev_column_by(max(1, self.cursor.column_window_size() / 2));
|
||||
.prev_column_by(max(1, self.cursor.window_width_in_columns() / 2));
|
||||
|
||||
Some(Transition::Ok)
|
||||
}
|
||||
KeyCode::Right => {
|
||||
self.cursor
|
||||
.next_column_by(max(1, self.cursor.column_window_size() / 2));
|
||||
.next_column_by(max(1, self.cursor.window_width_in_columns() / 2));
|
||||
|
||||
Some(Transition::Ok)
|
||||
}
|
||||
|
@ -128,7 +132,7 @@ impl View for Preview {
|
|||
//
|
||||
// todo: improve somehow?
|
||||
|
||||
self.cursor.set_position(row, 0);
|
||||
self.cursor.set_window_start_position(row, 0);
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -152,7 +156,7 @@ fn set_status_end(view: &Preview, info: &mut ViewInfo) {
|
|||
}
|
||||
|
||||
fn set_status_top(view: &Preview, info: &mut ViewInfo) {
|
||||
if view.cursor.row_starts_at() == 0 {
|
||||
if view.cursor.window_origin().row == 0 {
|
||||
info.status = Some(Report::info("TOP"));
|
||||
} else {
|
||||
info.status = Some(Report::default());
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
mod table_widget;
|
||||
|
||||
use self::table_widget::{TableStyle, TableWidget, TableWidgetState};
|
||||
use self::table_widget::{TableWidget, TableWidgetState};
|
||||
use super::{
|
||||
cursor::XYCursor,
|
||||
cursor::{Position, WindowCursor2D},
|
||||
util::{make_styled_string, nu_style_to_tui},
|
||||
Layout, View, ViewConfig,
|
||||
};
|
||||
use crate::{
|
||||
nu_common::{collect_input, lscolorize, NuConfig, NuSpan, NuStyle, NuText},
|
||||
explore::ExploreConfig,
|
||||
nu_common::{collect_input, lscolorize, NuSpan, NuText},
|
||||
pager::{
|
||||
report::{Report, Severity},
|
||||
ConfigMap, Frame, Transition, ViewInfo,
|
||||
Frame, Transition, ViewInfo,
|
||||
},
|
||||
util::create_map,
|
||||
views::ElementInfo,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||
use nu_color_config::{get_color_map, StyleComputer};
|
||||
use nu_color_config::StyleComputer;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
Record, Span, Value,
|
||||
Config, Record, Span, Value,
|
||||
};
|
||||
use ratatui::{layout::Rect, widgets::Block};
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
|
@ -32,7 +32,7 @@ pub struct RecordView<'a> {
|
|||
layer_stack: Vec<RecordLayer<'a>>,
|
||||
mode: UIMode,
|
||||
orientation: Orientation,
|
||||
theme: TableTheme,
|
||||
cfg: ExploreConfig,
|
||||
}
|
||||
|
||||
impl<'a> RecordView<'a> {
|
||||
|
@ -44,52 +44,18 @@ impl<'a> RecordView<'a> {
|
|||
layer_stack: vec![RecordLayer::new(columns, records)],
|
||||
mode: UIMode::View,
|
||||
orientation: Orientation::Top,
|
||||
theme: TableTheme::default(),
|
||||
// TODO: It's kind of gross how this temporarily has an incorrect/default config.
|
||||
// See if we can pass correct config in through the constructor
|
||||
cfg: ExploreConfig::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tail(&mut self, width: u16, height: u16) {
|
||||
let page_size =
|
||||
estimate_page_size(Rect::new(0, 0, width, height), self.theme.table.show_header);
|
||||
estimate_page_size(Rect::new(0, 0, width, height), self.cfg.table.show_header);
|
||||
tail_data(self, page_size as usize);
|
||||
}
|
||||
|
||||
pub fn set_style_split_line(&mut self, style: NuStyle) {
|
||||
self.theme.table.splitline_style = style
|
||||
}
|
||||
|
||||
pub fn set_style_selected_cell(&mut self, style: NuStyle) {
|
||||
self.theme.cursor.selected_cell = Some(style)
|
||||
}
|
||||
|
||||
pub fn set_style_selected_row(&mut self, style: NuStyle) {
|
||||
self.theme.cursor.selected_row = Some(style)
|
||||
}
|
||||
|
||||
pub fn set_style_selected_column(&mut self, style: NuStyle) {
|
||||
self.theme.cursor.selected_column = Some(style)
|
||||
}
|
||||
|
||||
pub fn set_padding_column(&mut self, (left, right): (usize, usize)) {
|
||||
self.theme.table.column_padding_left = left;
|
||||
self.theme.table.column_padding_right = right;
|
||||
}
|
||||
|
||||
pub fn get_padding_column(&self) -> (usize, usize) {
|
||||
(
|
||||
self.theme.table.column_padding_left,
|
||||
self.theme.table.column_padding_right,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_theme(&self) -> &TableTheme {
|
||||
&self.theme
|
||||
}
|
||||
|
||||
pub fn set_theme(&mut self, theme: TableTheme) {
|
||||
self.theme = theme;
|
||||
}
|
||||
|
||||
pub fn transpose(&mut self) {
|
||||
let layer = self.get_layer_last_mut();
|
||||
transpose_table(layer);
|
||||
|
@ -133,22 +99,22 @@ impl<'a> RecordView<'a> {
|
|||
layer.reset_cursor();
|
||||
}
|
||||
|
||||
pub fn get_current_position(&self) -> (usize, usize) {
|
||||
/// Get the current position of the cursor in the table as a whole
|
||||
pub fn get_cursor_position(&self) -> Position {
|
||||
let layer = self.get_layer_last();
|
||||
(layer.cursor.row(), layer.cursor.column())
|
||||
layer.cursor.position()
|
||||
}
|
||||
|
||||
pub fn get_current_window(&self) -> (usize, usize) {
|
||||
/// Get the current position of the cursor in the window being shown
|
||||
pub fn get_cursor_position_in_window(&self) -> Position {
|
||||
let layer = self.get_layer_last();
|
||||
(layer.cursor.row_window(), layer.cursor.column_window())
|
||||
layer.cursor.window_relative_position()
|
||||
}
|
||||
|
||||
pub fn get_current_offset(&self) -> (usize, usize) {
|
||||
/// Get the origin of the window being shown. (0,0), top left corner.
|
||||
pub fn get_window_origin(&self) -> Position {
|
||||
let layer = self.get_layer_last();
|
||||
(
|
||||
layer.cursor.row_starts_at(),
|
||||
layer.cursor.column_starts_at(),
|
||||
)
|
||||
layer.cursor.window_origin()
|
||||
}
|
||||
|
||||
pub fn set_cursor_mode(&mut self) {
|
||||
|
@ -160,7 +126,7 @@ impl<'a> RecordView<'a> {
|
|||
}
|
||||
|
||||
pub fn get_current_value(&self) -> Value {
|
||||
let (row, column) = self.get_current_position();
|
||||
let Position { row, column } = self.get_cursor_position();
|
||||
let layer = self.get_layer_last();
|
||||
|
||||
let (row, column) = match layer.orientation {
|
||||
|
@ -175,15 +141,17 @@ impl<'a> RecordView<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_tablew(&'a self, cfg: ViewConfig<'a>) -> TableWidget<'a> {
|
||||
/// Create a table widget.
|
||||
/// WARNING: this is currently really slow on large data sets.
|
||||
/// It creates a string representation of every cell in the table and looks at every row for lscolorize.
|
||||
fn create_table_widget(&'a self, cfg: ViewConfig<'a>) -> TableWidget<'a> {
|
||||
let layer = self.get_layer_last();
|
||||
let mut data = convert_records_to_string(&layer.records, cfg.nu_config, cfg.style_computer);
|
||||
|
||||
lscolorize(&layer.columns, &mut data, cfg.lscolors);
|
||||
|
||||
let headers = layer.columns.as_ref();
|
||||
let style_computer = cfg.style_computer;
|
||||
let (row, column) = self.get_current_offset();
|
||||
let Position { row, column } = self.get_window_origin();
|
||||
|
||||
TableWidget::new(
|
||||
headers,
|
||||
|
@ -191,7 +159,7 @@ impl<'a> RecordView<'a> {
|
|||
style_computer,
|
||||
row,
|
||||
column,
|
||||
self.theme.table,
|
||||
self.cfg.table,
|
||||
layer.orientation,
|
||||
)
|
||||
}
|
||||
|
@ -199,11 +167,17 @@ impl<'a> RecordView<'a> {
|
|||
fn update_cursors(&mut self, rows: usize, columns: usize) {
|
||||
match self.get_layer_last().orientation {
|
||||
Orientation::Top => {
|
||||
self.get_layer_last_mut().cursor.set_window(rows, columns);
|
||||
let _ = self
|
||||
.get_layer_last_mut()
|
||||
.cursor
|
||||
.set_window_size(rows, columns);
|
||||
}
|
||||
|
||||
Orientation::Left => {
|
||||
self.get_layer_last_mut().cursor.set_window(rows, columns);
|
||||
let _ = self
|
||||
.get_layer_last_mut()
|
||||
.cursor
|
||||
.set_window_size(rows, columns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +200,10 @@ impl<'a> RecordView<'a> {
|
|||
impl View for RecordView<'_> {
|
||||
fn draw(&mut self, f: &mut Frame, area: Rect, cfg: ViewConfig<'_>, layout: &mut Layout) {
|
||||
let mut table_layout = TableWidgetState::default();
|
||||
let table = self.create_tablew(cfg);
|
||||
// TODO: creating the table widget is O(N) where N is the number of cells in the grid.
|
||||
// Way too slow to do on every draw call!
|
||||
// To make explore work for larger data sets, this needs to be improved.
|
||||
let table = self.create_table_widget(cfg);
|
||||
f.render_stateful_widget(table, area, &mut table_layout);
|
||||
|
||||
*layout = table_layout.layout;
|
||||
|
@ -234,18 +211,18 @@ impl View for RecordView<'_> {
|
|||
self.update_cursors(table_layout.count_rows, table_layout.count_columns);
|
||||
|
||||
if self.mode == UIMode::Cursor {
|
||||
let (row, column) = self.get_current_window();
|
||||
let Position { row, column } = self.get_cursor_position_in_window();
|
||||
let info = get_element_info(
|
||||
layout,
|
||||
row,
|
||||
column,
|
||||
table_layout.count_rows,
|
||||
self.get_layer_last().orientation,
|
||||
self.theme.table.show_header,
|
||||
self.cfg.table.show_header,
|
||||
);
|
||||
|
||||
if let Some(info) = info {
|
||||
highlight_cell(f, area, info.clone(), &self.theme.cursor);
|
||||
highlight_selected_cell(f, info.clone(), &self.cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +266,7 @@ impl View for RecordView<'_> {
|
|||
|
||||
let data = convert_records_to_string(
|
||||
&self.get_layer_last().records,
|
||||
&NuConfig::default(),
|
||||
&nu_protocol::Config::default(),
|
||||
&style_computer,
|
||||
);
|
||||
|
||||
|
@ -308,7 +285,9 @@ impl View for RecordView<'_> {
|
|||
|
||||
for (column, _) in cells.iter().enumerate() {
|
||||
if i == pos {
|
||||
self.get_layer_last_mut().cursor.set_position(row, column);
|
||||
self.get_layer_last_mut()
|
||||
.cursor
|
||||
.set_window_start_position(row, column);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -325,22 +304,7 @@ impl View for RecordView<'_> {
|
|||
|
||||
// todo: move the method to Command?
|
||||
fn setup(&mut self, cfg: ViewConfig<'_>) {
|
||||
if let Some(hm) = cfg.config.get("table").and_then(create_map) {
|
||||
self.theme = theme_from_config(&hm);
|
||||
|
||||
if let Some(orientation) = hm.get("orientation").and_then(|v| v.coerce_str().ok()) {
|
||||
let orientation = match orientation.as_ref() {
|
||||
"left" => Some(Orientation::Left),
|
||||
"top" => Some(Orientation::Top),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(orientation) = orientation {
|
||||
self.set_orientation(orientation);
|
||||
self.set_orientation_current(orientation);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.cfg = cfg.explore_config.clone();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,7 +338,7 @@ pub struct RecordLayer<'a> {
|
|||
orientation: Orientation,
|
||||
name: Option<String>,
|
||||
was_transposed: bool,
|
||||
cursor: XYCursor,
|
||||
cursor: WindowCursor2D,
|
||||
}
|
||||
|
||||
impl<'a> RecordLayer<'a> {
|
||||
|
@ -384,7 +348,10 @@ impl<'a> RecordLayer<'a> {
|
|||
) -> Self {
|
||||
let columns = columns.into();
|
||||
let records = records.into();
|
||||
let cursor = XYCursor::new(records.len(), columns.len());
|
||||
|
||||
// TODO: refactor so this is fallible and returns a Result instead of panicking
|
||||
let cursor =
|
||||
WindowCursor2D::new(records.len(), columns.len()).expect("Failed to create cursor");
|
||||
|
||||
Self {
|
||||
columns,
|
||||
|
@ -420,7 +387,9 @@ impl<'a> RecordLayer<'a> {
|
|||
}
|
||||
|
||||
fn reset_cursor(&mut self) {
|
||||
self.cursor = XYCursor::new(self.count_rows(), self.count_columns());
|
||||
// TODO: refactor so this is fallible and returns a Result instead of panicking
|
||||
self.cursor = WindowCursor2D::new(self.count_rows(), self.count_columns())
|
||||
.expect("Failed to create cursor");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -634,13 +603,15 @@ fn tail_data(state: &mut RecordView<'_>, page_size: usize) {
|
|||
let layer = state.get_layer_last_mut();
|
||||
let count_rows = layer.records.len();
|
||||
if count_rows > page_size {
|
||||
layer.cursor.set_position(count_rows - page_size, 0);
|
||||
layer
|
||||
.cursor
|
||||
.set_window_start_position(count_rows - page_size, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_records_to_string(
|
||||
records: &[Vec<Value>],
|
||||
cfg: &NuConfig,
|
||||
cfg: &Config,
|
||||
style_computer: &StyleComputer,
|
||||
) -> Vec<Vec<NuText>> {
|
||||
records
|
||||
|
@ -658,31 +629,8 @@ fn convert_records_to_string(
|
|||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn highlight_cell(f: &mut Frame, area: Rect, info: ElementInfo, theme: &CursorStyle) {
|
||||
// highlight selected column
|
||||
if let Some(style) = theme.selected_column {
|
||||
let highlight_block = Block::default().style(nu_style_to_tui(style));
|
||||
let area = Rect::new(info.area.x, area.y, info.area.width, area.height);
|
||||
f.render_widget(highlight_block.clone(), area);
|
||||
}
|
||||
|
||||
// highlight selected row
|
||||
if let Some(style) = theme.selected_row {
|
||||
let highlight_block = Block::default().style(nu_style_to_tui(style));
|
||||
let area = Rect::new(area.x, info.area.y, area.width, 1);
|
||||
f.render_widget(highlight_block.clone(), area);
|
||||
}
|
||||
|
||||
// highlight selected cell
|
||||
let cell_style = match theme.selected_cell {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
let mut style = nu_ansi_term::Style::new();
|
||||
// light blue chosen somewhat arbitrarily, looks OK but I'm not set on it
|
||||
style.background = Some(nu_ansi_term::Color::LightBlue);
|
||||
style
|
||||
}
|
||||
};
|
||||
fn highlight_selected_cell(f: &mut Frame, info: ElementInfo, cfg: &ExploreConfig) {
|
||||
let cell_style = cfg.selected_cell;
|
||||
let highlight_block = Block::default().style(nu_style_to_tui(cell_style));
|
||||
let area = Rect::new(info.area.x, info.area.y, info.area.width, 1);
|
||||
f.render_widget(highlight_block.clone(), area)
|
||||
|
@ -731,20 +679,18 @@ fn build_table_as_record(v: &RecordView) -> Value {
|
|||
Value::record(record, NuSpan::unknown())
|
||||
}
|
||||
|
||||
fn report_cursor_position(mode: UIMode, cursor: XYCursor) -> String {
|
||||
fn report_cursor_position(mode: UIMode, cursor: WindowCursor2D) -> String {
|
||||
if mode == UIMode::Cursor {
|
||||
let row = cursor.row();
|
||||
let column = cursor.column();
|
||||
let Position { row, column } = cursor.position();
|
||||
format!("{row},{column}")
|
||||
} else {
|
||||
let rows_seen = cursor.row_starts_at();
|
||||
let columns_seen = cursor.column_starts_at();
|
||||
format!("{rows_seen},{columns_seen}")
|
||||
let Position { row, column } = cursor.window_origin();
|
||||
format!("{row},{column}")
|
||||
}
|
||||
}
|
||||
|
||||
fn report_row_position(cursor: XYCursor) -> String {
|
||||
if cursor.row_starts_at() == 0 {
|
||||
fn report_row_position(cursor: WindowCursor2D) -> String {
|
||||
if cursor.window_origin().row == 0 {
|
||||
String::from("Top")
|
||||
} else {
|
||||
let percent_rows = get_percentage(cursor.row(), cursor.row_limit());
|
||||
|
@ -824,53 +770,3 @@ fn _transpose_table(
|
|||
|
||||
data
|
||||
}
|
||||
|
||||
fn theme_from_config(config: &ConfigMap) -> TableTheme {
|
||||
let mut theme = TableTheme::default();
|
||||
|
||||
let colors = get_color_map(config);
|
||||
|
||||
if let Some(s) = colors.get("split_line") {
|
||||
theme.table.splitline_style = *s;
|
||||
}
|
||||
|
||||
theme.cursor.selected_cell = colors.get("selected_cell").cloned();
|
||||
theme.cursor.selected_row = colors.get("selected_row").cloned();
|
||||
theme.cursor.selected_column = colors.get("selected_column").cloned();
|
||||
|
||||
theme.table.show_header = config_get_bool(config, "show_head", true);
|
||||
theme.table.show_index = config_get_bool(config, "show_index", false);
|
||||
|
||||
theme.table.column_padding_left = config_get_usize(config, "column_padding_left", 1);
|
||||
theme.table.column_padding_right = config_get_usize(config, "column_padding_right", 1);
|
||||
|
||||
theme
|
||||
}
|
||||
|
||||
fn config_get_bool(config: &ConfigMap, key: &str, default: bool) -> bool {
|
||||
config
|
||||
.get(key)
|
||||
.and_then(|v| v.as_bool().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize {
|
||||
config
|
||||
.get(key)
|
||||
.and_then(|v| v.coerce_str().ok())
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.unwrap_or(default)
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct TableTheme {
|
||||
table: TableStyle,
|
||||
cursor: CursorStyle,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
struct CursorStyle {
|
||||
selected_cell: Option<NuStyle>,
|
||||
selected_column: Option<NuStyle>,
|
||||
selected_row: Option<NuStyle>,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use super::Layout;
|
||||
use crate::{
|
||||
explore::TableConfig,
|
||||
nu_common::{truncate_str, NuStyle, NuText},
|
||||
views::util::{nu_style_to_tui, text_style_to_tui_style},
|
||||
};
|
||||
|
@ -23,7 +24,7 @@ pub struct TableWidget<'a> {
|
|||
data: Cow<'a, [Vec<NuText>]>,
|
||||
index_row: usize,
|
||||
index_column: usize,
|
||||
style: TableStyle,
|
||||
config: TableConfig,
|
||||
header_position: Orientation,
|
||||
style_computer: &'a StyleComputer<'a>,
|
||||
}
|
||||
|
@ -35,15 +36,6 @@ pub enum Orientation {
|
|||
Left,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub struct TableStyle {
|
||||
pub splitline_style: NuStyle,
|
||||
pub show_index: bool,
|
||||
pub show_header: bool,
|
||||
pub column_padding_left: usize,
|
||||
pub column_padding_right: usize,
|
||||
}
|
||||
|
||||
impl<'a> TableWidget<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
|
@ -52,7 +44,7 @@ impl<'a> TableWidget<'a> {
|
|||
style_computer: &'a StyleComputer<'a>,
|
||||
index_row: usize,
|
||||
index_column: usize,
|
||||
style: TableStyle,
|
||||
config: TableConfig,
|
||||
header_position: Orientation,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -61,7 +53,7 @@ impl<'a> TableWidget<'a> {
|
|||
style_computer,
|
||||
index_row,
|
||||
index_column,
|
||||
style,
|
||||
config,
|
||||
header_position,
|
||||
}
|
||||
}
|
||||
|
@ -100,13 +92,13 @@ impl StatefulWidget for TableWidget<'_> {
|
|||
// todo: refactoring these to methods as they have quite a bit in common.
|
||||
impl<'a> TableWidget<'a> {
|
||||
fn render_table_horizontal(self, area: Rect, buf: &mut Buffer, state: &mut TableWidgetState) {
|
||||
let padding_l = self.style.column_padding_left as u16;
|
||||
let padding_r = self.style.column_padding_right as u16;
|
||||
let padding_l = self.config.column_padding_left as u16;
|
||||
let padding_r = self.config.column_padding_right as u16;
|
||||
|
||||
let show_index = self.style.show_index;
|
||||
let show_head = self.style.show_header;
|
||||
let show_index = self.config.show_index;
|
||||
let show_head = self.config.show_header;
|
||||
|
||||
let splitline_s = self.style.splitline_style;
|
||||
let separator_s = self.config.separator_style;
|
||||
|
||||
let mut data_height = area.height;
|
||||
let mut data_y = area.y;
|
||||
|
@ -137,7 +129,7 @@ impl<'a> TableWidget<'a> {
|
|||
}
|
||||
|
||||
if show_head {
|
||||
render_header_borders(buf, area, 1, splitline_s);
|
||||
render_header_borders(buf, area, 1, separator_s);
|
||||
}
|
||||
|
||||
if show_index {
|
||||
|
@ -158,7 +150,7 @@ impl<'a> TableWidget<'a> {
|
|||
data_height,
|
||||
show_head,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -250,7 +242,7 @@ impl<'a> TableWidget<'a> {
|
|||
data_height,
|
||||
show_head,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -268,12 +260,12 @@ impl<'a> TableWidget<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
let padding_l = self.style.column_padding_left as u16;
|
||||
let padding_r = self.style.column_padding_right as u16;
|
||||
let padding_l = self.config.column_padding_left as u16;
|
||||
let padding_r = self.config.column_padding_right as u16;
|
||||
|
||||
let show_index = self.style.show_index;
|
||||
let show_head = self.style.show_header;
|
||||
let splitline_s = self.style.splitline_style;
|
||||
let show_index = self.config.show_index;
|
||||
let show_head = self.config.show_header;
|
||||
let separator_s = self.config.separator_style;
|
||||
|
||||
let mut left_w = 0;
|
||||
|
||||
|
@ -295,7 +287,7 @@ impl<'a> TableWidget<'a> {
|
|||
area.height,
|
||||
false,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -327,7 +319,7 @@ impl<'a> TableWidget<'a> {
|
|||
area.height,
|
||||
false,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -352,7 +344,7 @@ impl<'a> TableWidget<'a> {
|
|||
area.height,
|
||||
false,
|
||||
false,
|
||||
splitline_s,
|
||||
separator_s,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
use super::{
|
||||
record::{RecordView, TableTheme},
|
||||
util::{lookup_tui_color, nu_style_to_tui},
|
||||
Layout, Orientation, View, ViewConfig,
|
||||
};
|
||||
use super::{record::RecordView, util::nu_style_to_tui, Layout, Orientation, View, ViewConfig};
|
||||
use crate::{
|
||||
nu_common::{collect_pipeline, run_command_with_value},
|
||||
pager::{report::Report, Frame, Transition, ViewInfo},
|
||||
util::create_map,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use nu_color_config::get_color_map;
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack},
|
||||
PipelineData, Value,
|
||||
|
@ -22,26 +16,22 @@ use ratatui::{
|
|||
};
|
||||
use std::cmp::min;
|
||||
|
||||
pub struct InteractiveView<'a> {
|
||||
pub struct TryView<'a> {
|
||||
input: Value,
|
||||
command: String,
|
||||
immediate: bool,
|
||||
reactive: bool,
|
||||
table: Option<RecordView<'a>>,
|
||||
table_theme: TableTheme,
|
||||
view_mode: bool,
|
||||
border_color: Style,
|
||||
highlighted_color: Style,
|
||||
}
|
||||
|
||||
impl<'a> InteractiveView<'a> {
|
||||
impl<'a> TryView<'a> {
|
||||
pub fn new(input: Value) -> Self {
|
||||
Self {
|
||||
input,
|
||||
table: None,
|
||||
immediate: false,
|
||||
table_theme: TableTheme::default(),
|
||||
reactive: false,
|
||||
border_color: Style::default(),
|
||||
highlighted_color: Style::default(),
|
||||
view_mode: false,
|
||||
command: String::new(),
|
||||
}
|
||||
|
@ -52,18 +42,15 @@ impl<'a> InteractiveView<'a> {
|
|||
}
|
||||
|
||||
pub fn try_run(&mut self, engine_state: &EngineState, stack: &mut Stack) -> Result<()> {
|
||||
let mut view = run_command(&self.command, &self.input, engine_state, stack)?;
|
||||
view.set_theme(self.table_theme.clone());
|
||||
|
||||
let view = run_command(&self.command, &self.input, engine_state, stack)?;
|
||||
self.table = Some(view);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl View for InteractiveView<'_> {
|
||||
impl View for TryView<'_> {
|
||||
fn draw(&mut self, f: &mut Frame, area: Rect, cfg: ViewConfig<'_>, layout: &mut Layout) {
|
||||
let border_color = self.border_color;
|
||||
let highlighted_color = self.highlighted_color;
|
||||
|
||||
let cmd_block = ratatui::widgets::Block::default()
|
||||
.borders(Borders::ALL)
|
||||
|
@ -77,7 +64,7 @@ impl View for InteractiveView<'_> {
|
|||
cmd_block
|
||||
.border_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.border_type(BorderType::Double)
|
||||
.border_style(highlighted_color)
|
||||
.border_style(border_color)
|
||||
};
|
||||
|
||||
f.render_widget(cmd_block, cmd_area);
|
||||
|
@ -127,7 +114,7 @@ impl View for InteractiveView<'_> {
|
|||
table_block
|
||||
.border_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.border_type(BorderType::Double)
|
||||
.border_style(highlighted_color)
|
||||
.border_style(border_color)
|
||||
} else {
|
||||
table_block
|
||||
};
|
||||
|
@ -135,6 +122,7 @@ impl View for InteractiveView<'_> {
|
|||
f.render_widget(table_block, table_area);
|
||||
|
||||
if let Some(table) = &mut self.table {
|
||||
table.setup(cfg);
|
||||
let area = Rect::new(
|
||||
area.x + 2,
|
||||
area.y + 4,
|
||||
|
@ -160,7 +148,7 @@ impl View for InteractiveView<'_> {
|
|||
.as_mut()
|
||||
.expect("we know that we have a table cause of a flag");
|
||||
|
||||
let was_at_the_top = table.get_current_position().0 == 0;
|
||||
let was_at_the_top = table.get_cursor_position().row == 0;
|
||||
|
||||
if was_at_the_top && matches!(key.code, KeyCode::Up | KeyCode::PageUp) {
|
||||
self.view_mode = false;
|
||||
|
@ -190,7 +178,7 @@ impl View for InteractiveView<'_> {
|
|||
if !self.command.is_empty() {
|
||||
self.command.pop();
|
||||
|
||||
if self.immediate {
|
||||
if self.reactive {
|
||||
match self.try_run(engine_state, stack) {
|
||||
Ok(_) => info.report = Some(Report::default()),
|
||||
Err(err) => info.report = Some(Report::error(format!("Error: {err}"))),
|
||||
|
@ -203,7 +191,7 @@ impl View for InteractiveView<'_> {
|
|||
KeyCode::Char(c) => {
|
||||
self.command.push(*c);
|
||||
|
||||
if self.immediate {
|
||||
if self.reactive {
|
||||
match self.try_run(engine_state, stack) {
|
||||
Ok(_) => info.report = Some(Report::default()),
|
||||
Err(err) => info.report = Some(Report::error(format!("Error: {err}"))),
|
||||
|
@ -246,31 +234,14 @@ impl View for InteractiveView<'_> {
|
|||
}
|
||||
|
||||
fn setup(&mut self, config: ViewConfig<'_>) {
|
||||
self.border_color = lookup_tui_color(config.style_computer, "separator");
|
||||
|
||||
if let Some(hm) = config.config.get("try").and_then(create_map) {
|
||||
let colors = get_color_map(&hm);
|
||||
|
||||
if let Some(color) = colors.get("highlighted_color").copied() {
|
||||
self.highlighted_color = nu_style_to_tui(color);
|
||||
}
|
||||
|
||||
if self.border_color != Style::default() && self.highlighted_color == Style::default() {
|
||||
self.highlighted_color = self.border_color;
|
||||
}
|
||||
|
||||
if let Some(val) = hm.get("reactive").and_then(|v| v.as_bool().ok()) {
|
||||
self.immediate = val;
|
||||
}
|
||||
}
|
||||
self.border_color = nu_style_to_tui(config.explore_config.table.separator_style);
|
||||
self.reactive = config.explore_config.try_reactive;
|
||||
|
||||
let mut r = RecordView::new(vec![], vec![]);
|
||||
r.setup(config);
|
||||
|
||||
self.table_theme = r.get_theme().clone();
|
||||
|
||||
if let Some(view) = &mut self.table {
|
||||
view.set_theme(self.table_theme.clone());
|
||||
view.setup(config);
|
||||
view.set_orientation(r.get_orientation_current());
|
||||
view.set_orientation_current(r.get_orientation_current());
|
||||
}
|
|
@ -31,11 +31,6 @@ pub fn set_span(
|
|||
text_width as u16
|
||||
}
|
||||
|
||||
pub fn lookup_tui_color(style_computer: &StyleComputer, key: &str) -> Style {
|
||||
let nu_style = style_computer.compute(key, &Value::nothing(nu_protocol::Span::unknown()));
|
||||
nu_style_to_tui(nu_style)
|
||||
}
|
||||
|
||||
pub fn nu_style_to_tui(style: NuStyle) -> ratatui::style::Style {
|
||||
let mut out = ratatui::style::Style::default();
|
||||
if let Some(clr) = style.background {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "nu-glob"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
authors = ["The Nushell Project Developers", "The Rust Project Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
description = """
|
||||
|
@ -14,4 +14,4 @@ categories = ["filesystem"]
|
|||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
doc-comment = "0.3"
|
||||
doc-comment = "0.3"
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-json"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-json"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -23,5 +23,5 @@ serde = { workspace = true }
|
|||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# nu-path = { path="../nu-path", version = "0.94.2" }
|
||||
# serde_json = "1.0"
|
||||
# nu-path = { path="../nu-path", version = "0.94.3" }
|
||||
# serde_json = "1.0"
|
||||
|
|
|
@ -3,14 +3,14 @@ authors = ["The Nushell Project Developers"]
|
|||
description = "Nushell's integrated LSP server"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-lsp"
|
||||
name = "nu-lsp"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "../nu-cli", version = "0.94.2" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-cli = { path = "../nu-cli", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
|
||||
reedline = { workspace = true }
|
||||
|
||||
|
@ -23,8 +23,8 @@ serde = { workspace = true }
|
|||
serde_json = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.3" }
|
||||
|
||||
assert-json-diff = "2.0"
|
||||
assert-json-diff = "2.0"
|
||||
|
|
|
@ -5,17 +5,17 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-parser"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-parser"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
exclude = ["/fuzz"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", optional = true, version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", optional = true, version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
|
||||
bytesize = { workspace = true }
|
||||
chrono = { default-features = false, features = ['std'], workspace = true }
|
||||
|
@ -27,4 +27,4 @@ serde_json = { workspace = true }
|
|||
rstest = { workspace = true, default-features = false }
|
||||
|
||||
[features]
|
||||
plugin = ["nu-plugin-engine"]
|
||||
plugin = ["nu-plugin-engine"]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{
|
||||
ast::{Argument, Expr, Expression},
|
||||
engine::CommandType,
|
||||
engine::{CommandType, UNKNOWN_SPAN_ID},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -56,43 +56,49 @@ impl Command for KnownExternal {
|
|||
};
|
||||
|
||||
let extern_name: Vec<_> = extern_name.split(' ').collect();
|
||||
let call_head_id = engine_state
|
||||
.find_span_id(call.head)
|
||||
.unwrap_or(UNKNOWN_SPAN_ID);
|
||||
|
||||
let arg_extern_name = Expression {
|
||||
expr: Expr::String(extern_name[0].to_string()),
|
||||
span: call.head,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
};
|
||||
let arg_extern_name = Expression::new_existing(
|
||||
Expr::String(extern_name[0].to_string()),
|
||||
call.head,
|
||||
call_head_id,
|
||||
Type::String,
|
||||
);
|
||||
|
||||
extern_call.add_positional(arg_extern_name);
|
||||
|
||||
for subcommand in extern_name.into_iter().skip(1) {
|
||||
extern_call.add_positional(Expression {
|
||||
expr: Expr::String(subcommand.to_string()),
|
||||
span: call.head,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
});
|
||||
extern_call.add_positional(Expression::new_existing(
|
||||
Expr::String(subcommand.to_string()),
|
||||
call.head,
|
||||
call_head_id,
|
||||
Type::String,
|
||||
));
|
||||
}
|
||||
|
||||
for arg in &call.arguments {
|
||||
match arg {
|
||||
Argument::Positional(positional) => extern_call.add_positional(positional.clone()),
|
||||
Argument::Named(named) => {
|
||||
let named_span_id = engine_state
|
||||
.find_span_id(named.0.span)
|
||||
.unwrap_or(UNKNOWN_SPAN_ID);
|
||||
if let Some(short) = &named.1 {
|
||||
extern_call.add_positional(Expression {
|
||||
expr: Expr::String(format!("-{}", short.item)),
|
||||
span: named.0.span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
});
|
||||
extern_call.add_positional(Expression::new_existing(
|
||||
Expr::String(format!("-{}", short.item)),
|
||||
named.0.span,
|
||||
named_span_id,
|
||||
Type::String,
|
||||
));
|
||||
} else {
|
||||
extern_call.add_positional(Expression {
|
||||
expr: Expr::String(format!("--{}", named.0.item)),
|
||||
span: named.0.span,
|
||||
ty: Type::String,
|
||||
custom_completion: None,
|
||||
});
|
||||
extern_call.add_positional(Expression::new_existing(
|
||||
Expr::String(format!("--{}", named.0.item)),
|
||||
named.0.span,
|
||||
named_span_id,
|
||||
Type::String,
|
||||
));
|
||||
}
|
||||
if let Some(arg) = &named.2 {
|
||||
extern_call.add_positional(arg.clone());
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -68,7 +68,7 @@ pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool {
|
|||
}
|
||||
|
||||
pub fn math_result_type(
|
||||
_working_set: &StateWorkingSet,
|
||||
working_set: &mut StateWorkingSet,
|
||||
lhs: &mut Expression,
|
||||
op: &mut Expression,
|
||||
rhs: &mut Expression,
|
||||
|
@ -104,7 +104,7 @@ pub fn math_result_type(
|
|||
| Type::Filesize,
|
||||
_,
|
||||
) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -118,7 +118,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -130,7 +130,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
},
|
||||
Operator::Math(Math::Append) => check_append(lhs, rhs, op),
|
||||
Operator::Math(Math::Append) => check_append(working_set, lhs, rhs, op),
|
||||
Operator::Math(Math::Minus) => match (&lhs.ty, &rhs.ty) {
|
||||
(Type::Int, Type::Int) => (Type::Int, None),
|
||||
(Type::Float, Type::Int) => (Type::Float, None),
|
||||
|
@ -152,7 +152,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Any, None),
|
||||
(_, Type::Any) => (Type::Any, None),
|
||||
(Type::Int | Type::Float | Type::Date | Type::Duration | Type::Filesize, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -166,7 +166,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -209,7 +209,7 @@ pub fn math_result_type(
|
|||
| (Type::Duration, _)
|
||||
| (Type::Filesize, _)
|
||||
| (Type::List(_), _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -223,7 +223,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -252,7 +252,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Any, None),
|
||||
(_, Type::Any) => (Type::Any, None),
|
||||
(Type::Int | Type::Float, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -266,7 +266,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -302,7 +302,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Any, None),
|
||||
(_, Type::Any) => (Type::Any, None),
|
||||
(Type::Int | Type::Float | Type::Filesize | Type::Duration, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -316,7 +316,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -348,7 +348,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Any, None),
|
||||
(_, Type::Any) => (Type::Any, None),
|
||||
(Type::Int | Type::Float | Type::Filesize | Type::Duration, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -362,7 +362,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -390,7 +390,7 @@ pub fn math_result_type(
|
|||
// definitions. As soon as that syntax is added this should be removed
|
||||
(a, b) if a == b => (Type::Bool, None),
|
||||
(Type::Bool, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -404,7 +404,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -441,7 +441,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Bool, None),
|
||||
(_, Type::Any) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -455,7 +455,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -491,7 +491,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Bool, None),
|
||||
(_, Type::Any) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -505,7 +505,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -541,7 +541,7 @@ pub fn math_result_type(
|
|||
(Type::Nothing, _) => (Type::Nothing, None),
|
||||
(_, Type::Nothing) => (Type::Nothing, None),
|
||||
(Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -555,7 +555,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -591,7 +591,7 @@ pub fn math_result_type(
|
|||
(Type::Nothing, _) => (Type::Nothing, None),
|
||||
(_, Type::Nothing) => (Type::Nothing, None),
|
||||
(Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -605,7 +605,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -638,7 +638,7 @@ pub fn math_result_type(
|
|||
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||
|
||||
(Type::String, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -652,7 +652,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -673,7 +673,7 @@ pub fn math_result_type(
|
|||
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||
|
||||
(Type::String, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -687,7 +687,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -708,7 +708,7 @@ pub fn math_result_type(
|
|||
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||
|
||||
(Type::String, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -722,7 +722,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -743,7 +743,7 @@ pub fn math_result_type(
|
|||
(Type::Custom(a), _) => (Type::Custom(a.clone()), None),
|
||||
|
||||
(Type::String, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -757,7 +757,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -781,7 +781,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Bool, None),
|
||||
(_, Type::Any) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::String, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -795,7 +795,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -819,7 +819,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Bool, None),
|
||||
(_, Type::Any) => (Type::Bool, None),
|
||||
(Type::Int | Type::Float | Type::String, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -833,7 +833,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -855,7 +855,7 @@ pub fn math_result_type(
|
|||
(Type::Any, _) => (Type::Any, None),
|
||||
(_, Type::Any) => (Type::Any, None),
|
||||
(Type::Int, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -869,7 +869,7 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
@ -881,7 +881,9 @@ pub fn math_result_type(
|
|||
)
|
||||
}
|
||||
},
|
||||
Operator::Assignment(Assignment::AppendAssign) => check_append(lhs, rhs, op),
|
||||
Operator::Assignment(Assignment::AppendAssign) => {
|
||||
check_append(working_set, lhs, rhs, op)
|
||||
}
|
||||
Operator::Assignment(_) => match (&lhs.ty, &rhs.ty) {
|
||||
(x, y) if x == y => (Type::Nothing, None),
|
||||
(Type::Any, _) => (Type::Nothing, None),
|
||||
|
@ -894,7 +896,7 @@ pub fn math_result_type(
|
|||
},
|
||||
},
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
|
||||
(
|
||||
Type::Any,
|
||||
|
@ -1026,6 +1028,7 @@ pub fn check_block_input_output(working_set: &StateWorkingSet, block: &Block) ->
|
|||
}
|
||||
|
||||
fn check_append(
|
||||
working_set: &mut StateWorkingSet,
|
||||
lhs: &Expression,
|
||||
rhs: &Expression,
|
||||
op: &mut Expression,
|
||||
|
@ -1050,7 +1053,7 @@ fn check_append(
|
|||
(Type::Binary, Type::Binary) => (Type::Binary, None),
|
||||
(Type::Any, _) | (_, Type::Any) => (Type::Any, None),
|
||||
(Type::Table(_) | Type::String | Type::Binary, _) => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationRHS(
|
||||
|
@ -1064,7 +1067,7 @@ fn check_append(
|
|||
)
|
||||
}
|
||||
_ => {
|
||||
*op = Expression::garbage(op.span);
|
||||
*op = Expression::garbage(working_set, op.span);
|
||||
(
|
||||
Type::Any,
|
||||
Some(ParseError::UnsupportedOperationLHS(
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-path"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-path"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
exclude = ["/fuzz"]
|
||||
|
||||
[lib]
|
||||
|
@ -18,4 +18,4 @@ dirs-next = { workspace = true }
|
|||
omnipath = { workspace = true }
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))'.dependencies]
|
||||
pwd = { workspace = true }
|
||||
pwd = { workspace = true }
|
||||
|
|
|
@ -5,14 +5,14 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-core
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-plugin-core"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2", default-features = false }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.3", default-features = false }
|
||||
|
||||
rmp-serde = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
@ -25,4 +25,4 @@ default = ["local-socket"]
|
|||
local-socket = ["interprocess", "nu-plugin-protocol/local-socket"]
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
windows = { workspace = true }
|
||||
windows = { workspace = true }
|
||||
|
|
|
@ -5,17 +5,17 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-engi
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-plugin-engine"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.2" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.2", default-features = false }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.3" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.3" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.3", default-features = false }
|
||||
|
||||
serde = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
@ -31,4 +31,4 @@ local-socket = ["nu-plugin-core/local-socket"]
|
|||
windows = { workspace = true, features = [
|
||||
# For setting process creation flags
|
||||
"Win32_System_Threading",
|
||||
] }
|
||||
] }
|
||||
|
|
|
@ -5,14 +5,14 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin-prot
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
|
||||
bincode = "1.3"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
@ -21,4 +21,4 @@ typetag = "0.2"
|
|||
|
||||
[features]
|
||||
default = ["local-socket"]
|
||||
local-socket = []
|
||||
local-socket = []
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "nu-plugin-test-support"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
description = "Testing support for Nushell plugins"
|
||||
|
@ -12,17 +12,17 @@ bench = false
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2", features = ["plugin"] }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2", features = ["plugin"] }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.2", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.2" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.2" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.2" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.2" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3", features = ["plugin"] }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.3" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.3" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.3" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
similar = "2.5"
|
||||
|
||||
[dev-dependencies]
|
||||
typetag = "0.2"
|
||||
serde = "1.0"
|
||||
serde = "1.0"
|
||||
|
|
|
@ -5,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-plugin"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-plugin"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.2" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.2" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.2" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.2", default-features = false }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.3" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.3", default-features = false }
|
||||
|
||||
log = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
|
@ -29,4 +29,4 @@ local-socket = ["nu-plugin-core/local-socket"]
|
|||
|
||||
[target.'cfg(target_family = "unix")'.dependencies]
|
||||
# For setting the process group ID (EnterForeground / LeaveForeground)
|
||||
nix = { workspace = true, default-features = false, features = ["process"] }
|
||||
nix = { workspace = true, default-features = false, features = ["process"] }
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-pretty-hex"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
@ -18,4 +18,4 @@ nu-ansi-term = { workspace = true }
|
|||
|
||||
[dev-dependencies]
|
||||
heapless = { version = "0.8", default-features = false }
|
||||
rand = "0.8"
|
||||
rand = "0.8"
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-protocol"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-protocol"
|
||||
version = "0.94.2"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -13,10 +13,10 @@ version = "0.94.2"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.2" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.2" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.2" }
|
||||
nu-derive-value = { path = "../nu-derive-value", version = "0.94.2" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.3" }
|
||||
nu-derive-value = { path = "../nu-derive-value", version = "0.94.3" }
|
||||
|
||||
brotli = { workspace = true, optional = true }
|
||||
byte-unit = { version = "5.1", features = [ "serde" ] }
|
||||
|
@ -46,11 +46,11 @@ plugin = [
|
|||
serde_json = { workspace = true }
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.2" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.3" }
|
||||
pretty_assertions = { workspace = true }
|
||||
rstest = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
os_pipe = { workspace = true }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
all-features = true
|
||||
|
|
|
@ -338,9 +338,13 @@ impl Call {
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::engine::EngineState;
|
||||
|
||||
#[test]
|
||||
fn argument_span_named() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
|
||||
let named = Spanned {
|
||||
item: "named".to_string(),
|
||||
span: Span::new(2, 3),
|
||||
|
@ -349,7 +353,7 @@ mod test {
|
|||
item: "short".to_string(),
|
||||
span: Span::new(5, 7),
|
||||
};
|
||||
let expr = Expression::garbage(Span::new(11, 13));
|
||||
let expr = Expression::garbage(&mut working_set, Span::new(11, 13));
|
||||
|
||||
let arg = Argument::Named((named.clone(), None, None));
|
||||
|
||||
|
@ -370,8 +374,11 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn argument_span_positional() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
|
||||
let span = Span::new(2, 3);
|
||||
let expr = Expression::garbage(span);
|
||||
let expr = Expression::garbage(&mut working_set, span);
|
||||
let arg = Argument::Positional(expr);
|
||||
|
||||
assert_eq!(span, arg.span());
|
||||
|
@ -379,8 +386,11 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn argument_span_unknown() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
|
||||
let span = Span::new(2, 3);
|
||||
let expr = Expression::garbage(span);
|
||||
let expr = Expression::garbage(&mut working_set, span);
|
||||
let arg = Argument::Unknown(expr);
|
||||
|
||||
assert_eq!(span, arg.span());
|
||||
|
@ -388,9 +398,12 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn call_arguments_span() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
|
||||
let mut call = Call::new(Span::new(0, 1));
|
||||
call.add_positional(Expression::garbage(Span::new(2, 3)));
|
||||
call.add_positional(Expression::garbage(Span::new(5, 7)));
|
||||
call.add_positional(Expression::garbage(&mut working_set, Span::new(2, 3)));
|
||||
call.add_positional(Expression::garbage(&mut working_set, Span::new(5, 7)));
|
||||
|
||||
assert_eq!(Span::new(2, 7), call.arguments_span());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
ast::{Argument, Block, Expr, ExternalArgument, ImportPattern, MatchPattern, RecordItem},
|
||||
engine::StateWorkingSet,
|
||||
BlockId, DeclId, Signature, Span, Type, VarId, IN_VARIABLE_ID,
|
||||
engine::{EngineState, StateWorkingSet},
|
||||
BlockId, DeclId, Signature, Span, SpanId, Type, VarId, IN_VARIABLE_ID,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
@ -10,15 +10,18 @@ use std::sync::Arc;
|
|||
pub struct Expression {
|
||||
pub expr: Expr,
|
||||
pub span: Span,
|
||||
pub span_id: SpanId,
|
||||
pub ty: Type,
|
||||
pub custom_completion: Option<DeclId>,
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn garbage(span: Span) -> Expression {
|
||||
pub fn garbage(working_set: &mut StateWorkingSet, span: Span) -> Expression {
|
||||
let span_id = working_set.add_span(span);
|
||||
Expression {
|
||||
expr: Expr::Garbage,
|
||||
span,
|
||||
span_id,
|
||||
ty: Type::Any,
|
||||
custom_completion: None,
|
||||
}
|
||||
|
@ -471,4 +474,49 @@ impl Expression {
|
|||
Expr::VarDecl(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(working_set: &mut StateWorkingSet, expr: Expr, span: Span, ty: Type) -> Expression {
|
||||
let span_id = working_set.add_span(span);
|
||||
Expression {
|
||||
expr,
|
||||
span,
|
||||
span_id,
|
||||
ty,
|
||||
custom_completion: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_existing(expr: Expr, span: Span, span_id: SpanId, ty: Type) -> Expression {
|
||||
Expression {
|
||||
expr,
|
||||
span,
|
||||
span_id,
|
||||
ty,
|
||||
custom_completion: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_unknown(expr: Expr, span: Span, ty: Type) -> Expression {
|
||||
Expression {
|
||||
expr,
|
||||
span,
|
||||
span_id: SpanId(0),
|
||||
ty,
|
||||
custom_completion: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_span_id(self, span_id: SpanId) -> Expression {
|
||||
Expression {
|
||||
expr: self.expr,
|
||||
span: self.span,
|
||||
span_id,
|
||||
ty: self.ty,
|
||||
custom_completion: self.custom_completion,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self, engine_state: &EngineState) -> Span {
|
||||
engine_state.get_span(self.span_id)
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user