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:
pwygab 2022-06-30 09:01:34 +08:00 committed by GitHub
parent 6ee13126f7
commit a0db4ce747
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 4 deletions

View file

@ -2,8 +2,8 @@ use nu_engine::CallExt;
use nu_protocol::{
ast::{Call, CellPath},
engine::{Command, EngineState, Stack},
Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
into_code, Category, Config, Example, IntoPipelineData, PipelineData, ShellError, Signature,
Span, SyntaxShape, Value,
};
// 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),
span,
},
Value::Error { error } => Value::String {
val: {
match into_code(error) {
Some(code) => code,
None => "".to_string(),
}
},
span,
},
Value::Nothing { .. } => Value::String {
val: "".to_string(),
span,

View file

@ -1,7 +1,9 @@
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
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)]
pub struct Do;
@ -23,6 +25,11 @@ impl Command for Do {
"ignore errors as the block runs",
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")
.category(Category::Core)
}
@ -37,6 +44,7 @@ impl Command for Do {
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
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 block = engine_state.get_block(block.block_id);
@ -85,7 +93,7 @@ impl Command for Do {
block,
input,
call.redirect_stdout,
ignore_errors,
ignore_errors || capture_errors,
);
if ignore_errors {
@ -93,6 +101,11 @@ impl Command for Do {
Ok(x) => Ok(x),
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 {
result
}

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

View file

@ -9,6 +9,7 @@ mod cp;
mod date;
mod def;
mod default;
mod do_;
mod drop;
mod each;
mod echo;

View file

@ -171,3 +171,15 @@ fn from_nothing() {
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");
}

View file

@ -2670,6 +2670,7 @@ pub fn parse_shape_name(
b"record" => SyntaxShape::Record,
b"list" => SyntaxShape::List(Box::new(SyntaxShape::Any)),
b"table" => SyntaxShape::Table,
b"error" => SyntaxShape::Error,
_ => {
if bytes.contains(&b'@') {
let str = String::from_utf8_lossy(bytes);

View file

@ -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> {
let mut possible_matches: Vec<_> = possibilities
.iter()

View file

@ -92,6 +92,9 @@ pub enum SyntaxShape {
/// A record value
Record,
/// An error value
Error,
/// A custom shape with custom completion logic
Custom(Box<SyntaxShape>, DeclId),
}
@ -112,6 +115,7 @@ impl SyntaxShape {
SyntaxShape::Filesize => Type::Filesize,
SyntaxShape::FullCellPath => Type::Any,
SyntaxShape::GlobPattern => Type::String,
SyntaxShape::Error => Type::Error,
SyntaxShape::ImportPattern => Type::Any,
SyntaxShape::Int => Type::Int,
SyntaxShape::List(x) => {
@ -168,6 +172,7 @@ impl Display for SyntaxShape {
SyntaxShape::Signature => write!(f, "signature"),
SyntaxShape::Expression => write!(f, "expression"),
SyntaxShape::Boolean => write!(f, "bool"),
SyntaxShape::Error => write!(f, "error"),
SyntaxShape::Custom(x, _) => write!(f, "custom<{}>", x),
}
}