Skip to main content

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