nu_cli/
eval_cmds.rs

1use log::info;
2use nu_engine::eval_block;
3use nu_parser::parse;
4use nu_protocol::{
5    PipelineData, ShellError, Spanned, Value,
6    debugger::WithoutDebug,
7    engine::{EngineState, Stack, StateWorkingSet},
8    process::check_exit_status_future,
9    report_error::report_compile_error,
10    report_parse_error, report_parse_warning,
11};
12use std::sync::Arc;
13
14use crate::util::print_pipeline;
15
16#[derive(Default)]
17pub struct EvaluateCommandsOpts {
18    pub table_mode: Option<Value>,
19    pub error_style: Option<Value>,
20    pub no_newline: bool,
21}
22
23/// Run a command (or commands) given to us by the user
24pub fn evaluate_commands(
25    commands: &Spanned<String>,
26    engine_state: &mut EngineState,
27    stack: &mut Stack,
28    input: PipelineData,
29    opts: EvaluateCommandsOpts,
30) -> Result<(), ShellError> {
31    let EvaluateCommandsOpts {
32        table_mode,
33        error_style,
34        no_newline,
35    } = opts;
36
37    // Handle the configured error style early
38    if let Some(e_style) = error_style {
39        match e_style.coerce_str()?.parse() {
40            Ok(e_style) => {
41                Arc::make_mut(&mut engine_state.config).error_style = e_style;
42            }
43            Err(err) => {
44                return Err(ShellError::GenericError {
45                    error: "Invalid value for `--error-style`".into(),
46                    msg: err.into(),
47                    span: Some(e_style.span()),
48                    help: None,
49                    inner: vec![],
50                });
51            }
52        }
53    }
54
55    // Parse the source code
56    let (block, delta) = {
57        if let Some(ref t_mode) = table_mode {
58            Arc::make_mut(&mut engine_state.config).table.mode =
59                t_mode.coerce_str()?.parse().unwrap_or_default();
60        }
61
62        let mut working_set = StateWorkingSet::new(engine_state);
63
64        let output = parse(&mut working_set, None, commands.item.as_bytes(), false);
65        if let Some(warning) = working_set.parse_warnings.first() {
66            report_parse_warning(&working_set, warning);
67        }
68
69        if let Some(err) = working_set.parse_errors.first() {
70            report_parse_error(&working_set, err);
71            std::process::exit(1);
72        }
73
74        if let Some(err) = working_set.compile_errors.first() {
75            report_compile_error(&working_set, err);
76            std::process::exit(1);
77        }
78
79        (output, working_set.render())
80    };
81
82    // Update permanent state
83    engine_state.merge_delta(delta)?;
84
85    // Run the block
86    let pipeline = eval_block::<WithoutDebug>(engine_state, stack, &block, input)?;
87
88    let pipeline_data = pipeline.body;
89    if let PipelineData::Value(Value::Error { error, .. }, ..) = pipeline_data {
90        return Err(*error);
91    }
92
93    if let Some(t_mode) = table_mode {
94        Arc::make_mut(&mut engine_state.config).table.mode =
95            t_mode.coerce_str()?.parse().unwrap_or_default();
96    }
97
98    print_pipeline(engine_state, stack, pipeline_data, no_newline)?;
99    info!("evaluate {}:{}:{}", file!(), line!(), column!());
100    let pipefail = nu_experimental::PIPE_FAIL.get();
101    if !pipefail {
102        return Ok(());
103    }
104    // After print pipeline, need to check exit status to implement pipeline feature.
105    check_exit_status_future(pipeline.exit)
106}