diff --git a/crates/nu-command/src/build_string.rs b/crates/nu-command/src/build_string.rs index 90516cde07..a0b64b9f3d 100644 --- a/crates/nu-command/src/build_string.rs +++ b/crates/nu-command/src/build_string.rs @@ -1,7 +1,7 @@ use nu_engine::eval_expression; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Signature, SyntaxShape, Value}; +use nu_protocol::{ShellError, Signature, SyntaxShape, Value}; pub struct BuildString; @@ -24,13 +24,12 @@ impl Command for BuildString { call: &Call, _input: Value, ) -> Result { - let mut output = vec![]; + let output = call + .positional + .iter() + .map(|expr| eval_expression(context, expr).map(|val| val.into_string())) + .collect::, ShellError>>()?; - for expr in &call.positional { - let val = eval_expression(context, expr)?; - - output.push(val.into_string()); - } Ok(Value::String { val: output.join(""), span: call.head, diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 5890d791cb..9beee6c1f1 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -67,6 +67,8 @@ pub fn create_default_context() -> Rc> { working_set.add_decl(sig.predeclare()); let sig = Signature::build("stack"); working_set.add_decl(sig.predeclare()); + let sig = Signature::build("contents"); + working_set.add_decl(sig.predeclare()); working_set.render() }; diff --git a/crates/nu-command/src/lines.rs b/crates/nu-command/src/lines.rs index f3517c8e65..74333ff3ef 100644 --- a/crates/nu-command/src/lines.rs +++ b/crates/nu-command/src/lines.rs @@ -62,7 +62,7 @@ impl Command for Lines { .filter_map(|s| { if !s.is_empty() { Some(Value::String { - val: s.into(), + val: s.trim().into(), span, }) } else { diff --git a/crates/nu-command/src/run_external.rs b/crates/nu-command/src/run_external.rs index 3ed506176b..8d03b4a7d3 100644 --- a/crates/nu-command/src/run_external.rs +++ b/crates/nu-command/src/run_external.rs @@ -117,7 +117,6 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> { Ok(mut child) => { // if there is a string or a stream, that is sent to the pipe std match input { - Value::Nothing { span: _ } => (), Value::String { val, span: _ } => { if let Some(mut stdin_write) = child.stdin.take() { self.write_to_stdin(&mut stdin_write, val.as_bytes())? @@ -143,12 +142,7 @@ impl<'call, 'contex> ExternalCommand<'call, 'contex> { } } } - _ => { - return Err(ShellError::ExternalCommand( - "Input is not string or binary".to_string(), - self.name.span, - )) - } + _ => (), } // If this external is not the last expression, then its output is piped to a channel diff --git a/crates/nu-command/src/table.rs b/crates/nu-command/src/table.rs index 45109cec3f..f9402872bd 100644 --- a/crates/nu-command/src/table.rs +++ b/crates/nu-command/src/table.rs @@ -65,7 +65,11 @@ fn convert_to_table(iter: impl IntoIterator) -> Option first.columns(), + _ => ["Column_0".to_string()].to_vec(), + }; + headers.insert(0, "#".into()); let mut data = vec![]; @@ -74,10 +78,13 @@ fn convert_to_table(iter: impl IntoIterator) -> Option item.clone().follow_cell_path(&[PathMember::String { + val: header.into(), + span: Span::unknown(), + }]), + _ => Ok(item.clone()), + }; match result { Ok(value) => row.push(value.into_string()), diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 6a75884289..11941fe428 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -113,6 +113,11 @@ impl EngineState { } } + pub fn print_contents(&self) { + let string = String::from_utf8_lossy(&self.file_contents); + println!("{}", string); + } + pub fn find_decl(&self, name: &[u8]) -> Option { for scope in self.scope.iter().rev() { if let Some(decl_id) = scope.decls.get(name) { diff --git a/src/main.rs b/src/main.rs index 8dc8d7c6e1..577a9c7211 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,14 @@ +use std::io::Write; + use miette::{IntoDiagnostic, Result}; use nu_cli::{report_error, NuCompleter, NuHighlighter, NuValidator}; use nu_command::create_default_context; use nu_engine::eval_block; use nu_parser::parse; use nu_protocol::{ + ast::Call, engine::{EngineState, EvaluationContext, StateWorkingSet}, - Value, + ShellError, Value, }; use reedline::DefaultCompletionActionHandler; @@ -99,6 +102,9 @@ fn main() -> Result<()> { } else if s.trim() == "stack" { stack.print_stack(); continue; + } else if s.trim() == "contents" { + engine_state.borrow().print_contents(); + continue; } let (block, delta) = { @@ -125,9 +131,7 @@ fn main() -> Result<()> { }; match eval_block(&state, &block, Value::nothing()) { - Ok(value) => { - println!("{}", value.into_string()); - } + Ok(value) => print_value(value, &state)?, Err(err) => { let engine_state = engine_state.borrow(); let working_set = StateWorkingSet::new(&*engine_state); @@ -157,3 +161,26 @@ fn main() -> Result<()> { Ok(()) } } + +fn print_value(value: Value, state: &EvaluationContext) -> Result<(), ShellError> { + // If the table function is in the declarations, then we can use it + // to create the table value that will be printed in the terminal + let engine_state = state.engine_state.borrow(); + let output = match engine_state.find_decl("table".as_bytes()) { + Some(decl_id) => { + let table = engine_state + .get_decl(decl_id) + .run(state, &Call::new(), value)?; + table.into_string() + } + None => value.into_string(), + }; + let stdout = std::io::stdout(); + + match stdout.lock().write_all(output.as_bytes()) { + Ok(_) => (), + Err(err) => eprintln!("{}", err), + }; + + Ok(()) +}