Revert PRs for 0.99.1 patch (#14119)

# Description

Temporarily reverts PRs merged after the 0.99.1 bump.
This commit is contained in:
Ian Manske 2024-10-17 19:51:14 -07:00 committed by GitHub
parent e735bd475f
commit 28b6db115a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
33 changed files with 287 additions and 782 deletions

166
Cargo.lock generated
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -46,7 +46,7 @@ impl Command for Uniq {
}
fn search_terms(&self) -> Vec<&str> {
vec!["distinct", "deduplicate", "count"]
vec!["distinct", "deduplicate"]
}
fn run(

View File

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

View File

@ -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\":[]}"
);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
"#
);

View File

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

View File

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