nu-command 0.115.1

Nushell's built-in commands
Documentation
use super::state::{FindSearchContext, stream_find};
use nu_engine::command_prelude::*;

#[derive(Clone)]
pub struct IdxFind;

impl Command for IdxFind {
    fn name(&self) -> &str {
        "idx find"
    }

    fn signature(&self) -> Signature {
        Signature::build(self.name())
            .required("query", SyntaxShape::String, "Freeform fuzzy query.")
            .switch("verbose", "Include verbose scoring details.", Some('v'))
            .switch("dirs", "Search directories only.", Some('d'))
            .switch("files", "Search files only.", Some('f'))
            .named(
                "limit",
                SyntaxShape::Int,
                "Maximum number of rows to return (default 100).",
                Some('l'),
            )
            .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::record())))])
            .category(Category::FileSystem)
    }

    fn description(&self) -> &str {
        "Search idx with fuzzy matching across files and directories by default."
    }

    fn extra_description(&self) -> &str {
        "`idx find` searches both files and directories unless you narrow it with `--files` or `--dirs`."
    }

    fn examples(&self) -> Vec<Example<'_>> {
        vec![
            Example {
                description: "Fuzzy search for files and directories matching 'main'.",
                example: "idx find main",
                result: None,
            },
            Example {
                description: "Search only files with verbose scoring output.",
                example: "idx find config --files --verbose",
                result: None,
            },
            Example {
                description: "Search only directories, limited to top 10 results.",
                example: "idx find src --dirs --limit 10",
                result: None,
            },
        ]
    }

    fn run(
        &self,
        engine_state: &EngineState,
        stack: &mut Stack,
        call: &Call,
        _input: PipelineData,
    ) -> Result<PipelineData, ShellError> {
        let query: String = call.req(engine_state, stack, 0)?;
        let verbose = call.has_flag(engine_state, stack, "verbose")?;
        let dirs = call.has_flag(engine_state, stack, "dirs")?;
        let files = call.has_flag(engine_state, stack, "files")?;

        if files && dirs {
            return Err(ShellError::IncompatibleParameters {
                left_message: "--files cannot be used with --dirs".to_string(),
                left_span: call.get_flag_span(stack, "files").unwrap_or(call.head),
                right_message: "--dirs cannot be used with --files".to_string(),
                right_span: call.get_flag_span(stack, "dirs").unwrap_or(call.head),
            });
        }

        let limit = call
            .get_flag::<i64>(engine_state, stack, "limit")?
            .map(|value| {
                usize::try_from(value)
                    .map_err(|_| ShellError::NeedsPositiveValue { span: call.head })
            })
            .transpose()?
            .unwrap_or(100);

        let cwd = engine_state.cwd(Some(stack))?.into_std_path_buf();
        stream_find(FindSearchContext {
            query: &query,
            files_only: files,
            dirs_only: dirs,
            verbose,
            limit,
            span: call.head,
            cwd: Some(cwd.as_path()),
            signals: engine_state.signals(),
        })
    }
}