1
0
mirror of https://github.com/nushell/nushell.git synced 2025-03-10 05:28:29 +01:00

Find with regex flag ()

* split find functions

* find command with regex

* corrected message

* cargo fmt
This commit is contained in:
Fernando Herrera 2022-02-26 09:19:19 +00:00 committed by GitHub
parent 3eca43c0bb
commit 11bc056576
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 199 additions and 112 deletions
crates
nu-command/src/filters
nu-protocol/src/value

View File

@ -5,6 +5,7 @@ use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
use regex::Regex;
#[derive(Clone)]
pub struct Find;
@ -22,6 +23,12 @@ impl Command for Find {
"the predicate to satisfy",
Some('p'),
)
.named(
"regex",
SyntaxShape::String,
"regex to match with",
Some('r'),
)
.rest("rest", SyntaxShape::Any, "terms to search")
.category(Category::Filters)
}
@ -59,8 +66,8 @@ impl Command for Find {
})
},
Example {
description: "Find the first odd value",
example: "echo [2 4 3 6 5 8] | find --predicate { |it| ($it mod 2) == 1 }",
description: "Find odd values",
example: "[2 4 3 6 5 8] | find --predicate { |it| ($it mod 2) == 1 }",
result: Some(Value::List {
vals: vec![Value::test_int(3), Value::test_int(5)],
span: Span::test_data()
@ -68,7 +75,7 @@ impl Command for Find {
},
Example {
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 {
vals: vec![Value::test_record(
vec!["version", "patch"],
@ -77,6 +84,33 @@ impl Command for Find {
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,
call: &Call,
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> {
let span = call.head;
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let metadata = input.metadata();
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_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 block_id = capture_block.block_id;
@ -134,7 +211,19 @@ impl Command for Find {
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 lower_terms = terms
.iter()
@ -154,6 +243,7 @@ impl Command for Find {
} else {
value.clone()
};
lower_terms.iter().any(|term| match value {
Value::Bool { .. }
| Value::Int { .. }
@ -191,16 +281,12 @@ impl Command for Find {
},
ctrlc,
)?;
match metadata {
Some(m) => {
Ok(pipe.into_pipeline_data_with_metadata(m, engine_state.ctrlc.clone()))
}
Some(m) => Ok(pipe.into_pipeline_data_with_metadata(m, engine_state.ctrlc.clone())),
None => Ok(pipe),
}
}
}
}
}
#[cfg(test)]
mod tests {

View File

@ -171,6 +171,7 @@ impl Clone for Value {
}
impl Value {
/// Converts into string values that can be changed into string natively
pub fn as_string(&self) -> Result<String, ShellError> {
match self {
Value::Int { val, .. } => Ok(val.to_string()),