mirror of
https://github.com/nushell/nushell
synced 2025-01-15 14:44:14 +00:00
Better error handling using do
(#5890)
* adds `capture-errors` flag for `do` * adds `get-type` core command to get type * fmt * add tests in example * fmt * fix tests * manually revert previous changes related to `get-type` * adds method to check for error name using `into string` * fix clippy
This commit is contained in:
parent
6ee13126f7
commit
a0db4ce747
8 changed files with 62 additions and 4 deletions
|
@ -2,8 +2,8 @@ use nu_engine::CallExt;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, CellPath},
|
ast::{Call, CellPath},
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span,
|
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
|
||||||
SyntaxShape, Value,
|
Span, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO num_format::SystemLocale once platform-specific dependencies are stable (see Cargo.toml)
|
// TODO num_format::SystemLocale once platform-specific dependencies are stable (see Cargo.toml)
|
||||||
|
@ -247,6 +247,15 @@ pub fn action(
|
||||||
val: input.into_string(", ", config),
|
val: input.into_string(", ", config),
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
|
Value::Error { error } => Value::String {
|
||||||
|
val: {
|
||||||
|
match into_code(error) {
|
||||||
|
Some(code) => code,
|
||||||
|
None => "".to_string(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
},
|
||||||
Value::Nothing { .. } => Value::String {
|
Value::Nothing { .. } => Value::String {
|
||||||
val: "".to_string(),
|
val: "".to_string(),
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use nu_engine::{eval_block, CallExt};
|
use nu_engine::{eval_block, CallExt};
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Value};
|
use nu_protocol::{
|
||||||
|
Category, Example, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Do;
|
pub struct Do;
|
||||||
|
@ -23,6 +25,11 @@ impl Command for Do {
|
||||||
"ignore errors as the block runs",
|
"ignore errors as the block runs",
|
||||||
Some('i'),
|
Some('i'),
|
||||||
)
|
)
|
||||||
|
.switch(
|
||||||
|
"capture-errors",
|
||||||
|
"capture errors as the block runs and return it",
|
||||||
|
Some('c'),
|
||||||
|
)
|
||||||
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
.rest("rest", SyntaxShape::Any, "the parameter(s) for the block")
|
||||||
.category(Category::Core)
|
.category(Category::Core)
|
||||||
}
|
}
|
||||||
|
@ -37,6 +44,7 @@ impl Command for Do {
|
||||||
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
|
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
|
||||||
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
|
||||||
let ignore_errors = call.has_flag("ignore-errors");
|
let ignore_errors = call.has_flag("ignore-errors");
|
||||||
|
let capture_errors = call.has_flag("capture-errors");
|
||||||
|
|
||||||
let mut stack = stack.captures_to_stack(&block.captures);
|
let mut stack = stack.captures_to_stack(&block.captures);
|
||||||
let block = engine_state.get_block(block.block_id);
|
let block = engine_state.get_block(block.block_id);
|
||||||
|
@ -85,7 +93,7 @@ impl Command for Do {
|
||||||
block,
|
block,
|
||||||
input,
|
input,
|
||||||
call.redirect_stdout,
|
call.redirect_stdout,
|
||||||
ignore_errors,
|
ignore_errors || capture_errors,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ignore_errors {
|
if ignore_errors {
|
||||||
|
@ -93,6 +101,11 @@ impl Command for Do {
|
||||||
Ok(x) => Ok(x),
|
Ok(x) => Ok(x),
|
||||||
Err(_) => Ok(PipelineData::new(call.head)),
|
Err(_) => Ok(PipelineData::new(call.head)),
|
||||||
}
|
}
|
||||||
|
} else if capture_errors {
|
||||||
|
match result {
|
||||||
|
Ok(x) => Ok(x),
|
||||||
|
Err(err) => Ok((Value::Error { error: err }).into_pipeline_data()),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
13
crates/nu-command/tests/commands/do_.rs
Normal file
13
crates/nu-command/tests/commands/do_.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use nu_test_support::{nu, pipeline};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capture_errors_works() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(
|
||||||
|
r#"
|
||||||
|
do -c {$env.use} | describe
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "error");
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ mod cp;
|
||||||
mod date;
|
mod date;
|
||||||
mod def;
|
mod def;
|
||||||
mod default;
|
mod default;
|
||||||
|
mod do_;
|
||||||
mod drop;
|
mod drop;
|
||||||
mod each;
|
mod each;
|
||||||
mod echo;
|
mod echo;
|
||||||
|
|
|
@ -171,3 +171,15 @@ fn from_nothing() {
|
||||||
|
|
||||||
assert_eq!(actual.out, "");
|
assert_eq!(actual.out, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_error() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(
|
||||||
|
r#"
|
||||||
|
do -c {$env.use} | into string
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(actual.out, "nu::shell::name_not_found");
|
||||||
|
}
|
||||||
|
|
|
@ -2670,6 +2670,7 @@ pub fn parse_shape_name(
|
||||||
b"record" => SyntaxShape::Record,
|
b"record" => SyntaxShape::Record,
|
||||||
b"list" => SyntaxShape::List(Box::new(SyntaxShape::Any)),
|
b"list" => SyntaxShape::List(Box::new(SyntaxShape::Any)),
|
||||||
b"table" => SyntaxShape::Table,
|
b"table" => SyntaxShape::Table,
|
||||||
|
b"error" => SyntaxShape::Error,
|
||||||
_ => {
|
_ => {
|
||||||
if bytes.contains(&b'@') {
|
if bytes.contains(&b'@') {
|
||||||
let str = String::from_utf8_lossy(bytes);
|
let str = String::from_utf8_lossy(bytes);
|
||||||
|
|
|
@ -724,6 +724,10 @@ impl From<Box<dyn std::error::Error + Send + Sync>> for ShellError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn into_code(err: &ShellError) -> Option<String> {
|
||||||
|
err.code().map(|code| code.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn did_you_mean(possibilities: &[String], tried: &str) -> Option<String> {
|
pub fn did_you_mean(possibilities: &[String], tried: &str) -> Option<String> {
|
||||||
let mut possible_matches: Vec<_> = possibilities
|
let mut possible_matches: Vec<_> = possibilities
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -92,6 +92,9 @@ pub enum SyntaxShape {
|
||||||
/// A record value
|
/// A record value
|
||||||
Record,
|
Record,
|
||||||
|
|
||||||
|
/// An error value
|
||||||
|
Error,
|
||||||
|
|
||||||
/// A custom shape with custom completion logic
|
/// A custom shape with custom completion logic
|
||||||
Custom(Box<SyntaxShape>, DeclId),
|
Custom(Box<SyntaxShape>, DeclId),
|
||||||
}
|
}
|
||||||
|
@ -112,6 +115,7 @@ impl SyntaxShape {
|
||||||
SyntaxShape::Filesize => Type::Filesize,
|
SyntaxShape::Filesize => Type::Filesize,
|
||||||
SyntaxShape::FullCellPath => Type::Any,
|
SyntaxShape::FullCellPath => Type::Any,
|
||||||
SyntaxShape::GlobPattern => Type::String,
|
SyntaxShape::GlobPattern => Type::String,
|
||||||
|
SyntaxShape::Error => Type::Error,
|
||||||
SyntaxShape::ImportPattern => Type::Any,
|
SyntaxShape::ImportPattern => Type::Any,
|
||||||
SyntaxShape::Int => Type::Int,
|
SyntaxShape::Int => Type::Int,
|
||||||
SyntaxShape::List(x) => {
|
SyntaxShape::List(x) => {
|
||||||
|
@ -168,6 +172,7 @@ impl Display for SyntaxShape {
|
||||||
SyntaxShape::Signature => write!(f, "signature"),
|
SyntaxShape::Signature => write!(f, "signature"),
|
||||||
SyntaxShape::Expression => write!(f, "expression"),
|
SyntaxShape::Expression => write!(f, "expression"),
|
||||||
SyntaxShape::Boolean => write!(f, "bool"),
|
SyntaxShape::Boolean => write!(f, "bool"),
|
||||||
|
SyntaxShape::Error => write!(f, "error"),
|
||||||
SyntaxShape::Custom(x, _) => write!(f, "custom<{}>", x),
|
SyntaxShape::Custom(x, _) => write!(f, "custom<{}>", x),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue