mirror of
https://github.com/nushell/nushell.git
synced 2025-02-02 11:39:55 +01:00
Find with regex flag (#4649)
* split find functions * find command with regex * corrected message * cargo fmt
This commit is contained in:
parent
3eca43c0bb
commit
11bc056576
@ -5,6 +5,7 @@ use nu_protocol::{
|
|||||||
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
|
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
|
||||||
SyntaxShape, Value,
|
SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Find;
|
pub struct Find;
|
||||||
@ -22,6 +23,12 @@ impl Command for Find {
|
|||||||
"the predicate to satisfy",
|
"the predicate to satisfy",
|
||||||
Some('p'),
|
Some('p'),
|
||||||
)
|
)
|
||||||
|
.named(
|
||||||
|
"regex",
|
||||||
|
SyntaxShape::String,
|
||||||
|
"regex to match with",
|
||||||
|
Some('r'),
|
||||||
|
)
|
||||||
.rest("rest", SyntaxShape::Any, "terms to search")
|
.rest("rest", SyntaxShape::Any, "terms to search")
|
||||||
.category(Category::Filters)
|
.category(Category::Filters)
|
||||||
}
|
}
|
||||||
@ -59,8 +66,8 @@ impl Command for Find {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Find the first odd value",
|
description: "Find odd values",
|
||||||
example: "echo [2 4 3 6 5 8] | find --predicate { |it| ($it mod 2) == 1 }",
|
example: "[2 4 3 6 5 8] | find --predicate { |it| ($it mod 2) == 1 }",
|
||||||
result: Some(Value::List {
|
result: Some(Value::List {
|
||||||
vals: vec![Value::test_int(3), Value::test_int(5)],
|
vals: vec![Value::test_int(3), Value::test_int(5)],
|
||||||
span: Span::test_data()
|
span: Span::test_data()
|
||||||
@ -68,7 +75,7 @@ impl Command for Find {
|
|||||||
},
|
},
|
||||||
Example {
|
Example {
|
||||||
description: "Find if a service is not running",
|
description: "Find if a service is not running",
|
||||||
example: "echo [[version patch]; [0.1.0 $false] [0.1.1 $true] [0.2.0 $false]] | find -p { |it| $it.patch }",
|
example: "[[version patch]; [0.1.0 $false] [0.1.1 $true] [0.2.0 $false]] | find -p { |it| $it.patch }",
|
||||||
result: Some(Value::List {
|
result: Some(Value::List {
|
||||||
vals: vec![Value::test_record(
|
vals: vec![Value::test_record(
|
||||||
vec!["version", "patch"],
|
vec!["version", "patch"],
|
||||||
@ -77,6 +84,33 @@ impl Command for Find {
|
|||||||
span: Span::test_data()
|
span: Span::test_data()
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
Example {
|
||||||
|
description: "Find using regex",
|
||||||
|
example: r#"[abc bde arc abf] | find --regex "ab""#,
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_string("abc".to_string()), Value::test_string("abf".to_string())],
|
||||||
|
span: Span::test_data()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Find using regex case insensitive",
|
||||||
|
example: r#"[aBc bde Arc abf] | find --regex "(?i)ab""#,
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_string("aBc".to_string()), Value::test_string("abf".to_string())],
|
||||||
|
span: Span::test_data()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Find value in records",
|
||||||
|
example: r#"[[version name]; [0.1.0 nushell] [0.1.1 fish] [0.2.0 zsh]] | find -r "nu""#,
|
||||||
|
result: Some(Value::List {
|
||||||
|
vals: vec![Value::test_record(
|
||||||
|
vec!["version", "name"],
|
||||||
|
vec![Value::test_string("0.1.0"), Value::test_string("nushell".to_string())]
|
||||||
|
)],
|
||||||
|
span: Span::test_data()
|
||||||
|
}),
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,18 +120,61 @@ impl Command for Find {
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let predicate = call.get_flag::<CaptureBlock>(engine_state, stack, "predicate")?;
|
||||||
|
let regex = call.get_flag::<String>(engine_state, stack, "regex")?;
|
||||||
|
|
||||||
|
match (regex, predicate) {
|
||||||
|
(None, Some(predicate)) => {
|
||||||
|
find_with_predicate(predicate, engine_state, stack, call, input)
|
||||||
|
}
|
||||||
|
(Some(regex), None) => find_with_regex(regex, engine_state, stack, call, input),
|
||||||
|
(None, None) => find_with_rest(engine_state, stack, call, input),
|
||||||
|
(Some(_), Some(_)) => Err(ShellError::IncompatibleParametersSingle(
|
||||||
|
"expected either predicate or regex flag, not both".to_owned(),
|
||||||
|
call.head,
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_with_regex(
|
||||||
|
regex: String,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let engine_state = engine_state.clone();
|
|
||||||
let metadata = input.metadata();
|
|
||||||
let config = stack.get_config()?;
|
let config = stack.get_config()?;
|
||||||
|
|
||||||
|
let re = Regex::new(regex.as_str())
|
||||||
|
.map_err(|e| ShellError::UnsupportedInput(format!("incorrect regex: {}", e), span))?;
|
||||||
|
|
||||||
|
input.filter(
|
||||||
|
move |value| {
|
||||||
|
let string = value.into_string(" ", &config);
|
||||||
|
re.is_match(string.as_str())
|
||||||
|
},
|
||||||
|
ctrlc,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_with_predicate(
|
||||||
|
predicate: CaptureBlock,
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let span = call.head;
|
||||||
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
let metadata = input.metadata();
|
||||||
let redirect_stdout = call.redirect_stdout;
|
let redirect_stdout = call.redirect_stdout;
|
||||||
let redirect_stderr = call.redirect_stderr;
|
let redirect_stderr = call.redirect_stderr;
|
||||||
|
let engine_state = engine_state.clone();
|
||||||
|
|
||||||
match call.get_flag::<CaptureBlock>(&engine_state, stack, "predicate")? {
|
|
||||||
Some(predicate) => {
|
|
||||||
let capture_block = predicate;
|
let capture_block = predicate;
|
||||||
let block_id = capture_block.block_id;
|
let block_id = capture_block.block_id;
|
||||||
|
|
||||||
@ -134,7 +211,19 @@ impl Command for Find {
|
|||||||
ctrlc,
|
ctrlc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
None => {
|
|
||||||
|
fn find_with_rest(
|
||||||
|
engine_state: &EngineState,
|
||||||
|
stack: &mut Stack,
|
||||||
|
call: &Call,
|
||||||
|
input: PipelineData,
|
||||||
|
) -> Result<PipelineData, ShellError> {
|
||||||
|
let span = call.head;
|
||||||
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
|
let metadata = input.metadata();
|
||||||
|
let engine_state = engine_state.clone();
|
||||||
|
let config = stack.get_config()?;
|
||||||
|
|
||||||
let terms = call.rest::<Value>(&engine_state, stack, 0)?;
|
let terms = call.rest::<Value>(&engine_state, stack, 0)?;
|
||||||
let lower_terms = terms
|
let lower_terms = terms
|
||||||
.iter()
|
.iter()
|
||||||
@ -154,6 +243,7 @@ impl Command for Find {
|
|||||||
} else {
|
} else {
|
||||||
value.clone()
|
value.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
lower_terms.iter().any(|term| match value {
|
lower_terms.iter().any(|term| match value {
|
||||||
Value::Bool { .. }
|
Value::Bool { .. }
|
||||||
| Value::Int { .. }
|
| Value::Int { .. }
|
||||||
@ -191,16 +281,12 @@ impl Command for Find {
|
|||||||
},
|
},
|
||||||
ctrlc,
|
ctrlc,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
match metadata {
|
match metadata {
|
||||||
Some(m) => {
|
Some(m) => Ok(pipe.into_pipeline_data_with_metadata(m, engine_state.ctrlc.clone())),
|
||||||
Ok(pipe.into_pipeline_data_with_metadata(m, engine_state.ctrlc.clone()))
|
|
||||||
}
|
|
||||||
None => Ok(pipe),
|
None => Ok(pipe),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -171,6 +171,7 @@ impl Clone for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
/// Converts into string values that can be changed into string natively
|
||||||
pub fn as_string(&self) -> Result<String, ShellError> {
|
pub fn as_string(&self) -> Result<String, ShellError> {
|
||||||
match self {
|
match self {
|
||||||
Value::Int { val, .. } => Ok(val.to_string()),
|
Value::Int { val, .. } => Ok(val.to_string()),
|
||||||
|
Loading…
Reference in New Issue
Block a user