mirror of
https://github.com/nushell/nushell.git
synced 2025-02-23 05:51:28 +01:00
Getting closer to multiline scripts (#2738)
* Begin allowing comments and multiline scripts. * clippy * Finish moving to groups. Test pass
This commit is contained in:
parent
3924e9d50a
commit
e66bf70589
@ -290,8 +290,8 @@ pub fn create_default_context(interactive: bool) -> Result<EvaluationContext, Bo
|
||||
Ok(context)
|
||||
}
|
||||
|
||||
pub async fn run_vec_of_pipelines(
|
||||
pipelines: Vec<String>,
|
||||
pub async fn run_script_file(
|
||||
file_contents: String,
|
||||
redirect_stdin: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut syncer = EnvironmentSyncer::new();
|
||||
@ -313,9 +313,7 @@ pub async fn run_vec_of_pipelines(
|
||||
|
||||
let _ = run_startup_commands(&mut context, &config).await;
|
||||
|
||||
for pipeline in pipelines {
|
||||
run_pipeline_standalone(pipeline, redirect_stdin, &mut context, true).await?;
|
||||
}
|
||||
run_script_standalone(file_contents, redirect_stdin, &mut context, true).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -475,7 +473,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
|
||||
}
|
||||
|
||||
let line = match convert_rustyline_result_to_string(readline) {
|
||||
LineResult::Success(s) => process_line(&s, &mut context, false, true).await,
|
||||
LineResult::Success(s) => process_script(&s, &mut context, false, true).await,
|
||||
x => x,
|
||||
};
|
||||
|
||||
@ -602,8 +600,7 @@ async fn run_startup_commands(
|
||||
} => {
|
||||
for pipeline in pipelines {
|
||||
if let Ok(pipeline_string) = pipeline.as_string() {
|
||||
let _ =
|
||||
run_pipeline_standalone(pipeline_string, false, context, false).await;
|
||||
let _ = run_script_standalone(pipeline_string, false, context, false).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -618,13 +615,13 @@ async fn run_startup_commands(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn run_pipeline_standalone(
|
||||
pipeline: String,
|
||||
pub async fn run_script_standalone(
|
||||
script_text: String,
|
||||
redirect_stdin: bool,
|
||||
context: &mut EvaluationContext,
|
||||
exit_on_error: bool,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let line = process_line(&pipeline, context, redirect_stdin, false).await;
|
||||
let line = process_script(&script_text, context, redirect_stdin, false).await;
|
||||
|
||||
match line {
|
||||
LineResult::Success(line) => {
|
||||
@ -892,16 +889,16 @@ pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result<S
|
||||
}
|
||||
|
||||
/// Process the line by parsing the text to turn it into commands, classify those commands so that we understand what is being called in the pipeline, and then run this pipeline
|
||||
pub async fn process_line(
|
||||
line: &str,
|
||||
pub async fn process_script(
|
||||
script_text: &str,
|
||||
ctx: &mut EvaluationContext,
|
||||
redirect_stdin: bool,
|
||||
cli_mode: bool,
|
||||
) -> LineResult {
|
||||
if line.trim() == "" {
|
||||
LineResult::Success(line.to_string())
|
||||
if script_text.trim() == "" {
|
||||
LineResult::Success(script_text.to_string())
|
||||
} else {
|
||||
let line = chomp_newline(line);
|
||||
let line = chomp_newline(script_text);
|
||||
ctx.raw_input = line.to_string();
|
||||
|
||||
let (result, err) = nu_parser::lite_parse(&line, 0);
|
||||
@ -930,11 +927,12 @@ pub async fn process_line(
|
||||
// ...then change to this directory
|
||||
if cli_mode
|
||||
&& classified_block.block.block.len() == 1
|
||||
&& classified_block.block.block[0].list.len() == 1
|
||||
&& classified_block.block.block[0].pipelines.len() == 1
|
||||
&& classified_block.block.block[0].pipelines[0].list.len() == 1
|
||||
{
|
||||
if let ClassifiedCommand::Internal(InternalCommand {
|
||||
ref name, ref args, ..
|
||||
}) = classified_block.block.block[0].list[0]
|
||||
}) = classified_block.block.block[0].pipelines[0].list[0]
|
||||
{
|
||||
let internal_name = name;
|
||||
let name = args
|
||||
|
@ -5,7 +5,7 @@ use crate::prelude::*;
|
||||
use heim::cpu::time;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{
|
||||
hir::{Block, ClassifiedCommand, Commands, InternalCommand},
|
||||
hir::{Block, ClassifiedCommand, Group, InternalCommand, Pipeline},
|
||||
Dictionary, Scope, Signature, SyntaxShape, UntaggedValue, Value,
|
||||
};
|
||||
use rand::{
|
||||
@ -175,15 +175,19 @@ where
|
||||
|
||||
fn add_implicit_autoview(mut block: Block) -> Block {
|
||||
if block.block.is_empty() {
|
||||
block.push({
|
||||
let mut commands = Commands::new(block.span);
|
||||
commands.push(ClassifiedCommand::Internal(InternalCommand::new(
|
||||
"autoview".to_string(),
|
||||
block.span,
|
||||
block.span,
|
||||
)));
|
||||
commands
|
||||
});
|
||||
let group = Group::new(
|
||||
vec![{
|
||||
let mut commands = Pipeline::new(block.span);
|
||||
commands.push(ClassifiedCommand::Internal(InternalCommand::new(
|
||||
"autoview".to_string(),
|
||||
block.span,
|
||||
block.span,
|
||||
)));
|
||||
commands
|
||||
}],
|
||||
block.span,
|
||||
);
|
||||
block.push(group);
|
||||
}
|
||||
block
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ use crate::prelude::*;
|
||||
use crate::stream::InputStream;
|
||||
use futures::stream::TryStreamExt;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::hir::{Block, ClassifiedCommand, Commands};
|
||||
use nu_protocol::hir::{
|
||||
Block, Call, ClassifiedCommand, Expression, Pipeline, SpannedExpression, Synthetic,
|
||||
};
|
||||
use nu_protocol::{ReturnSuccess, Scope, UntaggedValue, Value};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
@ -16,35 +18,52 @@ pub(crate) async fn run_block(
|
||||
scope: Arc<Scope>,
|
||||
) -> Result<InputStream, ShellError> {
|
||||
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
|
||||
for pipeline in &block.block {
|
||||
for group in &block.block {
|
||||
match output {
|
||||
Ok(inp) if inp.is_empty() => {}
|
||||
Ok(inp) => {
|
||||
let mut output_stream = inp.to_output_stream();
|
||||
|
||||
loop {
|
||||
match output_stream.try_next().await {
|
||||
Ok(Some(ReturnSuccess::Value(Value {
|
||||
value: UntaggedValue::Error(e),
|
||||
..
|
||||
}))) => return Err(e),
|
||||
Ok(Some(_item)) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
// Run autoview on the values we've seen so far
|
||||
// We may want to make this configurable for other kinds of hosting
|
||||
if let Some(autoview) = ctx.get_command("autoview") {
|
||||
let mut output_stream = ctx
|
||||
.run_command(
|
||||
autoview,
|
||||
Tag::unknown(),
|
||||
Call::new(
|
||||
Box::new(SpannedExpression::new(
|
||||
Expression::Synthetic(Synthetic::String("autoview".into())),
|
||||
Span::unknown(),
|
||||
)),
|
||||
Span::unknown(),
|
||||
),
|
||||
scope.clone(),
|
||||
inp,
|
||||
)
|
||||
.await?;
|
||||
loop {
|
||||
match output_stream.try_next().await {
|
||||
Ok(Some(ReturnSuccess::Value(Value {
|
||||
value: UntaggedValue::Error(e),
|
||||
..
|
||||
}))) => return Err(e),
|
||||
Ok(Some(_item)) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
if ctx.ctrl_c.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ctx.ctrl_c.load(Ordering::SeqCst) {
|
||||
Ok(None) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
Ok(None) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,16 +71,54 @@ pub(crate) async fn run_block(
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
output = run_pipeline(pipeline, ctx, input, scope.clone()).await;
|
||||
output = Ok(InputStream::empty());
|
||||
for pipeline in &group.pipelines {
|
||||
match output {
|
||||
Ok(inp) if inp.is_empty() => {}
|
||||
Ok(inp) => {
|
||||
let mut output_stream = inp.to_output_stream();
|
||||
|
||||
input = InputStream::empty();
|
||||
loop {
|
||||
match output_stream.try_next().await {
|
||||
Ok(Some(ReturnSuccess::Value(Value {
|
||||
value: UntaggedValue::Error(e),
|
||||
..
|
||||
}))) => return Err(e),
|
||||
Ok(Some(_item)) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
if ctx.ctrl_c.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
if let Some(err) = ctx.get_errors().get(0) {
|
||||
ctx.clear_errors();
|
||||
return Err(err.clone());
|
||||
}
|
||||
break;
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
output = run_pipeline(pipeline, ctx, input, scope.clone()).await;
|
||||
|
||||
input = InputStream::empty();
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
async fn run_pipeline(
|
||||
commands: &Commands,
|
||||
commands: &Pipeline,
|
||||
ctx: &mut EvaluationContext,
|
||||
mut input: InputStream,
|
||||
scope: Arc<Scope>,
|
||||
|
@ -94,9 +94,9 @@ async fn if_command(
|
||||
tag,
|
||||
));
|
||||
}
|
||||
match condition.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
match condition.block[0].pipelines.get(0) {
|
||||
Some(item) => match item.list.get(0) {
|
||||
Some(ClassifiedCommand::Expr(expr)) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
|
@ -51,9 +51,9 @@ impl WholeStreamCommand for SubCommand {
|
||||
tag,
|
||||
));
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
match block.block[0].pipelines.get(0) {
|
||||
Some(item) => match item.list.get(0) {
|
||||
Some(ClassifiedCommand::Expr(expr)) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
|
@ -50,9 +50,9 @@ impl WholeStreamCommand for SubCommand {
|
||||
tag,
|
||||
));
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
match block.block[0].pipelines.get(0) {
|
||||
Some(item) => match item.list.get(0) {
|
||||
Some(ClassifiedCommand::Expr(expr)) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
|
@ -50,9 +50,9 @@ impl WholeStreamCommand for SubCommand {
|
||||
tag,
|
||||
));
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
match block.block[0].pipelines.get(0) {
|
||||
Some(item) => match item.list.get(0) {
|
||||
Some(ClassifiedCommand::Expr(expr)) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
|
@ -50,9 +50,9 @@ impl WholeStreamCommand for SubCommand {
|
||||
tag,
|
||||
));
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
match block.block[0].pipelines.get(0) {
|
||||
Some(item) => match item.list.get(0) {
|
||||
Some(ClassifiedCommand::Expr(expr)) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
|
@ -81,9 +81,9 @@ async fn where_command(
|
||||
tag,
|
||||
));
|
||||
}
|
||||
match block.block[0].list.get(0) {
|
||||
Some(item) => match item {
|
||||
ClassifiedCommand::Expr(expr) => expr.clone(),
|
||||
match block.block[0].pipelines.get(0) {
|
||||
Some(item) => match item.list.get(0) {
|
||||
Some(ClassifiedCommand::Expr(expr)) => expr.clone(),
|
||||
_ => {
|
||||
return Err(ShellError::labeled_error(
|
||||
"Expected a condition",
|
||||
|
@ -138,7 +138,7 @@ impl<'s> Flatten<'s> {
|
||||
result
|
||||
}
|
||||
|
||||
fn pipeline(&self, pipeline: &Commands) -> Vec<CompletionLocation> {
|
||||
fn pipeline(&self, pipeline: &Pipeline) -> Vec<CompletionLocation> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for command in &pipeline.list {
|
||||
@ -158,7 +158,11 @@ impl<'s> Flatten<'s> {
|
||||
|
||||
/// Flattens the block into a Vec of completion locations
|
||||
pub fn completion_locations(&self, block: &Block) -> Vec<CompletionLocation> {
|
||||
block.block.iter().flat_map(|v| self.pipeline(v)).collect()
|
||||
block
|
||||
.block
|
||||
.iter()
|
||||
.flat_map(|g| g.pipelines.iter().flat_map(|v| self.pipeline(v)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn new(line: &'s str) -> Flatten<'s> {
|
||||
|
@ -43,8 +43,8 @@ mod examples;
|
||||
pub use crate::cli::cli;
|
||||
|
||||
pub use crate::cli::{
|
||||
create_default_context, parse_and_eval, process_line, register_plugins,
|
||||
run_pipeline_standalone, run_vec_of_pipelines, LineResult,
|
||||
create_default_context, parse_and_eval, process_script, register_plugins, run_script_file,
|
||||
run_script_standalone, LineResult,
|
||||
};
|
||||
pub use crate::command_registry::CommandRegistry;
|
||||
pub use crate::commands::command::{
|
||||
|
@ -5,8 +5,8 @@ use nu_errors::ShellError;
|
||||
use nu_parser::SignatureRegistry;
|
||||
use nu_protocol::{
|
||||
hir::{
|
||||
Binary, Block, ClassifiedCommand, Commands, Expression, Literal, NamedArguments,
|
||||
NamedValue, Operator, SpannedExpression,
|
||||
Binary, Block, ClassifiedCommand, Expression, Literal, NamedArguments, NamedValue,
|
||||
Operator, Pipeline, SpannedExpression,
|
||||
},
|
||||
NamedType, PositionalType, Signature, SyntaxShape,
|
||||
};
|
||||
@ -318,7 +318,7 @@ fn spanned_to_binary(bin_spanned: &SpannedExpression) -> &Binary {
|
||||
///Returns result shape of this math expr otherwise
|
||||
fn get_result_shape_of_math_expr(
|
||||
bin: &Binary,
|
||||
(pipeline_idx, pipeline): (usize, &Commands),
|
||||
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<Option<SyntaxShape>, ShellError> {
|
||||
let mut shapes: Vec<Option<SyntaxShape>> = vec![];
|
||||
@ -388,15 +388,17 @@ impl VarSyntaxShapeDeductor {
|
||||
|
||||
fn infer_shape(&mut self, block: &Block, registry: &CommandRegistry) -> Result<(), ShellError> {
|
||||
trace!("Infering vars in shape");
|
||||
for pipeline in &block.block {
|
||||
self.infer_pipeline(pipeline, registry)?;
|
||||
for group in &block.block {
|
||||
for pipeline in &group.pipelines {
|
||||
self.infer_pipeline(pipeline, registry)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn infer_pipeline(
|
||||
&mut self,
|
||||
pipeline: &Commands,
|
||||
pipeline: &Pipeline,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<(), ShellError> {
|
||||
trace!("Infering vars in pipeline");
|
||||
@ -534,7 +536,7 @@ impl VarSyntaxShapeDeductor {
|
||||
|
||||
fn infer_shapes_in_expr(
|
||||
&mut self,
|
||||
(pipeline_idx, pipeline): (usize, &Commands),
|
||||
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||
spanned_expr: &SpannedExpression,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<(), ShellError> {
|
||||
@ -660,7 +662,7 @@ impl VarSyntaxShapeDeductor {
|
||||
(var, expr): (&VarUsage, &SpannedExpression),
|
||||
//source_bin is binary having var on one and expr on other side
|
||||
source_bin: &SpannedExpression,
|
||||
(pipeline_idx, pipeline): (usize, &Commands),
|
||||
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<Option<SyntaxShape>, ShellError> {
|
||||
get_result_shape_of_math_expr(spanned_to_binary(expr), (pipeline_idx, pipeline), registry)
|
||||
@ -682,7 +684,7 @@ impl VarSyntaxShapeDeductor {
|
||||
(var, expr): (&VarUsage, &SpannedExpression),
|
||||
//source_bin is binary having var on one and expr on other side
|
||||
source_bin: &SpannedExpression,
|
||||
(pipeline_idx, pipeline): (usize, &Commands),
|
||||
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<Option<SyntaxShape>, ShellError> {
|
||||
trace!("Getting shape of binary arg {:?} for var {:?}", expr, var);
|
||||
@ -714,7 +716,7 @@ impl VarSyntaxShapeDeductor {
|
||||
var: &VarUsage,
|
||||
bin_spanned: &SpannedExpression,
|
||||
list: &[SpannedExpression],
|
||||
(_pipeline_idx, _pipeline): (usize, &Commands),
|
||||
(_pipeline_idx, _pipeline): (usize, &Pipeline),
|
||||
_registry: &CommandRegistry,
|
||||
) -> Option<Vec<SyntaxShape>> {
|
||||
let shapes_in_list = list
|
||||
@ -740,7 +742,7 @@ impl VarSyntaxShapeDeductor {
|
||||
var_side: BinarySide,
|
||||
//Binary having expr on one side and var on other
|
||||
bin_spanned: &SpannedExpression,
|
||||
(pipeline_idx, pipeline): (usize, &Commands),
|
||||
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<(), ShellError> {
|
||||
trace!("Infering shapes between var {:?} and expr {:?}", var, expr);
|
||||
@ -893,7 +895,7 @@ impl VarSyntaxShapeDeductor {
|
||||
|
||||
fn infer_shapes_in_binary_expr(
|
||||
&mut self,
|
||||
(pipeline_idx, pipeline): (usize, &Commands),
|
||||
(pipeline_idx, pipeline): (usize, &Pipeline),
|
||||
bin_spanned: &SpannedExpression,
|
||||
registry: &CommandRegistry,
|
||||
) -> Result<(), ShellError> {
|
||||
|
@ -117,6 +117,17 @@ impl LiteGroup {
|
||||
pub fn push(&mut self, item: LitePipeline) {
|
||||
self.pipelines.push(item)
|
||||
}
|
||||
pub fn is_comment(&self) -> bool {
|
||||
if !self.is_empty()
|
||||
&& !self.pipelines[0].is_empty()
|
||||
&& !self.pipelines[0].commands.is_empty()
|
||||
&& !self.pipelines[0].commands[0].parts.is_empty()
|
||||
{
|
||||
self.pipelines[0].commands[0].parts[0].item.starts_with('#')
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub(crate) fn span(&self) -> Span {
|
||||
let start = if !self.pipelines.is_empty() {
|
||||
self.pipelines[0].span().start()
|
||||
@ -348,7 +359,9 @@ fn group(tokens: Vec<Token>) -> (LiteBlock, Option<ParseError>) {
|
||||
pipeline = LitePipeline::new();
|
||||
}
|
||||
if !group.is_empty() {
|
||||
groups.push(group);
|
||||
if !group.is_comment() {
|
||||
groups.push(group);
|
||||
}
|
||||
group = LiteGroup::new();
|
||||
}
|
||||
}
|
||||
@ -389,7 +402,7 @@ fn group(tokens: Vec<Token>) -> (LiteBlock, Option<ParseError>) {
|
||||
if !pipeline.is_empty() {
|
||||
group.push(pipeline);
|
||||
}
|
||||
if !group.is_empty() {
|
||||
if !group.is_empty() && !group.is_comment() {
|
||||
groups.push(group);
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,9 @@ use std::path::Path;
|
||||
use log::trace;
|
||||
use nu_errors::{ArgumentError, ParseError};
|
||||
use nu_protocol::hir::{
|
||||
self, Binary, Block, ClassifiedBlock, ClassifiedCommand, ClassifiedPipeline, Commands,
|
||||
Expression, ExternalRedirection, Flag, FlagKind, InternalCommand, Member, NamedArguments,
|
||||
Operator, RangeOperator, SpannedExpression, Unit,
|
||||
self, Binary, Block, ClassifiedBlock, ClassifiedCommand, ClassifiedPipeline, Expression,
|
||||
ExternalRedirection, Flag, FlagKind, Group, InternalCommand, Member, NamedArguments, Operator,
|
||||
Pipeline, RangeOperator, SpannedExpression, Unit,
|
||||
};
|
||||
use nu_protocol::{NamedType, PositionalType, Signature, SyntaxShape, UnspannedPathMember};
|
||||
use nu_source::{Span, Spanned, SpannedItem};
|
||||
@ -584,7 +584,7 @@ fn parse_interpolated_string(
|
||||
}
|
||||
}
|
||||
|
||||
let block = vec![Commands {
|
||||
let pipelines = vec![Pipeline {
|
||||
span: lite_arg.span,
|
||||
list: vec![ClassifiedCommand::Internal(InternalCommand {
|
||||
name: "build-string".to_owned(),
|
||||
@ -602,8 +602,10 @@ fn parse_interpolated_string(
|
||||
})],
|
||||
}];
|
||||
|
||||
let group = Group::new(pipelines, lite_arg.span);
|
||||
|
||||
let call = SpannedExpression {
|
||||
expr: Expression::Invocation(Block::new(vec![], block, lite_arg.span)),
|
||||
expr: Expression::Invocation(Block::new(vec![], vec![group], lite_arg.span)),
|
||||
span: lite_arg.span,
|
||||
};
|
||||
|
||||
@ -1341,10 +1343,14 @@ fn parse_positional_argument(
|
||||
parse_math_expression(idx, &lite_cmd.parts[idx..end_idx], registry, true);
|
||||
|
||||
let span = arg.span;
|
||||
let mut commands = hir::Commands::new(span);
|
||||
let mut commands = hir::Pipeline::new(span);
|
||||
commands.push(ClassifiedCommand::Expr(Box::new(arg)));
|
||||
|
||||
let block = hir::Block::new(vec![], vec![commands], span);
|
||||
let block = hir::Block::new(
|
||||
vec![],
|
||||
vec![Group::new(vec![commands], lite_cmd.span())],
|
||||
span,
|
||||
);
|
||||
|
||||
let arg = SpannedExpression::new(Expression::Block(block), span);
|
||||
|
||||
@ -1538,7 +1544,7 @@ fn classify_pipeline(
|
||||
lite_pipeline: &LitePipeline,
|
||||
registry: &dyn SignatureRegistry,
|
||||
) -> (ClassifiedPipeline, Option<ParseError>) {
|
||||
let mut commands = Commands::new(lite_pipeline.span());
|
||||
let mut commands = Pipeline::new(lite_pipeline.span());
|
||||
let mut error = None;
|
||||
|
||||
let mut iter = lite_pipeline.commands.iter().peekable();
|
||||
@ -1745,10 +1751,10 @@ fn expand_shorthand_forms(
|
||||
}
|
||||
|
||||
pub fn classify_block(lite_block: &LiteBlock, registry: &dyn SignatureRegistry) -> ClassifiedBlock {
|
||||
let mut command_list = vec![];
|
||||
|
||||
let mut block = vec![];
|
||||
let mut error = None;
|
||||
for lite_group in &lite_block.block {
|
||||
let mut command_list = vec![];
|
||||
for lite_pipeline in &lite_group.pipelines {
|
||||
let (lite_pipeline, vars, err) = expand_shorthand_forms(lite_pipeline);
|
||||
if error.is_none() {
|
||||
@ -1759,7 +1765,8 @@ pub fn classify_block(lite_block: &LiteBlock, registry: &dyn SignatureRegistry)
|
||||
|
||||
let pipeline = if let Some(vars) = vars {
|
||||
let span = pipeline.commands.span;
|
||||
let block = hir::Block::new(vec![], vec![pipeline.commands.clone()], span);
|
||||
let group = Group::new(vec![pipeline.commands.clone()], span);
|
||||
let block = hir::Block::new(vec![], vec![group], span);
|
||||
let mut call = hir::Call::new(
|
||||
Box::new(SpannedExpression {
|
||||
expr: Expression::string("with-env".to_string()),
|
||||
@ -1792,7 +1799,7 @@ pub fn classify_block(lite_block: &LiteBlock, registry: &dyn SignatureRegistry)
|
||||
args: call,
|
||||
});
|
||||
ClassifiedPipeline {
|
||||
commands: Commands {
|
||||
commands: Pipeline {
|
||||
list: vec![classified_with_env],
|
||||
span,
|
||||
},
|
||||
@ -1806,8 +1813,10 @@ pub fn classify_block(lite_block: &LiteBlock, registry: &dyn SignatureRegistry)
|
||||
error = err;
|
||||
}
|
||||
}
|
||||
let group = Group::new(command_list, lite_block.span());
|
||||
block.push(group);
|
||||
}
|
||||
let block = Block::new(vec![], command_list, lite_block.span());
|
||||
let block = Block::new(vec![], block, lite_block.span());
|
||||
|
||||
ClassifiedBlock::new(block, error)
|
||||
}
|
||||
|
@ -88,35 +88,39 @@ pub fn expression_to_flat_shape(e: &SpannedExpression) -> Vec<Spanned<FlatShape>
|
||||
pub fn shapes(commands: &Block) -> Vec<Spanned<FlatShape>> {
|
||||
let mut output = vec![];
|
||||
|
||||
for pipeline in &commands.block {
|
||||
for command in &pipeline.list {
|
||||
match command {
|
||||
ClassifiedCommand::Internal(internal) => {
|
||||
output.append(&mut expression_to_flat_shape(&internal.args.head));
|
||||
for group in &commands.block {
|
||||
for pipeline in &group.pipelines {
|
||||
for command in &pipeline.list {
|
||||
match command {
|
||||
ClassifiedCommand::Internal(internal) => {
|
||||
output.append(&mut expression_to_flat_shape(&internal.args.head));
|
||||
|
||||
if let Some(positionals) = &internal.args.positional {
|
||||
for positional_arg in positionals {
|
||||
output.append(&mut expression_to_flat_shape(positional_arg));
|
||||
if let Some(positionals) = &internal.args.positional {
|
||||
for positional_arg in positionals {
|
||||
output.append(&mut expression_to_flat_shape(positional_arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(named) = &internal.args.named {
|
||||
for (_, named_arg) in named.iter() {
|
||||
match named_arg {
|
||||
NamedValue::PresentSwitch(span) => {
|
||||
output.push(FlatShape::Flag.spanned(*span));
|
||||
if let Some(named) = &internal.args.named {
|
||||
for (_, named_arg) in named.iter() {
|
||||
match named_arg {
|
||||
NamedValue::PresentSwitch(span) => {
|
||||
output.push(FlatShape::Flag.spanned(*span));
|
||||
}
|
||||
NamedValue::Value(span, expr) => {
|
||||
output.push(FlatShape::Flag.spanned(*span));
|
||||
output.append(&mut expression_to_flat_shape(expr));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
NamedValue::Value(span, expr) => {
|
||||
output.push(FlatShape::Flag.spanned(*span));
|
||||
output.append(&mut expression_to_flat_shape(expr));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
ClassifiedCommand::Expr(expr) => {
|
||||
output.append(&mut expression_to_flat_shape(expr))
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ClassifiedCommand::Expr(expr) => output.append(&mut expression_to_flat_shape(expr)),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,11 +62,11 @@ impl ClassifiedBlock {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct ClassifiedPipeline {
|
||||
pub commands: Commands,
|
||||
pub commands: Pipeline,
|
||||
}
|
||||
|
||||
impl ClassifiedPipeline {
|
||||
pub fn new(commands: Commands) -> ClassifiedPipeline {
|
||||
pub fn new(commands: Pipeline) -> ClassifiedPipeline {
|
||||
ClassifiedPipeline { commands }
|
||||
}
|
||||
}
|
||||
@ -92,14 +92,14 @@ impl ClassifiedCommand {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Commands {
|
||||
pub struct Pipeline {
|
||||
pub list: Vec<ClassifiedCommand>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Commands {
|
||||
pub fn new(span: Span) -> Commands {
|
||||
Commands { list: vec![], span }
|
||||
impl Pipeline {
|
||||
pub fn new(span: Span) -> Pipeline {
|
||||
Pipeline { list: vec![], span }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, command: ClassifiedCommand) {
|
||||
@ -111,15 +111,34 @@ impl Commands {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Group {
|
||||
pub pipelines: Vec<Pipeline>,
|
||||
pub span: Span,
|
||||
}
|
||||
impl Group {
|
||||
pub fn new(pipelines: Vec<Pipeline>, span: Span) -> Group {
|
||||
Group { pipelines, span }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, pipeline: Pipeline) {
|
||||
self.pipelines.push(pipeline);
|
||||
}
|
||||
|
||||
pub fn has_it_usage(&self) -> bool {
|
||||
self.pipelines.iter().any(|cc| cc.has_it_usage())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)]
|
||||
pub struct Block {
|
||||
pub params: Vec<String>,
|
||||
pub block: Vec<Commands>,
|
||||
pub block: Vec<Group>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new(params: Vec<String>, block: Vec<Commands>, span: Span) -> Block {
|
||||
pub fn new(params: Vec<String>, block: Vec<Group>, span: Span) -> Block {
|
||||
let mut output = Block {
|
||||
params,
|
||||
block,
|
||||
@ -130,16 +149,18 @@ impl Block {
|
||||
output
|
||||
}
|
||||
|
||||
pub fn push(&mut self, commands: Commands) {
|
||||
self.block.push(commands);
|
||||
pub fn push(&mut self, group: Group) {
|
||||
self.block.push(group);
|
||||
self.infer_params();
|
||||
}
|
||||
|
||||
pub fn set_redirect(&mut self, external_redirection: ExternalRedirection) {
|
||||
if let Some(pipeline) = self.block.last_mut() {
|
||||
if let Some(command) = pipeline.list.last_mut() {
|
||||
if let ClassifiedCommand::Internal(internal) = command {
|
||||
internal.args.external_redirection = external_redirection;
|
||||
if let Some(group) = self.block.last_mut() {
|
||||
if let Some(pipeline) = group.pipelines.last_mut() {
|
||||
if let Some(command) = pipeline.list.last_mut() {
|
||||
if let ClassifiedCommand::Internal(internal) = command {
|
||||
internal.args.external_redirection = external_redirection;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
src/main.rs
34
src/main.rs
@ -4,7 +4,7 @@ use nu_cli::create_default_context;
|
||||
use nu_cli::utils::test_bins as binaries;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::{prelude::*, BufReader};
|
||||
use std::io::prelude::*;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let matches = App::new("nushell")
|
||||
@ -124,9 +124,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
match matches.values_of("commands") {
|
||||
None => {}
|
||||
Some(values) => {
|
||||
let pipelines: Vec<String> = values.map(|x| x.to_string()).collect();
|
||||
futures::executor::block_on(nu_cli::run_vec_of_pipelines(
|
||||
pipelines,
|
||||
let script_text: String = values
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join("\n");
|
||||
futures::executor::block_on(nu_cli::run_script_file(
|
||||
script_text,
|
||||
matches.is_present("stdin"),
|
||||
))?;
|
||||
return Ok(());
|
||||
@ -135,25 +138,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
match matches.value_of("script") {
|
||||
Some(script) => {
|
||||
let file = File::open(script)?;
|
||||
let reader = BufReader::new(file);
|
||||
let pipelines: Vec<String> = reader
|
||||
.lines()
|
||||
.filter_map(|x| {
|
||||
if let Ok(x) = x {
|
||||
if !x.starts_with('#') {
|
||||
Some(x)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let mut file = File::open(script)?;
|
||||
let mut buffer = String::new();
|
||||
file.read_to_string(&mut buffer)?;
|
||||
|
||||
futures::executor::block_on(nu_cli::run_vec_of_pipelines(
|
||||
pipelines,
|
||||
futures::executor::block_on(nu_cli::run_script_file(
|
||||
buffer,
|
||||
matches.is_present("stdin"),
|
||||
))?;
|
||||
return Ok(());
|
||||
|
Loading…
Reference in New Issue
Block a user