mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 22:57:58 +02:00
Merge branch 'main' into ecow-record
This commit is contained in:
@ -5,26 +5,26 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cli"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cli"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.92.3" }
|
||||
nu-command = { path = "../nu-command", version = "0.92.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.92.3" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.93.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.93.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.93.1" }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.92.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.92.3" }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.92.3", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.92.3" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.92.3" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.93.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.93.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.93.1" }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.93.1", optional = true }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.93.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.93.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
reedline = { workspace = true, features = ["bashisms", "sqlite"] }
|
||||
|
||||
@ -45,5 +45,5 @@ uuid = { workspace = true, features = ["v4"] }
|
||||
which = { workspace = true }
|
||||
|
||||
[features]
|
||||
plugin = ["nu-plugin"]
|
||||
plugin = ["nu-plugin-engine"]
|
||||
system-clipboard = ["reedline/system_clipboard"]
|
||||
|
@ -1,5 +1,4 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Commandline;
|
||||
@ -11,45 +10,12 @@ impl Command for Commandline {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("commandline")
|
||||
.input_output_types(vec![
|
||||
(Type::Nothing, Type::Nothing),
|
||||
(Type::String, Type::String),
|
||||
])
|
||||
.switch(
|
||||
"cursor",
|
||||
"Set or get the current cursor position",
|
||||
Some('c'),
|
||||
)
|
||||
.switch(
|
||||
"cursor-end",
|
||||
"Set the current cursor position to the end of the buffer",
|
||||
Some('e'),
|
||||
)
|
||||
.switch(
|
||||
"append",
|
||||
"appends the string to the end of the buffer",
|
||||
Some('a'),
|
||||
)
|
||||
.switch(
|
||||
"insert",
|
||||
"inserts the string into the buffer at the cursor position",
|
||||
Some('i'),
|
||||
)
|
||||
.switch(
|
||||
"replace",
|
||||
"replaces the current contents of the buffer (default)",
|
||||
Some('r'),
|
||||
)
|
||||
.optional(
|
||||
"cmd",
|
||||
SyntaxShape::String,
|
||||
"the string to perform the operation with",
|
||||
)
|
||||
.input_output_types(vec![(Type::Nothing, Type::String)])
|
||||
.category(Category::Core)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"View or modify the current command line input buffer."
|
||||
"View the current command line input buffer."
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
@ -59,126 +25,11 @@ impl Command for Commandline {
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
_stack: &mut Stack,
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
if let Some(cmd) = call.opt::<Value>(engine_state, stack, 0)? {
|
||||
let span = cmd.span();
|
||||
let cmd = cmd.coerce_into_string()?;
|
||||
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
|
||||
|
||||
if call.has_flag(engine_state, stack, "cursor")? {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "`--cursor (-c)` is deprecated".into(),
|
||||
msg: "Setting the current cursor position by `--cursor (-c)` is deprecated"
|
||||
.into(),
|
||||
span: Some(call.arguments_span()),
|
||||
help: Some("Use `commandline set-cursor`".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
match cmd.parse::<i64>() {
|
||||
Ok(n) => {
|
||||
repl.cursor_pos = if n <= 0 {
|
||||
0usize
|
||||
} else {
|
||||
repl.buffer
|
||||
.grapheme_indices(true)
|
||||
.map(|(i, _c)| i)
|
||||
.nth(n as usize)
|
||||
.unwrap_or(repl.buffer.len())
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(ShellError::CantConvert {
|
||||
to_type: "int".to_string(),
|
||||
from_type: "string".to_string(),
|
||||
span,
|
||||
help: Some(format!(r#"string "{cmd}" does not represent a valid int"#)),
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if call.has_flag(engine_state, stack, "append")? {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "`--append (-a)` is deprecated".into(),
|
||||
msg: "Appending the string to the end of the buffer by `--append (-a)` is deprecated".into(),
|
||||
span: Some(call.arguments_span()),
|
||||
help: Some("Use `commandline edit --append (-a)`".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
repl.buffer.push_str(&cmd);
|
||||
} else if call.has_flag(engine_state, stack, "insert")? {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "`--insert (-i)` is deprecated".into(),
|
||||
msg: "Inserts the string into the buffer at the cursor position by `--insert (-i)` is deprecated".into(),
|
||||
span: Some(call.arguments_span()),
|
||||
help: Some("Use `commandline edit --insert (-i)`".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
let cursor_pos = repl.cursor_pos;
|
||||
repl.buffer.insert_str(cursor_pos, &cmd);
|
||||
repl.cursor_pos += cmd.len();
|
||||
} else {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "`--replace (-r)` is deprecated".into(),
|
||||
msg: "Replacing the current contents of the buffer by `--replace (-p)` or positional argument is deprecated".into(),
|
||||
span: Some(call.arguments_span()),
|
||||
help: Some("Use `commandline edit --replace (-r)`".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
repl.buffer = cmd;
|
||||
repl.cursor_pos = repl.buffer.len();
|
||||
}
|
||||
Ok(Value::nothing(call.head).into_pipeline_data())
|
||||
} else {
|
||||
let mut repl = engine_state.repl_state.lock().expect("repl state mutex");
|
||||
if call.has_flag(engine_state, stack, "cursor-end")? {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "`--cursor-end (-e)` is deprecated".into(),
|
||||
msg: "Setting the current cursor position to the end of the buffer by `--cursor-end (-e)` is deprecated".into(),
|
||||
span: Some(call.arguments_span()),
|
||||
help: Some("Use `commandline set-cursor --end (-e)`".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
repl.cursor_pos = repl.buffer.len();
|
||||
Ok(Value::nothing(call.head).into_pipeline_data())
|
||||
} else if call.has_flag(engine_state, stack, "cursor")? {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "`--cursor (-c)` is deprecated".into(),
|
||||
msg: "Getting the current cursor position by `--cursor (-c)` is deprecated"
|
||||
.into(),
|
||||
span: Some(call.arguments_span()),
|
||||
help: Some("Use `commandline get-cursor`".into()),
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
let char_pos = repl
|
||||
.buffer
|
||||
.grapheme_indices(true)
|
||||
.chain(std::iter::once((repl.buffer.len(), "")))
|
||||
.position(|(i, _c)| i == repl.cursor_pos)
|
||||
.expect("Cursor position isn't on a grapheme boundary");
|
||||
Ok(Value::string(char_pos.to_string(), call.head).into_pipeline_data())
|
||||
} else {
|
||||
Ok(Value::string(repl.buffer.to_string(), call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
let repl = engine_state.repl_state.lock().expect("repl state mutex");
|
||||
Ok(Value::string(repl.buffer.clone(), call.head).into_pipeline_data())
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ impl Command for KeybindingsDefault {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.category(Category::Platform)
|
||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -14,7 +14,7 @@ impl Command for KeybindingsList {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
.switch("modifiers", "list of modifiers", Some('m'))
|
||||
.switch("keycodes", "list of keycodes", Some('k'))
|
||||
.switch("modes", "list of edit modes", Some('o'))
|
||||
|
@ -6,7 +6,7 @@ use nu_protocol::{
|
||||
report_error, HistoryFileFormat, PipelineData,
|
||||
};
|
||||
#[cfg(feature = "plugin")]
|
||||
use nu_protocol::{ParseError, PluginCacheFile, Spanned};
|
||||
use nu_protocol::{ParseError, PluginRegistryFile, Spanned};
|
||||
#[cfg(feature = "plugin")]
|
||||
use nu_utils::utils::perf;
|
||||
use std::path::PathBuf;
|
||||
@ -51,7 +51,7 @@ pub fn read_plugin_file(
|
||||
}
|
||||
|
||||
let mut start_time = std::time::Instant::now();
|
||||
// Reading signatures from plugin cache file
|
||||
// Reading signatures from plugin registry file
|
||||
// The plugin.msgpackz file stores the parsed signature collected from each registered plugin
|
||||
add_plugin_file(engine_state, plugin_file.clone(), storage_path);
|
||||
perf(
|
||||
@ -89,7 +89,7 @@ pub fn read_plugin_file(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: format!(
|
||||
"Error while opening plugin cache file: {}",
|
||||
"Error while opening plugin registry file: {}",
|
||||
plugin_path.display()
|
||||
),
|
||||
msg: "plugin path defined here".into(),
|
||||
@ -113,15 +113,15 @@ pub fn read_plugin_file(
|
||||
}
|
||||
|
||||
// Read the contents of the plugin file
|
||||
let contents = match PluginCacheFile::read_from(&mut file, span) {
|
||||
let contents = match PluginRegistryFile::read_from(&mut file, span) {
|
||||
Ok(contents) => contents,
|
||||
Err(err) => {
|
||||
log::warn!("Failed to read plugin cache file: {err:?}");
|
||||
log::warn!("Failed to read plugin registry file: {err:?}");
|
||||
report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: format!(
|
||||
"Error while reading plugin cache file: {}",
|
||||
"Error while reading plugin registry file: {}",
|
||||
plugin_path.display()
|
||||
),
|
||||
msg: "plugin path defined here".into(),
|
||||
@ -150,7 +150,7 @@ pub fn read_plugin_file(
|
||||
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
nu_plugin::load_plugin_file(&mut working_set, &contents, span);
|
||||
nu_plugin_engine::load_plugin_file(&mut working_set, &contents, span);
|
||||
|
||||
if let Err(err) = engine_state.merge_delta(working_set.render()) {
|
||||
report_error_new(engine_state, &err);
|
||||
@ -265,8 +265,8 @@ pub(crate) fn get_history_path(storage_path: &str, mode: HistoryFileFormat) -> O
|
||||
#[cfg(feature = "plugin")]
|
||||
pub fn migrate_old_plugin_file(engine_state: &EngineState, storage_path: &str) -> bool {
|
||||
use nu_protocol::{
|
||||
report_error_new, PluginCacheItem, PluginCacheItemData, PluginExample, PluginIdentity,
|
||||
PluginSignature, ShellError,
|
||||
report_error_new, PluginExample, PluginIdentity, PluginRegistryItem,
|
||||
PluginRegistryItemData, PluginSignature, ShellError,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@ -318,7 +318,7 @@ pub fn migrate_old_plugin_file(engine_state: &EngineState, storage_path: &str) -
|
||||
}
|
||||
|
||||
// Now that the plugin commands are loaded, we just have to generate the file
|
||||
let mut contents = PluginCacheFile::new();
|
||||
let mut contents = PluginRegistryFile::new();
|
||||
|
||||
let mut groups = BTreeMap::<PluginIdentity, Vec<PluginSignature>>::new();
|
||||
|
||||
@ -339,11 +339,11 @@ pub fn migrate_old_plugin_file(engine_state: &EngineState, storage_path: &str) -
|
||||
}
|
||||
|
||||
for (identity, commands) in groups {
|
||||
contents.upsert_plugin(PluginCacheItem {
|
||||
contents.upsert_plugin(PluginRegistryItem {
|
||||
name: identity.name().to_owned(),
|
||||
filename: identity.filename().to_owned(),
|
||||
shell: identity.shell().map(|p| p.to_owned()),
|
||||
data: PluginCacheItemData::Valid { commands },
|
||||
data: PluginRegistryItemData::Valid { commands },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,11 @@ use nu_engine::{convert_env_values, current_dir, eval_block};
|
||||
use nu_parser::parse;
|
||||
use nu_path::canonicalize_with;
|
||||
use nu_protocol::{
|
||||
ast::Call,
|
||||
debugger::WithoutDebug,
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
report_error, Config, PipelineData, ShellError, Span, Value,
|
||||
};
|
||||
use nu_utils::stdout_write_all_and_flush;
|
||||
use std::sync::Arc;
|
||||
use std::{io::Write, sync::Arc};
|
||||
|
||||
/// Entry point for evaluating a file.
|
||||
///
|
||||
@ -210,29 +208,8 @@ pub(crate) fn print_table_or_error(
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if let Some(decl_id) = engine_state.find_decl("table".as_bytes(), &[]) {
|
||||
let command = engine_state.get_decl(decl_id);
|
||||
if command.get_block_id().is_some() {
|
||||
print_or_exit(pipeline_data, engine_state, config, no_newline);
|
||||
} else {
|
||||
// The final call on table command, it's ok to set redirect_output to false.
|
||||
let call = Call::new(Span::new(0, 0));
|
||||
let table = command.run(engine_state, stack, &call, pipeline_data);
|
||||
|
||||
match table {
|
||||
Ok(table) => {
|
||||
print_or_exit(table, engine_state, config, no_newline);
|
||||
}
|
||||
Err(error) => {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &error);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
print_or_exit(pipeline_data, engine_state, config, no_newline);
|
||||
}
|
||||
// We don't need to do anything special to print a table because print() handles it
|
||||
print_or_exit(pipeline_data, engine_state, stack, no_newline);
|
||||
|
||||
// Make sure everything has finished
|
||||
if let Some(exit_code) = exit_code {
|
||||
@ -250,23 +227,19 @@ pub(crate) fn print_table_or_error(
|
||||
|
||||
fn print_or_exit(
|
||||
pipeline_data: PipelineData,
|
||||
engine_state: &mut EngineState,
|
||||
config: &Config,
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
no_newline: bool,
|
||||
) {
|
||||
for item in pipeline_data {
|
||||
if let Value::Error { error, .. } = item {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
let result = pipeline_data.print(engine_state, stack, no_newline, false);
|
||||
|
||||
report_error(&working_set, &*error);
|
||||
let _ = std::io::stdout().flush();
|
||||
let _ = std::io::stderr().flush();
|
||||
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let mut out = item.to_expanded_string("\n", config);
|
||||
if !no_newline {
|
||||
out.push('\n');
|
||||
}
|
||||
let _ = stdout_write_all_and_flush(out).map_err(|err| eprintln!("{err}"));
|
||||
if let Err(error) = result {
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
report_error(&working_set, &error);
|
||||
let _ = std::io::stderr().flush();
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ fn find_matching_block_end_in_expr(
|
||||
Expr::Nothing => None,
|
||||
Expr::Garbage => None,
|
||||
|
||||
Expr::Table(hdr, rows) => {
|
||||
Expr::Table(table) => {
|
||||
if expr_last == global_cursor_offset {
|
||||
// cursor is at table end
|
||||
Some(expr_first)
|
||||
@ -370,11 +370,11 @@ fn find_matching_block_end_in_expr(
|
||||
Some(expr_last)
|
||||
} else {
|
||||
// cursor is inside table
|
||||
for inner_expr in hdr {
|
||||
for inner_expr in table.columns.as_ref() {
|
||||
find_in_expr_or_continue!(inner_expr);
|
||||
}
|
||||
for row in rows {
|
||||
for inner_expr in row {
|
||||
for row in table.rows.as_ref() {
|
||||
for inner_expr in row.as_ref() {
|
||||
find_in_expr_or_continue!(inner_expr);
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,15 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-base"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-base"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.92.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.92.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.93.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.93.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
|
||||
indexmap = { workspace = true }
|
||||
miette = { workspace = true }
|
||||
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-dataframe"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-dataframe"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,9 +13,9 @@ version = "0.92.3"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.92.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.93.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
chrono = { workspace = true, features = ["std", "unstable-locales"], default-features = false }
|
||||
@ -72,4 +72,4 @@ dataframe = ["num", "polars", "polars-io", "polars-arrow", "polars-ops", "polars
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.92.3" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.93.1" }
|
||||
|
@ -24,7 +24,7 @@ impl Command for ToNu {
|
||||
.switch("tail", "shows tail rows", Some('t'))
|
||||
.input_output_types(vec![
|
||||
(Type::Custom("expression".into()), Type::Any),
|
||||
(Type::Custom("dataframe".into()), Type::Table(vec![])),
|
||||
(Type::Custom("dataframe".into()), Type::table()),
|
||||
])
|
||||
//.input_output_type(Type::Any, Type::Any)
|
||||
.category(Category::Custom("dataframe".into()))
|
||||
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-extra"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-extra"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,13 +13,13 @@ version = "0.92.3"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-json = { version = "0.92.3", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.92.3" }
|
||||
nu-pretty-hex = { version = "0.92.3", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.92.3" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.93.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-json = { version = "0.93.1", path = "../nu-json" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.93.1" }
|
||||
nu-pretty-hex = { version = "0.93.1", path = "../nu-pretty-hex" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.93.1" }
|
||||
|
||||
# Potential dependencies for extras
|
||||
heck = { workspace = true }
|
||||
@ -37,6 +37,6 @@ extra = ["default"]
|
||||
default = []
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.92.3" }
|
||||
nu-command = { path = "../nu-command", version = "0.92.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.92.3" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.93.1" }
|
||||
nu-command = { path = "../nu-command", version = "0.93.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.93.1" }
|
||||
|
@ -30,8 +30,8 @@ impl Command for BitsInto {
|
||||
(Type::Duration, Type::String),
|
||||
(Type::String, Type::String),
|
||||
(Type::Bool, Type::String),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true) // TODO: supply exhaustive examples
|
||||
.rest(
|
||||
@ -64,7 +64,7 @@ impl Command for BitsInto {
|
||||
vec![
|
||||
Example {
|
||||
description: "convert a binary value into a string, padded to 8 places with 0s",
|
||||
example: "01b | into bits",
|
||||
example: "0x[1] | into bits",
|
||||
result: Some(Value::string("00000001",
|
||||
Span::test_data(),
|
||||
)),
|
||||
|
@ -15,7 +15,7 @@ impl Command for Fmt {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("fmt")
|
||||
.input_output_types(vec![(Type::Number, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::Number, Type::record())])
|
||||
.category(Category::Conversions)
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ impl Command for RollDown {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
// TODO: It also operates on List
|
||||
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.named("by", SyntaxShape::Int, "Number of rows to roll", Some('b'))
|
||||
.category(Category::Filters)
|
||||
}
|
||||
|
@ -16,8 +16,8 @@ impl Command for RollLeft {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.input_output_types(vec![
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::record(), Type::record()),
|
||||
(Type::table(), Type::table()),
|
||||
])
|
||||
.named(
|
||||
"by",
|
||||
|
@ -16,8 +16,8 @@ impl Command for RollRight {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.input_output_types(vec![
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::record(), Type::record()),
|
||||
(Type::table(), Type::table()),
|
||||
])
|
||||
.named(
|
||||
"by",
|
||||
|
@ -16,7 +16,7 @@ impl Command for RollUp {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
// TODO: It also operates on List
|
||||
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.named("by", SyntaxShape::Int, "Number of rows to roll", Some('b'))
|
||||
.category(Category::Filters)
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ impl Command for Rotate {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("rotate")
|
||||
.input_output_types(vec![
|
||||
(Type::Record(vec![]), Type::Table(vec![])),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::record(), Type::table()),
|
||||
(Type::table(), Type::table()),
|
||||
])
|
||||
.switch("ccw", "rotate counter clockwise", None)
|
||||
.rest(
|
||||
|
@ -12,7 +12,7 @@ impl Command for UpdateCells {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("update cells")
|
||||
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.required(
|
||||
"closure",
|
||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||
|
@ -10,7 +10,7 @@ impl Command for FromUrl {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("from url")
|
||||
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::String, Type::record())])
|
||||
.category(Category::Formats)
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Platform)
|
||||
|
@ -17,8 +17,8 @@ impl Command for DecodeHex {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -17,8 +17,8 @@ impl Command for EncodeHex {
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -13,8 +13,8 @@ impl Command for FormatPattern {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("format pattern")
|
||||
.input_output_types(vec![
|
||||
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
||||
(Type::Record(vec![]), Type::Any),
|
||||
(Type::table(), Type::List(Box::new(Type::String))),
|
||||
(Type::record(), Type::Any),
|
||||
])
|
||||
.required(
|
||||
"pattern",
|
||||
|
@ -18,8 +18,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -14,8 +14,8 @@ impl Command for SubCommand {
|
||||
Signature::build("str kebab-case")
|
||||
.input_output_types(vec![
|
||||
(Type::String, Type::String),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
(
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
|
@ -14,8 +14,8 @@ impl Command for SubCommand {
|
||||
Signature::build("str pascal-case")
|
||||
.input_output_types(vec![
|
||||
(Type::String, Type::String),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
(
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
|
@ -18,8 +18,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -18,8 +18,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -18,8 +18,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -6,16 +6,16 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-lang"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-lang"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.92.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.93.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.93.1" }
|
||||
|
||||
itertools = { workspace = true }
|
||||
shadow-rs = { version = "0.27", default-features = false }
|
||||
|
@ -38,12 +38,12 @@ impl Command for Collect {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let closure: Closure = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let block = engine_state.get_block(closure.block_id).clone();
|
||||
let block = engine_state.get_block(closure.block_id);
|
||||
let mut stack_captures =
|
||||
stack.captures_to_stack_preserve_out_dest(closure.captures.clone());
|
||||
|
||||
let metadata = input.metadata();
|
||||
let input: Value = input.into_value(call.head);
|
||||
let input = input.into_value(call.head);
|
||||
|
||||
let mut saved_positional = None;
|
||||
if let Some(var) = block.signature.get_positional(0) {
|
||||
@ -58,7 +58,7 @@ impl Command for Collect {
|
||||
let result = eval_block(
|
||||
engine_state,
|
||||
&mut stack_captures,
|
||||
&block,
|
||||
block,
|
||||
input.into_pipeline_data(),
|
||||
)
|
||||
.map(|x| x.set_metadata(metadata));
|
||||
|
@ -46,6 +46,19 @@ impl Command for Describe {
|
||||
detailed: call.has_flag(engine_state, stack, "detailed")?,
|
||||
collect_lazyrecords: call.has_flag(engine_state, stack, "collect-lazyrecords")?,
|
||||
};
|
||||
if options.collect_lazyrecords {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "Deprecated flag".into(),
|
||||
msg: "the `--collect-lazyrecords` flag is deprecated, since lazy records will be removed in 0.94.0"
|
||||
.into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
}
|
||||
run(Some(engine_state), call, input, options)
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ impl Command for Do {
|
||||
None,
|
||||
)
|
||||
})
|
||||
.map_err(|e| e.into_spanned(call.head))
|
||||
.err_span(call.head)
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
|
@ -41,11 +41,7 @@ impl Command for HideEnv {
|
||||
|
||||
for name in env_var_names {
|
||||
if !stack.remove_env_var(engine_state, &name.item) && !ignore_errors {
|
||||
let all_names: Vec<String> = stack
|
||||
.get_env_var_names(engine_state)
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
let all_names = stack.get_env_var_names(engine_state);
|
||||
if let Some(closest_match) = did_you_mean(&all_names, &name.item) {
|
||||
return Err(ShellError::DidYouMeanCustom {
|
||||
msg: format!("Environment variable '{}' not found", name.item),
|
||||
|
@ -59,43 +59,27 @@ impl Command for If {
|
||||
.expect("internal error: missing block");
|
||||
let else_case = call.positional_nth(2);
|
||||
|
||||
let result = eval_constant(working_set, cond)?;
|
||||
match &result {
|
||||
Value::Bool { val, .. } => {
|
||||
if *val {
|
||||
let block = working_set.get_block(then_block);
|
||||
if eval_constant(working_set, cond)?.as_bool()? {
|
||||
let block = working_set.get_block(then_block);
|
||||
eval_const_subexpression(working_set, block, input, block.span.unwrap_or(call.head))
|
||||
} else if let Some(else_case) = else_case {
|
||||
if let Some(else_expr) = else_case.as_keyword() {
|
||||
if let Some(block_id) = else_expr.as_block() {
|
||||
let block = working_set.get_block(block_id);
|
||||
eval_const_subexpression(
|
||||
working_set,
|
||||
block,
|
||||
input,
|
||||
block.span.unwrap_or(call.head),
|
||||
)
|
||||
} else if let Some(else_case) = else_case {
|
||||
if let Some(else_expr) = else_case.as_keyword() {
|
||||
if let Some(block_id) = else_expr.as_block() {
|
||||
let block = working_set.get_block(block_id);
|
||||
eval_const_subexpression(
|
||||
working_set,
|
||||
block,
|
||||
input,
|
||||
block.span.unwrap_or(call.head),
|
||||
)
|
||||
} else {
|
||||
eval_constant_with_input(working_set, else_expr, input)
|
||||
}
|
||||
} else {
|
||||
eval_constant_with_input(working_set, else_case, input)
|
||||
}
|
||||
} else {
|
||||
Ok(PipelineData::empty())
|
||||
eval_constant_with_input(working_set, else_expr, input)
|
||||
}
|
||||
} else {
|
||||
eval_constant_with_input(working_set, else_case, input)
|
||||
}
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "bool".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: result.span(),
|
||||
help: None,
|
||||
}),
|
||||
} else {
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,35 +102,23 @@ impl Command for If {
|
||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
let result = eval_expression(engine_state, stack, cond)?;
|
||||
match &result {
|
||||
Value::Bool { val, .. } => {
|
||||
if *val {
|
||||
let block = engine_state.get_block(then_block);
|
||||
if eval_expression(engine_state, stack, cond)?.as_bool()? {
|
||||
let block = engine_state.get_block(then_block);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else if let Some(else_case) = else_case {
|
||||
if let Some(else_expr) = else_case.as_keyword() {
|
||||
if let Some(block_id) = else_expr.as_block() {
|
||||
let block = engine_state.get_block(block_id);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else if let Some(else_case) = else_case {
|
||||
if let Some(else_expr) = else_case.as_keyword() {
|
||||
if let Some(block_id) = else_expr.as_block() {
|
||||
let block = engine_state.get_block(block_id);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else {
|
||||
eval_expression_with_input(engine_state, stack, else_expr, input)
|
||||
.map(|res| res.0)
|
||||
}
|
||||
} else {
|
||||
eval_expression_with_input(engine_state, stack, else_case, input)
|
||||
.map(|res| res.0)
|
||||
}
|
||||
} else {
|
||||
Ok(PipelineData::empty())
|
||||
eval_expression_with_input(engine_state, stack, else_expr, input)
|
||||
.map(|res| res.0)
|
||||
}
|
||||
} else {
|
||||
eval_expression_with_input(engine_state, stack, else_case, input).map(|res| res.0)
|
||||
}
|
||||
x => Err(ShellError::CantConvert {
|
||||
to_type: "bool".into(),
|
||||
from_type: x.get_type().to_string(),
|
||||
span: result.span(),
|
||||
help: None,
|
||||
}),
|
||||
} else {
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ impl Command for LazyMake {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("lazy make")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::record())])
|
||||
.required_named(
|
||||
"columns",
|
||||
SyntaxShape::List(Box::new(SyntaxShape::String)),
|
||||
@ -54,6 +54,18 @@ impl Command for LazyMake {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
nu_protocol::report_error_new(
|
||||
engine_state,
|
||||
&ShellError::GenericError {
|
||||
error: "Deprecated command".into(),
|
||||
msg: "warning: lazy records and the `lazy make` command will be removed in 0.94.0"
|
||||
.into(),
|
||||
span: Some(call.head),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
},
|
||||
);
|
||||
|
||||
let span = call.head;
|
||||
let columns: Vec<Spanned<String>> = call
|
||||
.get_flag(engine_state, stack, "columns")?
|
||||
|
@ -61,7 +61,7 @@ impl Command for Let {
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
let stack = &mut stack.start_capture();
|
||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
||||
let mut value = pipeline_data.into_value(call.head);
|
||||
let value = pipeline_data.into_value(call.head);
|
||||
|
||||
// if given variable type is Glob, and our result is string
|
||||
// then nushell need to convert from Value::String to Value::Glob
|
||||
@ -69,12 +69,12 @@ impl Command for Let {
|
||||
// if we pass it to other commands.
|
||||
let var_type = &engine_state.get_var(var_id).ty;
|
||||
let val_span = value.span();
|
||||
match value {
|
||||
let value = match value {
|
||||
Value::String { val, .. } if var_type == &Type::Glob => {
|
||||
value = Value::glob(val, false, val_span);
|
||||
Value::glob(val, false, val_span)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
value => value,
|
||||
};
|
||||
|
||||
stack.add_var(var_id, value);
|
||||
Ok(PipelineData::empty())
|
||||
|
@ -1,10 +1,7 @@
|
||||
use nu_engine::{
|
||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
||||
};
|
||||
use nu_protocol::{
|
||||
ast::{Expr, Expression},
|
||||
engine::Matcher,
|
||||
};
|
||||
use nu_protocol::engine::Matcher;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Match;
|
||||
@ -38,45 +35,45 @@ impl Command for Match {
|
||||
input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let value: Value = call.req(engine_state, stack, 0)?;
|
||||
let block = call.positional_nth(1);
|
||||
let matches = call
|
||||
.positional_nth(1)
|
||||
.expect("checked through parser")
|
||||
.as_match_block()
|
||||
.expect("missing match block");
|
||||
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
if let Some(Expression {
|
||||
expr: Expr::MatchBlock(matches),
|
||||
..
|
||||
}) = block
|
||||
{
|
||||
for match_ in matches {
|
||||
let mut match_variables = vec![];
|
||||
if match_.0.match_value(&value, &mut match_variables) {
|
||||
// This case does match, go ahead and return the evaluated expression
|
||||
for match_variable in match_variables {
|
||||
stack.add_var(match_variable.0, match_variable.1);
|
||||
}
|
||||
let mut match_variables = vec![];
|
||||
for (pattern, expr) in matches {
|
||||
if pattern.match_value(&value, &mut match_variables) {
|
||||
// This case does match, go ahead and return the evaluated expression
|
||||
for (id, value) in match_variables.drain(..) {
|
||||
stack.add_var(id, value);
|
||||
}
|
||||
|
||||
let guard_matches = if let Some(guard) = &match_.0.guard {
|
||||
let Value::Bool { val, .. } = eval_expression(engine_state, stack, guard)?
|
||||
else {
|
||||
return Err(ShellError::MatchGuardNotBool { span: guard.span });
|
||||
};
|
||||
|
||||
val
|
||||
} else {
|
||||
true
|
||||
let guard_matches = if let Some(guard) = &pattern.guard {
|
||||
let Value::Bool { val, .. } = eval_expression(engine_state, stack, guard)?
|
||||
else {
|
||||
return Err(ShellError::MatchGuardNotBool { span: guard.span });
|
||||
};
|
||||
|
||||
if guard_matches {
|
||||
return if let Some(block_id) = match_.1.as_block() {
|
||||
let block = engine_state.get_block(block_id);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else {
|
||||
eval_expression_with_input(engine_state, stack, &match_.1, input)
|
||||
.map(|x| x.0)
|
||||
};
|
||||
}
|
||||
val
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if guard_matches {
|
||||
return if let Some(block_id) = expr.as_block() {
|
||||
let block = engine_state.get_block(block_id);
|
||||
eval_block(engine_state, stack, block, input)
|
||||
} else {
|
||||
eval_expression_with_input(engine_state, stack, expr, input).map(|x| x.0)
|
||||
};
|
||||
}
|
||||
} else {
|
||||
match_variables.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ impl Command for Mut {
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
let stack = &mut stack.start_capture();
|
||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
||||
let mut value = pipeline_data.into_value(call.head);
|
||||
let value = pipeline_data.into_value(call.head);
|
||||
|
||||
// if given variable type is Glob, and our result is string
|
||||
// then nushell need to convert from Value::String to Value::Glob
|
||||
@ -69,12 +69,12 @@ impl Command for Mut {
|
||||
// if we pass it to other commands.
|
||||
let var_type = &engine_state.get_var(var_id).ty;
|
||||
let val_span = value.span();
|
||||
match value {
|
||||
let value = match value {
|
||||
Value::String { val, .. } if var_type == &Type::Glob => {
|
||||
value = Value::glob(val, false, val_span);
|
||||
Value::glob(val, false, val_span)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
value => value,
|
||||
};
|
||||
|
||||
stack.add_var(var_id, value);
|
||||
Ok(PipelineData::empty())
|
||||
|
@ -40,17 +40,11 @@ impl Command for Return {
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let return_value: Option<Value> = call.opt(engine_state, stack, 0)?;
|
||||
if let Some(value) = return_value {
|
||||
Err(ShellError::Return {
|
||||
span: call.head,
|
||||
value: Box::new(value),
|
||||
})
|
||||
} else {
|
||||
Err(ShellError::Return {
|
||||
span: call.head,
|
||||
value: Box::new(Value::nothing(call.head)),
|
||||
})
|
||||
}
|
||||
let value = return_value.unwrap_or(Value::nothing(call.head));
|
||||
Err(ShellError::Return {
|
||||
span: call.head,
|
||||
value: Box::new(value),
|
||||
})
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
|
@ -49,9 +49,7 @@ impl Command for Try {
|
||||
let try_block = engine_state.get_block(try_block);
|
||||
let eval_block = get_eval_block(engine_state);
|
||||
|
||||
let result = eval_block(engine_state, stack, try_block, input);
|
||||
|
||||
match result {
|
||||
match eval_block(engine_state, stack, try_block, input) {
|
||||
Err(error) => {
|
||||
let error = intercept_block_control(error)?;
|
||||
let err_record = err_to_record(error, call.head);
|
||||
@ -66,9 +64,8 @@ impl Command for Try {
|
||||
Ok(pipeline) => {
|
||||
let (pipeline, external_failed) = pipeline.check_external_failed();
|
||||
if external_failed {
|
||||
// Because external command errors aren't "real" errors,
|
||||
// (unless do -c is in effect)
|
||||
// they can't be passed in as Nushell values.
|
||||
let exit_code = pipeline.drain_with_exit_code()?;
|
||||
stack.add_env_var("LAST_EXIT_CODE".into(), Value::int(exit_code, call.head));
|
||||
let err_value = Value::nothing(call.head);
|
||||
handle_catch(err_value, catch_block, engine_state, stack, eval_block)
|
||||
} else {
|
||||
|
@ -16,7 +16,7 @@ impl Command for Version {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("version")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::record())])
|
||||
.allow_variants_without_examples(true)
|
||||
.category(Category::Core)
|
||||
}
|
||||
@ -36,7 +36,7 @@ impl Command for Version {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
version(engine_state, call)
|
||||
version(engine_state, call.head)
|
||||
}
|
||||
|
||||
fn run_const(
|
||||
@ -45,7 +45,7 @@ impl Command for Version {
|
||||
call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
version(working_set.permanent(), call)
|
||||
version(working_set.permanent(), call.head)
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -57,7 +57,13 @@ impl Command for Version {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(engine_state: &EngineState, call: &Call) -> Result<PipelineData, ShellError> {
|
||||
fn push_non_empty(record: &mut Record, name: &str, value: &str, span: Span) {
|
||||
if !value.is_empty() {
|
||||
record.push(name, Value::string(value, span))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn version(engine_state: &EngineState, span: Span) -> Result<PipelineData, ShellError> {
|
||||
// Pre-allocate the arrays in the worst case (17 items):
|
||||
// - version
|
||||
// - major
|
||||
@ -69,6 +75,7 @@ pub fn version(engine_state: &EngineState, call: &Call) -> Result<PipelineData,
|
||||
// - build_os
|
||||
// - build_target
|
||||
// - rust_version
|
||||
// - rust_channel
|
||||
// - cargo_version
|
||||
// - build_time
|
||||
// - build_rust_channel
|
||||
@ -77,68 +84,36 @@ pub fn version(engine_state: &EngineState, call: &Call) -> Result<PipelineData,
|
||||
// - installed_plugins
|
||||
let mut record = Record::with_capacity(17);
|
||||
|
||||
record.push(
|
||||
"version",
|
||||
Value::string(env!("CARGO_PKG_VERSION"), call.head),
|
||||
record.push("version", Value::string(env!("CARGO_PKG_VERSION"), span));
|
||||
|
||||
push_version_numbers(&mut record, span);
|
||||
|
||||
push_non_empty(&mut record, "pre", build::PKG_VERSION_PRE, span);
|
||||
|
||||
record.push("branch", Value::string(build::BRANCH, span));
|
||||
|
||||
if let Some(commit_hash) = option_env!("NU_COMMIT_HASH") {
|
||||
record.push("commit_hash", Value::string(commit_hash, span));
|
||||
}
|
||||
|
||||
push_non_empty(&mut record, "build_os", build::BUILD_OS, span);
|
||||
push_non_empty(&mut record, "build_target", build::BUILD_TARGET, span);
|
||||
push_non_empty(&mut record, "rust_version", build::RUST_VERSION, span);
|
||||
push_non_empty(&mut record, "rust_channel", build::RUST_CHANNEL, span);
|
||||
push_non_empty(&mut record, "cargo_version", build::CARGO_VERSION, span);
|
||||
push_non_empty(&mut record, "build_time", build::BUILD_TIME, span);
|
||||
push_non_empty(
|
||||
&mut record,
|
||||
"build_rust_channel",
|
||||
build::BUILD_RUST_CHANNEL,
|
||||
span,
|
||||
);
|
||||
|
||||
push_version_numbers(&mut record, call.head);
|
||||
|
||||
let version_pre = Some(build::PKG_VERSION_PRE).filter(|x| !x.is_empty());
|
||||
if let Some(version_pre) = version_pre {
|
||||
record.push("pre", Value::string(version_pre, call.head));
|
||||
}
|
||||
|
||||
record.push("branch", Value::string(build::BRANCH, call.head));
|
||||
|
||||
let commit_hash = option_env!("NU_COMMIT_HASH");
|
||||
if let Some(commit_hash) = commit_hash {
|
||||
record.push("commit_hash", Value::string(commit_hash, call.head));
|
||||
}
|
||||
|
||||
let build_os = Some(build::BUILD_OS).filter(|x| !x.is_empty());
|
||||
if let Some(build_os) = build_os {
|
||||
record.push("build_os", Value::string(build_os, call.head));
|
||||
}
|
||||
|
||||
let build_target = Some(build::BUILD_TARGET).filter(|x| !x.is_empty());
|
||||
if let Some(build_target) = build_target {
|
||||
record.push("build_target", Value::string(build_target, call.head));
|
||||
}
|
||||
|
||||
let rust_version = Some(build::RUST_VERSION).filter(|x| !x.is_empty());
|
||||
if let Some(rust_version) = rust_version {
|
||||
record.push("rust_version", Value::string(rust_version, call.head));
|
||||
}
|
||||
|
||||
let rust_channel = Some(build::RUST_CHANNEL).filter(|x| !x.is_empty());
|
||||
if let Some(rust_channel) = rust_channel {
|
||||
record.push("rust_channel", Value::string(rust_channel, call.head));
|
||||
}
|
||||
|
||||
let cargo_version = Some(build::CARGO_VERSION).filter(|x| !x.is_empty());
|
||||
if let Some(cargo_version) = cargo_version {
|
||||
record.push("cargo_version", Value::string(cargo_version, call.head));
|
||||
}
|
||||
|
||||
let build_time = Some(build::BUILD_TIME).filter(|x| !x.is_empty());
|
||||
if let Some(build_time) = build_time {
|
||||
record.push("build_time", Value::string(build_time, call.head));
|
||||
}
|
||||
|
||||
let build_rust_channel = Some(build::BUILD_RUST_CHANNEL).filter(|x| !x.is_empty());
|
||||
if let Some(build_rust_channel) = build_rust_channel {
|
||||
record.push(
|
||||
"build_rust_channel",
|
||||
Value::string(build_rust_channel, call.head),
|
||||
);
|
||||
}
|
||||
|
||||
record.push("allocator", Value::string(global_allocator(), call.head));
|
||||
record.push("allocator", Value::string(global_allocator(), span));
|
||||
|
||||
record.push(
|
||||
"features",
|
||||
Value::string(features_enabled().join(", "), call.head),
|
||||
Value::string(features_enabled().join(", "), span),
|
||||
);
|
||||
|
||||
// Get a list of plugin names
|
||||
@ -150,10 +125,10 @@ pub fn version(engine_state: &EngineState, call: &Call) -> Result<PipelineData,
|
||||
|
||||
record.push(
|
||||
"installed_plugins",
|
||||
Value::string(installed_plugins.join(", "), call.head),
|
||||
Value::string(installed_plugins.join(", "), span),
|
||||
);
|
||||
|
||||
Ok(Value::record(record, call.head).into_pipeline_data())
|
||||
Ok(Value::record(record, span).into_pipeline_data())
|
||||
}
|
||||
|
||||
/// Add version numbers as integers to the given record
|
||||
@ -167,9 +142,9 @@ fn push_version_numbers(record: &mut Record, head: Span) {
|
||||
build::PKG_VERSION_PATCH.parse().expect("Always set"),
|
||||
)
|
||||
});
|
||||
record.push("major", Value::int(major as _, head));
|
||||
record.push("minor", Value::int(minor as _, head));
|
||||
record.push("patch", Value::int(patch as _, head));
|
||||
record.push("major", Value::int(major.into(), head));
|
||||
record.push("minor", Value::int(minor.into(), head));
|
||||
record.push("patch", Value::int(patch.into(), head));
|
||||
}
|
||||
|
||||
fn global_allocator() -> &'static str {
|
||||
|
@ -5,15 +5,15 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-cmd-plugin"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-cmd-plugin"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.92.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3", features = ["plugin"] }
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.93.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1", features = ["plugin"] }
|
||||
nu-plugin-engine = { path = "../nu-plugin-engine", version = "0.93.1" }
|
||||
|
||||
itertools = { workspace = true }
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use nu_engine::{command_prelude::*, current_dir};
|
||||
use nu_plugin::{GetPlugin, PersistentPlugin};
|
||||
use nu_protocol::{PluginCacheItem, PluginGcConfig, PluginIdentity, RegisteredPlugin};
|
||||
use nu_plugin_engine::{GetPlugin, PersistentPlugin};
|
||||
use nu_protocol::{PluginGcConfig, PluginIdentity, PluginRegistryItem, RegisteredPlugin};
|
||||
|
||||
use crate::util::modify_plugin_file;
|
||||
use crate::util::{get_plugin_dirs, modify_plugin_file};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginAdd;
|
||||
@ -21,7 +21,7 @@ impl Command for PluginAdd {
|
||||
.named(
|
||||
"plugin-config",
|
||||
SyntaxShape::Filepath,
|
||||
"Use a plugin cache file other than the one set in `$nu.plugin-path`",
|
||||
"Use a plugin registry file other than the one set in `$nu.plugin-path`",
|
||||
None,
|
||||
)
|
||||
.named(
|
||||
@ -39,7 +39,7 @@ impl Command for PluginAdd {
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Add a plugin to the plugin cache file."
|
||||
"Add a plugin to the plugin registry file."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
@ -47,14 +47,14 @@ impl Command for PluginAdd {
|
||||
This does not load the plugin commands into the scope - see `register` for that.
|
||||
|
||||
Instead, it runs the plugin to get its command signatures, and then edits the
|
||||
plugin cache file (by default, `$nu.plugin-path`). The changes will be
|
||||
apparent the next time `nu` is next launched with that plugin cache file.
|
||||
plugin registry file (by default, `$nu.plugin-path`). The changes will be
|
||||
apparent the next time `nu` is next launched with that plugin registry file.
|
||||
"#
|
||||
.trim()
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["plugin", "add", "register", "load", "signature"]
|
||||
vec!["load", "register", "signature"]
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -66,7 +66,7 @@ apparent the next time `nu` is next launched with that plugin cache file.
|
||||
},
|
||||
Example {
|
||||
example: "plugin add --plugin-config polars.msgpackz nu_plugin_polars",
|
||||
description: "Run the `nu_plugin_polars` plugin from the current directory or $env.NU_PLUGIN_DIRS, and install its signatures to the \"polars.msgpackz\" plugin cache file.",
|
||||
description: "Run the `nu_plugin_polars` plugin from the current directory or $env.NU_PLUGIN_DIRS, and install its signatures to the \"polars.msgpackz\" plugin registry file.",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
@ -85,30 +85,14 @@ apparent the next time `nu` is next launched with that plugin cache file.
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
|
||||
// Check the current directory, or fall back to NU_PLUGIN_DIRS
|
||||
let filename_expanded = match nu_path::canonicalize_with(&filename.item, &cwd) {
|
||||
Ok(path) => path,
|
||||
Err(err) => {
|
||||
// Try to find it in NU_PLUGIN_DIRS first, before giving up
|
||||
let mut found = None;
|
||||
if let Some(nu_plugin_dirs) = stack.get_env_var(engine_state, "NU_PLUGIN_DIRS") {
|
||||
for dir in nu_plugin_dirs.into_list().unwrap_or(vec![]) {
|
||||
if let Ok(path) = nu_path::canonicalize_with(dir.as_str()?, &cwd)
|
||||
.and_then(|dir| nu_path::canonicalize_with(&filename.item, dir))
|
||||
{
|
||||
found = Some(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
found.ok_or(err.into_spanned(filename.span))?
|
||||
}
|
||||
};
|
||||
let filename_expanded = nu_path::locate_in_dirs(&filename.item, &cwd, || {
|
||||
get_plugin_dirs(engine_state, stack)
|
||||
})
|
||||
.err_span(filename.span)?;
|
||||
|
||||
let shell_expanded = shell
|
||||
.as_ref()
|
||||
.map(|s| {
|
||||
nu_path::canonicalize_with(&s.item, &cwd).map_err(|err| err.into_spanned(s.span))
|
||||
})
|
||||
.map(|s| nu_path::canonicalize_with(&s.item, &cwd).err_span(s.span))
|
||||
.transpose()?;
|
||||
|
||||
// Parse the plugin filename so it can be used to spawn the plugin
|
||||
@ -138,7 +122,7 @@ apparent the next time `nu` is next launched with that plugin cache file.
|
||||
|
||||
modify_plugin_file(engine_state, stack, call.head, custom_path, |contents| {
|
||||
// Update the file with the received signatures
|
||||
let item = PluginCacheItem::new(plugin.identity(), commands);
|
||||
let item = PluginRegistryItem::new(plugin.identity(), commands);
|
||||
contents.upsert_plugin(item);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -13,14 +13,17 @@ impl Command for PluginList {
|
||||
Signature::build("plugin list")
|
||||
.input_output_type(
|
||||
Type::Nothing,
|
||||
Type::Table(vec![
|
||||
("name".into(), Type::String),
|
||||
("is_running".into(), Type::Bool),
|
||||
("pid".into(), Type::Int),
|
||||
("filename".into(), Type::String),
|
||||
("shell".into(), Type::String),
|
||||
("commands".into(), Type::List(Type::String.into())),
|
||||
]),
|
||||
Type::Table(
|
||||
[
|
||||
("name".into(), Type::String),
|
||||
("is_running".into(), Type::Bool),
|
||||
("pid".into(), Type::Int),
|
||||
("filename".into(), Type::String),
|
||||
("shell".into(), Type::String),
|
||||
("commands".into(), Type::List(Type::String.into())),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
.category(Category::Plugin)
|
||||
}
|
||||
@ -29,6 +32,10 @@ impl Command for PluginList {
|
||||
"List installed plugins."
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["scope"]
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<nu_protocol::Example> {
|
||||
vec![
|
||||
Example {
|
||||
|
@ -4,11 +4,13 @@ mod add;
|
||||
mod list;
|
||||
mod rm;
|
||||
mod stop;
|
||||
mod use_;
|
||||
|
||||
pub use add::PluginAdd;
|
||||
pub use list::PluginList;
|
||||
pub use rm::PluginRm;
|
||||
pub use stop::PluginStop;
|
||||
pub use use_::PluginUse;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginCommand;
|
||||
@ -28,10 +30,6 @@ impl Command for PluginCommand {
|
||||
"Commands for managing plugins."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"To load a plugin, see `register`."
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
engine_state: &EngineState,
|
||||
@ -54,6 +52,21 @@ impl Command for PluginCommand {
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
example: "plugin add nu_plugin_inc",
|
||||
description: "Run the `nu_plugin_inc` plugin from the current directory and install its signatures.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin use inc",
|
||||
description: "
|
||||
Load (or reload) the `inc` plugin from the plugin registry file and put its
|
||||
commands in scope. The plugin must already be in the registry file at parse
|
||||
time.
|
||||
"
|
||||
.trim(),
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin list",
|
||||
description: "List installed plugins",
|
||||
@ -64,11 +77,6 @@ impl Command for PluginCommand {
|
||||
description: "Stop the plugin named `inc`.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin add nu_plugin_inc",
|
||||
description: "Run the `nu_plugin_inc` plugin from the current directory and install its signatures.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin rm inc",
|
||||
description: "Remove the installed signatures for the `inc` plugin.",
|
||||
|
@ -1,6 +1,6 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use crate::util::modify_plugin_file;
|
||||
use crate::util::{canonicalize_possible_filename_arg, modify_plugin_file};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginRm;
|
||||
@ -17,7 +17,7 @@ impl Command for PluginRm {
|
||||
.named(
|
||||
"plugin-config",
|
||||
SyntaxShape::Filepath,
|
||||
"Use a plugin cache file other than the one set in `$nu.plugin-path`",
|
||||
"Use a plugin registry file other than the one set in `$nu.plugin-path`",
|
||||
None,
|
||||
)
|
||||
.switch(
|
||||
@ -28,21 +28,21 @@ impl Command for PluginRm {
|
||||
.required(
|
||||
"name",
|
||||
SyntaxShape::String,
|
||||
"The name of the plugin to remove (not the filename)",
|
||||
"The name, or filename, of the plugin to remove",
|
||||
)
|
||||
.category(Category::Plugin)
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Remove a plugin from the plugin cache file."
|
||||
"Remove a plugin from the plugin registry file."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"
|
||||
This does not remove the plugin commands from the current scope or from `plugin
|
||||
list` in the current shell. It instead removes the plugin from the plugin
|
||||
cache file (by default, `$nu.plugin-path`). The changes will be apparent the
|
||||
next time `nu` is launched with that plugin cache file.
|
||||
registry file (by default, `$nu.plugin-path`). The changes will be apparent the
|
||||
next time `nu` is launched with that plugin registry file.
|
||||
|
||||
This can be useful for removing an invalid plugin signature, if it can't be
|
||||
fixed with `plugin add`.
|
||||
@ -51,7 +51,7 @@ fixed with `plugin add`.
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["plugin", "rm", "remove", "delete", "signature"]
|
||||
vec!["remove", "delete", "signature"]
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
@ -61,9 +61,14 @@ fixed with `plugin add`.
|
||||
description: "Remove the installed signatures for the `inc` plugin.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin rm ~/.cargo/bin/nu_plugin_inc",
|
||||
description: "Remove the installed signatures for the plugin with the filename `~/.cargo/bin/nu_plugin_inc`.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin rm --plugin-config polars.msgpackz polars",
|
||||
description: "Remove the installed signatures for the `polars` plugin from the \"polars.msgpackz\" plugin cache file.",
|
||||
description: "Remove the installed signatures for the `polars` plugin from the \"polars.msgpackz\" plugin registry file.",
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
@ -80,18 +85,26 @@ fixed with `plugin add`.
|
||||
let custom_path = call.get_flag(engine_state, stack, "plugin-config")?;
|
||||
let force = call.has_flag(engine_state, stack, "force")?;
|
||||
|
||||
let filename = canonicalize_possible_filename_arg(engine_state, stack, &name.item);
|
||||
|
||||
modify_plugin_file(engine_state, stack, call.head, custom_path, |contents| {
|
||||
if !force && !contents.plugins.iter().any(|p| p.name == name.item) {
|
||||
if let Some(index) = contents
|
||||
.plugins
|
||||
.iter()
|
||||
.position(|p| p.name == name.item || p.filename == filename)
|
||||
{
|
||||
contents.plugins.remove(index);
|
||||
Ok(())
|
||||
} else if force {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ShellError::GenericError {
|
||||
error: format!("Failed to remove the `{}` plugin", name.item),
|
||||
msg: "couldn't find a plugin with this name in the cache file".into(),
|
||||
msg: "couldn't find a plugin with this name in the registry file".into(),
|
||||
span: Some(name.span),
|
||||
help: None,
|
||||
inner: vec![],
|
||||
})
|
||||
} else {
|
||||
contents.remove_plugin(&name.item);
|
||||
Ok(())
|
||||
}
|
||||
})?;
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
use crate::util::canonicalize_possible_filename_arg;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginStop;
|
||||
|
||||
@ -14,7 +16,7 @@ impl Command for PluginStop {
|
||||
.required(
|
||||
"name",
|
||||
SyntaxShape::String,
|
||||
"The name of the plugin to stop.",
|
||||
"The name, or filename, of the plugin to stop",
|
||||
)
|
||||
.category(Category::Plugin)
|
||||
}
|
||||
@ -30,6 +32,11 @@ impl Command for PluginStop {
|
||||
description: "Stop the plugin named `inc`.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin stop ~/.cargo/bin/nu_plugin_inc",
|
||||
description: "Stop the plugin with the filename `~/.cargo/bin/nu_plugin_inc`.",
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
example: "plugin list | each { |p| plugin stop $p.name }",
|
||||
description: "Stop all plugins.",
|
||||
@ -47,9 +54,12 @@ impl Command for PluginStop {
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let name: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
|
||||
let filename = canonicalize_possible_filename_arg(engine_state, stack, &name.item);
|
||||
|
||||
let mut found = false;
|
||||
for plugin in engine_state.plugins() {
|
||||
if plugin.identity().name() == name.item {
|
||||
let id = &plugin.identity();
|
||||
if id.name() == name.item || id.filename() == filename {
|
||||
plugin.stop()?;
|
||||
found = true;
|
||||
}
|
||||
|
89
crates/nu-cmd-plugin/src/commands/plugin/use_.rs
Normal file
89
crates/nu-cmd-plugin/src/commands/plugin/use_.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use nu_engine::command_prelude::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PluginUse;
|
||||
|
||||
impl Command for PluginUse {
|
||||
fn name(&self) -> &str {
|
||||
"plugin use"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Load a plugin from the plugin registry file into scope."
|
||||
}
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build(self.name())
|
||||
.input_output_types(vec![(Type::Nothing, Type::Nothing)])
|
||||
.named(
|
||||
"plugin-config",
|
||||
SyntaxShape::Filepath,
|
||||
"Use a plugin registry file other than the one set in `$nu.plugin-path`",
|
||||
None,
|
||||
)
|
||||
.required(
|
||||
"name",
|
||||
SyntaxShape::String,
|
||||
"The name, or filename, of the plugin to load",
|
||||
)
|
||||
.category(Category::Plugin)
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"
|
||||
This command is a parser keyword. For details, check:
|
||||
https://www.nushell.sh/book/thinking_in_nu.html
|
||||
|
||||
The plugin definition must be available in the plugin registry file at parse
|
||||
time. Run `plugin add` first in the REPL to do this, or from a script consider
|
||||
preparing a plugin registry file and passing `--plugin-config`, or using the
|
||||
`--plugin` option to `nu` instead.
|
||||
|
||||
If the plugin was already loaded, this will reload the latest definition from
|
||||
the registry file into scope.
|
||||
|
||||
Note that even if the plugin filename is specified, it will only be loaded if
|
||||
it was already previously registered with `plugin add`.
|
||||
"#
|
||||
.trim()
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["add", "register", "scope"]
|
||||
}
|
||||
|
||||
fn is_parser_keyword(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_engine_state: &EngineState,
|
||||
_stack: &mut Stack,
|
||||
_call: &Call,
|
||||
_input: PipelineData,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
Ok(PipelineData::empty())
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![
|
||||
Example {
|
||||
description: "Load the commands for the `query` plugin from $nu.plugin-path",
|
||||
example: r#"plugin use query"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description: "Load the commands for the plugin with the filename `~/.cargo/bin/nu_plugin_query` from $nu.plugin-path",
|
||||
example: r#"plugin use ~/.cargo/bin/nu_plugin_query"#,
|
||||
result: None,
|
||||
},
|
||||
Example {
|
||||
description:
|
||||
"Load the commands for the `query` plugin from a custom plugin registry file",
|
||||
example: r#"plugin use --plugin-config local-plugins.msgpackz query"#,
|
||||
result: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
@ -35,12 +35,17 @@ impl Command for Register {
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"This command is a parser keyword. For details, check:
|
||||
https://www.nushell.sh/book/thinking_in_nu.html"#
|
||||
r#"
|
||||
Deprecated in favor of `plugin add` and `plugin use`.
|
||||
|
||||
This command is a parser keyword. For details, check:
|
||||
https://www.nushell.sh/book/thinking_in_nu.html
|
||||
"#
|
||||
.trim()
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["plugin", "add", "register"]
|
||||
vec!["add"]
|
||||
}
|
||||
|
||||
fn is_parser_keyword(&self) -> bool {
|
||||
|
@ -12,11 +12,12 @@ pub fn add_plugin_command_context(mut engine_state: EngineState) -> EngineState
|
||||
}
|
||||
|
||||
bind_command!(
|
||||
PluginCommand,
|
||||
PluginAdd,
|
||||
PluginCommand,
|
||||
PluginList,
|
||||
PluginRm,
|
||||
PluginStop,
|
||||
PluginUse,
|
||||
Register,
|
||||
);
|
||||
|
||||
|
@ -1,25 +1,28 @@
|
||||
use std::fs::{self, File};
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
use nu_engine::{command_prelude::*, current_dir};
|
||||
use nu_protocol::PluginCacheFile;
|
||||
use nu_protocol::{engine::StateWorkingSet, PluginRegistryFile};
|
||||
|
||||
pub(crate) fn modify_plugin_file(
|
||||
engine_state: &EngineState,
|
||||
stack: &mut Stack,
|
||||
span: Span,
|
||||
custom_path: Option<Spanned<String>>,
|
||||
operate: impl FnOnce(&mut PluginCacheFile) -> Result<(), ShellError>,
|
||||
operate: impl FnOnce(&mut PluginRegistryFile) -> Result<(), ShellError>,
|
||||
) -> Result<(), ShellError> {
|
||||
let cwd = current_dir(engine_state, stack)?;
|
||||
|
||||
let plugin_cache_file_path = if let Some(ref custom_path) = custom_path {
|
||||
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
|
||||
.clone()
|
||||
.ok_or_else(|| ShellError::GenericError {
|
||||
error: "Plugin cache file not set".into(),
|
||||
error: "Plugin registry file not set".into(),
|
||||
msg: "pass --plugin-config explicitly here".into(),
|
||||
span: Some(span),
|
||||
help: Some("you may be running `nu` with --no-config-file".into()),
|
||||
@ -28,13 +31,13 @@ pub(crate) fn modify_plugin_file(
|
||||
};
|
||||
|
||||
// Try to read the plugin file if it exists
|
||||
let mut contents = if fs::metadata(&plugin_cache_file_path).is_ok_and(|m| m.len() > 0) {
|
||||
PluginCacheFile::read_from(
|
||||
File::open(&plugin_cache_file_path).map_err(|err| err.into_spanned(span))?,
|
||||
let mut contents = if fs::metadata(&plugin_registry_file_path).is_ok_and(|m| m.len() > 0) {
|
||||
PluginRegistryFile::read_from(
|
||||
File::open(&plugin_registry_file_path).err_span(span)?,
|
||||
Some(span),
|
||||
)?
|
||||
} else {
|
||||
PluginCacheFile::default()
|
||||
PluginRegistryFile::default()
|
||||
};
|
||||
|
||||
// Do the operation
|
||||
@ -42,9 +45,45 @@ pub(crate) fn modify_plugin_file(
|
||||
|
||||
// Save the modified file on success
|
||||
contents.write_to(
|
||||
File::create(&plugin_cache_file_path).map_err(|err| err.into_spanned(span))?,
|
||||
File::create(&plugin_registry_file_path).err_span(span)?,
|
||||
Some(span),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn canonicalize_possible_filename_arg(
|
||||
engine_state: &EngineState,
|
||||
stack: &Stack,
|
||||
arg: &str,
|
||||
) -> PathBuf {
|
||||
// This results in the best possible chance of a match with the plugin item
|
||||
if let Ok(cwd) = nu_engine::current_dir(engine_state, stack) {
|
||||
let path = nu_path::expand_path_with(arg, &cwd, true);
|
||||
// Try to canonicalize
|
||||
nu_path::locate_in_dirs(&path, &cwd, || get_plugin_dirs(engine_state, stack))
|
||||
// If we couldn't locate it, return the expanded path alone
|
||||
.unwrap_or(path)
|
||||
} else {
|
||||
arg.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_plugin_dirs(
|
||||
engine_state: &EngineState,
|
||||
stack: &Stack,
|
||||
) -> impl Iterator<Item = String> {
|
||||
// Get the NU_PLUGIN_DIRS constant or env var
|
||||
let working_set = StateWorkingSet::new(engine_state);
|
||||
let value = working_set
|
||||
.find_variable(b"$NU_PLUGIN_DIRS")
|
||||
.and_then(|var_id| working_set.get_constant(var_id).ok().cloned())
|
||||
.or_else(|| stack.get_env_var(engine_state, "NU_PLUGIN_DIRS"));
|
||||
|
||||
// Get all of the strings in the list, if possible
|
||||
value
|
||||
.into_iter()
|
||||
.flat_map(|value| value.into_list().ok())
|
||||
.flatten()
|
||||
.flat_map(|list_item| list_item.coerce_into_string().ok())
|
||||
}
|
||||
|
@ -5,18 +5,18 @@ repository = "https://github.com/nushell/nushell/tree/main/crates/nu-color-confi
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-color-config"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-json = { path = "../nu-json", version = "0.92.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.93.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.92.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.93.1" }
|
||||
|
@ -5,7 +5,7 @@ edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu-command"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu-command"
|
||||
version = "0.92.3"
|
||||
version = "0.93.1"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@ -13,25 +13,26 @@ version = "0.92.3"
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.92.3" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.92.3" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.92.3" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.92.3" }
|
||||
nu-json = { path = "../nu-json", version = "0.92.3" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.92.3" }
|
||||
nu-path = { path = "../nu-path", version = "0.92.3" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.92.3" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.92.3" }
|
||||
nu-system = { path = "../nu-system", version = "0.92.3" }
|
||||
nu-table = { path = "../nu-table", version = "0.92.3" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.92.3" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.92.3" }
|
||||
nu-cmd-base = { path = "../nu-cmd-base", version = "0.93.1" }
|
||||
nu-color-config = { path = "../nu-color-config", version = "0.93.1" }
|
||||
nu-engine = { path = "../nu-engine", version = "0.93.1" }
|
||||
nu-glob = { path = "../nu-glob", version = "0.93.1" }
|
||||
nu-json = { path = "../nu-json", version = "0.93.1" }
|
||||
nu-parser = { path = "../nu-parser", version = "0.93.1" }
|
||||
nu-path = { path = "../nu-path", version = "0.93.1" }
|
||||
nu-pretty-hex = { path = "../nu-pretty-hex", version = "0.93.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.93.1" }
|
||||
nu-system = { path = "../nu-system", version = "0.93.1" }
|
||||
nu-table = { path = "../nu-table", version = "0.93.1" }
|
||||
nu-term-grid = { path = "../nu-term-grid", version = "0.93.1" }
|
||||
nu-utils = { path = "../nu-utils", version = "0.93.1" }
|
||||
nu-ansi-term = { workspace = true }
|
||||
nuon = { path = "../nuon", version = "0.92.3" }
|
||||
nuon = { path = "../nuon", version = "0.93.1" }
|
||||
|
||||
alphanumeric-sort = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
bracoxide = { workspace = true }
|
||||
brotli = { workspace = true }
|
||||
byteorder = { workspace = true }
|
||||
bytesize = { workspace = true }
|
||||
calamine = { workspace = true, features = ["dates"] }
|
||||
@ -74,6 +75,7 @@ rayon = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
roxmltree = { workspace = true }
|
||||
rusqlite = { workspace = true, features = ["bundled", "backup", "chrono"], optional = true }
|
||||
rmp = { workspace = true }
|
||||
same-file = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
@ -135,11 +137,12 @@ trash-support = ["trash"]
|
||||
which-support = ["which"]
|
||||
|
||||
[dev-dependencies]
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.92.3" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.92.3" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.93.1" }
|
||||
nu-test-support = { path = "../nu-test-support", version = "0.93.1" }
|
||||
|
||||
dirs-next = { workspace = true }
|
||||
mockito = { workspace = true, default-features = false }
|
||||
quickcheck = { workspace = true }
|
||||
quickcheck_macros = { workspace = true }
|
||||
rstest = { workspace = true, default-features = false }
|
||||
pretty_assertions = { workspace = true }
|
||||
|
@ -31,8 +31,8 @@ impl Command for BytesAdd {
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.required("data", SyntaxShape::Binary, "The binary to add.")
|
||||
|
@ -41,8 +41,8 @@ impl Command for BytesAt {
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.required("range", SyntaxShape::Range, "The range to get bytes.")
|
||||
.rest(
|
||||
|
@ -24,14 +24,21 @@ impl Command for BytesBuild {
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
example: "bytes build 0x[01 02] 0x[03] 0x[04]",
|
||||
description: "Builds binary data from 0x[01 02], 0x[03], 0x[04]",
|
||||
result: Some(Value::binary(
|
||||
vec![0x01, 0x02, 0x03, 0x04],
|
||||
Span::test_data(),
|
||||
)),
|
||||
}]
|
||||
vec![
|
||||
Example {
|
||||
example: "bytes build 0x[01 02] 0x[03] 0x[04]",
|
||||
description: "Builds binary data from 0x[01 02], 0x[03], 0x[04]",
|
||||
result: Some(Value::binary(
|
||||
vec![0x01, 0x02, 0x03, 0x04],
|
||||
Span::test_data(),
|
||||
)),
|
||||
},
|
||||
Example {
|
||||
example: "bytes build 255 254 253 252",
|
||||
description: "Builds binary data from byte numbers",
|
||||
result: Some(Value::test_binary(vec![0xff, 0xfe, 0xfd, 0xfc])),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn run(
|
||||
@ -46,8 +53,17 @@ impl Command for BytesBuild {
|
||||
let eval_expression = get_eval_expression(engine_state);
|
||||
eval_expression(engine_state, stack, expr)
|
||||
})? {
|
||||
let val_span = val.span();
|
||||
match val {
|
||||
Value::Binary { mut val, .. } => output.append(&mut val),
|
||||
Value::Int { val, .. } => {
|
||||
let byte: u8 = val.try_into().map_err(|_| ShellError::IncorrectValue {
|
||||
msg: format!("{val} is out of range for byte"),
|
||||
val_span,
|
||||
call_span: call.head,
|
||||
})?;
|
||||
output.push(byte);
|
||||
}
|
||||
// Explicitly propagate errors instead of dropping them.
|
||||
Value::Error { error, .. } => return Err(*error),
|
||||
other => {
|
||||
|
@ -24,8 +24,8 @@ impl Command for BytesEndsWith {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("bytes ends-with")
|
||||
.input_output_types(vec![(Type::Binary, Type::Bool),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.required("pattern", SyntaxShape::Binary, "The pattern to match.")
|
||||
|
@ -28,8 +28,8 @@ impl Command for BytesIndexOf {
|
||||
(Type::Binary, Type::Any),
|
||||
// FIXME: this shouldn't be needed, cell paths should work with the two
|
||||
// above
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.required(
|
||||
|
@ -17,8 +17,8 @@ impl Command for BytesLen {
|
||||
Type::List(Box::new(Type::Binary)),
|
||||
Type::List(Box::new(Type::Int)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -26,8 +26,8 @@ impl Command for BytesRemove {
|
||||
Signature::build("bytes remove")
|
||||
.input_output_types(vec![
|
||||
(Type::Binary, Type::Binary),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.required("pattern", SyntaxShape::Binary, "The pattern to find.")
|
||||
.rest(
|
||||
|
@ -26,8 +26,8 @@ impl Command for BytesReplace {
|
||||
Signature::build("bytes replace")
|
||||
.input_output_types(vec![
|
||||
(Type::Binary, Type::Binary),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.required("find", SyntaxShape::Binary, "The pattern to find.")
|
||||
|
@ -13,8 +13,8 @@ impl Command for BytesReverse {
|
||||
Signature::build("bytes reverse")
|
||||
.input_output_types(vec![
|
||||
(Type::Binary, Type::Binary),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -25,8 +25,8 @@ impl Command for BytesStartsWith {
|
||||
Signature::build("bytes starts-with")
|
||||
.input_output_types(vec![
|
||||
(Type::Binary, Type::Bool),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.required("pattern", SyntaxShape::Binary, "The pattern to match.")
|
||||
|
@ -19,7 +19,7 @@ impl Command for Histogram {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("histogram")
|
||||
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::Table(vec![])),])
|
||||
.input_output_types(vec![(Type::List(Box::new(Type::Any)), Type::table()),])
|
||||
.optional("column-name", SyntaxShape::String, "Column name to calc frequency, no need to provide if input is a list.")
|
||||
.optional("frequency-column-name", SyntaxShape::String, "Histogram's frequency column, default to be frequency column output.")
|
||||
.named("percentage-type", SyntaxShape::String, "percentage calculate method, can be 'normalize' or 'relative', in 'normalize', defaults to be 'normalize'", Some('t'))
|
||||
|
@ -30,8 +30,8 @@ impl Command for SubCommand {
|
||||
(Type::Bool, Type::Binary),
|
||||
(Type::Filesize, Type::Binary),
|
||||
(Type::Date, Type::Binary),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true) // TODO: supply exhaustive examples
|
||||
.switch("compact", "output without padding zeros", Some('c'))
|
||||
|
@ -16,9 +16,9 @@ impl Command for SubCommand {
|
||||
(Type::Number, Type::Bool),
|
||||
(Type::String, Type::Bool),
|
||||
(Type::Bool, Type::Bool),
|
||||
(Type::List(Box::new(Type::Any)), Type::Table(vec![])),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::List(Box::new(Type::Any)), Type::table()),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
|
@ -15,10 +15,9 @@ impl Command for IntoCellPath {
|
||||
(Type::Int, Type::CellPath),
|
||||
(Type::List(Box::new(Type::Any)), Type::CellPath),
|
||||
(
|
||||
Type::List(Box::new(Type::Record(vec![
|
||||
("value".into(), Type::Any),
|
||||
("optional".into(), Type::Bool),
|
||||
]))),
|
||||
Type::List(Box::new(Type::Record(
|
||||
[("value".into(), Type::Any), ("optional".into(), Type::Bool)].into(),
|
||||
))),
|
||||
Type::CellPath,
|
||||
),
|
||||
])
|
||||
|
@ -62,8 +62,8 @@ impl Command for SubCommand {
|
||||
(Type::Int, Type::Date),
|
||||
(Type::String, Type::Date),
|
||||
(Type::List(Box::new(Type::String)), Type::List(Box::new(Type::Date))),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.named(
|
||||
|
@ -17,9 +17,9 @@ impl Command for SubCommand {
|
||||
(Type::Int, Type::Duration),
|
||||
(Type::String, Type::Duration),
|
||||
(Type::Duration, Type::Duration),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
//todo: record<hour,minute,sign> | into duration -> Duration
|
||||
//(Type::Record(vec![]), Type::Record(vec![])),
|
||||
//(Type::record(), Type::record()),
|
||||
])
|
||||
//.allow_variants_without_examples(true)
|
||||
.named(
|
||||
@ -203,9 +203,9 @@ fn string_to_duration(s: &str, span: Span) -> Result<i64, ShellError> {
|
||||
Type::Duration,
|
||||
|x| x,
|
||||
) {
|
||||
if let Expr::ValueWithUnit(value, unit) = expression.expr {
|
||||
if let Expr::Int(x) = value.expr {
|
||||
match unit.item {
|
||||
if let Expr::ValueWithUnit(value) = expression.expr {
|
||||
if let Expr::Int(x) = value.expr.expr {
|
||||
match value.unit.item {
|
||||
Unit::Nanosecond => return Ok(x),
|
||||
Unit::Microsecond => return Ok(x * 1000),
|
||||
Unit::Millisecond => return Ok(x * 1000 * 1000),
|
||||
|
@ -18,8 +18,8 @@ impl Command for SubCommand {
|
||||
(Type::Number, Type::Filesize),
|
||||
(Type::String, Type::Filesize),
|
||||
(Type::Filesize, Type::Filesize),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
(
|
||||
Type::List(Box::new(Type::Int)),
|
||||
Type::List(Box::new(Type::Filesize)),
|
||||
|
@ -16,8 +16,8 @@ impl Command for SubCommand {
|
||||
(Type::String, Type::Float),
|
||||
(Type::Bool, Type::Float),
|
||||
(Type::Float, Type::Float),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
(
|
||||
Type::List(Box::new(Type::Any)),
|
||||
Type::List(Box::new(Type::Float)),
|
||||
|
@ -27,8 +27,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::Glob)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
|
||||
.rest(
|
||||
|
@ -36,8 +36,8 @@ impl Command for SubCommand {
|
||||
(Type::Duration, Type::Int),
|
||||
(Type::Filesize, Type::Int),
|
||||
(Type::Binary, Type::Int),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
(
|
||||
Type::List(Box::new(Type::String)),
|
||||
Type::List(Box::new(Type::Int)),
|
||||
|
@ -13,11 +13,11 @@ impl Command for SubCommand {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into record")
|
||||
.input_output_types(vec![
|
||||
(Type::Date, Type::Record(vec![])),
|
||||
(Type::Duration, Type::Record(vec![])),
|
||||
(Type::List(Box::new(Type::Any)), Type::Record(vec![])),
|
||||
(Type::Range, Type::Record(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::Date, Type::record()),
|
||||
(Type::Duration, Type::record()),
|
||||
(Type::List(Box::new(Type::Any)), Type::record()),
|
||||
(Type::Range, Type::record()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.category(Category::Conversions)
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ impl Command for SubCommand {
|
||||
Type::List(Box::new(Type::Any)),
|
||||
Type::List(Box::new(Type::String)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
|
||||
.rest(
|
||||
|
@ -15,7 +15,7 @@ impl Command for IntoValue {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("into value")
|
||||
.input_output_types(vec![(Type::Table(vec![]), Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::table(), Type::table())])
|
||||
.named(
|
||||
"columns",
|
||||
SyntaxShape::Table(vec![]),
|
||||
|
@ -24,8 +24,8 @@ impl Command for IntoSqliteDb {
|
||||
Signature::build("into sqlite")
|
||||
.category(Category::Conversions)
|
||||
.input_output_types(vec![
|
||||
(Type::Table(vec![]), Type::Nothing),
|
||||
(Type::Record(vec![]), Type::Nothing),
|
||||
(Type::table(), Type::Nothing),
|
||||
(Type::record(), Type::Nothing),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
.required(
|
||||
|
@ -11,7 +11,7 @@ impl Command for SubCommand {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date list-timezone")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
.category(Category::Date)
|
||||
}
|
||||
|
||||
|
@ -13,8 +13,8 @@ impl Command for SubCommand {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date to-record")
|
||||
.input_output_types(vec![
|
||||
(Type::Date, Type::Record(vec![])),
|
||||
(Type::String, Type::Record(vec![])),
|
||||
(Type::Date, Type::record()),
|
||||
(Type::String, Type::record()),
|
||||
])
|
||||
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
|
||||
.category(Category::Date)
|
||||
|
@ -13,8 +13,8 @@ impl Command for SubCommand {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("date to-table")
|
||||
.input_output_types(vec![
|
||||
(Type::Date, Type::Table(vec![])),
|
||||
(Type::String, Type::Table(vec![])),
|
||||
(Type::Date, Type::table()),
|
||||
(Type::String, Type::table()),
|
||||
])
|
||||
.allow_variants_without_examples(true) // https://github.com/nushell/nushell/issues/7032
|
||||
.category(Category::Date)
|
||||
|
@ -16,7 +16,7 @@ impl Command for Ast {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("ast")
|
||||
.input_output_types(vec![(Type::String, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::String, Type::record())])
|
||||
.required(
|
||||
"pipeline",
|
||||
SyntaxShape::String,
|
||||
|
@ -31,7 +31,7 @@ impl Command for DebugInfo {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("debug info")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::record())])
|
||||
.category(Category::Debug)
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ impl Command for Metadata {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("metadata")
|
||||
.input_output_types(vec![(Type::Any, Type::Record(vec![]))])
|
||||
.input_output_types(vec![(Type::Any, Type::record())])
|
||||
.allow_variants_without_examples(true)
|
||||
.optional(
|
||||
"expression",
|
||||
|
@ -34,7 +34,7 @@ impl Command for DebugProfile {
|
||||
"How many blocks/closures deep to step into (default 2)",
|
||||
Some('m'),
|
||||
)
|
||||
.input_output_types(vec![(Type::Any, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Any, Type::table())])
|
||||
.category(Category::Debug)
|
||||
}
|
||||
|
||||
|
@ -20,12 +20,15 @@ impl Command for ViewFiles {
|
||||
Signature::build("view files")
|
||||
.input_output_types(vec![(
|
||||
Type::Nothing,
|
||||
Type::Table(vec![
|
||||
("filename".into(), Type::String),
|
||||
("start".into(), Type::Int),
|
||||
("end".into(), Type::Int),
|
||||
("size".into(), Type::Int),
|
||||
]),
|
||||
Type::Table(
|
||||
[
|
||||
("filename".into(), Type::String),
|
||||
("start".into(), Type::Int),
|
||||
("end".into(), Type::Int),
|
||||
("size".into(), Type::Int),
|
||||
]
|
||||
.into(),
|
||||
),
|
||||
)])
|
||||
.category(Category::Debug)
|
||||
}
|
||||
|
@ -260,6 +260,8 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
||||
From,
|
||||
FromCsv,
|
||||
FromJson,
|
||||
FromMsgpack,
|
||||
FromMsgpackz,
|
||||
FromNuon,
|
||||
FromOds,
|
||||
FromSsv,
|
||||
@ -273,6 +275,8 @@ pub fn add_shell_command_context(mut engine_state: EngineState) -> EngineState {
|
||||
ToCsv,
|
||||
ToJson,
|
||||
ToMd,
|
||||
ToMsgpack,
|
||||
ToMsgpackz,
|
||||
ToNuon,
|
||||
ToText,
|
||||
ToToml,
|
||||
|
2
crates/nu-command/src/env/load_env.rs
vendored
2
crates/nu-command/src/env/load_env.rs
vendored
@ -15,7 +15,7 @@ impl Command for LoadEnv {
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("load-env")
|
||||
.input_output_types(vec![
|
||||
(Type::Record(vec![]), Type::Nothing),
|
||||
(Type::record(), Type::Nothing),
|
||||
(Type::Nothing, Type::Nothing),
|
||||
])
|
||||
.allow_variants_without_examples(true)
|
||||
|
@ -33,7 +33,7 @@ impl Command for Du {
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("du")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
.allow_variants_without_examples(true)
|
||||
.rest(
|
||||
"path",
|
||||
|
@ -45,7 +45,7 @@ impl Command for Ls {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("ls")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
// LsGlobPattern is similar to string, it won't auto-expand
|
||||
// and we use it to track if the user input is quoted.
|
||||
.rest("pattern", SyntaxShape::OneOf(vec![SyntaxShape::GlobPattern, SyntaxShape::String]), "The glob pattern to use.")
|
||||
|
@ -145,7 +145,7 @@ impl Command for Open {
|
||||
|
||||
let file_contents = PipelineData::ExternalStream {
|
||||
stdout: Some(RawStream::new(
|
||||
Box::new(BufferedReader { input: buf_reader }),
|
||||
Box::new(BufferedReader::new(buf_reader)),
|
||||
ctrlc.clone(),
|
||||
call_span,
|
||||
None,
|
||||
|
@ -133,7 +133,7 @@ impl Command for Save {
|
||||
.spawn(move || stderr.drain()),
|
||||
})
|
||||
.transpose()
|
||||
.map_err(|e| e.into_spanned(span))?;
|
||||
.err_span(span)?;
|
||||
|
||||
let res = stream_to_file(stdout, file, span, progress);
|
||||
if let Some(h) = handler {
|
||||
|
@ -38,7 +38,7 @@ impl Command for Watch {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("watch")
|
||||
.input_output_types(vec![(Type::Nothing, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Nothing, Type::table())])
|
||||
.required("path", SyntaxShape::Filepath, "The path to watch. Can be a file or directory.")
|
||||
.required("closure",
|
||||
SyntaxShape::Closure(Some(vec![SyntaxShape::String, SyntaxShape::String, SyntaxShape::String])),
|
||||
|
@ -11,8 +11,8 @@ impl Command for Columns {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.input_output_types(vec![
|
||||
(Type::Table(vec![]), Type::List(Box::new(Type::String))),
|
||||
(Type::Record(vec![]), Type::List(Box::new(Type::String))),
|
||||
(Type::table(), Type::List(Box::new(Type::String))),
|
||||
(Type::record(), Type::List(Box::new(Type::String))),
|
||||
])
|
||||
.category(Category::Filters)
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ impl Command for DropColumn {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.input_output_types(vec![
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::Record(vec![]), Type::Record(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(Type::record(), Type::record()),
|
||||
])
|
||||
.optional(
|
||||
"columns",
|
||||
|
@ -11,7 +11,7 @@ impl Command for Drop {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("drop")
|
||||
.input_output_types(vec![
|
||||
(Type::Table(vec![]), Type::Table(vec![])),
|
||||
(Type::table(), Type::table()),
|
||||
(
|
||||
Type::List(Box::new(Type::Any)),
|
||||
Type::List(Box::new(Type::Any)),
|
||||
|
@ -35,12 +35,12 @@ with 'transpose' first."#
|
||||
Type::List(Box::new(Type::Any)),
|
||||
Type::List(Box::new(Type::Any)),
|
||||
),
|
||||
(Type::Table(vec![]), Type::List(Box::new(Type::Any))),
|
||||
(Type::table(), Type::List(Box::new(Type::Any))),
|
||||
(Type::Any, Type::Any),
|
||||
])
|
||||
.required(
|
||||
"closure",
|
||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any, SyntaxShape::Int])),
|
||||
SyntaxShape::Closure(Some(vec![SyntaxShape::Any])),
|
||||
"The closure to run.",
|
||||
)
|
||||
.switch("keep-empty", "keep empty result cells", Some('k'))
|
||||
@ -49,53 +49,47 @@ with 'transpose' first."#
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
let stream_test_1 = vec![Value::test_int(2), Value::test_int(4), Value::test_int(6)];
|
||||
|
||||
let stream_test_2 = vec![
|
||||
Value::nothing(Span::test_data()),
|
||||
Value::test_string("found 2!"),
|
||||
Value::nothing(Span::test_data()),
|
||||
];
|
||||
|
||||
vec![
|
||||
Example {
|
||||
example: "[1 2 3] | each {|e| 2 * $e }",
|
||||
description: "Multiplies elements in the list",
|
||||
result: Some(Value::list(stream_test_1, Span::test_data())),
|
||||
result: Some(Value::test_list(vec![
|
||||
Value::test_int(2),
|
||||
Value::test_int(4),
|
||||
Value::test_int(6),
|
||||
])),
|
||||
},
|
||||
Example {
|
||||
example: "{major:2, minor:1, patch:4} | values | each {|| into string }",
|
||||
description: "Produce a list of values in the record, converted to string",
|
||||
result: Some(Value::list(
|
||||
vec![
|
||||
Value::test_string("2"),
|
||||
Value::test_string("1"),
|
||||
Value::test_string("4"),
|
||||
],
|
||||
Span::test_data(),
|
||||
)),
|
||||
result: Some(Value::test_list(vec![
|
||||
Value::test_string("2"),
|
||||
Value::test_string("1"),
|
||||
Value::test_string("4"),
|
||||
])),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3 2] | each {|e| if $e == 2 { "two" } }"#,
|
||||
description: "Produce a list that has \"two\" for each 2 in the input",
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("two"), Value::test_string("two")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
result: Some(Value::test_list(vec![
|
||||
Value::test_string("two"),
|
||||
Value::test_string("two"),
|
||||
])),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3] | enumerate | each {|e| if $e.item == 2 { $"found 2 at ($e.index)!"} }"#,
|
||||
description:
|
||||
"Iterate over each element, producing a list showing indexes of any 2s",
|
||||
result: Some(Value::list(
|
||||
vec![Value::test_string("found 2 at 1!")],
|
||||
Span::test_data(),
|
||||
)),
|
||||
result: Some(Value::test_list(vec![Value::test_string("found 2 at 1!")])),
|
||||
},
|
||||
Example {
|
||||
example: r#"[1 2 3] | each --keep-empty {|e| if $e == 2 { "found 2!"} }"#,
|
||||
description: "Iterate over each element, keeping null results",
|
||||
result: Some(Value::list(stream_test_2, Span::test_data())),
|
||||
result: Some(Value::test_list(vec![
|
||||
Value::nothing(Span::test_data()),
|
||||
Value::test_string("found 2!"),
|
||||
Value::nothing(Span::test_data()),
|
||||
])),
|
||||
},
|
||||
]
|
||||
}
|
||||
@ -124,6 +118,17 @@ with 'transpose' first."#
|
||||
let span = value.span();
|
||||
let is_error = value.is_error();
|
||||
match closure.run_with_value(value) {
|
||||
Ok(PipelineData::ListStream(s, ..)) => {
|
||||
let mut vals = vec![];
|
||||
for v in s {
|
||||
if let Value::Error { .. } = v {
|
||||
return Some(v);
|
||||
} else {
|
||||
vals.push(v)
|
||||
}
|
||||
}
|
||||
Some(Value::list(vals, span))
|
||||
}
|
||||
Ok(data) => Some(data.into_value(head)),
|
||||
Err(ShellError::Continue { span }) => Some(Value::nothing(span)),
|
||||
Err(ShellError::Break { .. }) => None,
|
||||
|
@ -18,7 +18,7 @@ impl Command for Enumerate {
|
||||
|
||||
fn signature(&self) -> nu_protocol::Signature {
|
||||
Signature::build("enumerate")
|
||||
.input_output_types(vec![(Type::Any, Type::Table(vec![]))])
|
||||
.input_output_types(vec![(Type::Any, Type::table())])
|
||||
.category(Category::Filters)
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ impl Command for Flatten {
|
||||
Type::List(Box::new(Type::Any)),
|
||||
Type::List(Box::new(Type::Any)),
|
||||
),
|
||||
(Type::Record(vec![]), Type::Table(vec![])),
|
||||
(Type::record(), Type::table()),
|
||||
])
|
||||
.rest(
|
||||
"rest",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user