nu_command/filesystem/idx/
search.rs1use super::state::stream_grep;
2use fff_search::GrepMode;
3use nu_engine::command_prelude::*;
4
5#[derive(Clone)]
6pub struct IdxSearch;
7
8impl Command for IdxSearch {
9 fn name(&self) -> &str {
10 "idx search"
11 }
12
13 fn signature(&self) -> Signature {
14 Signature::build(self.name())
15 .rest(
16 "pattern",
17 SyntaxShape::String,
18 "One or more search patterns.",
19 )
20 .switch("regex", "Use regular-expression matching mode.", Some('r'))
21 .switch("fuzzy", "Use fuzzy line-matching mode.", Some('f'))
22 .named(
23 "limit",
24 SyntaxShape::Int,
25 "Maximum number of matches to collect.",
26 Some('l'),
27 )
28 .input_output_types(vec![(Type::Nothing, Type::List(Box::new(Type::record())))])
29 .category(Category::FileSystem)
30 }
31
32 fn description(&self) -> &str {
33 "Search indexed file contents."
34 }
35
36 fn extra_description(&self) -> &str {
37 "Mode selection: plain text is the default and treats each pattern literally, `--regex` evaluates the patterns as regular expressions, and `--fuzzy` performs approximate line matching."
38 }
39
40 fn examples(&self) -> Vec<Example<'_>> {
41 vec![
42 Example {
43 description: "Search indexed file contents for a plain text pattern",
44 example: "idx search hello",
45 result: None,
46 },
47 Example {
48 description: "Search using a regular expression",
49 example: "idx search --regex 'fn \\w+'",
50 result: None,
51 },
52 Example {
53 description: "Search with multiple patterns simultaneously",
54 example: "idx search TODO FIXME HACK",
55 result: None,
56 },
57 ]
58 }
59
60 fn run(
61 &self,
62 engine_state: &EngineState,
63 stack: &mut Stack,
64 call: &Call,
65 _input: PipelineData,
66 ) -> Result<PipelineData, ShellError> {
67 let patterns: Vec<String> = call.rest(engine_state, stack, 0)?;
68 if patterns.is_empty() {
69 return Err(ShellError::MissingParameter {
70 param_name: "pattern".to_string(),
71 span: call.head,
72 });
73 }
74
75 let regex = call.has_flag(engine_state, stack, "regex")?;
76 let fuzzy = call.has_flag(engine_state, stack, "fuzzy")?;
77
78 if regex && fuzzy {
79 return Err(ShellError::IncompatibleParameters {
80 left_message: "--regex cannot be used with --fuzzy".to_string(),
81 left_span: call.get_flag_span(stack, "regex").unwrap_or(call.head),
82 right_message: "--fuzzy cannot be used with --regex".to_string(),
83 right_span: call.get_flag_span(stack, "fuzzy").unwrap_or(call.head),
84 });
85 }
86
87 let limit = call
88 .get_flag::<i64>(engine_state, stack, "limit")?
89 .and_then(|v| usize::try_from(v).ok())
90 .unwrap_or(50);
91
92 let mode = if fuzzy {
93 GrepMode::Fuzzy
94 } else if regex {
95 GrepMode::Regex
96 } else {
97 GrepMode::PlainText
98 };
99
100 let signals = engine_state.signals();
101 stream_grep(&patterns, mode, limit, call.head, signals)
102 }
103}