Merge branch 'main' into callgrind-benches
This commit is contained in:
commit
108a9a6878
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
|
||||
|
|
73
Cargo.lock
generated
73
Cargo.lock
generated
|
@ -2808,7 +2808,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"assert_cmd",
|
||||
"crossterm",
|
||||
|
@ -2862,7 +2862,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cli"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"crossterm",
|
||||
|
@ -2897,7 +2897,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-base"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"miette",
|
||||
|
@ -2909,7 +2909,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-extra"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"heck 0.5.0",
|
||||
|
@ -2934,7 +2934,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nu-engine",
|
||||
|
@ -2946,7 +2946,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-cmd-plugin"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"itertools 0.12.1",
|
||||
"nu-engine",
|
||||
|
@ -2957,7 +2957,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-color-config"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-engine",
|
||||
|
@ -2969,7 +2969,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-command"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"alphanumeric-sort",
|
||||
"base64 0.22.1",
|
||||
|
@ -3078,7 +3078,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-engine"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
|
@ -3088,7 +3088,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-explore"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"ansi-str",
|
||||
"anyhow",
|
||||
|
@ -3113,14 +3113,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-glob"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"doc-comment",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-json"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
"num-traits",
|
||||
|
@ -3130,7 +3130,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-lsp"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"crossbeam-channel",
|
||||
|
@ -3151,7 +3151,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-parser"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"bytesize",
|
||||
"chrono",
|
||||
|
@ -3167,7 +3167,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-path"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"dirs-next",
|
||||
"omnipath",
|
||||
|
@ -3176,7 +3176,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix",
|
||||
|
@ -3191,7 +3191,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-core"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"log",
|
||||
|
@ -3205,7 +3205,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-engine"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nu-engine",
|
||||
|
@ -3220,7 +3220,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-protocol"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"nu-protocol",
|
||||
|
@ -3232,7 +3232,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-plugin-test-support"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"nu-cmd-lang",
|
||||
|
@ -3250,7 +3250,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-pretty-hex"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"nu-ansi-term",
|
||||
|
@ -3259,7 +3259,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-protocol"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"brotli 5.0.0",
|
||||
"byte-unit",
|
||||
|
@ -3290,7 +3290,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-std"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"miette",
|
||||
|
@ -3301,7 +3301,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-system"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"itertools 0.12.1",
|
||||
|
@ -3319,7 +3319,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-table"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"fancy-regex",
|
||||
"nu-ansi-term",
|
||||
|
@ -3333,7 +3333,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-term-grid"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-utils",
|
||||
"unicode-width",
|
||||
|
@ -3341,7 +3341,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-test-support"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-glob",
|
||||
"nu-path",
|
||||
|
@ -3353,7 +3353,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu-utils"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"crossterm_winapi",
|
||||
"log",
|
||||
|
@ -3379,7 +3379,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_example"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-cmd-lang",
|
||||
"nu-plugin",
|
||||
|
@ -3389,7 +3389,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_formats"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"eml-parser",
|
||||
"ical",
|
||||
|
@ -3402,7 +3402,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_gstat"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"nu-plugin",
|
||||
|
@ -3411,7 +3411,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_inc"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"nu-plugin",
|
||||
"nu-protocol",
|
||||
|
@ -3420,7 +3420,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_polars"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz 0.9.0",
|
||||
|
@ -3451,7 +3451,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_query"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"gjson",
|
||||
"nu-plugin",
|
||||
|
@ -3463,7 +3463,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "nu_plugin_stress_internals"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"interprocess",
|
||||
"serde",
|
||||
|
@ -3589,7 +3589,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|||
|
||||
[[package]]
|
||||
name = "nuon"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fancy-regex",
|
||||
|
@ -6118,6 +6118,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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -174,22 +174,22 @@ windows = "0.54"
|
|||
winreg = "0.52"
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "./crates/nu-cli", version = "0.94.1" }
|
||||
nu-cmd-base = { path = "./crates/nu-cmd-base", version = "0.94.1" }
|
||||
nu-cmd-lang = { path = "./crates/nu-cmd-lang", version = "0.94.1" }
|
||||
nu-cmd-plugin = { path = "./crates/nu-cmd-plugin", version = "0.94.1", optional = true }
|
||||
nu-cmd-extra = { path = "./crates/nu-cmd-extra", version = "0.94.1" }
|
||||
nu-command = { path = "./crates/nu-command", version = "0.94.1" }
|
||||
nu-engine = { path = "./crates/nu-engine", version = "0.94.1" }
|
||||
nu-explore = { path = "./crates/nu-explore", version = "0.94.1" }
|
||||
nu-lsp = { path = "./crates/nu-lsp/", version = "0.94.1" }
|
||||
nu-parser = { path = "./crates/nu-parser", version = "0.94.1" }
|
||||
nu-path = { path = "./crates/nu-path", version = "0.94.1" }
|
||||
nu-plugin-engine = { path = "./crates/nu-plugin-engine", optional = true, version = "0.94.1" }
|
||||
nu-protocol = { path = "./crates/nu-protocol", version = "0.94.1" }
|
||||
nu-std = { path = "./crates/nu-std", version = "0.94.1" }
|
||||
nu-system = { path = "./crates/nu-system", version = "0.94.1" }
|
||||
nu-utils = { path = "./crates/nu-utils", version = "0.94.1" }
|
||||
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"] }
|
||||
|
||||
|
@ -218,9 +218,9 @@ nix = { workspace = true, default-features = false, features = [
|
|||
] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "./crates/nu-test-support", version = "0.94.1" }
|
||||
nu-plugin-protocol = { path = "./crates/nu-plugin-protocol", version = "0.94.1" }
|
||||
nu-plugin-core = { path = "./crates/nu-plugin-core", version = "0.94.1" }
|
||||
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 @@ harness = false
|
|||
# cargo bench --bench iai_benchmarks -- --save-summary=pretty-json
|
||||
[[bench]]
|
||||
name = "iai_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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.1" }
|
||||
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.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.1", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.1" }
|
||||
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(),
|
||||
},
|
||||
|
|
|
@ -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.1"
|
||||
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.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
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.1"
|
||||
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.1"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-json = { version = "0.94.1", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-pretty-hex = { version = "0.94.1", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.1" }
|
||||
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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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 = []
|
||||
|
|
|
@ -298,9 +298,7 @@ fn bind_args_to(
|
|||
if let Some(rest_positional) = &signature.rest_positional {
|
||||
let mut rest_items = vec![];
|
||||
|
||||
for result in
|
||||
val_iter.skip(signature.required_positional.len() + signature.optional_positional.len())
|
||||
{
|
||||
for result in val_iter {
|
||||
rest_items.push(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.1"
|
||||
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.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.1" }
|
||||
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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.1" }
|
||||
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.1" }
|
||||
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.1"
|
||||
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.1"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.94.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.1" }
|
||||
nu-table = { path = "../nu-table", version = "0.94.1" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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.1" }
|
||||
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.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.1" }
|
||||
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::*;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -104,10 +104,9 @@ If nothing is found, an empty string will be returned."#
|
|||
|
||||
fn path_type(path: &Path, span: Span, args: &Arguments) -> Value {
|
||||
let path = nu_path::expand_path_with(path, &args.pwd, true);
|
||||
match std::fs::symlink_metadata(path) {
|
||||
Ok(metadata) => Value::string(get_file_type(&metadata), span),
|
||||
Err(err) => Value::error(err.into(), span),
|
||||
}
|
||||
let meta = path.symlink_metadata();
|
||||
let ty = meta.as_ref().map(get_file_type).unwrap_or("");
|
||||
Value::string(ty, span)
|
||||
}
|
||||
|
||||
fn get_file_type(md: &std::fs::Metadata) -> &str {
|
||||
|
|
|
@ -4,7 +4,7 @@ use nu_protocol::{
|
|||
ast::{Expr, Expression},
|
||||
did_you_mean,
|
||||
process::ChildProcess,
|
||||
ByteStream, OutDest,
|
||||
ByteStream, NuGlob, OutDest,
|
||||
};
|
||||
use nu_system::ForegroundChild;
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
|
@ -13,7 +13,7 @@ use std::{
|
|||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::Stdio,
|
||||
sync::Arc,
|
||||
sync::{atomic::AtomicBool, Arc},
|
||||
thread,
|
||||
};
|
||||
|
||||
|
@ -155,6 +155,9 @@ impl Command for External {
|
|||
}
|
||||
};
|
||||
|
||||
// Log the command we're about to run in case it's useful for debugging purposes.
|
||||
log::trace!("run-external spawning: {command:?}");
|
||||
|
||||
// Spawn the child process. On Unix, also put the child process to
|
||||
// foreground if we're in an interactive session.
|
||||
#[cfg(windows)]
|
||||
|
@ -232,6 +235,7 @@ pub fn eval_arguments_from_call(
|
|||
stack: &mut Stack,
|
||||
call: &Call,
|
||||
) -> Result<Vec<Spanned<String>>, ShellError> {
|
||||
let ctrlc = &engine_state.ctrlc;
|
||||
let cwd = engine_state.cwd(Some(stack))?;
|
||||
let mut args: Vec<Spanned<String>> = vec![];
|
||||
for (expr, spread) in call.rest_iter(1) {
|
||||
|
@ -240,7 +244,7 @@ pub fn eval_arguments_from_call(
|
|||
// glob-expansion, and inner-quotes-removal, in that order.
|
||||
for arg in eval_argument(engine_state, stack, expr, spread)? {
|
||||
let tilde_expanded = expand_tilde(&arg);
|
||||
for glob_expanded in expand_glob(&tilde_expanded, &cwd, expr.span)? {
|
||||
for glob_expanded in expand_glob(&tilde_expanded, &cwd, expr.span, ctrlc)? {
|
||||
let inner_quotes_removed = remove_inner_quotes(&glob_expanded);
|
||||
args.push(inner_quotes_removed.into_owned().into_spanned(expr.span));
|
||||
}
|
||||
|
@ -321,37 +325,75 @@ fn expand_tilde(arg: &str) -> String {
|
|||
///
|
||||
/// Note: This matches the default behavior of Bash, but is known to be
|
||||
/// error-prone. We might want to change this behavior in the future.
|
||||
fn expand_glob(arg: &str, cwd: &Path, span: Span) -> Result<Vec<String>, ShellError> {
|
||||
let Ok(paths) = nu_glob::glob_with_parent(arg, nu_glob::MatchOptions::default(), cwd) else {
|
||||
fn expand_glob(
|
||||
arg: &str,
|
||||
cwd: &Path,
|
||||
span: Span,
|
||||
interrupt: &Option<Arc<AtomicBool>>,
|
||||
) -> Result<Vec<String>, ShellError> {
|
||||
const GLOB_CHARS: &[char] = &['*', '?', '['];
|
||||
|
||||
// Don't expand something that doesn't include the GLOB_CHARS
|
||||
if !arg.contains(GLOB_CHARS) {
|
||||
return Ok(vec![arg.into()]);
|
||||
}
|
||||
|
||||
// We must use `nu_engine::glob_from` here, in order to ensure we get paths from the correct
|
||||
// dir
|
||||
let glob = NuGlob::Expand(arg.to_owned()).into_spanned(span);
|
||||
let Ok((_prefix, paths)) = nu_engine::glob_from(&glob, cwd, span, None) else {
|
||||
// If an error occurred, return the original input
|
||||
return Ok(vec![arg.into()]);
|
||||
};
|
||||
|
||||
let mut result = vec![];
|
||||
for path in paths {
|
||||
let path = path.map_err(|err| ShellError::IOErrorSpanned {
|
||||
msg: format!("{}: {:?}", err.path().display(), err.error()),
|
||||
span,
|
||||
})?;
|
||||
// Strip PWD from the resulting paths if possible.
|
||||
let path_stripped = if let Ok(remainder) = path.strip_prefix(cwd) {
|
||||
// If stripping PWD results in an empty path, return `.` instead.
|
||||
if remainder.components().next().is_none() {
|
||||
Path::new(".")
|
||||
} else {
|
||||
remainder
|
||||
// If the first component of the original `arg` string path was '.', that should be preserved
|
||||
let relative_to_dot = Path::new(arg).starts_with(".");
|
||||
|
||||
let paths = paths
|
||||
// Skip over glob failures. These are usually just inaccessible paths.
|
||||
.flat_map(|path_result| match path_result {
|
||||
Ok(path) => Some(path),
|
||||
Err(err) => {
|
||||
// But internally log them just in case we need to debug this.
|
||||
log::warn!("Error in run_external::expand_glob(): {}", err);
|
||||
None
|
||||
}
|
||||
} else {
|
||||
&path
|
||||
};
|
||||
let path_string = path_stripped.to_string_lossy().to_string();
|
||||
result.push(path_string);
|
||||
}
|
||||
})
|
||||
// Make the paths relative to the cwd
|
||||
.map(|path| {
|
||||
path.strip_prefix(cwd)
|
||||
.map(|path| path.to_owned())
|
||||
.unwrap_or(path)
|
||||
})
|
||||
// Add './' to relative paths if the original pattern had it
|
||||
.map(|path| {
|
||||
if relative_to_dot && path.is_relative() {
|
||||
Path::new(".").join(path)
|
||||
} else {
|
||||
path
|
||||
}
|
||||
})
|
||||
// Convert the paths returned to UTF-8 strings.
|
||||
//
|
||||
// FIXME: this fails to return the correct results for non-UTF-8 paths, but we don't support
|
||||
// those in Nushell yet.
|
||||
.map(|path| path.to_string_lossy().into_owned())
|
||||
// Abandon if ctrl-c is pressed
|
||||
.map(|path| {
|
||||
if !nu_utils::ctrl_c::was_pressed(interrupt) {
|
||||
Ok(path)
|
||||
} else {
|
||||
Err(ShellError::InterruptedByUser { span: Some(span) })
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<String>, ShellError>>()?;
|
||||
|
||||
if result.is_empty() {
|
||||
result.push(arg.to_string());
|
||||
if !paths.is_empty() {
|
||||
Ok(paths)
|
||||
} else {
|
||||
// If we failed to match, return the original input
|
||||
Ok(vec![arg.into()])
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Transforms `--option="value"` into `--option=value`. `value` can be quoted
|
||||
|
@ -565,12 +607,20 @@ fn has_cmd_special_character(s: &str) -> bool {
|
|||
SPECIAL_CHARS.iter().any(|c| s.contains(*c))
|
||||
}
|
||||
|
||||
/// Escape an argument for CMD internal commands. The result can be safely
|
||||
/// passed to `raw_arg()`.
|
||||
/// Escape an argument for CMD internal commands. The result can be safely passed to `raw_arg()`.
|
||||
#[cfg(windows)]
|
||||
fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError> {
|
||||
let Spanned { item: arg, span } = arg;
|
||||
if arg.contains('"') {
|
||||
if arg.contains(['\r', '\n', '%']) {
|
||||
// \r and \n trunacte the rest of the arguments and % can expand environment variables
|
||||
Err(ShellError::ExternalCommand {
|
||||
label:
|
||||
"Arguments to CMD internal commands cannot contain new lines or percent signs '%'"
|
||||
.into(),
|
||||
help: "some characters currently cannot be securely escaped".into(),
|
||||
span: *span,
|
||||
})
|
||||
} else if arg.contains('"') {
|
||||
// If `arg` is already quoted by double quotes, confirm there's no
|
||||
// embedded double quotes, then leave it as is.
|
||||
if arg.chars().filter(|c| *c == '"').count() == 2
|
||||
|
@ -582,7 +632,7 @@ fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError
|
|||
Err(ShellError::ExternalCommand {
|
||||
label: "Arguments to CMD internal commands cannot contain embedded double quotes"
|
||||
.into(),
|
||||
help: "CMD doesn't support escaping double quotes inside double quotes".into(),
|
||||
help: "this case currently cannot be securely handled".into(),
|
||||
span: *span,
|
||||
})
|
||||
}
|
||||
|
@ -590,6 +640,7 @@ fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError
|
|||
// If `arg` contains space or special characters, quote the entire argument by double quotes.
|
||||
Ok(Cow::Owned(format!("\"{arg}\"")))
|
||||
} else {
|
||||
// FIXME?: what if `arg.is_empty()`?
|
||||
Ok(Cow::Borrowed(arg))
|
||||
}
|
||||
}
|
||||
|
@ -598,6 +649,7 @@ fn escape_cmd_argument(arg: &Spanned<String>) -> Result<Cow<'_, str>, ShellError
|
|||
mod test {
|
||||
use super::*;
|
||||
use nu_protocol::ast::ListItem;
|
||||
use nu_test_support::{fs::Stub, playground::Playground};
|
||||
|
||||
#[test]
|
||||
fn test_remove_quotes() {
|
||||
|
@ -613,12 +665,7 @@ mod test {
|
|||
#[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> {
|
||||
|
@ -660,26 +707,38 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_expand_glob() {
|
||||
let tempdir = tempfile::tempdir().unwrap();
|
||||
let cwd = tempdir.path();
|
||||
std::fs::File::create(cwd.join("a.txt")).unwrap();
|
||||
std::fs::File::create(cwd.join("b.txt")).unwrap();
|
||||
Playground::setup("test_expand_glob", |dirs, play| {
|
||||
play.with_files(&[Stub::EmptyFile("a.txt"), Stub::EmptyFile("b.txt")]);
|
||||
|
||||
let actual = expand_glob("*.txt", cwd, Span::unknown()).unwrap();
|
||||
let expected = &["a.txt", "b.txt"];
|
||||
assert_eq!(actual, expected);
|
||||
let cwd = dirs.test();
|
||||
|
||||
let actual = expand_glob("'*.txt'", cwd, Span::unknown()).unwrap();
|
||||
let expected = &["'*.txt'"];
|
||||
assert_eq!(actual, expected);
|
||||
let actual = expand_glob("*.txt", cwd, Span::unknown(), &None).unwrap();
|
||||
let expected = &["a.txt", "b.txt"];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = expand_glob(cwd.to_str().unwrap(), cwd, Span::unknown()).unwrap();
|
||||
let expected = &["."];
|
||||
assert_eq!(actual, expected);
|
||||
let actual = expand_glob("./*.txt", cwd, Span::unknown(), &None).unwrap();
|
||||
let expected = vec![
|
||||
Path::new(".").join("a.txt").to_string_lossy().into_owned(),
|
||||
Path::new(".").join("b.txt").to_string_lossy().into_owned(),
|
||||
];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = expand_glob("[*.txt", cwd, Span::unknown()).unwrap();
|
||||
let expected = &["[*.txt"];
|
||||
assert_eq!(actual, expected);
|
||||
let actual = expand_glob("'*.txt'", cwd, Span::unknown(), &None).unwrap();
|
||||
let expected = &["'*.txt'"];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = expand_glob(".", cwd, Span::unknown(), &None).unwrap();
|
||||
let expected = &["."];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = expand_glob("./a.txt", cwd, Span::unknown(), &None).unwrap();
|
||||
let expected = &["./a.txt"];
|
||||
assert_eq!(actual, expected);
|
||||
|
||||
let actual = expand_glob("[*.txt", cwd, Span::unknown(), &None).unwrap();
|
||||
let expected = &["[*.txt"];
|
||||
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,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-engine"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-engine"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", features = ["plugin"], version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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 = []
|
||||
|
|
|
@ -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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-table = { path = "../nu-table", version = "0.94.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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.1" }
|
||||
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 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,16 +17,20 @@ use crate::{
|
|||
ConfigMap, 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 +44,7 @@ impl BinaryView {
|
|||
pub fn new(data: Vec<u8>) -> Self {
|
||||
Self {
|
||||
data,
|
||||
cursor: XYCursor::default(),
|
||||
cursor: WindowCursor2D::default(),
|
||||
settings: Settings::default(),
|
||||
}
|
||||
}
|
||||
|
@ -95,12 +99,13 @@ impl View for BinaryView {
|
|||
|
||||
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;
|
||||
|
@ -203,7 +208,7 @@ fn config_get_usize(config: &ConfigMap, key: &str, default: usize) -> usize {
|
|||
.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 +221,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 +238,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,125 @@
|
|||
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;
|
||||
/// Constructor to create a new Cursor
|
||||
pub fn new(size: usize) -> Result<Self> {
|
||||
if size == 0 {
|
||||
bail!("Size cannot be zero");
|
||||
}
|
||||
|
||||
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
|
||||
Ok(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).unwrap();
|
||||
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).unwrap();
|
||||
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).unwrap();
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -160,7 +160,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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -2,7 +2,7 @@ mod table_widget;
|
|||
|
||||
use self::table_widget::{TableStyle, TableWidget, TableWidgetState};
|
||||
use super::{
|
||||
cursor::XYCursor,
|
||||
cursor::{Position, WindowCursor2D},
|
||||
util::{make_styled_string, nu_style_to_tui},
|
||||
Layout, View, ViewConfig,
|
||||
};
|
||||
|
@ -133,22 +133,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 +160,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 +175,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,
|
||||
|
@ -199,11 +201,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 +234,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,7 +245,7 @@ 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,
|
||||
|
@ -308,7 +319,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;
|
||||
}
|
||||
|
||||
|
@ -374,7 +387,7 @@ pub struct RecordLayer<'a> {
|
|||
orientation: Orientation,
|
||||
name: Option<String>,
|
||||
was_transposed: bool,
|
||||
cursor: XYCursor,
|
||||
cursor: WindowCursor2D,
|
||||
}
|
||||
|
||||
impl<'a> RecordLayer<'a> {
|
||||
|
@ -384,7 +397,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 +436,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,7 +652,9 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -731,20 +751,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());
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "nu-glob"
|
||||
version = "0.94.1"
|
||||
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.1"
|
||||
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.1" }
|
||||
# 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.1"
|
||||
version = "0.94.3"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
[dependencies]
|
||||
nu-cli = { path = "../nu-cli", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
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.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.1" }
|
||||
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.1"
|
||||
version = "0.94.3"
|
||||
exclude = ["/fuzz"]
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", optional = true, version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
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(
|
||||
|
|
|
@ -694,6 +694,221 @@ pub fn parse_call_missing_req_flag() {
|
|||
));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case("foo-external-call", "foo-external-call", "bare word")]
|
||||
#[case("^foo-external-call", "foo-external-call", "bare word with caret")]
|
||||
#[case(
|
||||
"foo/external-call",
|
||||
"foo/external-call",
|
||||
"bare word with forward slash"
|
||||
)]
|
||||
#[case(
|
||||
"^foo/external-call",
|
||||
"foo/external-call",
|
||||
"bare word with forward slash and caret"
|
||||
)]
|
||||
#[case(r"foo\external-call", r"foo\external-call", "bare word with backslash")]
|
||||
#[case(
|
||||
r"^foo\external-call",
|
||||
r"foo\external-call",
|
||||
"bare word with backslash and caret"
|
||||
)]
|
||||
#[case(
|
||||
"^'foo external call'",
|
||||
"'foo external call'",
|
||||
"single quote with caret"
|
||||
)]
|
||||
#[case(
|
||||
"^'foo/external call'",
|
||||
"'foo/external call'",
|
||||
"single quote with forward slash and caret"
|
||||
)]
|
||||
#[case(
|
||||
r"^'foo\external call'",
|
||||
r"'foo\external call'",
|
||||
"single quote with backslash and caret"
|
||||
)]
|
||||
#[case(
|
||||
r#"^"foo external call""#,
|
||||
r#""foo external call""#,
|
||||
"double quote with caret"
|
||||
)]
|
||||
#[case(
|
||||
r#"^"foo/external call""#,
|
||||
r#""foo/external call""#,
|
||||
"double quote with forward slash and caret"
|
||||
)]
|
||||
#[case(
|
||||
r#"^"foo\\external call""#,
|
||||
r#""foo\external call""#,
|
||||
"double quote with backslash and caret"
|
||||
)]
|
||||
#[case("`foo external call`", "`foo external call`", "backtick quote")]
|
||||
#[case(
|
||||
"^`foo external call`",
|
||||
"`foo external call`",
|
||||
"backtick quote with caret"
|
||||
)]
|
||||
#[case(
|
||||
"`foo/external call`",
|
||||
"`foo/external call`",
|
||||
"backtick quote with forward slash"
|
||||
)]
|
||||
#[case(
|
||||
"^`foo/external call`",
|
||||
"`foo/external call`",
|
||||
"backtick quote with forward slash and caret"
|
||||
)]
|
||||
#[case(
|
||||
r"^`foo\external call`",
|
||||
r"`foo\external call`",
|
||||
"backtick quote with backslash"
|
||||
)]
|
||||
#[case(
|
||||
r"^`foo\external call`",
|
||||
r"`foo\external call`",
|
||||
"backtick quote with backslash and caret"
|
||||
)]
|
||||
fn test_external_call_name(#[case] input: &str, #[case] expected: &str, #[case] tag: &str) {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let block = parse(&mut working_set, None, input.as_bytes(), true);
|
||||
assert!(
|
||||
working_set.parse_errors.is_empty(),
|
||||
"{tag}: errors: {:?}",
|
||||
working_set.parse_errors
|
||||
);
|
||||
|
||||
let pipeline = &block.pipelines[0];
|
||||
assert_eq!(1, pipeline.len());
|
||||
let element = &pipeline.elements[0];
|
||||
match &element.expr.expr {
|
||||
Expr::ExternalCall(name, args) => {
|
||||
match &name.expr {
|
||||
Expr::String(string) => {
|
||||
assert_eq!(expected, string);
|
||||
}
|
||||
other => {
|
||||
panic!("{tag}: Unexpected expression in command name position: {other:?}");
|
||||
}
|
||||
}
|
||||
assert_eq!(0, args.len());
|
||||
}
|
||||
other => {
|
||||
panic!("{tag}: Unexpected expression in pipeline: {other:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case("^foo bar-baz", "bar-baz", "bare word")]
|
||||
#[case("^foo bar/baz", "bar/baz", "bare word with forward slash")]
|
||||
#[case(r"^foo bar\baz", r"bar\baz", "bare word with backslash")]
|
||||
#[case("^foo 'bar baz'", "'bar baz'", "single quote")]
|
||||
#[case("foo 'bar/baz'", "'bar/baz'", "single quote with forward slash")]
|
||||
#[case(r"foo 'bar\baz'", r"'bar\baz'", "single quote with backslash")]
|
||||
#[case(r#"^foo "bar baz""#, r#""bar baz""#, "double quote")]
|
||||
#[case(r#"^foo "bar/baz""#, r#""bar/baz""#, "double quote with forward slash")]
|
||||
#[case(r#"^foo "bar\\baz""#, r#""bar\baz""#, "double quote with backslash")]
|
||||
#[case("^foo `bar baz`", "`bar baz`", "backtick quote")]
|
||||
#[case("^foo `bar/baz`", "`bar/baz`", "backtick quote with forward slash")]
|
||||
#[case(r"^foo `bar\baz`", r"`bar\baz`", "backtick quote with backslash")]
|
||||
fn test_external_call_argument_regular(
|
||||
#[case] input: &str,
|
||||
#[case] expected: &str,
|
||||
#[case] tag: &str,
|
||||
) {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let block = parse(&mut working_set, None, input.as_bytes(), true);
|
||||
assert!(
|
||||
working_set.parse_errors.is_empty(),
|
||||
"{tag}: errors: {:?}",
|
||||
working_set.parse_errors
|
||||
);
|
||||
|
||||
let pipeline = &block.pipelines[0];
|
||||
assert_eq!(1, pipeline.len());
|
||||
let element = &pipeline.elements[0];
|
||||
match &element.expr.expr {
|
||||
Expr::ExternalCall(name, args) => {
|
||||
match &name.expr {
|
||||
Expr::String(string) => {
|
||||
assert_eq!("foo", string, "{tag}: incorrect name");
|
||||
}
|
||||
other => {
|
||||
panic!("{tag}: Unexpected expression in command name position: {other:?}");
|
||||
}
|
||||
}
|
||||
assert_eq!(1, args.len());
|
||||
match &args[0] {
|
||||
ExternalArgument::Regular(expr) => match &expr.expr {
|
||||
Expr::String(string) => {
|
||||
assert_eq!(expected, string, "{tag}: incorrect arg");
|
||||
}
|
||||
other => {
|
||||
panic!("Unexpected expression in command arg position: {other:?}")
|
||||
}
|
||||
},
|
||||
other @ ExternalArgument::Spread(..) => {
|
||||
panic!("Unexpected external spread argument in command arg position: {other:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
other => {
|
||||
panic!("{tag}: Unexpected expression in pipeline: {other:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_external_call_argument_spread() {
|
||||
let engine_state = EngineState::new();
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let block = parse(&mut working_set, None, b"^foo ...[a b c]", true);
|
||||
assert!(
|
||||
working_set.parse_errors.is_empty(),
|
||||
"errors: {:?}",
|
||||
working_set.parse_errors
|
||||
);
|
||||
|
||||
let pipeline = &block.pipelines[0];
|
||||
assert_eq!(1, pipeline.len());
|
||||
let element = &pipeline.elements[0];
|
||||
match &element.expr.expr {
|
||||
Expr::ExternalCall(name, args) => {
|
||||
match &name.expr {
|
||||
Expr::String(string) => {
|
||||
assert_eq!("foo", string, "incorrect name");
|
||||
}
|
||||
other => {
|
||||
panic!("Unexpected expression in command name position: {other:?}");
|
||||
}
|
||||
}
|
||||
assert_eq!(1, args.len());
|
||||
match &args[0] {
|
||||
ExternalArgument::Spread(expr) => match &expr.expr {
|
||||
Expr::List(items) => {
|
||||
assert_eq!(3, items.len());
|
||||
// that's good enough, don't really need to go so deep into it...
|
||||
}
|
||||
other => {
|
||||
panic!("Unexpected expression in command arg position: {other:?}")
|
||||
}
|
||||
},
|
||||
other @ ExternalArgument::Regular(..) => {
|
||||
panic!(
|
||||
"Unexpected external regular argument in command arg position: {other:?}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
other => {
|
||||
panic!("Unexpected expression in pipeline: {other:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nothing_comparison_eq() {
|
||||
let engine_state = EngineState::new();
|
||||
|
|
|
@ -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.1"
|
||||
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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.1", 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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.1" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.1" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.1", 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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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.1"
|
||||
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.1", features = ["plugin"] }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.1" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.94.1" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.1" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.1" }
|
||||
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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-plugin-protocol = { path = "../nu-plugin-protocol", version = "0.94.1" }
|
||||
nu-plugin-core = { path = "../nu-plugin-core", version = "0.94.1", 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.1"
|
||||
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.1"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -13,9 +13,9 @@ version = "0.94.1"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-system = { path = "../nu-system", version = "0.94.1" }
|
||||
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" }
|
||||
|
||||
brotli = { workspace = true, optional = true }
|
||||
byte-unit = { version = "5.1", features = [ "serde" ] }
|
||||
|
@ -45,11 +45,11 @@ plugin = [
|
|||
serde_json = { workspace = true }
|
||||
strum = "0.26"
|
||||
strum_macros = "0.26"
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.94.1" }
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
},
|
||||
eval_const::create_nu_constant,
|
||||
BlockId, Category, Config, DeclId, FileId, HistoryConfig, Module, ModuleId, OverlayId,
|
||||
ShellError, Signature, Span, Type, Value, VarId, VirtualPathId,
|
||||
ShellError, Signature, Span, SpanId, Type, Value, VarId, VirtualPathId,
|
||||
};
|
||||
use fancy_regex::Regex;
|
||||
use lru::LruCache;
|
||||
|
@ -81,6 +81,7 @@ pub struct EngineState {
|
|||
// especially long, so it helps
|
||||
pub(super) blocks: Arc<Vec<Arc<Block>>>,
|
||||
pub(super) modules: Arc<Vec<Arc<Module>>>,
|
||||
pub spans: Vec<Span>,
|
||||
usage: Usage,
|
||||
pub scope: ScopeFrame,
|
||||
pub ctrlc: Option<Arc<AtomicBool>>,
|
||||
|
@ -115,6 +116,9 @@ pub const IN_VARIABLE_ID: usize = 1;
|
|||
pub const ENV_VARIABLE_ID: usize = 2;
|
||||
// NOTE: If you add more to this list, make sure to update the > checks based on the last in the list
|
||||
|
||||
// The first span is unknown span
|
||||
pub const UNKNOWN_SPAN_ID: SpanId = SpanId(0);
|
||||
|
||||
impl EngineState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
@ -132,6 +136,7 @@ impl EngineState {
|
|||
modules: Arc::new(vec![Arc::new(Module::new(
|
||||
DEFAULT_OVERLAY_NAME.as_bytes().to_vec(),
|
||||
))]),
|
||||
spans: vec![Span::unknown()],
|
||||
usage: Usage::new(),
|
||||
// make sure we have some default overlay:
|
||||
scope: ScopeFrame::with_empty_overlay(
|
||||
|
@ -184,6 +189,7 @@ impl EngineState {
|
|||
self.files.extend(delta.files);
|
||||
self.virtual_paths.extend(delta.virtual_paths);
|
||||
self.vars.extend(delta.vars);
|
||||
self.spans.extend(delta.spans);
|
||||
self.usage.merge_with(delta.usage);
|
||||
|
||||
// Avoid potentially cloning the Arcs if we aren't adding anything
|
||||
|
@ -565,6 +571,9 @@ impl EngineState {
|
|||
self.modules.len()
|
||||
}
|
||||
|
||||
pub fn num_spans(&self) -> usize {
|
||||
self.spans.len()
|
||||
}
|
||||
pub fn print_vars(&self) {
|
||||
for var in self.vars.iter().enumerate() {
|
||||
println!("var{}: {:?}", var.0, var.1);
|
||||
|
@ -1019,6 +1028,25 @@ impl EngineState {
|
|||
)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Add new span and return its ID
|
||||
pub fn add_span(&mut self, span: Span) -> SpanId {
|
||||
self.spans.push(span);
|
||||
SpanId(self.num_spans() - 1)
|
||||
}
|
||||
|
||||
/// Get existing span
|
||||
pub fn get_span(&self, span_id: SpanId) -> Span {
|
||||
*self
|
||||
.spans
|
||||
.get(span_id.0)
|
||||
.expect("internal error: missing span")
|
||||
}
|
||||
|
||||
/// Find ID of a span (should be avoided if possible)
|
||||
pub fn find_span_id(&self, span: Span) -> Option<SpanId> {
|
||||
self.spans.iter().position(|sp| sp == &span).map(SpanId)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EngineState {
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
usage::Usage, CachedFile, Command, EngineState, OverlayFrame, ScopeFrame, Variable,
|
||||
VirtualPath,
|
||||
},
|
||||
Module,
|
||||
Module, Span,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -21,6 +21,7 @@ pub struct StateDelta {
|
|||
pub(super) decls: Vec<Box<dyn Command>>, // indexed by DeclId
|
||||
pub blocks: Vec<Arc<Block>>, // indexed by BlockId
|
||||
pub(super) modules: Vec<Arc<Module>>, // indexed by ModuleId
|
||||
pub spans: Vec<Span>, // indexed by SpanId
|
||||
pub(super) usage: Usage,
|
||||
pub scope: Vec<ScopeFrame>,
|
||||
#[cfg(feature = "plugin")]
|
||||
|
@ -45,6 +46,7 @@ impl StateDelta {
|
|||
decls: vec![],
|
||||
blocks: vec![],
|
||||
modules: vec![],
|
||||
spans: vec![],
|
||||
scope: vec![scope_frame],
|
||||
usage: Usage::new(),
|
||||
#[cfg(feature = "plugin")]
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
StateDelta, Variable, VirtualPath, Visibility,
|
||||
},
|
||||
BlockId, Category, Config, DeclId, FileId, Module, ModuleId, ParseError, ParseWarning, Span,
|
||||
Type, Value, VarId, VirtualPathId,
|
||||
SpanId, Type, Value, VarId, VirtualPathId,
|
||||
};
|
||||
use core::panic;
|
||||
use std::{
|
||||
|
@ -1013,6 +1013,25 @@ impl<'a> StateWorkingSet<'a> {
|
|||
.expect("internal error: missing virtual path")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_span(&mut self, span: Span) -> SpanId {
|
||||
let num_permanent_spans = self.permanent_state.spans.len();
|
||||
self.delta.spans.push(span);
|
||||
SpanId(num_permanent_spans + self.delta.spans.len() - 1)
|
||||
}
|
||||
|
||||
pub fn get_span(&self, span_id: SpanId) -> Span {
|
||||
let num_permanent_spans = self.permanent_state.num_spans();
|
||||
if span_id.0 < num_permanent_spans {
|
||||
self.permanent_state.get_span(span_id)
|
||||
} else {
|
||||
*self
|
||||
.delta
|
||||
.spans
|
||||
.get(span_id.0 - num_permanent_spans)
|
||||
.expect("internal error: missing span")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> miette::SourceCode for &StateWorkingSet<'a> {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type VarId = usize;
|
||||
pub type DeclId = usize;
|
||||
pub type BlockId = usize;
|
||||
|
@ -5,3 +7,5 @@ pub type ModuleId = usize;
|
|||
pub type OverlayId = usize;
|
||||
pub type FileId = usize;
|
||||
pub type VirtualPathId = usize;
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct SpanId(pub usize); // more robust ID style used in the new parser
|
||||
|
|
|
@ -11,7 +11,7 @@ use crate::{PluginIdentity, PluginSignature, ShellError, Span};
|
|||
const BUFFER_SIZE: usize = 65536;
|
||||
|
||||
// Chose settings at the low end, because we're just trying to get the maximum speed
|
||||
const COMPRESSION_QUALITY: u32 = 1;
|
||||
const COMPRESSION_QUALITY: u32 = 3; // 1 can be very bad
|
||||
const WIN_SIZE: u32 = 20; // recommended 20-22
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
|
|
@ -5,12 +5,12 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-std"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-std"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[dependencies]
|
||||
nu-parser = { version = "0.94.1", path = "../nu-parser" }
|
||||
nu-protocol = { version = "0.94.1", path = "../nu-protocol" }
|
||||
nu-engine = { version = "0.94.1", path = "../nu-engine" }
|
||||
nu-parser = { version = "0.94.3", path = "../nu-parser" }
|
||||
nu-protocol = { version = "0.94.3", path = "../nu-protocol" }
|
||||
nu-engine = { version = "0.94.3", path = "../nu-engine" }
|
||||
miette = { workspace = true, features = ["fancy-no-backtrace"] }
|
||||
|
||||
log = "0.4"
|
||||
log = "0.4"
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
export def main [
|
||||
condition: bool, # Condition, which should be true
|
||||
message?: string, # Optional error message
|
||||
--error-label: record # Label for `error make` if you want to create a custom assert
|
||||
--error-label: record<text: string, span: record<start: int, end: int>> # Label for `error make` if you want to create a custom assert
|
||||
] {
|
||||
if $condition { return }
|
||||
error make {
|
||||
|
@ -81,7 +81,7 @@ export def main [
|
|||
export def not [
|
||||
condition: bool, # Condition, which should be false
|
||||
message?: string, # Optional error message
|
||||
--error-label: record # Label for `error make` if you want to create a custom assert
|
||||
--error-label: record<text: string, span: record<start: int, end: int>> # Label for `error make` if you want to create a custom assert
|
||||
] {
|
||||
if $condition {
|
||||
let span = (metadata $condition).span
|
||||
|
|
|
@ -3,7 +3,7 @@ authors = ["The Nushell Project Developers", "procs creators"]
|
|||
description = "Nushell system querying"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-system"
|
||||
name = "nu-system"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
||||
|
@ -45,4 +45,4 @@ windows = { workspace = true, features = [
|
|||
"Win32_System_SystemInformation",
|
||||
"Win32_System_Threading",
|
||||
"Win32_UI_Shell",
|
||||
]}
|
||||
]}
|
||||
|
|
|
@ -5,20 +5,20 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-table"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-table"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.94.3" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
once_cell = { workspace = true }
|
||||
fancy-regex = { workspace = true }
|
||||
tabled = { workspace = true, features = ["color"], default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
# nu-test-support = { path="../nu-test-support", version = "0.94.1" }
|
||||
# nu-test-support = { path="../nu-test-support", version = "0.94.3" }
|
||||
|
|
|
@ -5,12 +5,12 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-term-grid"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-term-grid"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.3" }
|
||||
|
||||
unicode-width = { workspace = true }
|
||||
unicode-width = { workspace = true }
|
||||
|
|
|
@ -5,17 +5,17 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-test-suppor
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-test-support"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.94.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.94.1" }
|
||||
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" }
|
||||
|
||||
num-format = { workspace = true }
|
||||
which = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu-utils"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-utils"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[[bin]]
|
||||
|
@ -29,4 +29,4 @@ unicase = "2.7.0"
|
|||
crossterm_winapi = "0.9"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
nix = { workspace = true, default-features = false, features = ["user", "fs"] }
|
||||
nix = { workspace = true, default-features = false, features = ["user", "fs"] }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Nushell Config File
|
||||
#
|
||||
# version = "0.94.1"
|
||||
# version = "0.94.3"
|
||||
|
||||
# For more information on defining custom themes, see
|
||||
# https://www.nushell.sh/book/coloring_and_theming.html
|
||||
|
@ -892,4 +892,4 @@ $env.config = {
|
|||
event: { edit: selectall }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Nushell Environment Config File
|
||||
#
|
||||
# version = "0.94.1"
|
||||
# version = "0.94.3"
|
||||
|
||||
def create_left_prompt [] {
|
||||
let dir = match (do --ignore-shell-errors { $env.PWD | path relative-to $nu.home-path }) {
|
||||
|
@ -97,4 +97,4 @@ $env.NU_PLUGIN_DIRS = [
|
|||
# $env.PATH = ($env.PATH | uniq)
|
||||
|
||||
# To load from a custom file you can use:
|
||||
# source ($nu.default-config-dir | path join 'custom.nu')
|
||||
# source ($nu.default-config-dir | path join 'custom.nu')
|
||||
|
|
|
@ -10,10 +10,10 @@ name = "nu_plugin_custom_values"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
serde = { workspace = true, default-features = false }
|
||||
typetag = "0.2"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.1" }
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.3" }
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_exam
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_example"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_example"
|
||||
|
@ -15,9 +15,9 @@ bench = false
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.1" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.1" }
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.3" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
|
|
|
@ -5,12 +5,12 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_form
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_formats"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
|
||||
indexmap = { workspace = true }
|
||||
eml-parser = "0.1"
|
||||
|
@ -18,4 +18,4 @@ ical = "0.11"
|
|||
rust-ini = "0.21.0"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.1" }
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.3" }
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_gsta
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_gstat"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
@ -16,7 +16,7 @@ name = "nu_plugin_gstat"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
|
||||
git2 = "0.18"
|
||||
git2 = "0.18"
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_inc"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_inc"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
@ -16,7 +16,7 @@ name = "nu_plugin_inc"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3", features = ["plugin"] }
|
||||
|
||||
semver = "1.0"
|
||||
semver = "1.0"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# it also allows us to test the plugin interface with something manually implemented in a scripting
|
||||
# language without adding any extra dependencies to our tests.
|
||||
|
||||
const NUSHELL_VERSION = "0.94.1"
|
||||
const NUSHELL_VERSION = "0.94.3"
|
||||
|
||||
def main [--stdio] {
|
||||
if ($stdio) {
|
||||
|
@ -257,4 +257,4 @@ def start_plugin [] {
|
|||
}) |
|
||||
each { from json | handle_input } |
|
||||
ignore
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ edition = "2021"
|
|||
license = "MIT"
|
||||
name = "nu_plugin_polars"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_polars"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
@ -17,9 +17,9 @@ bench = false
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.94.3" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
chrono = { workspace = true, features = ["std", "unstable-locales"], default-features = false }
|
||||
|
@ -73,9 +73,9 @@ optional = false
|
|||
version = "0.39"
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.1" }
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.1" }
|
||||
tempfile.workspace = true
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-command = { path = "../nu-command", version = "0.94.3" }
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.94.3" }
|
||||
tempfile.workspace = true
|
||||
|
|
|
@ -465,7 +465,7 @@ fn from_csv(
|
|||
let df: NuLazyFrame = csv_reader
|
||||
.finish()
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Parquet reader error".into(),
|
||||
error: "CSV reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
|
@ -531,7 +531,7 @@ fn from_csv(
|
|||
let df: NuDataFrame = csv_reader
|
||||
.finish()
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: "Parquet reader error".into(),
|
||||
error: "CSV reader error".into(),
|
||||
msg: format!("{e:?}"),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
|
|
|
@ -269,13 +269,36 @@ fn typed_column_to_series(name: &str, column: TypedColumn) -> Result<Series, She
|
|||
let series_values: Result<Vec<_>, _> = column
|
||||
.values
|
||||
.iter()
|
||||
.map(|v| v.as_f64().map(|v| v as f32))
|
||||
.map(|v| match v {
|
||||
Value::Float { val, .. } => Ok(*val as f32),
|
||||
Value::Int { val, .. } => Ok(*val as f32),
|
||||
x => Err(ShellError::GenericError {
|
||||
error: "Error converting to f32".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(format!("Unexpected type: {x:?}")),
|
||||
inner: vec![],
|
||||
}),
|
||||
})
|
||||
.collect();
|
||||
Ok(Series::new(name, series_values?))
|
||||
}
|
||||
DataType::Float64 => {
|
||||
let series_values: Result<Vec<_>, _> =
|
||||
column.values.iter().map(|v| v.as_f64()).collect();
|
||||
let series_values: Result<Vec<_>, _> = column
|
||||
.values
|
||||
.iter()
|
||||
.map(|v| match v {
|
||||
Value::Float { val, .. } => Ok(*val),
|
||||
Value::Int { val, .. } => Ok(*val as f64),
|
||||
x => Err(ShellError::GenericError {
|
||||
error: "Error converting to f64".into(),
|
||||
msg: "".into(),
|
||||
span: None,
|
||||
help: Some(format!("Unexpected type: {x:?}")),
|
||||
inner: vec![],
|
||||
}),
|
||||
})
|
||||
.collect();
|
||||
Ok(Series::new(name, series_values?))
|
||||
}
|
||||
DataType::UInt8 => {
|
||||
|
|
|
@ -27,7 +27,7 @@ import sys
|
|||
import json
|
||||
|
||||
|
||||
NUSHELL_VERSION = "0.94.1"
|
||||
NUSHELL_VERSION = "0.94.3"
|
||||
|
||||
|
||||
def signatures():
|
||||
|
@ -124,7 +124,7 @@ def process_call(id, plugin_call):
|
|||
span = plugin_call["call"]["head"]
|
||||
|
||||
# Creates a Value of type List that will be encoded and sent to Nushell
|
||||
f = lambda x, y: {
|
||||
def f(x, y): return {
|
||||
"Int": {
|
||||
"val": x * y,
|
||||
"span": span
|
||||
|
@ -169,7 +169,7 @@ def tell_nushell_hello():
|
|||
"""
|
||||
hello = {
|
||||
"Hello": {
|
||||
"protocol": "nu-plugin", # always this value
|
||||
"protocol": "nu-plugin", # always this value
|
||||
"version": NUSHELL_VERSION,
|
||||
"features": []
|
||||
}
|
||||
|
@ -246,8 +246,9 @@ def plugin():
|
|||
input = json.loads(line)
|
||||
handle_input(input)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "--stdio":
|
||||
plugin()
|
||||
else:
|
||||
print("Run me from inside nushell!")
|
||||
print("Run me from inside nushell!")
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_quer
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_query"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[lib]
|
||||
doctest = false
|
||||
|
@ -16,10 +16,10 @@ name = "nu_plugin_query"
|
|||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
|
||||
gjson = "0.8"
|
||||
scraper = { default-features = false, version = "0.19" }
|
||||
sxd-document = "0.3"
|
||||
sxd-xpath = "0.4"
|
||||
sxd-xpath = "0.4"
|
||||
|
|
|
@ -88,7 +88,7 @@ pub fn execute_xpath_query(
|
|||
|
||||
match r {
|
||||
sxd_xpath::Value::Nodeset(ns) => {
|
||||
for n in ns.into_iter() {
|
||||
for n in ns.document_order() {
|
||||
record.push(key.clone(), Value::string(n.string_value(), call.head));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_stre
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_stress_internals"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_stress_internals"
|
||||
|
@ -16,4 +16,4 @@ bench = false
|
|||
# assumptions about the serialized format
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
interprocess = { workspace = true }
|
||||
interprocess = { workspace = true }
|
||||
|
|
|
@ -5,16 +5,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nuon"
|
|||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nuon"
|
||||
version = "0.94.1"
|
||||
version = "0.94.3"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.94.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.94.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.94.3" }
|
||||
once_cell = { workspace = true }
|
||||
fancy-regex = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
chrono = { workspace = true }
|
||||
chrono = { workspace = true }
|
||||
|
|
|
@ -56,12 +56,12 @@ pub fn from_nuon(input: &str, span: Option<Span>) -> Result<Value, ShellError> {
|
|||
}
|
||||
|
||||
let expr = if block.pipelines.is_empty() {
|
||||
Expression {
|
||||
expr: Expr::Nothing,
|
||||
span: span.unwrap_or(Span::unknown()),
|
||||
custom_completion: None,
|
||||
ty: Type::Nothing,
|
||||
}
|
||||
Expression::new(
|
||||
&mut working_set,
|
||||
Expr::Nothing,
|
||||
span.unwrap_or(Span::unknown()),
|
||||
Type::Nothing,
|
||||
)
|
||||
} else {
|
||||
let mut pipeline = Arc::make_mut(&mut block).pipelines.remove(0);
|
||||
|
||||
|
@ -81,12 +81,12 @@ pub fn from_nuon(input: &str, span: Option<Span>) -> Result<Value, ShellError> {
|
|||
}
|
||||
|
||||
if pipeline.elements.is_empty() {
|
||||
Expression {
|
||||
expr: Expr::Nothing,
|
||||
span: span.unwrap_or(Span::unknown()),
|
||||
custom_completion: None,
|
||||
ty: Type::Nothing,
|
||||
}
|
||||
Expression::new(
|
||||
&mut working_set,
|
||||
Expr::Nothing,
|
||||
span.unwrap_or(Span::unknown()),
|
||||
Type::Nothing,
|
||||
)
|
||||
} else {
|
||||
pipeline.elements.remove(0).expr
|
||||
}
|
||||
|
|
|
@ -539,6 +539,15 @@ fn dynamic_closure_optional_arg() {
|
|||
fn dynamic_closure_rest_args() {
|
||||
let actual = nu!(r#"let closure = {|...args| $args | str join ""}; do $closure 1 2 3"#);
|
||||
assert_eq!(actual.out, "123");
|
||||
|
||||
let actual = nu!(
|
||||
r#"let closure = {|required, ...args| $"($required), ($args | str join "")"}; do $closure 1 2 3"#
|
||||
);
|
||||
assert_eq!(actual.out, "1, 23");
|
||||
let actual = nu!(
|
||||
r#"let closure = {|required, optional?, ...args| $"($required), ($optional), ($args | str join "")"}; do $closure 1 2 3"#
|
||||
);
|
||||
assert_eq!(actual.out, "1, 2, 3");
|
||||
}
|
||||
|
||||
#[cfg(feature = "which-support")]
|
||||
|
|
Loading…
Reference in New Issue
Block a user