Repository: nushell/nushell
File: crates/nu-command/src/filters/drop/nth.rs (Rust)

Code before:
                    vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
                    Span::test_data(),
                )),
            },
        ]
    }

    fn run(
        &self,
        engine_state: &EngineState,
        stack: &mut Stack,
        call: &Call,
        input: PipelineData,
    ) -> Result<PipelineData, ShellError> {
        let head = call.head;
        let metadata = input.metadata();

        // Accept all arguments (int or range) from position 0 onwards
        let args: Vec<Value> = call.rest(engine_state, stack, 0)?;

        if args.is_empty() {
            return Err(ShellError::MissingParameter {
                param_name: "row number or row range".to_string(),
                span: head,
            });
        }

        // Accumulate all rows to drop
        let mut rows_to_drop = vec![];

        for value in args {
            if let Ok(i) = value.as_int() {
                if i < 0 {
                    return Err(ShellError::UnsupportedInput {
                        msg: "drop nth accepts only positive ints".into(),
                        input: "value originates from here".into(),
                        msg_span: head,
                        input_span: value.span(),
                    });
                }
                rows_to_drop.push(i as usize);
            } else if let Ok(range) = value.as_range() {
                match range {
                    Range::IntRange(range) => {
                        let start = range.start();
                        if start < 0 {
                            return Err(ShellError::UnsupportedInput {
                                msg: "drop nth accepts only positive ints".into(),
                                input: "value originates from here".into(),
                                msg_span: head,
                                input_span: value.span(),

Review comment (suggestion):
I think we should just pass through the value if no row number/range is provided, for consistency with `drop` and `select`. I'm not sure if this is the behavior we definitely want, but we should be consistent and if we want to change the behavior we should change it for all of them.

Code after:
                result: Some(Value::list(
                    vec![Value::test_int(0), Value::test_int(1), Value::test_int(2)],
                    Span::test_data(),
                )),
            },
        ]
    }

    fn run(
        &self,
        engine_state: &EngineState,
        stack: &mut Stack,
        call: &Call,
        input: PipelineData,
    ) -> Result<PipelineData, ShellError> {
        let head = call.head;
        let metadata = input.metadata();

        let args: Vec<Value> = call.rest(engine_state, stack, 0)?;
        if args.is_empty() {
            return Ok(input);
        }

        let (rows_to_drop, min_unbounded_start) = get_rows_to_drop(&args, head)?;

        let input = if let Some(cutoff) = min_unbounded_start {
            input
                .into_iter()
                .take(cutoff)
                .into_pipeline_data_with_metadata(
                    head,
                    engine_state.signals().clone(),
                    metadata.clone(),
                )
        } else {
            input
        };

        Ok(DropNthIterator {
            input: input.into_iter(),
            rows: rows_to_drop,
            current: 0,
        }
        .into_pipeline_data_with_metadata(head, engine_state.signals().clone(), metadata))
    }
}

fn get_rows_to_drop(
    args: &[Value],
    head: Span,
) -> Result<(VecDeque<usize>, Option<usize>), ShellError> {