forked from extern/nushell
Merge pull request #615 from jonathandturner/echo
Fix exec::shell and add echo command
This commit is contained in:
commit
07151b8360
@ -210,6 +210,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||||||
per_item_command(Open),
|
per_item_command(Open),
|
||||||
per_item_command(Post),
|
per_item_command(Post),
|
||||||
per_item_command(Where),
|
per_item_command(Where),
|
||||||
|
per_item_command(Echo),
|
||||||
whole_stream_command(Config),
|
whole_stream_command(Config),
|
||||||
whole_stream_command(SkipWhile),
|
whole_stream_command(SkipWhile),
|
||||||
per_item_command(Enter),
|
per_item_command(Enter),
|
||||||
|
@ -11,6 +11,7 @@ pub(crate) mod config;
|
|||||||
pub(crate) mod cp;
|
pub(crate) mod cp;
|
||||||
pub(crate) mod date;
|
pub(crate) mod date;
|
||||||
pub(crate) mod debug;
|
pub(crate) mod debug;
|
||||||
|
pub(crate) mod echo;
|
||||||
pub(crate) mod enter;
|
pub(crate) mod enter;
|
||||||
pub(crate) mod exit;
|
pub(crate) mod exit;
|
||||||
pub(crate) mod fetch;
|
pub(crate) mod fetch;
|
||||||
@ -76,6 +77,7 @@ pub(crate) use config::Config;
|
|||||||
pub(crate) use cp::Cpy;
|
pub(crate) use cp::Cpy;
|
||||||
pub(crate) use date::Date;
|
pub(crate) use date::Date;
|
||||||
pub(crate) use debug::Debug;
|
pub(crate) use debug::Debug;
|
||||||
|
pub(crate) use echo::Echo;
|
||||||
pub(crate) use enter::Enter;
|
pub(crate) use enter::Enter;
|
||||||
pub(crate) use exit::Exit;
|
pub(crate) use exit::Exit;
|
||||||
pub(crate) use fetch::Fetch;
|
pub(crate) use fetch::Fetch;
|
||||||
|
@ -58,7 +58,7 @@ pub fn autoview(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if is_single_text_value(&input) {
|
} else if is_single_origined_text_value(&input) {
|
||||||
let text = context.get_command("textview");
|
let text = context.get_command("textview");
|
||||||
if let Some(text) = text {
|
if let Some(text) = text {
|
||||||
let result = text.run(raw.with_input(input), &context.commands);
|
let result = text.run(raw.with_input(input), &context.commands);
|
||||||
@ -73,6 +73,15 @@ pub fn autoview(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if is_single_text_value(&input) {
|
||||||
|
for i in input {
|
||||||
|
match i.item {
|
||||||
|
Value::Primitive(Primitive::String(s)) => {
|
||||||
|
println!("{}", s);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let table = context.expect_command("table");
|
let table = context.expect_command("table");
|
||||||
let result = table.run(raw.with_input(input), &context.commands);
|
let result = table.run(raw.with_input(input), &context.commands);
|
||||||
@ -96,3 +105,20 @@ fn is_single_text_value(input: &Vec<Tagged<Value>>) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_single_origined_text_value(input: &Vec<Tagged<Value>>) -> bool {
|
||||||
|
if input.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if let Tagged {
|
||||||
|
item: Value::Primitive(Primitive::String(_)),
|
||||||
|
tag: Tag {
|
||||||
|
origin: Some(_), ..
|
||||||
|
},
|
||||||
|
} = input[0]
|
||||||
|
{
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -220,9 +220,7 @@ impl ExternalCommand {
|
|||||||
|
|
||||||
let mut process;
|
let mut process;
|
||||||
|
|
||||||
#[cfg(windows)]
|
process = Exec::cmd(&self.name);
|
||||||
{
|
|
||||||
process = Exec::shell(&self.name);
|
|
||||||
|
|
||||||
if arg_string.contains("$it") {
|
if arg_string.contains("$it") {
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
@ -275,56 +273,7 @@ impl ExternalCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
{
|
|
||||||
let mut new_arg_string = self.name.to_string();
|
|
||||||
|
|
||||||
if arg_string.contains("$it") {
|
|
||||||
let mut first = true;
|
|
||||||
for i in &inputs {
|
|
||||||
let i = match i.as_string() {
|
|
||||||
Err(_err) => {
|
|
||||||
let mut span = name_span;
|
|
||||||
for arg in &self.args {
|
|
||||||
if arg.item.contains("$it") {
|
|
||||||
span = arg.span();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(ShellError::labeled_error(
|
|
||||||
"External $it needs string data",
|
|
||||||
"given row instead of string data",
|
|
||||||
span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(val) => val,
|
|
||||||
};
|
|
||||||
|
|
||||||
if !first {
|
|
||||||
new_arg_string.push_str("&&");
|
|
||||||
new_arg_string.push_str(&self.name);
|
|
||||||
} else {
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for arg in &self.args {
|
|
||||||
if arg.chars().all(|c| c.is_whitespace()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_arg_string.push_str(" ");
|
|
||||||
new_arg_string.push_str(&arg.replace("$it", &i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for arg in &self.args {
|
|
||||||
new_arg_string.push_str(" ");
|
|
||||||
new_arg_string.push_str(&arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process = Exec::shell(new_arg_string);
|
|
||||||
}
|
|
||||||
process = process.cwd(context.shell_manager.path());
|
process = process.cwd(context.shell_manager.path());
|
||||||
|
|
||||||
let mut process = match stream_next {
|
let mut process = match stream_next {
|
||||||
|
72
src/commands/echo.rs
Normal file
72
src/commands/echo.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use crate::data::Value;
|
||||||
|
use crate::errors::ShellError;
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
use crate::parser::registry::Signature;
|
||||||
|
|
||||||
|
pub struct Echo;
|
||||||
|
|
||||||
|
impl PerItemCommand for Echo {
|
||||||
|
fn name(&self) -> &str {
|
||||||
|
"echo"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signature(&self) -> Signature {
|
||||||
|
Signature::build("echo").rest(SyntaxType::Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(&self) -> &str {
|
||||||
|
"Echo the argments back to the user."
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
&self,
|
||||||
|
call_info: &CallInfo,
|
||||||
|
registry: &CommandRegistry,
|
||||||
|
raw_args: &RawCommandArgs,
|
||||||
|
_input: Tagged<Value>,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
run(call_info, registry, raw_args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(
|
||||||
|
call_info: &CallInfo,
|
||||||
|
_registry: &CommandRegistry,
|
||||||
|
_raw_args: &RawCommandArgs,
|
||||||
|
) -> Result<OutputStream, ShellError> {
|
||||||
|
let name = call_info.name_span;
|
||||||
|
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
let mut first = true;
|
||||||
|
|
||||||
|
if let Some(ref positional) = call_info.args.positional {
|
||||||
|
for i in positional {
|
||||||
|
match i.as_string() {
|
||||||
|
Ok(s) => {
|
||||||
|
if !first {
|
||||||
|
output.push_str(" ");
|
||||||
|
} else {
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
output.push_str(&s);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(ShellError::labeled_error(
|
||||||
|
"Expect a string from pipeline",
|
||||||
|
"not a string-compatible value",
|
||||||
|
i.span(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let stream = VecDeque::from(vec![Ok(ReturnSuccess::Value(
|
||||||
|
Value::string(output).simple_spanned(name),
|
||||||
|
))]);
|
||||||
|
|
||||||
|
Ok(stream.to_output_stream())
|
||||||
|
}
|
@ -35,7 +35,7 @@ fn converts_structured_table_to_csv_text() {
|
|||||||
| to-csv
|
| to-csv
|
||||||
| lines
|
| lines
|
||||||
| nth 1
|
| nth 1
|
||||||
| echo "$it"
|
| echo $it
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() {
|
|||||||
| split-column "," a b c d origin
|
| split-column "," a b c d origin
|
||||||
| last 1
|
| last 1
|
||||||
| to-csv --headerless
|
| to-csv --headerless
|
||||||
| echo "$it"
|
| echo $it
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ fn converts_structured_table_to_tsv_text() {
|
|||||||
| to-tsv
|
| to-tsv
|
||||||
| lines
|
| lines
|
||||||
| nth 1
|
| nth 1
|
||||||
| echo "$it"
|
| echo $it
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -289,7 +289,7 @@ fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() {
|
|||||||
| split-column "\t" a b c d origin
|
| split-column "\t" a b c d origin
|
||||||
| last 1
|
| last 1
|
||||||
| to-tsv --headerless
|
| to-tsv --headerless
|
||||||
| echo "$it"
|
| echo $it
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -310,8 +310,7 @@ pub fn file_contents(full_path: impl AsRef<Path>) -> String {
|
|||||||
pub fn file_contents_binary(full_path: impl AsRef<Path>) -> Vec<u8> {
|
pub fn file_contents_binary(full_path: impl AsRef<Path>) -> Vec<u8> {
|
||||||
let mut file = std::fs::File::open(full_path.as_ref()).expect("can not open file");
|
let mut file = std::fs::File::open(full_path.as_ref()).expect("can not open file");
|
||||||
let mut contents = Vec::new();
|
let mut contents = Vec::new();
|
||||||
file.read_to_end(&mut contents)
|
file.read_to_end(&mut contents).expect("can not read file");
|
||||||
.expect("can not read file");
|
|
||||||
contents
|
contents
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,18 +326,6 @@ pub fn line_ending() -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normalize_string(input: &str) -> String {
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
input.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
{
|
|
||||||
format!("\"{}\"", input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_file_at(full_path: impl AsRef<Path>) -> Result<(), std::io::Error> {
|
pub fn create_file_at(full_path: impl AsRef<Path>) -> Result<(), std::io::Error> {
|
||||||
let full_path = full_path.as_ref();
|
let full_path = full_path.as_ref();
|
||||||
|
|
||||||
@ -377,9 +364,9 @@ pub fn in_directory(str: impl AsRef<Path>) -> String {
|
|||||||
str.as_ref().display().to_string()
|
str.as_ref().display().to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn pipeline(commands: &str) -> String {
|
pub fn pipeline(commands: &str) -> String {
|
||||||
commands.lines()
|
commands
|
||||||
|
.lines()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|line| line.trim())
|
.map(|line| line.trim())
|
||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
|
@ -12,9 +12,13 @@ fn pipeline_helper() {
|
|||||||
| str --to-int
|
| str --to-int
|
||||||
| sum
|
| sum
|
||||||
| echo "$it"
|
| echo "$it"
|
||||||
"#);
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(actual, r#"open los_tres_amigos.txt | from-csv | get rusty_luck | str --to-int | sum | echo "$it""#);
|
assert_eq!(
|
||||||
|
actual,
|
||||||
|
r#"open los_tres_amigos.txt | from-csv | get rusty_luck | str --to-int | sum | echo "$it""#
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -34,9 +38,7 @@ fn external_has_correct_quotes() {
|
|||||||
r#"echo "hello world""#
|
r#"echo "hello world""#
|
||||||
);
|
);
|
||||||
|
|
||||||
let actual = h::normalize_string(&actual);
|
assert_eq!(actual, r#"hello world"#);
|
||||||
|
|
||||||
assert_eq!(actual, r#""hello world""#);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user