Merge branch 'main' into callgrind-benches

This commit is contained in:
Filip Andersson 2024-06-05 08:03:00 +02:00 committed by GitHub
commit 108a9a6878
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
83 changed files with 2978 additions and 2457 deletions

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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",

View File

@ -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

View File

@ -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"]

View File

@ -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(),
},

View File

@ -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]

View File

@ -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" }

View File

@ -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 = []

View File

@ -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);
}

View File

@ -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]

View File

@ -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" }

View File

@ -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 }

View File

@ -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::*;

View File

@ -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(

View File

@ -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 {

View File

@ -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 {

View File

@ -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]

View File

@ -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

View File

@ -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 = []

View File

@ -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,
}
}

View File

@ -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",
] }
] }

View File

@ -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)
}

View File

@ -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 {

View File

@ -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);
}
}

View 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());
}
}

View 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)
}
}

View File

@ -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())
}
}

View File

@ -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)
}
}

View File

@ -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;

View File

@ -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());

View File

@ -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());

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"]

View File

@ -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

View File

@ -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(

View File

@ -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();

View File

@ -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 }

View File

@ -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 }

View File

@ -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",
] }
] }

View File

@ -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 = []

View File

@ -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"

View File

@ -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"] }

View File

@ -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"

View File

@ -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

View File

@ -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());
}

View File

@ -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)
}
}

View File

@ -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 {

View File

@ -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")]

View File

@ -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> {

View File

@ -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

View File

@ -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)]

View File

@ -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"

View File

@ -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

View File

@ -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",
]}
]}

View File

@ -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" }

View File

@ -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 }

View File

@ -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 }

View File

@ -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"] }

View File

@ -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 }
}
]
}
}

View File

@ -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')

View File

@ -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" }

View File

@ -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" }

View File

@ -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" }

View File

@ -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"

View File

@ -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"

View File

@ -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
}
}

View File

@ -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

View File

@ -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,

View File

@ -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 => {

View File

@ -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!")

View File

@ -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"

View File

@ -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));
}
}

View File

@ -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 }

View File

@ -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 }

View File

@ -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
}

View File

@ -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")]