1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::evaluate::scope::Scope;
use crate::evaluation_context::EvaluationContext;
use crate::shell::shell_manager::ShellManager;
use crate::FromValue;
use crate::{call_info::UnevaluatedCallInfo, config_holder::ConfigHolder};
use crate::{env::host::Host, evaluate_baseline_expr};
use getset::Getters;
use nu_errors::ShellError;
use nu_protocol::hir::SpannedExpression;
use nu_source::Tag;
use nu_stream::InputStream;
use parking_lot::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;

#[derive(Getters)]
#[get = "pub"]
pub struct CommandArgs {
    pub context: EvaluationContext,
    pub call_info: UnevaluatedCallInfo,
    pub input: InputStream,
}

impl CommandArgs {
    pub fn scope(&self) -> &Scope {
        &self.context.scope
    }

    pub fn host(&self) -> Arc<parking_lot::Mutex<Box<dyn Host>>> {
        self.context.host().clone()
    }

    pub fn current_errors(&self) -> Arc<Mutex<Vec<ShellError>>> {
        self.context.current_errors().clone()
    }

    pub fn ctrl_c(&self) -> Arc<AtomicBool> {
        self.context.ctrl_c().clone()
    }

    pub fn configs(&self) -> Arc<Mutex<ConfigHolder>> {
        self.context.configs().clone()
    }

    pub fn shell_manager(&self) -> ShellManager {
        self.context.shell_manager().clone()
    }

    pub fn nth(&self, pos: usize) -> Option<&SpannedExpression> {
        if let Some(positional) = &self.call_info.args.positional {
            positional.get(pos)
        } else {
            None
        }
    }

    pub fn req<T: FromValue>(&self, pos: usize) -> Result<T, ShellError> {
        if let Some(expr) = self.nth(pos) {
            let result = evaluate_baseline_expr(expr, &self.context)?;
            FromValue::from_value(&result)
        } else {
            Err(ShellError::labeled_error(
                "Position beyond end of command arguments",
                "can't access beyond end of command arguments",
                self.call_info.name_tag.span,
            ))
        }
    }

    pub fn req_named<T: FromValue>(&self, name: &str) -> Result<T, ShellError> {
        match self.get_flag(name)? {
            Some(v) => Ok(v),
            None => Err(ShellError::labeled_error(
                "Missing flag",
                format!("expected {} flag", name),
                &self.call_info.name_tag,
            )),
        }
    }

    pub fn has_flag(&self, name: &str) -> bool {
        self.call_info.args.switch_preset(name)
    }

    pub fn get_flag<T: FromValue>(&self, name: &str) -> Result<Option<T>, ShellError> {
        if let Some(expr) = self.call_info.args.get_flag(name) {
            let result = evaluate_baseline_expr(expr, &self.context)?;
            FromValue::from_value(&result).map(Some)
        } else {
            Ok(None)
        }
    }

    pub fn opt<T: FromValue>(&self, pos: usize) -> Result<Option<T>, ShellError> {
        if let Some(expr) = self.nth(pos) {
            let result = evaluate_baseline_expr(expr, &self.context)?;
            FromValue::from_value(&result).map(Some)
        } else {
            Ok(None)
        }
    }

    pub fn rest<T: FromValue>(&self, starting_pos: usize) -> Result<Vec<T>, ShellError> {
        let mut output = vec![];

        if let Some(positional) = &self.call_info.args.positional {
            for expr in positional.iter().skip(starting_pos) {
                let result = evaluate_baseline_expr(expr, &self.context)?;
                output.push(FromValue::from_value(&result)?);
            }
        }

        Ok(output)
    }

    pub fn rest_with_minimum<T: FromValue>(
        &self,
        pos: usize,
        count: usize,
    ) -> Result<Vec<T>, ShellError> {
        let mut output = vec![];
        for i in pos..pos + count {
            output.push(self.req(i)?);
        }
        output.extend(self.rest(pos + count)?);

        Ok(output)
    }

    pub fn name_tag(&self) -> Tag {
        self.call_info.name_tag.clone()
    }
}

pub type RunnableContext = CommandArgs;

impl std::fmt::Debug for CommandArgs {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.call_info.fmt(f)
    }
}