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
use crate::sdk::std::flowcontrol::get_line_key;
use crate::utils::state::get_core_sub_state_for_command;
use duckscript::runner;
use duckscript::types::command::{Command, CommandResult, Commands};
use duckscript::types::instruction::{
    Instruction, InstructionMetaInfo, InstructionType, ScriptInstruction,
};
use duckscript::types::runtime::StateValue;
use std::collections::HashMap;

#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;

static END_STATE_KEY: &str = "end";
pub(crate) static END_COMMAND_NAME: &str = "end";

fn get_command(line: usize, state: &mut HashMap<String, StateValue>) -> Option<String> {
    let key = get_line_key(line, state);
    let sub_state = get_core_sub_state_for_command(state, END_STATE_KEY.to_string());

    match sub_state.get(&key) {
        Some(state_value) => match state_value {
            StateValue::String(command) => Some(command.clone()),
            _ => {
                // remove corrupted data
                sub_state.remove(&key);

                None
            }
        },
        None => None,
    }
}

pub(crate) fn set_command(line: usize, state: &mut HashMap<String, StateValue>, command: String) {
    let key = get_line_key(line, state);
    let sub_state = get_core_sub_state_for_command(state, END_STATE_KEY.to_string());

    sub_state.insert(key, StateValue::String(command));
}

#[derive(Clone)]
pub(crate) struct CommandImpl {}

impl Command for CommandImpl {
    fn name(&self) -> String {
        END_COMMAND_NAME.to_string()
    }

    fn help(&self) -> String {
        "".to_string()
    }

    fn clone_and_box(&self) -> Box<dyn Command> {
        Box::new((*self).clone())
    }

    fn requires_context(&self) -> bool {
        true
    }

    fn run_with_context(
        &self,
        _arguments: Vec<String>,
        state: &mut HashMap<String, StateValue>,
        variables: &mut HashMap<String, String>,
        _output_variable: Option<String>,
        instructions: &Vec<Instruction>,
        commands: &mut Commands,
        line: usize,
    ) -> CommandResult {
        match get_command(line, state) {
            Some(command) => {
                let mut script_instruction = ScriptInstruction::new();
                script_instruction.command = Some(command);
                let mut instruction_meta_info = InstructionMetaInfo::new();
                instruction_meta_info.line = Some(line);
                let instruction = Instruction {
                    meta_info: instruction_meta_info,
                    instruction_type: InstructionType::Script(script_instruction),
                };

                let (command_result, _) = runner::run_instruction(
                    commands,
                    variables,
                    state,
                    instructions,
                    instruction,
                    line,
                );

                command_result
            }
            None => CommandResult::Continue(None),
        }
    }
}

pub(crate) fn create() -> Box<dyn Command> {
    Box::new(CommandImpl {})
}