mirror of
https://github.com/nushell/nushell.git
synced 2024-12-25 00:19:39 +01:00
Revert PRs for 0.99.1 patch (#14119)
# Description Temporarily reverts PRs merged after the 0.99.1 bump.
This commit is contained in:
parent
e735bd475f
commit
28b6db115a
166
Cargo.lock
generated
166
Cargo.lock
generated
@ -2611,6 +2611,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markup5ever"
|
||||
version = "0.12.1"
|
||||
@ -3016,7 +3025,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"reedline",
|
||||
"rstest",
|
||||
"sysinfo 0.32.0",
|
||||
"sysinfo",
|
||||
"tempfile",
|
||||
"unicode-segmentation",
|
||||
"uuid",
|
||||
@ -3178,7 +3187,7 @@ dependencies = [
|
||||
"serde_urlencoded",
|
||||
"serde_yaml",
|
||||
"sha2",
|
||||
"sysinfo 0.32.0",
|
||||
"sysinfo",
|
||||
"tabled",
|
||||
"tempfile",
|
||||
"terminal_size",
|
||||
@ -3201,7 +3210,7 @@ dependencies = [
|
||||
"v_htmlescape",
|
||||
"wax",
|
||||
"which",
|
||||
"windows 0.56.0",
|
||||
"windows 0.54.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
@ -3347,7 +3356,7 @@ dependencies = [
|
||||
"rmp-serde",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows 0.56.0",
|
||||
"windows 0.54.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3363,7 +3372,7 @@ dependencies = [
|
||||
"nu-utils",
|
||||
"serde",
|
||||
"typetag",
|
||||
"windows 0.56.0",
|
||||
"windows 0.54.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3468,8 +3477,8 @@ dependencies = [
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"procfs",
|
||||
"sysinfo 0.32.0",
|
||||
"windows 0.56.0",
|
||||
"sysinfo",
|
||||
"windows 0.54.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3752,6 +3761,15 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
@ -4711,7 +4729,7 @@ dependencies = [
|
||||
"rayon",
|
||||
"smartstring",
|
||||
"stacker",
|
||||
"sysinfo 0.30.13",
|
||||
"sysinfo",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@ -6097,21 +6115,8 @@ dependencies = [
|
||||
"libc",
|
||||
"ntapi",
|
||||
"once_cell",
|
||||
"windows 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"rayon",
|
||||
"windows 0.56.0",
|
||||
"windows 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6437,19 +6442,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "trash"
|
||||
version = "5.1.1"
|
||||
version = "3.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33caf2a9be1812a263a4bfce74d2de225fcde12ee7b77001361abd2b34ffdcc4"
|
||||
checksum = "c658458d46d9d5a153a3b5cdd88d8579ad50d4fb85d53961e4526c8fc7c55a57"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"libc",
|
||||
"log",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"scopeguard",
|
||||
"urlencoding",
|
||||
"windows 0.56.0",
|
||||
"url",
|
||||
"windows 0.44.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -6638,12 +6642,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urlencoding"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
@ -7085,6 +7083,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.44.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
@ -7097,11 +7104,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.56.0"
|
||||
version = "0.54.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
|
||||
checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49"
|
||||
dependencies = [
|
||||
"windows-core 0.56.0",
|
||||
"windows-core 0.54.0",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
@ -7116,38 +7123,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.56.0"
|
||||
version = "0.54.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
|
||||
checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.56.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.1.2"
|
||||
@ -7197,6 +7180,21 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.42.2",
|
||||
"windows_aarch64_msvc 0.42.2",
|
||||
"windows_i686_gnu 0.42.2",
|
||||
"windows_i686_msvc 0.42.2",
|
||||
"windows_x86_64_gnu 0.42.2",
|
||||
"windows_x86_64_gnullvm 0.42.2",
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
@ -7228,6 +7226,12 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@ -7246,6 +7250,12 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
@ -7264,6 +7274,12 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
@ -7288,6 +7304,12 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
@ -7306,6 +7328,12 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
@ -7318,6 +7346,12 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
@ -7336,6 +7370,12 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
|
10
Cargo.toml
10
Cargo.toml
@ -10,7 +10,7 @@ homepage = "https://www.nushell.sh"
|
||||
license = "MIT"
|
||||
name = "nu"
|
||||
repository = "https://github.com/nushell/nushell"
|
||||
rust-version = "1.80.1"
|
||||
rust-version = "1.79.0"
|
||||
version = "0.99.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -153,13 +153,13 @@ serde_yaml = "0.9"
|
||||
sha2 = "0.10"
|
||||
strip-ansi-escapes = "0.2.0"
|
||||
syn = "2.0"
|
||||
sysinfo = "0.32"
|
||||
sysinfo = "0.30"
|
||||
tabled = { version = "0.16.0", default-features = false }
|
||||
tempfile = "3.13"
|
||||
terminal_size = "0.3"
|
||||
titlecase = "2.0"
|
||||
toml = "0.8"
|
||||
trash = "5.1"
|
||||
trash = "3.3"
|
||||
umask = "2.1"
|
||||
unicode-segmentation = "1.12"
|
||||
unicode-width = "0.1"
|
||||
@ -176,7 +176,7 @@ uuid = "1.10.0"
|
||||
v_htmlescape = "0.15.0"
|
||||
wax = "0.6"
|
||||
which = "6.0.0"
|
||||
windows = "0.56"
|
||||
windows = "0.54"
|
||||
windows-sys = "0.48"
|
||||
winreg = "0.52"
|
||||
|
||||
@ -320,4 +320,4 @@ bench = false
|
||||
# Run individual benchmarks like `cargo bench -- <regex>` e.g. `cargo bench -- parse`
|
||||
[[bench]]
|
||||
name = "benchmarks"
|
||||
harness = false
|
||||
harness = false
|
@ -67,9 +67,7 @@ impl Completer for OperatorCompletion {
|
||||
],
|
||||
Expr::String(_) => vec![
|
||||
("=~", "Contains regex match"),
|
||||
("like", "Contains regex match"),
|
||||
("!~", "Does not contain regex match"),
|
||||
("not-like", "Does not contain regex match"),
|
||||
(
|
||||
"++",
|
||||
"Appends two lists, a list and a value, two strings, or two binary values",
|
||||
|
@ -107,11 +107,7 @@ fn run_catch(
|
||||
|
||||
if let Some(catch) = catch {
|
||||
stack.set_last_error(&error);
|
||||
let fancy_errors = match engine_state.get_config().error_style {
|
||||
nu_protocol::ErrorStyle::Fancy => true,
|
||||
nu_protocol::ErrorStyle::Plain => false,
|
||||
};
|
||||
let error = error.into_value(span, fancy_errors);
|
||||
let error = error.into_value(span);
|
||||
let block = engine_state.get_block(catch.block_id);
|
||||
// Put the error value in the positional closure var
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
|
@ -119,7 +119,7 @@ apparent the next time `nu` is next launched with that plugin registry file.
|
||||
let metadata = interface.get_metadata()?;
|
||||
let commands = interface.get_signature()?;
|
||||
|
||||
modify_plugin_file(engine_state, stack, call.head, &custom_path, |contents| {
|
||||
modify_plugin_file(engine_state, stack, call.head, custom_path, |contents| {
|
||||
// Update the file with the received metadata and signatures
|
||||
let item = PluginRegistryItem::new(plugin.identity(), metadata, commands);
|
||||
contents.upsert_plugin(item);
|
||||
|
@ -1,8 +1,5 @@
|
||||
use itertools::{EitherOrBoth, Itertools};
|
||||
use itertools::Itertools;
|
||||
use nu_engine::command_prelude::*;
|
||||
use nu_protocol::{IntoValue, PluginRegistryItemData};
|
||||
|
||||
use crate::util::read_plugin_file;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginList;
|
||||
@ -20,7 +17,7 @@ impl Command for PluginList {
|
||||
[
|
||||
("name".into(), Type::String),
|
||||
("version".into(), Type::String),
|
||||
("status".into(), Type::String),
|
||||
("is_running".into(), Type::Bool),
|
||||
("pid".into(), Type::Int),
|
||||
("filename".into(), Type::String),
|
||||
("shell".into(), Type::String),
|
||||
@ -29,54 +26,11 @@ impl Command for PluginList {
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
.named(
|
||||
"plugin-config",
|
||||
SyntaxShape::Filepath,
|
||||
"Use a plugin registry file other than the one set in `$nu.plugin-path`",
|
||||
None,
|
||||
)
|
||||
.switch(
|
||||
"engine",
|
||||
"Show info for plugins that are loaded into the engine only.",
|
||||
Some('e'),
|
||||
)
|
||||
.switch(
|
||||
"registry",
|
||||
"Show info for plugins from the registry file only.",
|
||||
Some('r'),
|
||||
)
|
||||
.category(Category::Plugin)
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"List loaded and installed plugins."
|
||||
}
|
||||
|
||||
fn extra_description(&self) -> &str {
|
||||
r#"
|
||||
The `status` column will contain one of the following values:
|
||||
|
||||
- `added`: The plugin is present in the plugin registry file, but not in
|
||||
the engine.
|
||||
- `loaded`: The plugin is present both in the plugin registry file and in
|
||||
the engine, but is not running.
|
||||
- `running`: The plugin is currently running, and the `pid` column should
|
||||
contain its process ID.
|
||||
- `modified`: The plugin state present in the plugin registry file is different
|
||||
from the state in the engine.
|
||||
- `removed`: The plugin is still loaded in the engine, but is not present in
|
||||
the plugin registry file.
|
||||
- `invalid`: The data in the plugin registry file couldn't be deserialized,
|
||||
and the plugin most likely needs to be added again.
|
||||
|
||||
`running` takes priority over any other status. Unless `--registry` is used
|
||||
or the plugin has not been loaded yet, the values of `version`, `filename`,
|
||||
`shell`, and `commands` reflect the values in the engine and not the ones in
|
||||
the plugin registry file.
|
||||
|
||||
See also: `plugin use`
|
||||
"#
|
||||
.trim()
|
||||
"List installed plugins."
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
@ -91,7 +45,7 @@ See also: `plugin use`
|
||||
result: Some(Value::test_list(vec![Value::test_record(record! {
|
||||
"name" => Value::test_string("inc"),
|
||||
"version" => Value::test_string(env!("CARGO_PKG_VERSION")),
|
||||
"status" => Value::test_string("running"),
|
||||
"is_running" => Value::test_bool(true),
|
||||
"pid" => Value::test_int(106480),
|
||||
"filename" => if cfg!(windows) {
|
||||
Value::test_string(r"C:\nu\plugins\nu_plugin_inc.exe")
|
||||
@ -113,189 +67,58 @@ See also: `plugin use`
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let custom_path = call.get_flag(engine_state, stack, "plugin-config")?;
|
||||
let engine_mode = call.has_flag(engine_state, stack, "engine")?;
|
||||
let registry_mode = call.has_flag(engine_state, stack, "registry")?;
|
||||
let head = call.head;
|
||||
|
||||
let plugins_info = match (engine_mode, registry_mode) {
|
||||
// --engine and --registry together is equivalent to the default.
|
||||
(false, false) | (true, true) => {
|
||||
if engine_state.plugin_path.is_some() || custom_path.is_some() {
|
||||
let plugins_in_engine = get_plugins_in_engine(engine_state);
|
||||
let plugins_in_registry =
|
||||
get_plugins_in_registry(engine_state, stack, call.head, &custom_path)?;
|
||||
merge_plugin_info(plugins_in_engine, plugins_in_registry)
|
||||
} else {
|
||||
// Don't produce error when running nu --no-config-file
|
||||
get_plugins_in_engine(engine_state)
|
||||
}
|
||||
}
|
||||
(true, false) => get_plugins_in_engine(engine_state),
|
||||
(false, true) => get_plugins_in_registry(engine_state, stack, call.head, &custom_path)?,
|
||||
};
|
||||
// Group plugin decls by plugin identity
|
||||
let decls = engine_state.plugin_decls().into_group_map_by(|decl| {
|
||||
decl.plugin_identity()
|
||||
.expect("plugin decl should have identity")
|
||||
});
|
||||
|
||||
Ok(plugins_info.into_value(call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, IntoValue, PartialOrd, Ord, PartialEq, Eq)]
|
||||
struct PluginInfo {
|
||||
name: String,
|
||||
version: Option<String>,
|
||||
status: PluginStatus,
|
||||
pid: Option<u32>,
|
||||
filename: String,
|
||||
shell: Option<String>,
|
||||
commands: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, IntoValue, PartialOrd, Ord, PartialEq, Eq)]
|
||||
#[nu_value(rename_all = "snake_case")]
|
||||
enum PluginStatus {
|
||||
Added,
|
||||
Loaded,
|
||||
Running,
|
||||
Modified,
|
||||
Removed,
|
||||
Invalid,
|
||||
}
|
||||
|
||||
fn get_plugins_in_engine(engine_state: &EngineState) -> Vec<PluginInfo> {
|
||||
// Group plugin decls by plugin identity
|
||||
let decls = engine_state.plugin_decls().into_group_map_by(|decl| {
|
||||
decl.plugin_identity()
|
||||
.expect("plugin decl should have identity")
|
||||
});
|
||||
|
||||
// Build plugins list
|
||||
engine_state
|
||||
.plugins()
|
||||
.iter()
|
||||
.map(|plugin| {
|
||||
// Build plugins list
|
||||
let list = engine_state.plugins().iter().map(|plugin| {
|
||||
// Find commands that belong to the plugin
|
||||
let commands = decls
|
||||
.get(plugin.identity())
|
||||
let commands = decls.get(plugin.identity())
|
||||
.into_iter()
|
||||
.flat_map(|decls| decls.iter().map(|decl| decl.name().to_owned()))
|
||||
.sorted()
|
||||
.flat_map(|decls| {
|
||||
decls.iter().map(|decl| Value::string(decl.name(), head))
|
||||
})
|
||||
.collect();
|
||||
|
||||
PluginInfo {
|
||||
name: plugin.identity().name().into(),
|
||||
version: plugin.metadata().and_then(|m| m.version),
|
||||
status: if plugin.pid().is_some() {
|
||||
PluginStatus::Running
|
||||
} else {
|
||||
PluginStatus::Loaded
|
||||
},
|
||||
pid: plugin.pid(),
|
||||
filename: plugin.identity().filename().to_string_lossy().into_owned(),
|
||||
shell: plugin
|
||||
.identity()
|
||||
.shell()
|
||||
.map(|path| path.to_string_lossy().into_owned()),
|
||||
commands,
|
||||
}
|
||||
})
|
||||
.sorted()
|
||||
.collect()
|
||||
}
|
||||
let pid = plugin
|
||||
.pid()
|
||||
.map(|p| Value::int(p as i64, head))
|
||||
.unwrap_or(Value::nothing(head));
|
||||
|
||||
fn get_plugins_in_registry(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
) -> Result<Vec<PluginInfo>, ShellError> {
|
||||
let plugin_file_contents = read_plugin_file(engine_state, stack, span, custom_path)?;
|
||||
let shell = plugin
|
||||
.identity()
|
||||
.shell()
|
||||
.map(|s| Value::string(s.to_string_lossy(), head))
|
||||
.unwrap_or(Value::nothing(head));
|
||||
|
||||
let plugins_info = plugin_file_contents
|
||||
.plugins
|
||||
.into_iter()
|
||||
.map(|plugin| {
|
||||
let mut info = PluginInfo {
|
||||
name: plugin.name,
|
||||
version: None,
|
||||
status: PluginStatus::Added,
|
||||
pid: None,
|
||||
filename: plugin.filename.to_string_lossy().into_owned(),
|
||||
shell: plugin.shell.map(|path| path.to_string_lossy().into_owned()),
|
||||
commands: vec![],
|
||||
let metadata = plugin.metadata();
|
||||
let version = metadata
|
||||
.and_then(|m| m.version)
|
||||
.map(|s| Value::string(s, head))
|
||||
.unwrap_or(Value::nothing(head));
|
||||
|
||||
let record = record! {
|
||||
"name" => Value::string(plugin.identity().name(), head),
|
||||
"version" => version,
|
||||
"is_running" => Value::bool(plugin.is_running(), head),
|
||||
"pid" => pid,
|
||||
"filename" => Value::string(plugin.identity().filename().to_string_lossy(), head),
|
||||
"shell" => shell,
|
||||
"commands" => Value::list(commands, head),
|
||||
};
|
||||
|
||||
if let PluginRegistryItemData::Valid { metadata, commands } = plugin.data {
|
||||
info.version = metadata.version;
|
||||
info.commands = commands
|
||||
.into_iter()
|
||||
.map(|command| command.sig.name)
|
||||
.sorted()
|
||||
.collect();
|
||||
} else {
|
||||
info.status = PluginStatus::Invalid;
|
||||
}
|
||||
info
|
||||
})
|
||||
.sorted()
|
||||
.collect();
|
||||
Value::record(record, head)
|
||||
}).collect();
|
||||
|
||||
Ok(plugins_info)
|
||||
}
|
||||
|
||||
/// If no options are provided, the command loads from both the plugin list in the engine and what's
|
||||
/// in the registry file. We need to reconcile the two to set the proper states and make sure that
|
||||
/// new plugins that were added to the plugin registry file show up.
|
||||
fn merge_plugin_info(
|
||||
from_engine: Vec<PluginInfo>,
|
||||
from_registry: Vec<PluginInfo>,
|
||||
) -> Vec<PluginInfo> {
|
||||
from_engine
|
||||
.into_iter()
|
||||
.merge_join_by(from_registry, |info_a, info_b| {
|
||||
info_a.name.cmp(&info_b.name)
|
||||
})
|
||||
.map(|either_or_both| match either_or_both {
|
||||
// Exists in the engine, but not in the registry file
|
||||
EitherOrBoth::Left(info) => PluginInfo {
|
||||
status: match info.status {
|
||||
PluginStatus::Running => info.status,
|
||||
// The plugin is not in the registry file, so it should be marked as `removed`
|
||||
_ => PluginStatus::Removed,
|
||||
},
|
||||
..info
|
||||
},
|
||||
// Exists in the registry file, but not in the engine
|
||||
EitherOrBoth::Right(info) => info,
|
||||
// Exists in both
|
||||
EitherOrBoth::Both(info_engine, info_registry) => PluginInfo {
|
||||
status: match (info_engine.status, info_registry.status) {
|
||||
// Above all, `running` should be displayed if the plugin is running
|
||||
(PluginStatus::Running, _) => PluginStatus::Running,
|
||||
// `invalid` takes precedence over other states because the user probably wants
|
||||
// to fix it
|
||||
(_, PluginStatus::Invalid) => PluginStatus::Invalid,
|
||||
// Display `modified` if the state in the registry is different somehow
|
||||
_ if info_engine.is_modified(&info_registry) => PluginStatus::Modified,
|
||||
// Otherwise, `loaded` (it's not running)
|
||||
_ => PluginStatus::Loaded,
|
||||
},
|
||||
..info_engine
|
||||
},
|
||||
})
|
||||
.sorted()
|
||||
.collect()
|
||||
}
|
||||
|
||||
impl PluginInfo {
|
||||
/// True if the plugin info shows some kind of change (other than status/pid) relative to the
|
||||
/// other
|
||||
fn is_modified(&self, other: &PluginInfo) -> bool {
|
||||
self.name != other.name
|
||||
|| self.filename != other.filename
|
||||
|| self.shell != other.shell
|
||||
|| self.commands != other.commands
|
||||
Ok(Value::list(list, head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ fixed with `plugin add`.
|
||||
|
||||
let filename = canonicalize_possible_filename_arg(engine_state, stack, &name.item);
|
||||
|
||||
modify_plugin_file(engine_state, stack, call.head, &custom_path, |contents| {
|
||||
modify_plugin_file(engine_state, stack, call.head, custom_path, |contents| {
|
||||
if let Some(index) = contents
|
||||
.plugins
|
||||
.iter()
|
||||
|
@ -6,17 +6,18 @@ use std::{
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
fn get_plugin_registry_file_path(
|
||||
pub(crate) fn modify_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
) -> Result<PathBuf, ShellError> {
|
||||
custom_path: Option<Spanned<String>>,
|
||||
operate: impl FnOnce(&mut PluginRegistryFile) -> Result<(), ShellError>,
|
||||
) -> Result<(), ShellError> {
|
||||
#[allow(deprecated)]
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
|
||||
if let Some(ref custom_path) = custom_path {
|
||||
Ok(nu_path::expand_path_with(&custom_path.item, cwd, true))
|
||||
let plugin_registry_file_path = if let Some(ref custom_path) = custom_path {
|
||||
nu_path::expand_path_with(&custom_path.item, cwd, true)
|
||||
} else {
|
||||
engine_state
|
||||
.plugin_path
|
||||
@ -27,53 +28,8 @@ fn get_plugin_registry_file_path(
|
||||
span: Some(span),
|
||||
help: Some("you may be running `nu` with --no-config-file".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
) -> Result<PluginRegistryFile, ShellError> {
|
||||
let plugin_registry_file_path =
|
||||
get_plugin_registry_file_path(engine_state, stack, span, custom_path)?;
|
||||
|
||||
let file_span = custom_path.as_ref().map(|p| p.span).unwrap_or(span);
|
||||
|
||||
// Try to read the plugin file if it exists
|
||||
if fs::metadata(&plugin_registry_file_path).is_ok_and(|m| m.len() > 0) {
|
||||
PluginRegistryFile::read_from(
|
||||
File::open(&plugin_registry_file_path).map_err(|err| ShellError::IOErrorSpanned {
|
||||
msg: format!(
|
||||
"failed to read `{}`: {}",
|
||||
plugin_registry_file_path.display(),
|
||||
err
|
||||
),
|
||||
span: file_span,
|
||||
})?,
|
||||
Some(file_span),
|
||||
)
|
||||
} else if let Some(path) = custom_path {
|
||||
Err(ShellError::FileNotFound {
|
||||
file: path.item.clone(),
|
||||
span: path.span,
|
||||
})
|
||||
} else {
|
||||
Ok(PluginRegistryFile::default())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn modify_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: &Option<Spanned<String>>,
|
||||
operate: impl FnOnce(&mut PluginRegistryFile) -> Result<(), ShellError>,
|
||||
) -> Result<(), ShellError> {
|
||||
let plugin_registry_file_path =
|
||||
get_plugin_registry_file_path(engine_state, stack, span, custom_path)?;
|
||||
})?
|
||||
};
|
||||
|
||||
let file_span = custom_path.as_ref().map(|p| p.span).unwrap_or(span);
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl Command for IntoValue {
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.named(
|
||||
"columns",
|
||||
SyntaxShape::List(Box::new(SyntaxShape::Any)),
|
||||
SyntaxShape::Table(vec![]),
|
||||
"list of columns to update",
|
||||
Some('c'),
|
||||
)
|
||||
|
@ -101,7 +101,7 @@ fn all_columns(span: Span) -> Value {
|
||||
let environment = {
|
||||
let mut env_rec = Record::new();
|
||||
for val in p.environ() {
|
||||
if let Some((key, value)) = val.to_string_lossy().split_once('=') {
|
||||
if let Some((key, value)) = val.split_once('=') {
|
||||
let is_env_var_a_list = {
|
||||
{
|
||||
#[cfg(target_family = "windows")]
|
||||
@ -146,8 +146,8 @@ fn all_columns(span: Span) -> Value {
|
||||
"root" => root,
|
||||
"cwd" => cwd,
|
||||
"exe_path" => exe_path,
|
||||
"command" => Value::string(p.cmd().join(std::ffi::OsStr::new(" ")).to_string_lossy(), span),
|
||||
"name" => Value::string(p.name().to_string_lossy(), span),
|
||||
"command" => Value::string(p.cmd().join(" "), span),
|
||||
"name" => Value::string(p.name(), span),
|
||||
"environment" => environment,
|
||||
},
|
||||
span,
|
||||
|
@ -38,14 +38,6 @@ impl Command for GroupBy {
|
||||
"Splits a list or table into groups, and returns a record containing those groups."
|
||||
}
|
||||
|
||||
fn extra_description(&self) -> &str {
|
||||
r#"the group-by command makes some assumptions:
|
||||
- if the input data is not a string, the grouper will convert the key to string but the values will remain in their original format. e.g. with bools, "true" and true would be in the same group (see example).
|
||||
- datetime is formatted based on your configuration setting. use `format date` to change the format.
|
||||
- filesize is formatted based on your configuration setting. use `format filesize` to change the format.
|
||||
- some nushell values are not supported, such as closures."#
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
@ -122,20 +114,6 @@ impl Command for GroupBy {
|
||||
}),
|
||||
])),
|
||||
},
|
||||
Example {
|
||||
description: "Group bools, whether they are strings or actual bools",
|
||||
example: r#"[true "true" false "false"] | group-by"#,
|
||||
result: Some(Value::test_record(record! {
|
||||
"true" => Value::test_list(vec![
|
||||
Value::test_bool(true),
|
||||
Value::test_string("true"),
|
||||
]),
|
||||
"false" => Value::test_list(vec![
|
||||
Value::test_bool(false),
|
||||
Value::test_string("false"),
|
||||
]),
|
||||
})),
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -149,7 +127,6 @@ pub fn group_by(
|
||||
let head = call.head;
|
||||
let grouper: Option<Value> = call.opt(engine_state, stack, 0)?;
|
||||
let to_table = call.has_flag(engine_state, stack, "to-table")?;
|
||||
let config = engine_state.get_config();
|
||||
|
||||
let values: Vec<Value> = input.into_iter().collect();
|
||||
if values.is_empty() {
|
||||
@ -160,7 +137,7 @@ pub fn group_by(
|
||||
Some(grouper) => {
|
||||
let span = grouper.span();
|
||||
match grouper {
|
||||
Value::CellPath { val, .. } => group_cell_path(val, values, config)?,
|
||||
Value::CellPath { val, .. } => group_cell_path(val, values)?,
|
||||
Value::Closure { val, .. } => {
|
||||
group_closure(values, span, *val, engine_state, stack)?
|
||||
}
|
||||
@ -172,7 +149,7 @@ pub fn group_by(
|
||||
}
|
||||
}
|
||||
}
|
||||
None => group_no_grouper(values, config)?,
|
||||
None => group_no_grouper(values)?,
|
||||
};
|
||||
|
||||
let value = if to_table {
|
||||
@ -187,7 +164,6 @@ pub fn group_by(
|
||||
fn group_cell_path(
|
||||
column_name: CellPath,
|
||||
values: Vec<Value>,
|
||||
config: &nu_protocol::Config,
|
||||
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||
let mut groups = IndexMap::<_, Vec<_>>::new();
|
||||
|
||||
@ -200,21 +176,18 @@ fn group_cell_path(
|
||||
continue; // likely the result of a failed optional access, ignore this value
|
||||
}
|
||||
|
||||
let key = key.to_abbreviated_string(config);
|
||||
let key = key.coerce_string()?;
|
||||
groups.entry(key).or_default().push(value);
|
||||
}
|
||||
|
||||
Ok(groups)
|
||||
}
|
||||
|
||||
fn group_no_grouper(
|
||||
values: Vec<Value>,
|
||||
config: &nu_protocol::Config,
|
||||
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||
fn group_no_grouper(values: Vec<Value>) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||
let mut groups = IndexMap::<_, Vec<_>>::new();
|
||||
|
||||
for value in values.into_iter() {
|
||||
let key = value.to_abbreviated_string(config);
|
||||
let key = value.coerce_string()?;
|
||||
groups.entry(key).or_default().push(value);
|
||||
}
|
||||
|
||||
@ -230,13 +203,12 @@ fn group_closure(
|
||||
) -> Result<IndexMap<String, Vec<Value>>, ShellError> {
|
||||
let mut groups = IndexMap::<_, Vec<_>>::new();
|
||||
let mut closure = ClosureEval::new(engine_state, stack, closure);
|
||||
let config = engine_state.get_config();
|
||||
|
||||
for value in values {
|
||||
let key = closure
|
||||
.run_with_value(value.clone())?
|
||||
.into_value(span)?
|
||||
.to_abbreviated_string(config);
|
||||
.coerce_into_string()?;
|
||||
|
||||
groups.entry(key).or_default().push(value);
|
||||
}
|
||||
|
@ -84,16 +84,16 @@ pub fn split_by(
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name = call.head;
|
||||
let config = engine_state.get_config();
|
||||
|
||||
let splitter: Option<Value> = call.opt(engine_state, stack, 0)?;
|
||||
|
||||
match splitter {
|
||||
Some(v) => {
|
||||
let splitter = Some(Spanned {
|
||||
item: v.to_abbreviated_string(config),
|
||||
item: v.coerce_into_string()?,
|
||||
span: name,
|
||||
});
|
||||
Ok(split(splitter.as_ref(), input, name, config)?)
|
||||
Ok(split(splitter.as_ref(), input, name)?)
|
||||
}
|
||||
// This uses the same format as the 'requires a column name' error in sort_utils.rs
|
||||
None => Err(ShellError::GenericError {
|
||||
@ -110,7 +110,6 @@ pub fn split(
|
||||
column_name: Option<&Spanned<String>>,
|
||||
values: PipelineData,
|
||||
span: Span,
|
||||
config: &nu_protocol::Config,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let grouper = if let Some(column_name) = column_name {
|
||||
Grouper::ByColumn(Some(column_name.clone()))
|
||||
@ -128,7 +127,7 @@ pub fn split(
|
||||
};
|
||||
|
||||
match group_key {
|
||||
Some(group_key) => Ok(group_key.to_abbreviated_string(config)),
|
||||
Some(group_key) => Ok(group_key.coerce_string()?),
|
||||
None => Err(ShellError::CantFindColumn {
|
||||
col_name: column_name.item.to_string(),
|
||||
span: Some(column_name.span),
|
||||
@ -137,12 +136,12 @@ pub fn split(
|
||||
}
|
||||
};
|
||||
|
||||
data_split(values, Some(&block), span, config)
|
||||
data_split(values, Some(&block), span)
|
||||
}
|
||||
Grouper::ByColumn(None) => {
|
||||
let block = move |_, row: &Value| Ok(row.to_abbreviated_string(config));
|
||||
let block = move |_, row: &Value| row.coerce_string();
|
||||
|
||||
data_split(values, Some(&block), span, config)
|
||||
data_split(values, Some(&block), span)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -152,7 +151,6 @@ fn data_group(
|
||||
values: &Value,
|
||||
grouper: Option<&dyn Fn(usize, &Value) -> Result<String, ShellError>>,
|
||||
span: Span,
|
||||
config: &nu_protocol::Config,
|
||||
) -> Result<Value, ShellError> {
|
||||
let mut groups: IndexMap<String, Vec<Value>> = IndexMap::new();
|
||||
|
||||
@ -160,7 +158,7 @@ fn data_group(
|
||||
let group_key = if let Some(ref grouper) = grouper {
|
||||
grouper(idx, &value)
|
||||
} else {
|
||||
Ok(value.to_abbreviated_string(config))
|
||||
value.coerce_string()
|
||||
};
|
||||
|
||||
let group = groups.entry(group_key?).or_default();
|
||||
@ -181,7 +179,6 @@ pub fn data_split(
|
||||
value: PipelineData,
|
||||
splitter: Option<&dyn Fn(usize, &Value) -> Result<String, ShellError>>,
|
||||
dst_span: Span,
|
||||
config: &nu_protocol::Config,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let mut splits = indexmap::IndexMap::new();
|
||||
|
||||
@ -191,7 +188,7 @@ pub fn data_split(
|
||||
match v {
|
||||
Value::Record { val: grouped, .. } => {
|
||||
for (outer_key, list) in grouped.into_owned() {
|
||||
match data_group(&list, splitter, span, config) {
|
||||
match data_group(&list, splitter, span) {
|
||||
Ok(grouped_vals) => {
|
||||
if let Value::Record { val: sub, .. } = grouped_vals {
|
||||
for (inner_key, subset) in sub.into_owned() {
|
||||
|
@ -46,7 +46,7 @@ impl Command for Uniq {
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["distinct", "deduplicate", "count"]
|
||||
vec!["distinct", "deduplicate"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
|
@ -23,33 +23,37 @@ fn groups() {
|
||||
|
||||
#[test]
|
||||
fn errors_if_given_unknown_column_name() {
|
||||
let sample = r#"{
|
||||
"nu": {
|
||||
"committers": [
|
||||
{"name": "Andrés N. Robalino"},
|
||||
{"name": "JT Turner"},
|
||||
{"name": "Yehuda Katz"}
|
||||
],
|
||||
"releases": [
|
||||
{"version": "0.2"}
|
||||
{"version": "0.8"},
|
||||
{"version": "0.9999999"}
|
||||
],
|
||||
"0xATYKARNU": [
|
||||
["Th", "e", " "],
|
||||
["BIG", " ", "UnO"],
|
||||
["punto", "cero"]
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let sample = r#"
|
||||
{
|
||||
"nu": {
|
||||
"committers": [
|
||||
{"name": "Andrés N. Robalino"},
|
||||
{"name": "JT Turner"},
|
||||
{"name": "Yehuda Katz"}
|
||||
],
|
||||
"releases": [
|
||||
{"version": "0.2"}
|
||||
{"version": "0.8"},
|
||||
{"version": "0.9999999"}
|
||||
],
|
||||
"0xATYKARNU": [
|
||||
["Th", "e", " "],
|
||||
["BIG", " ", "UnO"],
|
||||
["punto", "cero"]
|
||||
]
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let actual = nu!(pipeline(&format!(
|
||||
r#"'{sample}'
|
||||
| from json
|
||||
| group-by {{|| get nu.releases.missing_column }}"#
|
||||
r#"
|
||||
'{sample}'
|
||||
| from json
|
||||
| group-by {{|| get nu.releases.version }}
|
||||
"#
|
||||
)));
|
||||
assert!(actual.err.contains("cannot find column"));
|
||||
|
||||
assert!(actual.err.contains("can't convert list<string> to string"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -126,20 +126,3 @@ fn prints_only_if_last_pipeline() {
|
||||
let actual = nu!("try { ['should not print'] | every 1 }; 'last value'");
|
||||
assert_eq!(actual.out, "last value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_error_columns() {
|
||||
let actual = nu!(" try { non_existent_command } catch {|err| $err} | columns | to json -r");
|
||||
assert_eq!(
|
||||
actual.out,
|
||||
"[\"msg\",\"debug\",\"raw\",\"rendered\",\"json\"]"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_json_error() {
|
||||
let actual = nu!("try { non_existent_command } catch {|err| $err} | get json | from json | update labels.span {{start: 0 end: 0}} | to json -r");
|
||||
assert_eq!(
|
||||
actual.out, "{\"msg\":\"External command failed\",\"labels\":[{\"text\":\"Command `non_existent_command` not found\",\"span\":{\"start\":0,\"end\":0}}],\"code\":\"nu::shell::external_command\",\"url\":null,\"help\":\"`non_existent_command` is neither a Nushell built-in or a known external command\",\"inner\":[]}"
|
||||
);
|
||||
}
|
||||
|
@ -220,17 +220,8 @@ fn eval_ir_block_impl<D: DebugContext>(
|
||||
}
|
||||
Err(err) => {
|
||||
if let Some(error_handler) = ctx.stack.error_handlers.pop(ctx.error_handler_base) {
|
||||
let fancy_errors = match ctx.engine_state.get_config().error_style {
|
||||
nu_protocol::ErrorStyle::Fancy => true,
|
||||
nu_protocol::ErrorStyle::Plain => false,
|
||||
};
|
||||
// If an error handler is set, branch there
|
||||
prepare_error_handler(
|
||||
ctx,
|
||||
error_handler,
|
||||
Some(err.into_spanned(*span)),
|
||||
fancy_errors,
|
||||
);
|
||||
prepare_error_handler(ctx, error_handler, Some(err.into_spanned(*span)));
|
||||
pc = error_handler.handler_index;
|
||||
} else {
|
||||
// If not, exit the block with the error
|
||||
@ -255,7 +246,6 @@ fn prepare_error_handler(
|
||||
ctx: &mut EvalContext<'_>,
|
||||
error_handler: ErrorHandler,
|
||||
error: Option<Spanned<ShellError>>,
|
||||
fancy_errors: bool,
|
||||
) {
|
||||
if let Some(reg_id) = error_handler.error_register {
|
||||
if let Some(error) = error {
|
||||
@ -264,10 +254,7 @@ fn prepare_error_handler(
|
||||
// Create the error value and put it in the register
|
||||
ctx.put_reg(
|
||||
reg_id,
|
||||
error
|
||||
.item
|
||||
.into_value(error.span, fancy_errors)
|
||||
.into_pipeline_data(),
|
||||
error.item.into_value(error.span).into_pipeline_data(),
|
||||
);
|
||||
} else {
|
||||
// Set the register to empty
|
||||
|
@ -1067,27 +1067,30 @@ pub fn parse_internal_call(
|
||||
if let Some(arg_shape) = flag.arg {
|
||||
if let Some(arg) = spans.get(spans_idx + 1) {
|
||||
let arg = parse_value(working_set, *arg, &arg_shape);
|
||||
let (arg_name, val_expression) = ensure_flag_arg_type(
|
||||
working_set,
|
||||
flag.long.clone(),
|
||||
arg.clone(),
|
||||
&arg_shape,
|
||||
spans[spans_idx],
|
||||
);
|
||||
|
||||
if flag.long.is_empty() {
|
||||
if let Some(short) = flag.short {
|
||||
call.add_named((
|
||||
arg_name,
|
||||
Spanned {
|
||||
item: String::new(),
|
||||
span: spans[spans_idx],
|
||||
},
|
||||
Some(Spanned {
|
||||
item: short.to_string(),
|
||||
span: spans[spans_idx],
|
||||
}),
|
||||
Some(val_expression),
|
||||
Some(arg),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
call.add_named((arg_name, None, Some(val_expression)));
|
||||
call.add_named((
|
||||
Spanned {
|
||||
item: flag.long.clone(),
|
||||
span: spans[spans_idx],
|
||||
},
|
||||
None,
|
||||
Some(arg),
|
||||
));
|
||||
}
|
||||
spans_idx += 1;
|
||||
} else {
|
||||
@ -5018,8 +5021,8 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi
|
||||
b"<=" => Operator::Comparison(Comparison::LessThanOrEqual),
|
||||
b">" => Operator::Comparison(Comparison::GreaterThan),
|
||||
b">=" => Operator::Comparison(Comparison::GreaterThanOrEqual),
|
||||
b"=~" | b"like" => Operator::Comparison(Comparison::RegexMatch),
|
||||
b"!~" | b"not-like" => Operator::Comparison(Comparison::NotRegexMatch),
|
||||
b"=~" => Operator::Comparison(Comparison::RegexMatch),
|
||||
b"!~" => Operator::Comparison(Comparison::NotRegexMatch),
|
||||
b"+" => Operator::Math(Math::Plus),
|
||||
b"++" => Operator::Math(Math::Append),
|
||||
b"-" => Operator::Math(Math::Minus),
|
||||
|
@ -1091,7 +1091,8 @@ fn set_pgrp_from_enter_foreground(pgrp: i64) -> Result<(), ShellError> {
|
||||
fn set_pgrp_from_enter_foreground(_pgrp: i64) -> Result<(), ShellError> {
|
||||
Err(ShellError::NushellFailed {
|
||||
msg: concat!(
|
||||
"EnterForeground asked plugin to join process group, but this is not supported on non UNIX platforms.",
|
||||
"EnterForeground asked plugin to join process group, but not supported on ",
|
||||
cfg!(target_os)
|
||||
)
|
||||
.into(),
|
||||
})
|
||||
|
@ -35,7 +35,6 @@ miette = { workspace = true, features = ["fancy-no-backtrace"] }
|
||||
num-format = { workspace = true }
|
||||
rmp-serde = { workspace = true, optional = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
thiserror = "1.0"
|
||||
typetag = "0.2"
|
||||
os_pipe = { workspace = true, features = ["io_safety"] }
|
||||
|
@ -115,8 +115,8 @@ impl Display for Operator {
|
||||
Operator::Comparison(Comparison::NotEqual) => write!(f, "!="),
|
||||
Operator::Comparison(Comparison::LessThan) => write!(f, "<"),
|
||||
Operator::Comparison(Comparison::GreaterThan) => write!(f, ">"),
|
||||
Operator::Comparison(Comparison::RegexMatch) => write!(f, "=~ or like"),
|
||||
Operator::Comparison(Comparison::NotRegexMatch) => write!(f, "!~ or not-like"),
|
||||
Operator::Comparison(Comparison::RegexMatch) => write!(f, "=~"),
|
||||
Operator::Comparison(Comparison::NotRegexMatch) => write!(f, "!~"),
|
||||
Operator::Comparison(Comparison::LessThanOrEqual) => write!(f, "<="),
|
||||
Operator::Comparison(Comparison::GreaterThanOrEqual) => write!(f, ">="),
|
||||
Operator::Comparison(Comparison::StartsWith) => write!(f, "starts-with"),
|
||||
|
@ -139,23 +139,6 @@ impl LabeledError {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn render_error_to_string(diag: impl miette::Diagnostic, fancy_errors: bool) -> String {
|
||||
let theme = if fancy_errors {
|
||||
miette::GraphicalTheme::unicode()
|
||||
} else {
|
||||
miette::GraphicalTheme::none()
|
||||
};
|
||||
|
||||
let mut out = String::new();
|
||||
miette::GraphicalReportHandler::new()
|
||||
.with_width(80)
|
||||
.with_theme(theme)
|
||||
.render_report(&mut out, &diag)
|
||||
.unwrap_or_default();
|
||||
|
||||
out
|
||||
}
|
||||
|
||||
/// Create a [`LabeledError`] from a type that implements [`miette::Diagnostic`].
|
||||
///
|
||||
/// # Example
|
||||
|
@ -1474,16 +1474,13 @@ impl ShellError {
|
||||
self.external_exit_code().map(|e| e.item).unwrap_or(1)
|
||||
}
|
||||
|
||||
pub fn into_value(self, span: Span, fancy_errors: bool) -> Value {
|
||||
pub fn into_value(self, span: Span) -> Value {
|
||||
let exit_code = self.external_exit_code();
|
||||
|
||||
let mut record = record! {
|
||||
"msg" => Value::string(self.to_string(), span),
|
||||
"debug" => Value::string(format!("{self:?}"), span),
|
||||
"raw" => Value::error(self.clone(), span),
|
||||
// "labeled_error" => Value::string(LabeledError::from_diagnostic_and_render(self.clone()), span),
|
||||
"rendered" => Value::string(ShellError::render_error_to_string(self.clone(), fancy_errors), span),
|
||||
"json" => Value::string(serde_json::to_string(&self).expect("Could not serialize error"), span),
|
||||
"raw" => Value::error(self, span),
|
||||
};
|
||||
|
||||
if let Some(code) = exit_code {
|
||||
@ -1502,21 +1499,6 @@ impl ShellError {
|
||||
span,
|
||||
)
|
||||
}
|
||||
pub fn render_error_to_string(diag: impl miette::Diagnostic, fancy_errors: bool) -> String {
|
||||
let theme = if fancy_errors {
|
||||
miette::GraphicalTheme::unicode()
|
||||
} else {
|
||||
miette::GraphicalTheme::none()
|
||||
};
|
||||
let mut out = String::new();
|
||||
miette::GraphicalReportHandler::new()
|
||||
.with_width(80)
|
||||
.with_theme(theme)
|
||||
.render_report(&mut out, &diag)
|
||||
.unwrap_or_default();
|
||||
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for ShellError {
|
||||
|
@ -161,25 +161,20 @@ impl Module {
|
||||
}
|
||||
|
||||
let span = self.span.unwrap_or(backup_span);
|
||||
|
||||
// only needs to bring `$module` with a record value if it defines any constants.
|
||||
let constants = if const_rows.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
vec![(
|
||||
final_name.clone(),
|
||||
Value::record(
|
||||
const_rows
|
||||
.into_iter()
|
||||
.map(|(name, val)| (String::from_utf8_lossy(&name).to_string(), val))
|
||||
.collect(),
|
||||
span,
|
||||
),
|
||||
)]
|
||||
};
|
||||
let const_record = Value::record(
|
||||
const_rows
|
||||
.into_iter()
|
||||
.map(|(name, val)| (String::from_utf8_lossy(&name).to_string(), val))
|
||||
.collect(),
|
||||
span,
|
||||
);
|
||||
|
||||
return (
|
||||
ResolvedImportPattern::new(decls, vec![(final_name.clone(), self_id)], constants),
|
||||
ResolvedImportPattern::new(
|
||||
decls,
|
||||
vec![(final_name.clone(), self_id)],
|
||||
vec![(final_name, const_record)],
|
||||
),
|
||||
errors,
|
||||
);
|
||||
};
|
||||
|
@ -47,8 +47,8 @@ def get-all-operators [] { return [
|
||||
[Comparison, <=, LessThanOrEqual, "Checks if a value is less than or equal to another.", 80]
|
||||
[Comparison, >, GreaterThan, "Checks if a value is greater than another.", 80]
|
||||
[Comparison, >=, GreaterThanOrEqual, "Checks if a value is greater than or equal to another.", 80]
|
||||
[Comparison, '=~ or like', RegexMatch, "Checks if a value matches a regular expression.", 80]
|
||||
[Comparison, '!~ or not-like', NotRegexMatch, "Checks if a value does not match a regular expression.", 80]
|
||||
[Comparison, =~, RegexMatch, "Checks if a value matches a regular expression.", 80]
|
||||
[Comparison, !~, NotRegexMatch, "Checks if a value does not match a regular expression.", 80]
|
||||
[Comparison, in, In, "Checks if a value is in a list or string.", 80]
|
||||
[Comparison, not-in, NotIn, "Checks if a value is not in a list or string.", 80]
|
||||
[Comparison, starts-with, StartsWith, "Checks if a string starts with another.", 80]
|
||||
@ -771,7 +771,7 @@ You can also learn more at (ansi default_italic)(ansi light_cyan_underline)https
|
||||
|
||||
let modules = (try { modules $target_item --find $find })
|
||||
if not ($modules | is-empty) { return $modules }
|
||||
|
||||
|
||||
if ($find | is-not-empty) {
|
||||
print -e $"No help results found mentioning: ($find)"
|
||||
return []
|
||||
|
@ -32,7 +32,6 @@ mod sort_by_expr;
|
||||
pub mod sql_context;
|
||||
pub mod sql_expr;
|
||||
mod take;
|
||||
mod unnest;
|
||||
mod unpivot;
|
||||
mod with_column;
|
||||
use filter::LazyFilter;
|
||||
@ -110,6 +109,5 @@ pub(crate) fn data_commands() -> Vec<Box<dyn PluginCommand<Plugin = PolarsPlugin
|
||||
Box::new(LazyFilter),
|
||||
Box::new(Shift),
|
||||
Box::new(Unique),
|
||||
Box::new(unnest::UnnestDF),
|
||||
]
|
||||
}
|
||||
|
@ -1,145 +0,0 @@
|
||||
use nu_plugin::{EngineInterface, EvaluatedCall, PluginCommand};
|
||||
use nu_protocol::{
|
||||
Category, Example, LabeledError, PipelineData, ShellError, Signature, Span, SyntaxShape,
|
||||
};
|
||||
use polars::df;
|
||||
|
||||
use crate::{
|
||||
values::{CustomValueSupport, NuLazyFrame, PolarsPluginObject},
|
||||
PolarsPlugin,
|
||||
};
|
||||
|
||||
use crate::values::NuDataFrame;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UnnestDF;
|
||||
|
||||
impl PluginCommand for UnnestDF {
|
||||
type Plugin = PolarsPlugin;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"polars unnest"
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
"Decompose struct columns into separate columns for each of their fields. The new columns will be inserted into the dataframe at the location of the struct column."
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.rest("cols", SyntaxShape::String, "columns to unnest")
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Unnest a dataframe",
|
||||
example: r#"[[id person]; [1 {name: "Bob", age: 36}] [2 {name: "Betty", age: 63}]]
|
||||
| polars into-df -s {id: i64, person: {name: str, age: u8}}
|
||||
| polars unnest person
|
||||
| polars get id name age
|
||||
| polars sort-by id"#,
|
||||
result: Some(
|
||||
NuDataFrame::from(
|
||||
df!(
|
||||
"id" => [1, 2],
|
||||
"name" => ["Bob", "Betty"],
|
||||
"age" => [36, 63]
|
||||
)
|
||||
.expect("Should be able to create a simple dataframe"),
|
||||
)
|
||||
.into_value(Span::test_data()),
|
||||
),
|
||||
},
|
||||
Example {
|
||||
description: "Unnest a lazy dataframe",
|
||||
example: r#"[[id person]; [1 {name: "Bob", age: 36}] [2 {name: "Betty", age: 63}]]
|
||||
| polars into-df -s {id: i64, person: {name: str, age: u8}}
|
||||
| polars into-lazy
|
||||
| polars unnest person
|
||||
| polars select (polars col id) (polars col name) (polars col age)
|
||||
| polars collect
|
||||
| polars sort-by id"#,
|
||||
result: Some(
|
||||
NuDataFrame::from(
|
||||
df!(
|
||||
"id" => [1, 2],
|
||||
"name" => ["Bob", "Betty"],
|
||||
"age" => [36, 63]
|
||||
)
|
||||
.expect("Should be able to create a simple dataframe"),
|
||||
)
|
||||
.into_value(Span::test_data()),
|
||||
),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
plugin: &Self::Plugin,
|
||||
engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, LabeledError> {
|
||||
match PolarsPluginObject::try_from_pipeline(plugin, input, call.head)? {
|
||||
PolarsPluginObject::NuDataFrame(df) => command_eager(plugin, engine, call, df),
|
||||
PolarsPluginObject::NuLazyFrame(lazy) => command_lazy(plugin, engine, call, lazy),
|
||||
_ => Err(ShellError::GenericError {
|
||||
error: "Must be a dataframe or lazy dataframe".into(),
|
||||
msg: "".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
}),
|
||||
}
|
||||
.map_err(LabeledError::from)
|
||||
}
|
||||
}
|
||||
|
||||
fn command_eager(
|
||||
plugin: &PolarsPlugin,
|
||||
engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
df: NuDataFrame,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cols = call.rest::<String>(0)?;
|
||||
let polars = df.to_polars();
|
||||
let result: NuDataFrame = polars
|
||||
.unnest(cols)
|
||||
.map_err(|e| ShellError::GenericError {
|
||||
error: format!("Error unnesting dataframe: {e}"),
|
||||
msg: "".into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})?
|
||||
.into();
|
||||
result.to_pipeline_data(plugin, engine, call.head)
|
||||
}
|
||||
|
||||
fn command_lazy(
|
||||
plugin: &PolarsPlugin,
|
||||
engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
df: NuLazyFrame,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let cols = call.rest::<String>(0)?;
|
||||
|
||||
let polars = df.to_polars();
|
||||
let result: NuLazyFrame = polars.unnest(cols).into();
|
||||
result.to_pipeline_data(plugin, engine, call.head)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::test::test_polars_plugin_command;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_examples() -> Result<(), ShellError> {
|
||||
test_polars_plugin_command(&UnnestDF)
|
||||
}
|
||||
}
|
@ -31,13 +31,13 @@ impl PluginCommand for UnpivotDF {
|
||||
Signature::build(self.name())
|
||||
.required_named(
|
||||
"index",
|
||||
SyntaxShape::List(Box::new(SyntaxShape::Any)),
|
||||
SyntaxShape::Table(vec![]),
|
||||
"column names for unpivoting",
|
||||
Some('i'),
|
||||
)
|
||||
.required_named(
|
||||
"on",
|
||||
SyntaxShape::List(Box::new(SyntaxShape::Any)),
|
||||
SyntaxShape::Table(vec![]),
|
||||
"column names used as value columns",
|
||||
Some('o'),
|
||||
)
|
||||
|
@ -16,4 +16,4 @@ profile = "default"
|
||||
# use in nushell, we may opt to use the bleeding edge stable version of rust.
|
||||
# I believe rust is on a 6 week release cycle and nushell is on a 4 week release cycle.
|
||||
# So, every two nushell releases, this version number should be bumped by one.
|
||||
channel = "1.80.1"
|
||||
channel = "1.79.0"
|
||||
|
@ -238,30 +238,13 @@ fn complex_const_export() {
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert_eq!(actual.out, "eats");
|
||||
|
||||
let inp = &[MODULE_SETUP, "use spam", "'none' in $spam.eggs.bacon"];
|
||||
let inp = &[
|
||||
MODULE_SETUP,
|
||||
"use spam",
|
||||
"($spam.eggs.bacon.none | is-empty)",
|
||||
];
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert_eq!(actual.out, "false");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_nested_module_have_const() {
|
||||
let setup = r#"
|
||||
module spam {
|
||||
export module eggs {
|
||||
export module bacon {
|
||||
export const viking = 'eats'
|
||||
export module none {}
|
||||
}
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let inp = &[setup, "use spam", "$spam.eggs.bacon.viking"];
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert_eq!(actual.out, "eats");
|
||||
|
||||
let inp = &[setup, "use spam", "'none' in $spam.eggs.bacon"];
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert_eq!(actual.out, "false");
|
||||
assert_eq!(actual.out, "true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -278,16 +261,20 @@ fn complex_const_glob_export() {
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert_eq!(actual.out, "eats");
|
||||
|
||||
let inp = &[MODULE_SETUP, "use spam *", "'none' in $eggs.bacon"];
|
||||
let inp = &[MODULE_SETUP, "use spam *", "($eggs.bacon.none | is-empty)"];
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert_eq!(actual.out, "false");
|
||||
assert_eq!(actual.out, "true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_const_drill_export() {
|
||||
let inp = &[MODULE_SETUP, "use spam eggs bacon none", "$none"];
|
||||
let inp = &[
|
||||
MODULE_SETUP,
|
||||
"use spam eggs bacon none",
|
||||
"($none | is-empty)",
|
||||
];
|
||||
let actual = nu!(&inp.join("; "));
|
||||
assert!(actual.err.contains("variable not found"));
|
||||
assert_eq!(actual.out, "true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -12,7 +12,7 @@ fn plugin_list_shows_installed_plugins() {
|
||||
plugins: [("nu_plugin_inc"), ("nu_plugin_custom_values")],
|
||||
r#"(plugin list).name | str join ','"#
|
||||
);
|
||||
assert_eq!("custom_values,inc", out.out);
|
||||
assert_eq!("inc,custom_values", out.out);
|
||||
assert!(out.status.success());
|
||||
}
|
||||
|
||||
@ -34,15 +34,15 @@ fn plugin_keeps_running_after_calling_it() {
|
||||
plugin: ("nu_plugin_inc"),
|
||||
r#"
|
||||
plugin stop inc
|
||||
(plugin list).0.status == running | print
|
||||
(plugin list).0.is_running | print
|
||||
print ";"
|
||||
"2.0.0" | inc -m | ignore
|
||||
(plugin list).0.status == running | print
|
||||
(plugin list).0.is_running | print
|
||||
"#
|
||||
);
|
||||
assert_eq!(
|
||||
"false;true", out.out,
|
||||
"plugin list didn't show status = running"
|
||||
"plugin list didn't show is_running = true"
|
||||
);
|
||||
assert!(out.status.success());
|
||||
}
|
||||
@ -244,7 +244,7 @@ fn plugin_gc_can_be_configured_to_stop_plugins_immediately() {
|
||||
$env.config.plugin_gc = { default: { stop_after: 0sec } }
|
||||
"2.3.0" | inc -M
|
||||
sleep 100ms
|
||||
(plugin list | where name == inc).0.status == running
|
||||
(plugin list | where name == inc).0.is_running
|
||||
"#
|
||||
);
|
||||
assert!(out.status.success());
|
||||
@ -261,7 +261,7 @@ fn plugin_gc_can_be_configured_to_stop_plugins_immediately() {
|
||||
}
|
||||
"2.3.0" | inc -M
|
||||
sleep 100ms
|
||||
(plugin list | where name == inc).0.status == running
|
||||
(plugin list | where name == inc).0.is_running
|
||||
"#
|
||||
);
|
||||
assert!(out.status.success());
|
||||
@ -281,7 +281,7 @@ fn plugin_gc_can_be_configured_to_stop_plugins_after_delay() {
|
||||
while $cond {
|
||||
sleep 100ms
|
||||
$cond = (
|
||||
(plugin list | where name == inc).0.status == running and
|
||||
(plugin list | where name == inc).0.is_running and
|
||||
((date now) - $start) < 5sec
|
||||
)
|
||||
}
|
||||
@ -310,7 +310,7 @@ fn plugin_gc_can_be_configured_to_stop_plugins_after_delay() {
|
||||
while $cond {
|
||||
sleep 100ms
|
||||
$cond = (
|
||||
(plugin list | where name == inc).0.status == running and
|
||||
(plugin list | where name == inc).0.is_running and
|
||||
((date now) - $start) < 5sec
|
||||
)
|
||||
}
|
||||
@ -333,7 +333,7 @@ fn plugin_gc_can_be_configured_as_disabled() {
|
||||
r#"
|
||||
$env.config.plugin_gc = { default: { enabled: false, stop_after: 0sec } }
|
||||
"2.3.0" | inc -M
|
||||
(plugin list | where name == inc).0.status == running
|
||||
(plugin list | where name == inc).0.is_running
|
||||
"#
|
||||
);
|
||||
assert!(out.status.success());
|
||||
@ -350,7 +350,7 @@ fn plugin_gc_can_be_configured_as_disabled() {
|
||||
}
|
||||
}
|
||||
"2.3.0" | inc -M
|
||||
(plugin list | where name == inc).0.status == running
|
||||
(plugin list | where name == inc).0.is_running
|
||||
"#
|
||||
);
|
||||
assert!(out.status.success());
|
||||
@ -367,7 +367,7 @@ fn plugin_gc_can_be_disabled_by_plugin() {
|
||||
$env.config.plugin_gc = { default: { stop_after: 0sec } }
|
||||
example one 1 foo | ignore # ensure we've run the plugin with the new config
|
||||
sleep 100ms
|
||||
(plugin list | where name == example).0.status == running
|
||||
(plugin list | where name == example).0.is_running
|
||||
"#
|
||||
);
|
||||
assert!(out.status.success());
|
||||
|
@ -37,7 +37,7 @@ fn plugin_add_then_restart_nu() {
|
||||
--config $nu.config-path
|
||||
--env-config $nu.env-path
|
||||
--plugin-config $nu.plugin-path
|
||||
--commands 'plugin list --engine | get name | to json --raw'
|
||||
--commands 'plugin list | get name | to json --raw'
|
||||
)
|
||||
", example_plugin_path().display())
|
||||
);
|
||||
@ -69,7 +69,7 @@ fn plugin_add_in_nu_plugin_dirs_const() {
|
||||
--config $nu.config-path
|
||||
--env-config $nu.env-path
|
||||
--plugin-config $nu.plugin-path
|
||||
--commands 'plugin list --engine | get name | to json --raw'
|
||||
--commands 'plugin list | get name | to json --raw'
|
||||
)
|
||||
"#,
|
||||
dirname.display(),
|
||||
@ -103,7 +103,7 @@ fn plugin_add_in_nu_plugin_dirs_env() {
|
||||
--config $nu.config-path
|
||||
--env-config $nu.env-path
|
||||
--plugin-config $nu.plugin-path
|
||||
--commands 'plugin list --engine | get name | to json --raw'
|
||||
--commands 'plugin list | get name | to json --raw'
|
||||
)
|
||||
"#,
|
||||
dirname.display(),
|
||||
@ -199,7 +199,7 @@ fn plugin_rm_then_restart_nu() {
|
||||
"--plugin-config",
|
||||
"test-plugin-file.msgpackz",
|
||||
"--commands",
|
||||
"plugin list --engine | get name | to json --raw",
|
||||
"plugin list | get name | to json --raw",
|
||||
])
|
||||
.assert()
|
||||
.success()
|
||||
@ -364,7 +364,7 @@ fn warning_on_invalid_plugin_item() {
|
||||
"--plugin-config",
|
||||
"test-plugin-file.msgpackz",
|
||||
"--commands",
|
||||
"plugin list --engine | get name | to json --raw",
|
||||
"plugin list | get name | to json --raw",
|
||||
])
|
||||
.output()
|
||||
.expect("failed to run nu");
|
||||
@ -412,43 +412,6 @@ fn plugin_use_error_not_found() {
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_shows_up_in_default_plugin_list_after_add() {
|
||||
let example_plugin_path = example_plugin_path();
|
||||
let result = nu_with_plugins!(
|
||||
cwd: ".",
|
||||
plugins: [],
|
||||
&format!(r#"
|
||||
plugin add '{}'
|
||||
plugin list | get status | to json --raw
|
||||
"#, example_plugin_path.display())
|
||||
);
|
||||
assert!(result.status.success());
|
||||
assert_eq!(r#"["added"]"#, result.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_shows_removed_after_removing() {
|
||||
let example_plugin_path = example_plugin_path();
|
||||
let result = nu_with_plugins!(
|
||||
cwd: ".",
|
||||
plugins: [],
|
||||
&format!(r#"
|
||||
plugin add '{}'
|
||||
plugin list | get status | to json --raw
|
||||
(
|
||||
^$nu.current-exe
|
||||
--config $nu.config-path
|
||||
--env-config $nu.env-path
|
||||
--plugin-config $nu.plugin-path
|
||||
--commands 'plugin rm example; plugin list | get status | to json --raw'
|
||||
)
|
||||
"#, example_plugin_path.display())
|
||||
);
|
||||
assert!(result.status.success());
|
||||
assert_eq!(r#"["removed"]"#, result.out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plugin_add_and_then_use() {
|
||||
let example_plugin_path = example_plugin_path();
|
||||
@ -462,7 +425,7 @@ fn plugin_add_and_then_use() {
|
||||
--config $nu.config-path
|
||||
--env-config $nu.env-path
|
||||
--plugin-config $nu.plugin-path
|
||||
--commands 'plugin use example; plugin list --engine | get name | to json --raw'
|
||||
--commands 'plugin use example; plugin list | get name | to json --raw'
|
||||
)
|
||||
"#, example_plugin_path.display())
|
||||
);
|
||||
@ -483,7 +446,7 @@ fn plugin_add_and_then_use_by_filename() {
|
||||
--config $nu.config-path
|
||||
--env-config $nu.env-path
|
||||
--plugin-config $nu.plugin-path
|
||||
--commands 'plugin use '{0}'; plugin list --engine | get name | to json --raw'
|
||||
--commands 'plugin use '{0}'; plugin list | get name | to json --raw'
|
||||
)
|
||||
"#, example_plugin_path.display())
|
||||
);
|
||||
@ -508,7 +471,7 @@ fn plugin_add_then_use_with_custom_path() {
|
||||
cwd: dirs.test(),
|
||||
r#"
|
||||
plugin use --plugin-config test-plugin-file.msgpackz example
|
||||
plugin list --engine | get name | to json --raw
|
||||
plugin list | get name | to json --raw
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::repl::tests::{fail_test, run_test, run_test_contains, TestResult};
|
||||
use nu_test_support::nu;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
|
||||
#[test]
|
||||
fn no_scope_leak1() -> TestResult {
|
||||
@ -74,21 +73,10 @@ fn custom_switch1() -> TestResult {
|
||||
)
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn custom_flag_with_type_checking(
|
||||
#[values(
|
||||
("int", "\"3\""),
|
||||
("int", "null"),
|
||||
("record<i: int>", "{i: \"\"}"),
|
||||
("list<int>", "[\"\"]")
|
||||
)]
|
||||
type_sig_value: (&str, &str),
|
||||
#[values("--dry-run", "-d")] flag: &str,
|
||||
) -> TestResult {
|
||||
let (type_sig, value) = type_sig_value;
|
||||
|
||||
#[test]
|
||||
fn custom_flag_with_type_checking() -> TestResult {
|
||||
fail_test(
|
||||
&format!("def florb [{flag}: {type_sig}] {{}}; let y = {value}; florb {flag} $y"),
|
||||
r#"def florb [--dry-run: int] { $dry_run }; let y = "3"; florb --dry-run=$y"#,
|
||||
"type_mismatch",
|
||||
)
|
||||
}
|
||||
|
@ -120,11 +120,6 @@ fn export_consts() -> TestResult {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dont_export_module_name_as_a_variable() -> TestResult {
|
||||
fail_test(r#"module spam { }; use spam; $spam"#, "variable not found")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn func_use_consts() -> TestResult {
|
||||
run_test(
|
||||
|
Loading…
Reference in New Issue
Block a user