6582 - Incorrect documentation for some string operations (#6610)

* 6582 - Incorrect documentation for some string operations

* Update crates/nu-command/src/strings/str_/contains.rs

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>

* Update crates/nu-command/src/strings/str_/ends_with.rs

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>

* Update crates/nu-command/src/strings/str_/index_of.rs

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>

* Update crates/nu-command/src/strings/str_/starts_with.rs

Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>

* Run rustfmt

Co-authored-by: MichelMunoz <>
Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
This commit is contained in:
MichelMunoz 2022-09-25 18:09:09 +02:00 committed by GitHub
parent 0ab4e5af2a
commit 7f21b7fd7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 67 deletions

View File

@ -17,11 +17,11 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("str contains") Signature::build("str contains")
.required("pattern", SyntaxShape::String, "the pattern to find") .required("string", SyntaxShape::String, "the string to find")
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,
"optionally check if string contains pattern by column paths", "optionally check if input contains string by column paths",
) )
.switch("insensitive", "search is case insensitive", Some('i')) .switch("insensitive", "search is case insensitive", Some('i'))
.switch("not", "does not contain", Some('n')) .switch("not", "does not contain", Some('n'))
@ -29,11 +29,11 @@ impl Command for SubCommand {
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Checks if string contains pattern" "Checks if input contains string"
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
vec!["pattern", "match", "find", "search"] vec!["substring", "match", "find", "search"]
} }
fn run( fn run(
@ -49,7 +49,7 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example { Example {
description: "Check if string contains pattern", description: "Check if input contains string",
example: "'my_library.rb' | str contains '.rb'", example: "'my_library.rb' | str contains '.rb'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: true, val: true,
@ -57,7 +57,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if string contains pattern case insensitive", description: "Check if input contains string case insensitive",
example: "'my_library.rb' | str contains -i '.RB'", example: "'my_library.rb' | str contains -i '.RB'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: true, val: true,
@ -65,7 +65,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if string contains pattern in a table", description: "Check if input contains string in a table",
example: " [[ColA ColB]; [test 100]] | str contains 'e' ColA", example: " [[ColA ColB]; [test 100]] | str contains 'e' ColA",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::Record { vals: vec![Value::Record {
@ -83,7 +83,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if string contains pattern in a table", description: "Check if input contains string in a table",
example: " [[ColA ColB]; [test 100]] | str contains -i 'E' ColA", example: " [[ColA ColB]; [test 100]] | str contains -i 'E' ColA",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::Record { vals: vec![Value::Record {
@ -101,7 +101,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if string contains pattern in a table", description: "Check if input contains string in a table",
example: " [[ColA ColB]; [test hello]] | str contains 'e' ColA ColB", example: " [[ColA ColB]; [test hello]] | str contains 'e' ColA ColB",
result: Some(Value::List { result: Some(Value::List {
vals: vec![Value::Record { vals: vec![Value::Record {
@ -122,7 +122,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if string contains pattern", description: "Check if input string contains 'banana'",
example: "'hello' | str contains 'banana'", example: "'hello' | str contains 'banana'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: false, val: false,
@ -130,7 +130,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if list contains pattern", description: "Check if list contains string",
example: "[one two three] | str contains o", example: "[one two three] | str contains o",
result: Some(Value::List { result: Some(Value::List {
vals: vec![ vals: vec![
@ -151,7 +151,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Check if list does not contain pattern", description: "Check if list does not contain string",
example: "[one two three] | str contains -n o", example: "[one two three] | str contains -n o",
result: Some(Value::List { result: Some(Value::List {
vals: vec![ vals: vec![
@ -182,7 +182,7 @@ fn operate(
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let head = call.head; let head = call.head;
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?; let substring: Spanned<String> = call.req(engine_state, stack, 0)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?; let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
let case_insensitive = call.has_flag("insensitive"); let case_insensitive = call.has_flag("insensitive");
let not_contain = call.has_flag("not"); let not_contain = call.has_flag("not");
@ -190,11 +190,11 @@ fn operate(
input.map( input.map(
move |v| { move |v| {
if column_paths.is_empty() { if column_paths.is_empty() {
action(&v, case_insensitive, not_contain, &pattern.item, head) action(&v, case_insensitive, not_contain, &substring.item, head)
} else { } else {
let mut ret = v; let mut ret = v;
for path in &column_paths { for path in &column_paths {
let p = pattern.item.clone(); let p = substring.item.clone();
let r = ret.update_cell_path( let r = ret.update_cell_path(
&path.members, &path.members,
Box::new(move |old| action(old, case_insensitive, not_contain, &p, head)), Box::new(move |old| action(old, case_insensitive, not_contain, &p, head)),
@ -214,7 +214,7 @@ fn action(
input: &Value, input: &Value,
case_insensitive: bool, case_insensitive: bool,
not_contain: bool, not_contain: bool,
pattern: &str, substring: &str,
head: Span, head: Span,
) -> Value { ) -> Value {
match input { match input {
@ -222,16 +222,18 @@ fn action(
val: match case_insensitive { val: match case_insensitive {
true => { true => {
if not_contain { if not_contain {
!val.to_lowercase().contains(pattern.to_lowercase().as_str()) !val.to_lowercase()
.contains(substring.to_lowercase().as_str())
} else { } else {
val.to_lowercase().contains(pattern.to_lowercase().as_str()) val.to_lowercase()
.contains(substring.to_lowercase().as_str())
} }
} }
false => { false => {
if not_contain { if not_contain {
!val.contains(pattern) !val.contains(substring)
} else { } else {
val.contains(pattern) val.contains(substring)
} }
} }
}, },

View File

@ -16,7 +16,7 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("str ends-with") Signature::build("str ends-with")
.required("pattern", SyntaxShape::String, "the pattern to match") .required("string", SyntaxShape::String, "the string to match")
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,
@ -26,11 +26,11 @@ impl Command for SubCommand {
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Check if a string ends with a pattern" "Check if an input ends with a string"
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
vec!["pattern", "match", "find", "search"] vec!["suffix", "match", "find", "search"]
} }
fn run( fn run(
@ -46,7 +46,7 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example { Example {
description: "Checks if string ends with '.rb' pattern", description: "Checks if string ends with '.rb'",
example: "'my_library.rb' | str ends-with '.rb'", example: "'my_library.rb' | str ends-with '.rb'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: true, val: true,
@ -54,7 +54,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Checks if string ends with '.txt' pattern", description: "Checks if string ends with '.txt'",
example: "'my_library.rb' | str ends-with '.txt'", example: "'my_library.rb' | str ends-with '.txt'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: false, val: false,
@ -72,17 +72,17 @@ fn operate(
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let head = call.head; let head = call.head;
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?; let substring: Spanned<String> = call.req(engine_state, stack, 0)?;
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?; let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 1)?;
input.map( input.map(
move |v| { move |v| {
if column_paths.is_empty() { if column_paths.is_empty() {
action(&v, &pattern.item, head) action(&v, &substring.item, head)
} else { } else {
let mut ret = v; let mut ret = v;
for path in &column_paths { for path in &column_paths {
let p = pattern.item.clone(); let p = substring.item.clone();
let r = ret.update_cell_path( let r = ret.update_cell_path(
&path.members, &path.members,
Box::new(move |old| action(old, &p, head)), Box::new(move |old| action(old, &p, head)),
@ -98,10 +98,10 @@ fn operate(
) )
} }
fn action(input: &Value, pattern: &str, head: Span) -> Value { fn action(input: &Value, substring: &str, head: Span) -> Value {
match input { match input {
Value::String { val, .. } => Value::Bool { Value::String { val, .. } => Value::Bool {
val: val.ends_with(pattern), val: val.ends_with(substring),
span: head, span: head,
}, },
other => Value::Error { other => Value::Error {

View File

@ -9,7 +9,7 @@ use std::sync::Arc;
struct Arguments { struct Arguments {
end: bool, end: bool,
pattern: String, substring: String,
range: Option<Value>, range: Option<Value>,
column_paths: Vec<CellPath>, column_paths: Vec<CellPath>,
} }
@ -27,15 +27,11 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("str index-of") Signature::build("str index-of")
.required( .required("string", SyntaxShape::String, "the string to find index of")
"pattern",
SyntaxShape::String,
"the pattern to find index of",
)
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,
"optionally returns index of pattern in string by column paths", "optionally returns index of string in input by column paths",
) )
.named( .named(
"range", "range",
@ -43,16 +39,16 @@ impl Command for SubCommand {
"optional start and/or end index", "optional start and/or end index",
Some('r'), Some('r'),
) )
.switch("end", "search from the end of the string", Some('e')) .switch("end", "search from the end of the input", Some('e'))
.category(Category::Strings) .category(Category::Strings)
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Returns start index of first occurrence of pattern in string, or -1 if no match" "Returns start index of first occurrence of string in input, or -1 if no match"
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
vec!["pattern", "match", "find", "search"] vec!["match", "find", "search"]
} }
fn run( fn run(
@ -68,22 +64,22 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example { Example {
description: "Returns index of pattern in string", description: "Returns index of string in input",
example: " 'my_library.rb' | str index-of '.rb'", example: " 'my_library.rb' | str index-of '.rb'",
result: Some(Value::test_int(10)), result: Some(Value::test_int(10)),
}, },
Example { Example {
description: "Returns index of pattern in string with start index", description: "Returns index of string in input with start index",
example: " '.rb.rb' | str index-of '.rb' -r '1,'", example: " '.rb.rb' | str index-of '.rb' -r '1,'",
result: Some(Value::test_int(3)), result: Some(Value::test_int(3)),
}, },
Example { Example {
description: "Returns index of pattern in string with end index", description: "Returns index of string in input with end index",
example: " '123456' | str index-of '6' -r ',4'", example: " '123456' | str index-of '6' -r ',4'",
result: Some(Value::test_int(-1)), result: Some(Value::test_int(-1)),
}, },
Example { Example {
description: "Returns index of pattern in string with start and end index", description: "Returns index of string in input with start and end index",
example: " '123456' | str index-of '3' -r '1,4'", example: " '123456' | str index-of '3' -r '1,4'",
result: Some(Value::test_int(2)), result: Some(Value::test_int(2)),
}, },
@ -93,7 +89,7 @@ impl Command for SubCommand {
result: Some(Value::test_int(2)), result: Some(Value::test_int(2)),
}, },
Example { Example {
description: "Returns index of pattern in string", description: "Returns index of string in input",
example: " '/this/is/some/path/file.txt' | str index-of '/' -e", example: " '/this/is/some/path/file.txt' | str index-of '/' -e",
result: Some(Value::test_int(18)), result: Some(Value::test_int(18)),
}, },
@ -107,10 +103,10 @@ fn operate(
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?; let substring: Spanned<String> = call.req(engine_state, stack, 0)?;
let options = Arc::new(Arguments { let options = Arc::new(Arguments {
pattern: pattern.item, substring: substring.item,
range: call.get_flag(engine_state, stack, "range")?, range: call.get_flag(engine_state, stack, "range")?,
end: call.has_flag("end"), end: call.has_flag("end"),
column_paths: call.rest(engine_state, stack, 1)?, column_paths: call.rest(engine_state, stack, 1)?,
@ -142,7 +138,7 @@ fn operate(
fn action( fn action(
input: &Value, input: &Value,
Arguments { Arguments {
ref pattern, ref substring,
range, range,
end, end,
.. ..
@ -167,7 +163,7 @@ fn action(
}; };
if *end { if *end {
if let Some(result) = s[start_index..end_index].rfind(&**pattern) { if let Some(result) = s[start_index..end_index].rfind(&**substring) {
Value::Int { Value::Int {
val: result as i64 + start_index as i64, val: result as i64 + start_index as i64,
span: head, span: head,
@ -178,7 +174,7 @@ fn action(
span: head, span: head,
} }
} }
} else if let Some(result) = s[start_index..end_index].find(&**pattern) { } else if let Some(result) = s[start_index..end_index].find(&**substring) {
Value::Int { Value::Int {
val: result as i64 + start_index as i64, val: result as i64 + start_index as i64,
span: head, span: head,
@ -292,7 +288,7 @@ mod tests {
}; };
let options = Arguments { let options = Arguments {
pattern: String::from(".tomL"), substring: String::from(".tomL"),
range: Some(Value::String { range: Some(Value::String {
val: String::from(""), val: String::from(""),
@ -314,7 +310,7 @@ mod tests {
}; };
let options = Arguments { let options = Arguments {
pattern: String::from("Lm"), substring: String::from("Lm"),
range: Some(Value::String { range: Some(Value::String {
val: String::from(""), val: String::from(""),
@ -337,7 +333,7 @@ mod tests {
}; };
let options = Arguments { let options = Arguments {
pattern: String::from("Cargo"), substring: String::from("Cargo"),
range: Some(Value::String { range: Some(Value::String {
val: String::from("1"), val: String::from("1"),
@ -359,7 +355,7 @@ mod tests {
}; };
let options = Arguments { let options = Arguments {
pattern: String::from("Banana"), substring: String::from("Banana"),
range: Some(Value::String { range: Some(Value::String {
val: String::from(",5"), val: String::from(",5"),
@ -381,7 +377,7 @@ mod tests {
}; };
let options = Arguments { let options = Arguments {
pattern: String::from("123"), substring: String::from("123"),
range: Some(Value::String { range: Some(Value::String {
val: String::from("2,6"), val: String::from("2,6"),
@ -403,7 +399,7 @@ mod tests {
}; };
let options = Arguments { let options = Arguments {
pattern: String::from("1"), substring: String::from("1"),
range: Some(Value::String { range: Some(Value::String {
val: String::from("2,4"), val: String::from("2,4"),

View File

@ -8,7 +8,7 @@ use nu_protocol::{Example, PipelineData, ShellError, Signature, Span, SyntaxShap
use std::sync::Arc; use std::sync::Arc;
struct Arguments { struct Arguments {
pattern: String, substring: String,
column_paths: Vec<CellPath>, column_paths: Vec<CellPath>,
} }
@ -23,7 +23,7 @@ impl Command for SubCommand {
fn signature(&self) -> Signature { fn signature(&self) -> Signature {
Signature::build("str starts-with") Signature::build("str starts-with")
.required("pattern", SyntaxShape::String, "the pattern to match") .required("string", SyntaxShape::String, "the string to match")
.rest( .rest(
"rest", "rest",
SyntaxShape::CellPath, SyntaxShape::CellPath,
@ -33,11 +33,11 @@ impl Command for SubCommand {
} }
fn usage(&self) -> &str { fn usage(&self) -> &str {
"Check if string starts with a pattern" "Check if an input starts with a string"
} }
fn search_terms(&self) -> Vec<&str> { fn search_terms(&self) -> Vec<&str> {
vec!["pattern", "match", "find", "search"] vec!["prefix", "match", "find", "search"]
} }
fn run( fn run(
@ -53,7 +53,7 @@ impl Command for SubCommand {
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![
Example { Example {
description: "Checks if string starts with 'my' pattern", description: "Checks if input string starts with 'my'",
example: "'my_library.rb' | str starts-with 'my'", example: "'my_library.rb' | str starts-with 'my'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: true, val: true,
@ -61,7 +61,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Checks if string starts with 'my' pattern", description: "Checks if input string starts with 'my'",
example: "'Cargo.toml' | str starts-with 'Car'", example: "'Cargo.toml' | str starts-with 'Car'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: true, val: true,
@ -69,7 +69,7 @@ impl Command for SubCommand {
}), }),
}, },
Example { Example {
description: "Checks if string starts with 'my' pattern", description: "Checks if input string starts with 'my'",
example: "'Cargo.toml' | str starts-with '.toml'", example: "'Cargo.toml' | str starts-with '.toml'",
result: Some(Value::Bool { result: Some(Value::Bool {
val: false, val: false,
@ -86,10 +86,10 @@ fn operate(
call: &Call, call: &Call,
input: PipelineData, input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let pattern: Spanned<String> = call.req(engine_state, stack, 0)?; let substring: Spanned<String> = call.req(engine_state, stack, 0)?;
let options = Arc::new(Arguments { let options = Arc::new(Arguments {
pattern: pattern.item, substring: substring.item,
column_paths: call.rest(engine_state, stack, 1)?, column_paths: call.rest(engine_state, stack, 1)?,
}); });
let head = call.head; let head = call.head;
@ -116,10 +116,10 @@ fn operate(
) )
} }
fn action(input: &Value, Arguments { pattern, .. }: &Arguments, head: Span) -> Value { fn action(input: &Value, Arguments { substring, .. }: &Arguments, head: Span) -> Value {
match input { match input {
Value::String { val: s, .. } => { Value::String { val: s, .. } => {
let starts_with = s.starts_with(pattern); let starts_with = s.starts_with(substring);
Value::Bool { Value::Bool {
val: starts_with, val: starts_with,
span: head, span: head,