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
use crate::prelude::*;
use log::trace;
use nu_engine::evaluate_baseline_expr;
use nu_engine::WholeStreamCommand;
use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value};

pub struct SubCommand;

#[async_trait]
impl WholeStreamCommand for SubCommand {
    fn name(&self) -> &str {
        "skip until"
    }

    fn signature(&self) -> Signature {
        Signature::build("skip until")
            .required(
                "condition",
                SyntaxShape::RowCondition,
                "The condition that must be met to stop skipping",
            )
            .filter()
    }

    fn usage(&self) -> &str {
        "Skips rows until the condition matches."
    }

    async fn run(&self, args: CommandArgs) -> Result<OutputStream, ShellError> {
        let ctx = Arc::new(EvaluationContext::from_args(&args));
        let call_info = args.evaluate_once().await?;

        let block = call_info.args.expect_nth(0)?.clone();

        let (condition, captured) = match block {
            Value {
                value: UntaggedValue::Block(captured_block),
                tag,
            } => {
                if captured_block.block.block.len() != 1 {
                    return Err(ShellError::labeled_error(
                        "Expected a condition",
                        "expected a condition",
                        tag,
                    ));
                }
                match captured_block.block.block[0].pipelines.get(0) {
                    Some(item) => match item.list.get(0) {
                        Some(ClassifiedCommand::Expr(expr)) => {
                            (Arc::new(expr.clone()), captured_block.captured.clone())
                        }
                        _ => {
                            return Err(ShellError::labeled_error(
                                "Expected a condition",
                                "expected a condition",
                                tag,
                            ));
                        }
                    },
                    None => {
                        return Err(ShellError::labeled_error(
                            "Expected a condition",
                            "expected a condition",
                            tag,
                        ));
                    }
                }
            }
            Value { tag, .. } => {
                return Err(ShellError::labeled_error(
                    "Expected a condition",
                    "expected a condition",
                    tag,
                ));
            }
        };

        Ok(call_info
            .input
            .skip_while(move |item| {
                let condition = condition.clone();
                let ctx = ctx.clone();

                ctx.scope.enter_scope();
                ctx.scope.add_var("$it", item.clone());
                ctx.scope.add_vars(&captured.entries);
                trace!("ITEM = {:?}", item);

                async move {
                    let result = evaluate_baseline_expr(&*condition, &*ctx).await;
                    ctx.scope.exit_scope();
                    trace!("RESULT = {:?}", result);

                    !matches!(result, Ok(ref v) if v.is_true())
                }
            })
            .to_output_stream())
    }
}

#[cfg(test)]
mod tests {
    use super::ShellError;
    use super::SubCommand;

    #[test]
    fn examples_work_as_expected() -> Result<(), ShellError> {
        use crate::examples::test as test_examples;

        test_examples(SubCommand {})
    }
}