Add exit code argument (#3132)

This commit is contained in:
Tiffany Bennett 2021-03-05 21:46:27 -08:00 committed by GitHub
parent 983de8974b
commit d43489a6a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 12 deletions

View File

@ -1,6 +1,6 @@
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{CommandAction, ReturnSuccess, Signature}; use nu_protocol::{CommandAction, ReturnSuccess, Signature, SyntaxShape};
pub struct Exit; pub struct Exit;
@ -11,7 +11,13 @@ impl WholeStreamCommand for Exit {
} }
fn signature(&self) -> Signature { 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 { fn usage(&self) -> &str {
@ -41,10 +47,16 @@ impl WholeStreamCommand for Exit {
pub async fn exit(args: CommandArgs) -> Result<OutputStream, ShellError> { pub async fn exit(args: CommandArgs) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once().await?; let args = args.evaluate_once().await?;
let command_action = if args.call_info.args.has("now") { let code = if let Some(value) = args.call_info.args.nth(0) {
CommandAction::Exit value.as_i32()?
} else { } 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))) Ok(OutputStream::one(ReturnSuccess::action(command_action)))

View File

@ -62,7 +62,7 @@ pub(crate) async fn run_internal_command(
context.shell_manager.set_path(path); context.shell_manager.set_path(path);
InputStream::empty() 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) => { CommandAction::Error(err) => {
context.error(err); context.error(err);
InputStream::empty() InputStream::empty()
@ -213,10 +213,10 @@ pub(crate) async fn run_internal_command(
context.shell_manager.next(); context.shell_manager.next();
InputStream::empty() InputStream::empty()
} }
CommandAction::LeaveShell => { CommandAction::LeaveShell(code) => {
context.shell_manager.remove_at_current(); context.shell_manager.remove_at_current();
if context.shell_manager.is_empty() { if context.shell_manager.is_empty() {
std::process::exit(0); // TODO: save history.txt std::process::exit(code); // TODO: save history.txt
} }
InputStream::empty() InputStream::empty()
} }

View File

@ -9,7 +9,7 @@ pub enum CommandAction {
/// Change to a new directory or path (in non-filesystem situations) /// Change to a new directory or path (in non-filesystem situations)
ChangePath(String), ChangePath(String),
/// Exit out of Nu /// Exit out of Nu
Exit, Exit(i32),
/// Display an error /// Display an error
Error(ShellError), Error(ShellError),
/// Enter a new shell at the given path /// 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 /// Go to the next shell in the shell ring buffer
NextShell, NextShell,
/// Leave the current shell. If it's the last shell, exit out of Nu /// Leave the current shell. If it's the last shell, exit out of Nu
LeaveShell, LeaveShell(i32),
} }
impl PrettyDebug for CommandAction { impl PrettyDebug for CommandAction {
@ -37,7 +37,7 @@ impl PrettyDebug for CommandAction {
CommandAction::ChangePath(path) => { CommandAction::ChangePath(path) => {
DbgDocBldr::typed("change path", DbgDocBldr::description(path)) DbgDocBldr::typed("change path", DbgDocBldr::description(path))
} }
CommandAction::Exit => DbgDocBldr::description("exit"), CommandAction::Exit(_) => DbgDocBldr::description("exit"),
CommandAction::Error(_) => DbgDocBldr::error("error"), CommandAction::Error(_) => DbgDocBldr::error("error"),
CommandAction::AutoConvert(_, extension) => { CommandAction::AutoConvert(_, extension) => {
DbgDocBldr::typed("auto convert", DbgDocBldr::description(extension)) DbgDocBldr::typed("auto convert", DbgDocBldr::description(extension))
@ -50,7 +50,7 @@ impl PrettyDebug for CommandAction {
CommandAction::AddPlugins(..) => DbgDocBldr::description("add plugins"), CommandAction::AddPlugins(..) => DbgDocBldr::description("add plugins"),
CommandAction::PreviousShell => DbgDocBldr::description("previous shell"), CommandAction::PreviousShell => DbgDocBldr::description("previous shell"),
CommandAction::NextShell => DbgDocBldr::description("next shell"), CommandAction::NextShell => DbgDocBldr::description("next shell"),
CommandAction::LeaveShell => DbgDocBldr::description("leave shell"), CommandAction::LeaveShell(_) => DbgDocBldr::description("leave shell"),
} }
} }
} }

View File

@ -445,6 +445,14 @@ impl Value {
} }
} }
/// View the Value as signed 64-bit, if possible
pub fn as_i32(&self) -> Result<i32, ShellError> {
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 /// View the Value as boolean, if possible
pub fn as_bool(&self) -> Result<bool, ShellError> { pub fn as_bool(&self) -> Result<bool, ShellError> {
match &self.value { match &self.value {

View File

@ -107,6 +107,29 @@ impl Primitive {
} }
} }
pub fn as_i32(&self, span: Span) -> Result<i32, ShellError> {
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. // 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<chrono::Duration, ShellError> { pub fn into_chrono_duration(self, span: Span) -> Result<chrono::Duration, ShellError> {
match self { match self {