From d43489a6a00387f49c9cac91c28e4a66a86c7cf2 Mon Sep 17 00:00:00 2001 From: Tiffany Bennett Date: Fri, 5 Mar 2021 21:46:27 -0800 Subject: [PATCH] Add exit code argument (#3132) --- crates/nu-command/src/commands/exit.rs | 22 +++++++++++++++++----- crates/nu-engine/src/evaluate/internal.rs | 6 +++--- crates/nu-protocol/src/return_value.rs | 8 ++++---- crates/nu-protocol/src/value.rs | 8 ++++++++ crates/nu-protocol/src/value/primitive.rs | 23 +++++++++++++++++++++++ 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/crates/nu-command/src/commands/exit.rs b/crates/nu-command/src/commands/exit.rs index 3bc68398a..475abb849 100644 --- a/crates/nu-command/src/commands/exit.rs +++ b/crates/nu-command/src/commands/exit.rs @@ -1,6 +1,6 @@ use crate::prelude::*; use nu_errors::ShellError; -use nu_protocol::{CommandAction, ReturnSuccess, Signature}; +use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape}; pub struct Exit; @@ -11,7 +11,13 @@ impl WholeStreamCommand for Exit { } fn signature(&self) -> Signature { - Signature::build("exit").switch("now", "exit out of the shell immediately", Some('n')) + Signature::build("exit") + .optional( + "code", + SyntaxShape::Number, + "Status code to return if this was the last shell or --now was specified", + ) + .switch("now", "Exit out of the shell immediately", Some('n')) } fn usage(&self) -> &str { @@ -41,10 +47,16 @@ impl WholeStreamCommand for Exit { pub async fn exit(args: CommandArgs) -> Result { let args = args.evaluate_once().await?; - let command_action = if args.call_info.args.has("now") { - CommandAction::Exit + let code = if let Some(value) = args.call_info.args.nth(0) { + value.as_i32()? } else { - CommandAction::LeaveShell + 0 + }; + + let command_action = if args.call_info.args.has("now") { + CommandAction::Exit(code) + } else { + CommandAction::LeaveShell(code) }; Ok(OutputStream::one(ReturnSuccess::action(command_action))) diff --git a/crates/nu-engine/src/evaluate/internal.rs b/crates/nu-engine/src/evaluate/internal.rs index 98e12e12a..f0b0bdc89 100644 --- a/crates/nu-engine/src/evaluate/internal.rs +++ b/crates/nu-engine/src/evaluate/internal.rs @@ -62,7 +62,7 @@ pub(crate) async fn run_internal_command( context.shell_manager.set_path(path); InputStream::empty() } - CommandAction::Exit => std::process::exit(0), // TODO: save history.txt + CommandAction::Exit(code) => std::process::exit(code), // TODO: save history.txt CommandAction::Error(err) => { context.error(err); InputStream::empty() @@ -213,10 +213,10 @@ pub(crate) async fn run_internal_command( context.shell_manager.next(); InputStream::empty() } - CommandAction::LeaveShell => { + CommandAction::LeaveShell(code) => { context.shell_manager.remove_at_current(); if context.shell_manager.is_empty() { - std::process::exit(0); // TODO: save history.txt + std::process::exit(code); // TODO: save history.txt } InputStream::empty() } diff --git a/crates/nu-protocol/src/return_value.rs b/crates/nu-protocol/src/return_value.rs index 14299d2b1..9e1f8fdca 100644 --- a/crates/nu-protocol/src/return_value.rs +++ b/crates/nu-protocol/src/return_value.rs @@ -9,7 +9,7 @@ pub enum CommandAction { /// Change to a new directory or path (in non-filesystem situations) ChangePath(String), /// Exit out of Nu - Exit, + Exit(i32), /// Display an error Error(ShellError), /// Enter a new shell at the given path @@ -27,7 +27,7 @@ pub enum CommandAction { /// Go to the next shell in the shell ring buffer NextShell, /// Leave the current shell. If it's the last shell, exit out of Nu - LeaveShell, + LeaveShell(i32), } impl PrettyDebug for CommandAction { @@ -37,7 +37,7 @@ impl PrettyDebug for CommandAction { CommandAction::ChangePath(path) => { DbgDocBldr::typed("change path", DbgDocBldr::description(path)) } - CommandAction::Exit => DbgDocBldr::description("exit"), + CommandAction::Exit(_) => DbgDocBldr::description("exit"), CommandAction::Error(_) => DbgDocBldr::error("error"), CommandAction::AutoConvert(_, extension) => { DbgDocBldr::typed("auto convert", DbgDocBldr::description(extension)) @@ -50,7 +50,7 @@ impl PrettyDebug for CommandAction { CommandAction::AddPlugins(..) => DbgDocBldr::description("add plugins"), CommandAction::PreviousShell => DbgDocBldr::description("previous shell"), CommandAction::NextShell => DbgDocBldr::description("next shell"), - CommandAction::LeaveShell => DbgDocBldr::description("leave shell"), + CommandAction::LeaveShell(_) => DbgDocBldr::description("leave shell"), } } } diff --git a/crates/nu-protocol/src/value.rs b/crates/nu-protocol/src/value.rs index 176404bf5..569a1d926 100644 --- a/crates/nu-protocol/src/value.rs +++ b/crates/nu-protocol/src/value.rs @@ -445,6 +445,14 @@ impl Value { } } + /// View the Value as signed 64-bit, if possible + pub fn as_i32(&self) -> Result { + match &self.value { + UntaggedValue::Primitive(primitive) => primitive.as_i32(self.tag.span), + _ => Err(ShellError::type_error("integer", self.spanned_type_name())), + } + } + /// View the Value as boolean, if possible pub fn as_bool(&self) -> Result { match &self.value { diff --git a/crates/nu-protocol/src/value/primitive.rs b/crates/nu-protocol/src/value/primitive.rs index 1561469c7..e91a3e40a 100644 --- a/crates/nu-protocol/src/value/primitive.rs +++ b/crates/nu-protocol/src/value/primitive.rs @@ -107,6 +107,29 @@ impl Primitive { } } + pub fn as_i32(&self, span: Span) -> Result { + match self { + Primitive::Int(int) => int.to_i32().ok_or_else(|| { + ShellError::range_error( + ExpectedRange::I32, + &format!("{}", int).spanned(span), + "converting an integer into a signed 32-bit integer", + ) + }), + Primitive::Decimal(decimal) => decimal.to_i32().ok_or_else(|| { + ShellError::range_error( + ExpectedRange::I32, + &format!("{}", decimal).spanned(span), + "converting a decimal into a signed 32-bit integer", + ) + }), + other => Err(ShellError::type_error( + "number", + other.type_name().spanned(span), + )), + } + } + // FIXME: This is a bad name, but no other way to differentiate with our own Duration. pub fn into_chrono_duration(self, span: Span) -> Result { match self {