mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 15:39:06 +01:00
Add -c flag and others to cmdline args (#853)
* Add -c flag and others to cmdline args * finish a little bit of cleanup * Oops, forgot file
This commit is contained in:
parent
8ee619954d
commit
83ec374995
@ -206,7 +206,10 @@ pub fn get_documentation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(rest_positional) = &sig.rest_positional {
|
if let Some(rest_positional) = &sig.rest_positional {
|
||||||
long_desc.push_str(&format!(" ...args: {}\n", rest_positional.desc));
|
long_desc.push_str(&format!(
|
||||||
|
" ...{}: {}\n",
|
||||||
|
rest_positional.name, rest_positional.desc
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,7 +270,7 @@ fn get_flags_section(signature: &Signature) -> String {
|
|||||||
if let Some(short) = flag.short {
|
if let Some(short) = flag.short {
|
||||||
if flag.required {
|
if flag.required {
|
||||||
format!(
|
format!(
|
||||||
" -{}{} (required parameter) {:?} {}\n",
|
" -{}{} (required parameter) {:?}\n {}\n",
|
||||||
short,
|
short,
|
||||||
if !flag.long.is_empty() {
|
if !flag.long.is_empty() {
|
||||||
format!(", --{}", flag.long)
|
format!(", --{}", flag.long)
|
||||||
@ -279,7 +282,7 @@ fn get_flags_section(signature: &Signature) -> String {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
" -{}{} {:?} {}\n",
|
" -{}{} <{:?}>\n {}\n",
|
||||||
short,
|
short,
|
||||||
if !flag.long.is_empty() {
|
if !flag.long.is_empty() {
|
||||||
format!(", --{}", flag.long)
|
format!(", --{}", flag.long)
|
||||||
@ -292,16 +295,16 @@ fn get_flags_section(signature: &Signature) -> String {
|
|||||||
}
|
}
|
||||||
} else if flag.required {
|
} else if flag.required {
|
||||||
format!(
|
format!(
|
||||||
" --{} (required parameter) {:?} {}\n",
|
" --{} (required parameter) <{:?}>\n {}\n",
|
||||||
flag.long, arg, flag.desc
|
flag.long, arg, flag.desc
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(" --{} {:?} {}\n", flag.long, arg, flag.desc)
|
format!(" --{} {:?}\n {}\n", flag.long, arg, flag.desc)
|
||||||
}
|
}
|
||||||
} else if let Some(short) = flag.short {
|
} else if let Some(short) = flag.short {
|
||||||
if flag.required {
|
if flag.required {
|
||||||
format!(
|
format!(
|
||||||
" -{}{} (required parameter) {}\n",
|
" -{}{} (required parameter)\n {}\n",
|
||||||
short,
|
short,
|
||||||
if !flag.long.is_empty() {
|
if !flag.long.is_empty() {
|
||||||
format!(", --{}", flag.long)
|
format!(", --{}", flag.long)
|
||||||
@ -312,7 +315,7 @@ fn get_flags_section(signature: &Signature) -> String {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(
|
format!(
|
||||||
" -{}{} {}\n",
|
" -{}{}\n {}\n",
|
||||||
short,
|
short,
|
||||||
if !flag.long.is_empty() {
|
if !flag.long.is_empty() {
|
||||||
format!(", --{}", flag.long)
|
format!(", --{}", flag.long)
|
||||||
@ -323,9 +326,12 @@ fn get_flags_section(signature: &Signature) -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if flag.required {
|
} else if flag.required {
|
||||||
format!(" --{} (required parameter) {}\n", flag.long, flag.desc)
|
format!(
|
||||||
|
" --{} (required parameter)\n {}\n",
|
||||||
|
flag.long, flag.desc
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!(" --{} {}\n", flag.long, flag.desc)
|
format!(" --{}\n {}\n", flag.long, flag.desc)
|
||||||
};
|
};
|
||||||
long_desc.push_str(&msg);
|
long_desc.push_str(&msg);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ pub use flatten::{
|
|||||||
pub use lex::{lex, Token, TokenContents};
|
pub use lex::{lex, Token, TokenContents};
|
||||||
pub use lite_parse::{lite_parse, LiteBlock};
|
pub use lite_parse::{lite_parse, LiteBlock};
|
||||||
|
|
||||||
pub use parser::{find_captures_in_expr, parse, trim_quotes, Import};
|
pub use parser::{find_captures_in_expr, parse, parse_block, trim_quotes, Import};
|
||||||
|
|
||||||
#[cfg(feature = "plugin")]
|
#[cfg(feature = "plugin")]
|
||||||
pub use parse_keywords::parse_register;
|
pub use parse_keywords::parse_register;
|
||||||
|
136
src/commands.rs
Normal file
136
src/commands.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use miette::Result;
|
||||||
|
use nu_engine::{convert_env_values, eval_block};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use nu_parser::{lex, lite_parse, parse_block, trim_quotes};
|
||||||
|
use nu_protocol::{
|
||||||
|
engine::{EngineState, StateDelta, StateWorkingSet},
|
||||||
|
Config, PipelineData, Span, Spanned, Value, CONFIG_VARIABLE_ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::utils::{gather_parent_env_vars, report_error};
|
||||||
|
|
||||||
|
pub(crate) fn evaluate(
|
||||||
|
commands: &Spanned<String>,
|
||||||
|
init_cwd: &Path,
|
||||||
|
engine_state: &mut EngineState,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<()> {
|
||||||
|
// First, set up env vars as strings only
|
||||||
|
gather_parent_env_vars(engine_state);
|
||||||
|
|
||||||
|
// Run a command (or commands) given to us by the user
|
||||||
|
let (block, delta) = {
|
||||||
|
let mut working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
|
let (input, span_offset) =
|
||||||
|
if commands.item.starts_with('\'') || commands.item.starts_with('"') {
|
||||||
|
(
|
||||||
|
trim_quotes(commands.item.as_bytes()),
|
||||||
|
commands.span.start + 1,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(commands.item.as_bytes(), commands.span.start)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (output, err) = lex(input, span_offset, &[], &[], false);
|
||||||
|
if let Some(err) = err {
|
||||||
|
report_error(&working_set, &err);
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (output, err) = lite_parse(&output);
|
||||||
|
if let Some(err) = err {
|
||||||
|
report_error(&working_set, &err);
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (output, err) = parse_block(&mut working_set, &output, false);
|
||||||
|
if let Some(err) = err {
|
||||||
|
report_error(&working_set, &err);
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(err) = err {
|
||||||
|
report_error(&working_set, &err);
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
(output, working_set.render())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(err) = engine_state.merge_delta(delta, None, init_cwd) {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
report_error(&working_set, &err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stack = nu_protocol::engine::Stack::new();
|
||||||
|
|
||||||
|
// Set up our initial config to start from
|
||||||
|
stack.vars.insert(
|
||||||
|
CONFIG_VARIABLE_ID,
|
||||||
|
Value::Record {
|
||||||
|
cols: vec![],
|
||||||
|
vals: vec![],
|
||||||
|
span: Span { start: 0, end: 0 },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let config = match stack.get_config() {
|
||||||
|
Ok(config) => config,
|
||||||
|
Err(e) => {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
|
report_error(&working_set, &e);
|
||||||
|
Config::default()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Merge the delta in case env vars changed in the config
|
||||||
|
match nu_engine::env::current_dir(engine_state, &stack) {
|
||||||
|
Ok(cwd) => {
|
||||||
|
if let Err(e) = engine_state.merge_delta(StateDelta::new(), Some(&mut stack), cwd) {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
report_error(&working_set, &e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
report_error(&working_set, &e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate environment variables from Strings to Values
|
||||||
|
if let Some(e) = convert_env_values(engine_state, &stack, &config) {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
report_error(&working_set, &e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
match eval_block(engine_state, &mut stack, &block, input) {
|
||||||
|
Ok(pipeline_data) => {
|
||||||
|
for item in pipeline_data {
|
||||||
|
if let Value::Error { error } = item {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
|
report_error(&working_set, &error);
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
println!("{}", item.into_string("\n", &config));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let working_set = StateWorkingSet::new(engine_state);
|
||||||
|
|
||||||
|
report_error(&working_set, &err);
|
||||||
|
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
80
src/main.rs
80
src/main.rs
@ -1,3 +1,4 @@
|
|||||||
|
mod commands;
|
||||||
mod config_files;
|
mod config_files;
|
||||||
mod eval_file;
|
mod eval_file;
|
||||||
mod logger;
|
mod logger;
|
||||||
@ -75,9 +76,17 @@ fn main() -> Result<()> {
|
|||||||
let mut collect_arg_nushell = false;
|
let mut collect_arg_nushell = false;
|
||||||
for arg in std::env::args().skip(1) {
|
for arg in std::env::args().skip(1) {
|
||||||
if !script_name.is_empty() {
|
if !script_name.is_empty() {
|
||||||
args_to_script.push(arg);
|
args_to_script.push(if arg.contains(' ') {
|
||||||
|
format!("'{}'", arg)
|
||||||
|
} else {
|
||||||
|
arg
|
||||||
|
});
|
||||||
} else if collect_arg_nushell {
|
} else if collect_arg_nushell {
|
||||||
args_to_nushell.push(arg);
|
args_to_nushell.push(if arg.contains(' ') {
|
||||||
|
format!("'{}'", arg)
|
||||||
|
} else {
|
||||||
|
arg
|
||||||
|
});
|
||||||
collect_arg_nushell = false;
|
collect_arg_nushell = false;
|
||||||
} else if arg.starts_with('-') {
|
} else if arg.starts_with('-') {
|
||||||
// Cool, it's a flag
|
// Cool, it's a flag
|
||||||
@ -106,23 +115,25 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
match nushell_config {
|
match nushell_config {
|
||||||
Ok(nushell_config) => {
|
Ok(nushell_config) => {
|
||||||
if !script_name.is_empty() {
|
let input = if let Some(redirect_stdin) = &nushell_config.redirect_stdin {
|
||||||
let input = if let Some(redirect_stdin) = &nushell_config.redirect_stdin {
|
let stdin = std::io::stdin();
|
||||||
let stdin = std::io::stdin();
|
let buf_reader = BufReader::new(stdin);
|
||||||
let buf_reader = BufReader::new(stdin);
|
|
||||||
|
|
||||||
PipelineData::ByteStream(
|
PipelineData::ByteStream(
|
||||||
ByteStream {
|
ByteStream {
|
||||||
stream: Box::new(BufferedReader::new(buf_reader)),
|
stream: Box::new(BufferedReader::new(buf_reader)),
|
||||||
ctrlc: Some(ctrlc),
|
ctrlc: Some(ctrlc),
|
||||||
},
|
},
|
||||||
redirect_stdin.span,
|
redirect_stdin.span,
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
PipelineData::new(Span::new(0, 0))
|
PipelineData::new(Span::new(0, 0))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(commands) = &nushell_config.commands {
|
||||||
|
commands::evaluate(commands, &init_cwd, &mut engine_state, input)
|
||||||
|
} else if !script_name.is_empty() && nushell_config.interactive_shell.is_none() {
|
||||||
eval_file::evaluate(
|
eval_file::evaluate(
|
||||||
script_name,
|
script_name,
|
||||||
&args_to_script,
|
&args_to_script,
|
||||||
@ -131,7 +142,7 @@ fn main() -> Result<()> {
|
|||||||
input,
|
input,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
repl::evaluate(ctrlc, &mut engine_state)
|
repl::evaluate(&mut engine_state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => std::process::exit(1),
|
Err(_) => std::process::exit(1),
|
||||||
@ -178,6 +189,20 @@ fn parse_commandline_args(
|
|||||||
}) = expressions.get(0)
|
}) = expressions.get(0)
|
||||||
{
|
{
|
||||||
let redirect_stdin = call.get_named_arg("stdin");
|
let redirect_stdin = call.get_named_arg("stdin");
|
||||||
|
let login_shell = call.get_named_arg("login");
|
||||||
|
let interactive_shell = call.get_named_arg("interactive");
|
||||||
|
let commands: Option<Expression> = call.get_flag_expr("commands");
|
||||||
|
|
||||||
|
let commands = if let Some(expression) = commands {
|
||||||
|
let contents = engine_state.get_span_contents(&expression.span);
|
||||||
|
|
||||||
|
Some(Spanned {
|
||||||
|
item: String::from_utf8_lossy(contents).to_string(),
|
||||||
|
span: expression.span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let help = call.has_flag("help");
|
let help = call.has_flag("help");
|
||||||
|
|
||||||
@ -188,7 +213,12 @@ fn parse_commandline_args(
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(NushellConfig { redirect_stdin });
|
return Ok(NushellConfig {
|
||||||
|
redirect_stdin,
|
||||||
|
login_shell,
|
||||||
|
interactive_shell,
|
||||||
|
commands,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +230,10 @@ fn parse_commandline_args(
|
|||||||
|
|
||||||
struct NushellConfig {
|
struct NushellConfig {
|
||||||
redirect_stdin: Option<Spanned<String>>,
|
redirect_stdin: Option<Spanned<String>>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
login_shell: Option<Spanned<String>>,
|
||||||
|
interactive_shell: Option<Spanned<String>>,
|
||||||
|
commands: Option<Spanned<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -214,6 +248,14 @@ impl Command for Nu {
|
|||||||
Signature::build("nu")
|
Signature::build("nu")
|
||||||
.desc("The nushell language and shell.")
|
.desc("The nushell language and shell.")
|
||||||
.switch("stdin", "redirect the stdin", None)
|
.switch("stdin", "redirect the stdin", None)
|
||||||
|
.switch("login", "start as a login shell", Some('l'))
|
||||||
|
.switch("interactive", "start as an interactive shell", Some('i'))
|
||||||
|
.named(
|
||||||
|
"commands",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"run the given commands and then exit",
|
||||||
|
Some('c'),
|
||||||
|
)
|
||||||
.optional(
|
.optional(
|
||||||
"script file",
|
"script file",
|
||||||
SyntaxShape::Filepath,
|
SyntaxShape::Filepath,
|
||||||
|
14
src/repl.rs
14
src/repl.rs
@ -1,10 +1,4 @@
|
|||||||
use std::{
|
use std::{sync::atomic::Ordering, time::Instant};
|
||||||
sync::{
|
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
time::Instant,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{config_files, prompt_update, reedline_config};
|
use crate::{config_files, prompt_update, reedline_config};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -23,7 +17,7 @@ use nu_protocol::{
|
|||||||
};
|
};
|
||||||
use reedline::{DefaultHinter, Emacs, Vi};
|
use reedline::{DefaultHinter, Emacs, Vi};
|
||||||
|
|
||||||
pub(crate) fn evaluate(ctrlc: Arc<AtomicBool>, engine_state: &mut EngineState) -> Result<()> {
|
pub(crate) fn evaluate(engine_state: &mut EngineState) -> Result<()> {
|
||||||
use crate::logger::{configure, logger};
|
use crate::logger::{configure, logger};
|
||||||
use reedline::{FileBackedHistory, Reedline, Signal};
|
use reedline::{FileBackedHistory, Reedline, Signal};
|
||||||
|
|
||||||
@ -97,7 +91,9 @@ pub(crate) fn evaluate(ctrlc: Arc<AtomicBool>, engine_state: &mut EngineState) -
|
|||||||
};
|
};
|
||||||
|
|
||||||
//Reset the ctrl-c handler
|
//Reset the ctrl-c handler
|
||||||
ctrlc.store(false, Ordering::SeqCst);
|
if let Some(ctrlc) = &mut engine_state.ctrlc {
|
||||||
|
ctrlc.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
let line_editor = Reedline::create()
|
let line_editor = Reedline::create()
|
||||||
.into_diagnostic()?
|
.into_diagnostic()?
|
||||||
|
@ -72,7 +72,7 @@ fn in_variable_6() -> TestResult {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn help_works_with_missing_requirements() -> TestResult {
|
fn help_works_with_missing_requirements() -> TestResult {
|
||||||
run_test(r#"each --help | lines | length"#, "15")
|
run_test(r#"each --help | lines | length"#, "17")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user