From 9fd6aecad27240ccedab4487f6c157914142ca47 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 17 Aug 2026 07:36:34 +0900 Subject: refactor(preg): return the preg_* $matches instead of filling an out-param PHP fills `$matches` through a by-ref parameter, which the port mirrored with a `&mut` out-param plus a bool or count return. Every caller then had to declare an empty binding one line ahead of the call, and nothing in the type said the binding is only meaningful when the call succeeded. Return the matches instead: preg_match() and preg_match2() hand back an Option, and the three preg_match_all* functions hand back the collection they used to fill. The occurrence count the two map-shaped preg_match_all* functions used to return is the length of any one of the map's columns, so it is not lost -- Preg::match_all() and friends derive it via occurrence_count(). preg_replace2() keeps its `count: Option<&mut usize>`: that one is not derivable from the replaced string, and callers that do not want it pay nothing for passing None. Co-Authored-By: Claude Opus 5 (1M context) --- crates/shirabe-pcre/src/preg.rs | 58 ++++++------ crates/shirabe-php-shim/src/preg.rs | 91 +++++++------------ crates/shirabe-semver/src/version_parser.rs | 100 +++++++-------------- .../shirabe-symfony-console/src/command/command.rs | 3 +- .../src/formatter/output_formatter.rs | 16 ++-- .../shirabe-symfony-console/src/helper/helper.rs | 4 +- .../src/input/argv_input.rs | 3 +- crates/shirabe-symfony-console/src/input/input.rs | 3 +- .../src/input/string_input.rs | 14 ++- .../src/output/stream_output.rs | 3 +- .../src/question/choice_question.rs | 8 +- .../src/question/confirmation_question.rs | 5 +- crates/shirabe-symfony-console/src/terminal.rs | 29 ++---- crates/shirabe-symfony-process/src/process.rs | 6 +- crates/shirabe/src/console/application.rs | 9 +- 15 files changed, 127 insertions(+), 225 deletions(-) (limited to 'crates') diff --git a/crates/shirabe-pcre/src/preg.rs b/crates/shirabe-pcre/src/preg.rs index aa986ae8..dd6e4950 100644 --- a/crates/shirabe-pcre/src/preg.rs +++ b/crates/shirabe-pcre/src/preg.rs @@ -46,19 +46,20 @@ impl Preg { matches: Option<&mut PregMatchedGroups>, offset: usize, ) -> bool { - let mut internal = PregMatches::new(); - let result = preg_match2(pattern, subject, &mut internal, offset); + let internal = preg_match2(pattern, subject, offset); if let Some(out) = matches { - *out = drop_null_matches(internal); + *out = match &internal { + Some(internal) => drop_null_matches(internal), + None => PregMatchedGroups::new(), + }; } - result + internal.is_some() } pub fn match_all(pattern: impl PregPattern, subject: &str) -> usize { - let mut dummy = PregMatchesAll::new(); - preg_match_all2(pattern, subject, &mut dummy) + occurrence_count(&preg_match_all2(pattern, subject)) } pub fn match_all2( @@ -66,7 +67,8 @@ impl Preg { subject: &str, matches: &mut PregMatchesAll, ) -> usize { - preg_match_all2(pattern, subject, matches) + *matches = preg_match_all2(pattern, subject); + occurrence_count(matches) } fn match_all_with_offsets5( @@ -74,14 +76,14 @@ impl Preg { subject: &str, matches: Option<&mut PregMatchesAllWithOffsets>, ) -> usize { - let mut internal = PregMatchesAllWithOffsets::new(); - let result = preg_match_all_offset_capture(pattern, subject, &mut internal); + let internal = preg_match_all_offset_capture(pattern, subject); + let count = internal[&CaptureKey::ByIndex(0)].len(); if let Some(out) = matches { *out = internal; } - result + count } pub fn replace(pattern: impl PregPattern, replacement: &str, subject: &str) -> String { @@ -112,7 +114,7 @@ impl Preg { mut replacement: F, subject: &str, ) -> String { - let adapter = |internal: &PregMatches| Ok(replacement(&drop_null_matches_ref(internal))); + let adapter = |internal: &PregMatches| Ok(replacement(&drop_null_matches(internal))); preg_replace_callback(pattern, adapter, subject).expect("$replacement cannot fail") } @@ -150,13 +152,15 @@ impl Preg { subject: &str, matches: &mut PregNamedGroups, ) -> bool { - let mut internal = PregMatches::new(); - let result = preg_match2(pattern, subject, &mut internal, 0); + let internal = preg_match2(pattern, subject, 0); + let result = internal.is_some(); matches.clear(); - for (key, value) in internal { - if let (CaptureKey::ByName(name), Some(value)) = (key, value) { - matches.insert(name, value); + if let Some(internal) = internal { + for (key, value) in internal { + if let (CaptureKey::ByName(name), Some(value)) = (key, value) { + matches.insert(name, value); + } } } @@ -169,13 +173,8 @@ impl Preg { pattern: impl PregPattern, subject: &str, ) -> Option>> { - let mut internal = PregMatches::new(); - if !preg_match2(pattern, subject, &mut internal, 0) { - return None; - } - Some( - internal + preg_match2(pattern, subject, 0)? .into_iter() .filter_map(|(key, value)| match key { CaptureKey::ByIndex(_) => Some(value), @@ -204,16 +203,15 @@ impl Preg { // Drops `null` (unmatched) groups, mirroring how the public `string`-valued // `matches` map represents PHP's `string|null` entries by their absence. -fn drop_null_matches(matches: PregMatches) -> PregMatchedGroups { - matches - .into_iter() - .filter_map(|(key, value)| value.map(|value| (key, value))) - .collect() -} - -fn drop_null_matches_ref(matches: &PregMatches) -> PregMatchedGroups { +fn drop_null_matches(matches: &PregMatches) -> PregMatchedGroups { matches .iter() .filter_map(|(key, value)| value.clone().map(|value| (key.clone(), value))) .collect() } + +// PHP's `preg_match_all` returns the number of occurrences; every column of a +// PREG_PATTERN_ORDER map holds one entry per occurrence. +fn occurrence_count(matches: &PregMatchesAll) -> usize { + matches[&CaptureKey::ByIndex(0)].len() +} diff --git a/crates/shirabe-php-shim/src/preg.rs b/crates/shirabe-php-shim/src/preg.rs index b16ee81d..c2aa0df3 100644 --- a/crates/shirabe-php-shim/src/preg.rs +++ b/crates/shirabe-php-shim/src/preg.rs @@ -117,34 +117,22 @@ pub fn preg_quote(str: &str, delimiter: Option) -> String { out } -// Returns whether the pattern matched; populates matches[0]=full match, matches[1..]=captures. -// Optional groups that did not participate in the match are stored as None. -pub fn preg_match( - pattern: impl PregPattern, - subject: &str, - matches: &mut Vec>, -) -> bool { +// Returns None if the pattern did not match; otherwise index 0 is the full match and 1.. the +// capture groups. A group that did not participate is None. +pub fn preg_match(pattern: impl PregPattern, subject: &str) -> Option>> { let __resolved = pattern.resolve(); let (re, _anchored) = __resolved.parts(); - matches.clear(); - match re.captures(subject) { - Some(caps) => { - for g in 0..caps.len() { - matches.push(caps.get(g).map(|m| m.as_str().to_string())); - } - true - } - None => false, - } + let caps = re.captures(subject)?; + Some( + (0..caps.len()) + .map(|g| caps.get(g).map(|m| m.as_str().to_string())) + .collect(), + ) } -// Returns whether the pattern matched, reporting the groups as single_match_map() does. -pub fn preg_match2( - pattern: impl PregPattern, - subject: &str, - matches: &mut PregMatches, - offset: usize, -) -> bool { +// Returns None if the pattern did not match; otherwise the groups as single_match_map() reports +// them. +pub fn preg_match2(pattern: impl PregPattern, subject: &str, offset: usize) -> Option { let __resolved = pattern.resolve(); let (re, anchored) = __resolved.parts(); // An anchored (`A`) pattern must match starting exactly at `offset`; the `regex` crate cannot @@ -155,15 +143,10 @@ pub fn preg_match2( .filter(|c| c.get(0).map(|m| m.start()) == Some(0)) } else { re.captures_at(subject, offset) - }; + }?; - matches.clear(); - if let Some(caps) = &caps { - let names: Vec> = re.capture_names().collect(); - *matches = single_match_map(caps, &names); - } - - caps.is_some() + let names: Vec> = re.capture_names().collect(); + Some(single_match_map(&caps, &names)) } // PREG_PATTERN_ORDER: the outer vec is indexed by capture group, the inner by @@ -181,11 +164,9 @@ pub fn preg_match_all(pattern: impl PregPattern, subject: &str) -> Vec usize { +// The number of occurrences the caller would get from PHP's return value is the length of any +// one column, `matches[&CaptureKey::ByIndex(0)].len()`. +pub fn preg_match_all2(pattern: impl PregPattern, subject: &str) -> PregMatchesAll { let __resolved = pattern.resolve(); let (re, _anchored) = __resolved.parts(); let group_count = re.captures_len(); @@ -193,16 +174,14 @@ pub fn preg_match_all2( // PREG_PATTERN_ORDER: one column per group, one row per match occurrence. let mut groups: Vec>> = vec![Vec::new(); group_count]; - let mut count = 0; for caps in re.captures_iter(subject) { - count += 1; for (g, column) in groups.iter_mut().enumerate() { let value = caps.get(g).map(|m| m.as_str().to_string()); column.push(value); } } - matches.clear(); + let mut matches = PregMatchesAll::new(); for (g, column) in groups.into_iter().enumerate() { if let Some(Some(name)) = names.get(g) { matches.insert(CaptureKey::ByName((*name).to_string()), column.clone()); @@ -210,7 +189,7 @@ pub fn preg_match_all2( matches.insert(CaptureKey::ByIndex(g), column); } - count + matches } // PREG_SET_ORDER: the outer vec is indexed by match occurrence, the inner by @@ -219,38 +198,32 @@ pub fn preg_match_all2( pub fn preg_match_all_set_order( pattern: impl PregPattern, subject: &str, - matches: &mut Vec>>, -) -> usize { +) -> Vec>> { let __resolved = pattern.resolve(); let (re, _anchored) = __resolved.parts(); - let mut rows: Vec>> = Vec::new(); - for caps in re.captures_iter(subject) { - rows.push( + re.captures_iter(subject) + .map(|caps| { (0..caps.len()) .map(|g| caps.get(g).map(|m| m.as_str().to_string())) - .collect(), - ); - } - let count = rows.len(); - *matches = rows; - count + .collect() + }) + .collect() } -// A non-participating group is reported as None, at offset -1. +// A non-participating group is reported as None, at offset -1. The number of occurrences the +// caller would get from PHP's return value is the length of any one column, +// `matches[&CaptureKey::ByIndex(0)].len()`. pub fn preg_match_all_offset_capture( pattern: impl PregPattern, subject: &str, - matches: &mut PregMatchesAllWithOffsets, -) -> usize { +) -> PregMatchesAllWithOffsets { let __resolved = pattern.resolve(); let (re, _anchored) = __resolved.parts(); let group_count = re.captures_len(); let names: Vec> = re.capture_names().collect(); let mut groups: Vec, i64)>> = vec![Vec::new(); group_count]; - let mut count = 0; for caps in re.captures_iter(subject) { - count += 1; for (g, column) in groups.iter_mut().enumerate() { let entry = match caps.get(g) { Some(m) => (Some(m.as_str().to_string()), m.start() as i64), @@ -260,7 +233,7 @@ pub fn preg_match_all_offset_capture( } } - matches.clear(); + let mut matches = PregMatchesAllWithOffsets::new(); for (g, column) in groups.into_iter().enumerate() { if let Some(Some(name)) = names.get(g) { matches.insert(CaptureKey::ByName((*name).to_string()), column.clone()); @@ -268,7 +241,7 @@ pub fn preg_match_all_offset_capture( matches.insert(CaptureKey::ByIndex(g), column); } - count + matches } pub fn preg_grep>( diff --git a/crates/shirabe-semver/src/version_parser.rs b/crates/shirabe-semver/src/version_parser.rs index d0031f04..56be329f 100644 --- a/crates/shirabe-semver/src/version_parser.rs +++ b/crates/shirabe-semver/src/version_parser.rs @@ -33,8 +33,7 @@ impl VersionParser { let pattern = format!("{{{}(?:\\+.*)?$}}i", MODIFIER_REGEX); let lower = shirabe_php_shim::strtolower(&version); - let mut match_: Vec> = Vec::new(); - preg_match(&pattern, &lower, &mut match_); + let match_ = preg_match(&pattern, &lower).unwrap_or_default(); // match_[3] = the ([.-]?dev)? capture if match_ @@ -86,19 +85,14 @@ impl VersionParser { let mut version = version; // strip off aliasing - let mut match_: Vec> = Vec::new(); - if preg_match( - php_regex!("{^([^,\\s]++) ++as ++([^,\\s]++)$}"), - &version, - &mut match_, - ) { + if let Some(match_) = preg_match(php_regex!("{^([^,\\s]++) ++as ++([^,\\s]++)$}"), &version) + { version = match_[1].clone().unwrap_or_default(); } // strip off stability flag let stab_pattern = format!("{{@(?:{})$}}i", STABILITIES_REGEX); - let mut match_: Vec> = Vec::new(); - if preg_match(&stab_pattern, &version, &mut match_) { + if let Some(match_) = preg_match(&stab_pattern, &version) { let match0_len = match_[0].as_deref().unwrap_or("").len(); version = version[..version.len() - match0_len].to_string(); } @@ -115,12 +109,7 @@ impl VersionParser { } // strip off build metadata - let mut match_: Vec> = Vec::new(); - if preg_match( - php_regex!("{^([^,\\s+]++)\\+[^\\s]++$}"), - &version, - &mut match_, - ) { + if let Some(match_) = preg_match(php_regex!("{^([^,\\s+]++)\\+[^\\s]++$}"), &version) { version = match_[1].clone().unwrap_or_default(); } @@ -137,7 +126,8 @@ impl VersionParser { "{{^v?(\\d{{1,5}})(\\.\\d++)?(\\.\\d++)?(\\.\\d++)?{}$}}i", MODIFIER_REGEX ); - if preg_match(&classical_pattern, &version, &mut matches) { + if let Some(m) = preg_match(&classical_pattern, &version) { + matches = m; let m2 = matches[2].as_deref().unwrap_or(""); let m3 = matches[3].as_deref().unwrap_or(""); let m4 = matches[4].as_deref().unwrap_or(""); @@ -155,7 +145,8 @@ impl VersionParser { "{{^v?(\\d{{4}}(?:[.:-]?\\d{{2}}){{1,6}}(?:[.:-]?\\d{{1,3}}){{0,2}}){}$}}i", MODIFIER_REGEX ); - if preg_match(&datetime_pattern, &version, &mut matches) { + if let Some(m) = preg_match(&datetime_pattern, &version) { + matches = m; version = preg_replace( php_regex!("{\\D}"), ".", @@ -201,8 +192,7 @@ impl VersionParser { } // match dev branches - let mut match_: Vec> = Vec::new(); - if preg_match(php_regex!("{(.*?)[.-]?dev$}i"), &version, &mut match_) { + if let Some(match_) = preg_match(php_regex!("{(.*?)[.-]?dev$}i"), &version) { let branch_name = match_[1].clone().unwrap_or_default(); // a branch ending with -dev is only valid if it is numeric // if it gets prefixed with dev- it means the branch name should @@ -221,8 +211,9 @@ impl VersionParser { STABILITIES_REGEX ), &full_version, - &mut Vec::new(), - ) { + ) + .is_some() + { format!( " in \"{}\", the alias must be an exact version", full_version @@ -234,8 +225,9 @@ impl VersionParser { STABILITIES_REGEX ), &full_version, - &mut Vec::new(), - ) { + ) + .is_some() + { format!( " in \"{}\", the alias source must be an exact version, if it is a branch name \ you should prefix it with dev-", @@ -253,12 +245,10 @@ impl VersionParser { } pub fn parse_numeric_alias_prefix(&self, branch: &str) -> Option { - let mut matches: Vec> = Vec::new(); // matches['version'] == matches[1] ((?P...) is group 1) - if preg_match( + if let Some(matches) = preg_match( php_regex!("{^(?P(\\d++\\.)*\\d++)(?:\\.x)?-dev$}i"), branch, - &mut matches, ) { let version = matches[1].clone().unwrap_or_default(); return Some(format!("{}.", version)); @@ -270,14 +260,12 @@ impl VersionParser { pub fn normalize_branch(&self, name: &str) -> anyhow::Result { let name = shirabe_php_shim::trim(name, None); - let mut matches: Vec> = Vec::new(); // Groups: 1=major, 2=".minor"(outer), 3=minor(inner), 4=".patch"(outer), // 5=patch(inner), 6=".fourth"(outer), 7=fourth(inner). // We use the outer groups [1,2,4,6] to replicate PHP's groups [1,2,3,4]. - if preg_match( + if let Some(matches) = preg_match( php_regex!("{^v?(\\d++)(\\.(\\d++|[xX*]))?(\\.(\\d++|[xX*]))?(\\.(\\d++|[xX*]))?$}i"), &name, - &mut matches, ) { let mut version = String::new(); for i in [1usize, 2, 4, 6] { @@ -349,20 +337,17 @@ impl VersionParser { let mut constraint = constraint.to_string(); // strip off aliasing - let mut match_: Vec> = Vec::new(); - if preg_match( + if let Some(match_) = preg_match( php_regex!("{^([^,\\s]++) ++as ++([^,\\s]++)$}"), &constraint, - &mut match_, ) { constraint = match_[1].clone().unwrap_or_default(); } // strip @stability flags, and keep it for later use let mut stability_modifier: Option = None; - let mut match_: Vec> = Vec::new(); let stab_pattern = format!("{{^([^,\\s]*?)@({})$}}i", STABILITIES_REGEX); - if preg_match(&stab_pattern, &constraint, &mut match_) { + if let Some(match_) = preg_match(&stab_pattern, &constraint) { let m1 = match_[1].as_deref().unwrap_or(""); constraint = if !m1.is_empty() { m1.to_string() @@ -376,21 +361,14 @@ impl VersionParser { } // get rid of #refs as those are used by composer only - let mut match_: Vec> = Vec::new(); - if preg_match( + if let Some(match_) = preg_match( php_regex!("{^(dev-[^,\\s@]+?|[^,\\s@]+?\\.x-dev)#.+$}i"), &constraint, - &mut match_, ) { constraint = match_[1].clone().unwrap_or_default(); } - let mut match_: Vec> = Vec::new(); - if preg_match( - php_regex!("{^(v)?[xX*](\\.[xX*])*$}i"), - &constraint, - &mut match_, - ) { + if let Some(match_) = preg_match(php_regex!("{^(v)?[xX*](\\.[xX*])*$}i"), &constraint) { let m1_nonempty = !match_ .get(1) .and_then(|o| o.as_deref()) @@ -423,9 +401,8 @@ impl VersionParser { // than the previous version, to ensure that unstable instances of the current version are // allowed. However, if a stability suffix is added to the constraint, then a >= match on // the current version is used instead. - let mut matches: Vec> = Vec::new(); let tilde_pattern = format!("{{^~>?{}$}}i", version_regex); - if preg_match(&tilde_pattern, &constraint, &mut matches) { + if let Some(matches) = preg_match(&tilde_pattern, &constraint) { if constraint.starts_with("~>") { anyhow::bail!( "Could not parse version constraint {}: Invalid operator \"~>\", you probably \ @@ -486,9 +463,8 @@ impl VersionParser { // Allows changes that do not modify the left-most non-zero digit in the [major, minor, // patch] tuple. In other words, this allows patch and minor updates for versions 1.0.0 // and above, patch updates for versions 0.X >=0.1.0, and no updates for versions 0.0.X - let mut matches: Vec> = Vec::new(); let caret_pattern = format!("{{^\\^{}($)}}i", version_regex); - if preg_match(&caret_pattern, &constraint, &mut matches) { + if let Some(matches) = preg_match(&caret_pattern, &constraint) { // Work out which position in the version we are operating at let m1 = matches[1].as_deref().unwrap_or(""); let m2 = matches[2].as_deref().unwrap_or(""); @@ -535,11 +511,9 @@ impl VersionParser { // Any of X, x, or * may be used to "stand in" for one of the numeric values in the // [major, minor, patch] tuple. A partial version range is treated as an X-Range, so the // special character is in fact optional. - let mut matches: Vec> = Vec::new(); - if preg_match( + if let Some(matches) = preg_match( php_regex!("{^v?(\\d++)(?:\\.(\\d++))?(?:\\.(\\d++))?(?:\\.[xX*])++$}"), &constraint, - &mut matches, ) { let position = if !matches[3].as_deref().unwrap_or("").is_empty() { 3 @@ -581,12 +555,11 @@ impl VersionParser { // version is provided as the second version in the inclusive range, then all versions // that start with the supplied parts of the tuple are accepted, but nothing that would // be greater than the provided tuple parts. - let mut matches: Vec> = Vec::new(); let hyphen_pattern = format!( "{{^(?P{}) +- +(?P{})($)}}i", version_regex, version_regex ); - if preg_match(&hyphen_pattern, &constraint, &mut matches) { + if let Some(matches) = preg_match(&hyphen_pattern, &constraint) { // matches[1]='from' string, matches[2..9]=from captures, matches[10]='to' string, // matches[11..18]=to captures, matches[19]='($)' // matches[6]=from stability, matches[8]=from dev, matches[9]=from wildcard-dev @@ -651,12 +624,8 @@ impl VersionParser { } // Basic Comparators - let mut match_: Vec> = Vec::new(); - if preg_match( - php_regex!("{^(<>|!=|>=?|<=?|==?)?\\s*(.*)}"), - &constraint, - &mut match_, - ) { + if let Some(match_) = preg_match(php_regex!("{^(<>|!=|>=?|<=?|==?)?\\s*(.*)}"), &constraint) + { let version_str = match_[2].clone().unwrap_or_default(); let op_str = match_[1].clone().unwrap_or_default(); @@ -667,11 +636,7 @@ impl VersionParser { // dev-foobar except if the constraint uses a known operator, in which // case it must be a parse error if version_str.ends_with("-dev") - && preg_match( - php_regex!("{^[0-9a-zA-Z-./]+$}"), - &version_str, - &mut Vec::new(), - ) + && preg_match(php_regex!("{^[0-9a-zA-Z-./]+$}"), &version_str).is_some() { self.normalize( &format!("dev-{}", &version_str[..version_str.len() - 4]), @@ -696,11 +661,12 @@ impl VersionParser { } if op == "<" || op == ">=" { let modifier_pattern = format!("{{-{}$}}", MODIFIER_REGEX); - if !preg_match( + if preg_match( &modifier_pattern, &shirabe_php_shim::strtolower(&version_str), - &mut Vec::new(), - ) && !version_str.starts_with("dev-") + ) + .is_none() + && !version_str.starts_with("dev-") { version = format!("{}-dev", version); } diff --git a/crates/shirabe-symfony-console/src/command/command.rs b/crates/shirabe-symfony-console/src/command/command.rs index b2af47e2..848cece3 100644 --- a/crates/shirabe-symfony-console/src/command/command.rs +++ b/crates/shirabe-symfony-console/src/command/command.rs @@ -108,8 +108,7 @@ impl CommandData { /// /// Throws InvalidArgumentException when the name is invalid. fn validate_name(&self, name: &str) -> anyhow::Result> { - let mut matches: Vec> = Vec::new(); - if !preg_match(php_regex!(r"/^[^\:]++(\:[^\:]++)*$/"), name, &mut matches) { + if preg_match(php_regex!(r"/^[^\:]++(\:[^\:]++)*$/"), name).is_none() { return Ok(Err(InvalidArgumentException::new(format!( "Command name \"{}\" is invalid.", name diff --git a/crates/shirabe-symfony-console/src/formatter/output_formatter.rs b/crates/shirabe-symfony-console/src/formatter/output_formatter.rs index c7c06cf5..1153bc9e 100644 --- a/crates/shirabe-symfony-console/src/formatter/output_formatter.rs +++ b/crates/shirabe-symfony-console/src/formatter/output_formatter.rs @@ -7,8 +7,8 @@ use crate::formatter::output_formatter_style_interface::OutputFormatterStyleInte use crate::formatter::output_formatter_style_stack::OutputFormatterStyleStack; use crate::formatter::wrappable_output_formatter_interface::WrappableOutputFormatterInterface; use shirabe_php_shim::{ - CaptureKey, PregMatchesAllWithOffsets, php_regex, preg_match, preg_match_all, - preg_match_all_offset_capture, preg_match_all_set_order, preg_replace, + CaptureKey, php_regex, preg_match, preg_match_all, preg_match_all_offset_capture, + preg_match_all_set_order, preg_replace, }; use shirabe_symfony_string::b; @@ -109,9 +109,8 @@ impl OutputFormatter { return Ok(Some(style.borrow().clone_box())); } - let mut matches: Vec>> = vec![]; - if preg_match_all_set_order(php_regex!("/([^=]+)=([^;]+)(;|$)/"), string, &mut matches) == 0 - { + let matches = preg_match_all_set_order(php_regex!("/([^=]+)=([^;]+)(;|$)/"), string); + if matches.is_empty() { return Ok(None); } @@ -191,8 +190,7 @@ impl OutputFormatter { prefix = String::new(); } - let mut matches: Vec> = vec![]; - preg_match(php_regex!("~(\\n)$~"), &text, &mut matches); + let matches = preg_match(php_regex!("~(\\n)$~"), &text).unwrap_or_default(); text = format!("{}{}", prefix, self.add_line_breaks(&text, width)); let trailing = matches.get(1).and_then(|m| m.clone()).unwrap_or_default(); text = format!("{}{}", shirabe_php_shim::rtrim(&text, Some("\n")), trailing); @@ -294,11 +292,9 @@ impl WrappableOutputFormatterInterface for OutputFormatter { let open_tag_regex = "[a-z](?:[^\\\\<>]* | \\\\.)*"; let close_tag_regex = "[a-z][^<>]*"; let mut current_line_length: i64 = 0; - let mut matches = PregMatchesAllWithOffsets::new(); - preg_match_all_offset_capture( + let matches = preg_match_all_offset_capture( format!("#<(({open_tag_regex}) | /({close_tag_regex})?)>#ix"), message, - &mut matches, ); let full_matches = matches .get(&CaptureKey::ByIndex(0)) diff --git a/crates/shirabe-symfony-console/src/helper/helper.rs b/crates/shirabe-symfony-console/src/helper/helper.rs index 21f20d34..435648ca 100644 --- a/crates/shirabe-symfony-console/src/helper/helper.rs +++ b/crates/shirabe-symfony-console/src/helper/helper.rs @@ -40,7 +40,7 @@ impl Helper { /// Returns the width of a string, using mb_strwidth if it is available. /// The width is how many characters positions the string will use. pub fn width(string: &str) -> i64 { - if preg_match(php_regex!("//u"), string, &mut Vec::new()) { + if preg_match(php_regex!("//u"), string).is_some() { return UnicodeString::new(string).width(false); } @@ -56,7 +56,7 @@ impl Helper { /// Returns the length of a string, using mb_strlen if it is available. /// The length is related to how many bytes the string will use. pub fn length(string: &str) -> i64 { - if preg_match(php_regex!("//u"), string, &mut Vec::new()) { + if preg_match(php_regex!("//u"), string).is_some() { return UnicodeString::new(string).length(); } diff --git a/crates/shirabe-symfony-console/src/input/argv_input.rs b/crates/shirabe-symfony-console/src/input/argv_input.rs index b2b663a6..81582408 100644 --- a/crates/shirabe-symfony-console/src/input/argv_input.rs +++ b/crates/shirabe-symfony-console/src/input/argv_input.rs @@ -523,8 +523,7 @@ impl std::fmt::Display for ArgvInput { .tokens .iter() .map(|token| { - let mut r#match: Vec> = Vec::new(); - if preg_match(php_regex!("{^(-[^=]+=)(.+)}"), token, &mut r#match) { + if let Some(r#match) = preg_match(php_regex!("{^(-[^=]+=)(.+)}"), token) { return format!( "{}{}", r#match[1].as_deref().unwrap_or(""), diff --git a/crates/shirabe-symfony-console/src/input/input.rs b/crates/shirabe-symfony-console/src/input/input.rs index 89eedb03..4712a713 100644 --- a/crates/shirabe-symfony-console/src/input/input.rs +++ b/crates/shirabe-symfony-console/src/input/input.rs @@ -207,8 +207,7 @@ impl Input { /// Escapes a token through escapeshellarg if it contains unsafe chars. pub fn escape_token(&self, token: &str) -> String { - let mut matches: Vec> = vec![]; - if preg_match(php_regex!("{^[\\w-]+$}"), token, &mut matches) { + if preg_match(php_regex!("{^[\\w-]+$}"), token).is_some() { token.to_string() } else { shirabe_php_shim::escapeshellarg(token) diff --git a/crates/shirabe-symfony-console/src/input/string_input.rs b/crates/shirabe-symfony-console/src/input/string_input.rs index 245b948d..b0c3b159 100644 --- a/crates/shirabe-symfony-console/src/input/string_input.rs +++ b/crates/shirabe-symfony-console/src/input/string_input.rs @@ -6,7 +6,7 @@ use crate::input::InputDefinition; use crate::input::InputInterface; use crate::input::StreamableInputInterface; use indexmap::IndexMap; -use shirabe_php_shim::{CaptureKey, PhpMixed, PregMatches, php_regex, preg_match2}; +use shirabe_php_shim::{CaptureKey, PhpMixed, php_regex, preg_match2}; /// StringInput represents an input provided as a string. /// @@ -57,17 +57,15 @@ impl StringInput { continue; } - let mut m = PregMatches::new(); - if preg_match2(php_regex!(r"/\s+/A"), input, &mut m, cursor as usize) { + if let Some(m) = preg_match2(php_regex!(r"/\s+/A"), input, cursor as usize) { if token.is_some() { tokens.push(token.take().unwrap()); } cursor += shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or("")); - } else if preg_match2( + } else if let Some(m) = preg_match2( format!(r#"/([^="'\s]+?)(=?)({}+)/A"#, Self::REGEX_QUOTED_STRING), input, - &mut m, cursor as usize, ) { let inner = shirabe_php_shim::substr( @@ -86,10 +84,9 @@ impl StringInput { )); cursor += shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or("")); - } else if preg_match2( + } else if let Some(m) = preg_match2( format!(r"/{}/A", Self::REGEX_QUOTED_STRING), input, - &mut m, cursor as usize, ) { token = Some(format!( @@ -103,10 +100,9 @@ impl StringInput { )); cursor += shirabe_php_shim::strlen(m[&CaptureKey::ByIndex(0)].as_deref().unwrap_or("")); - } else if preg_match2( + } else if let Some(m) = preg_match2( format!(r"/{}/A", Self::REGEX_UNQUOTED_STRING), input, - &mut m, cursor as usize, ) { token = Some(format!( diff --git a/crates/shirabe-symfony-console/src/output/stream_output.rs b/crates/shirabe-symfony-console/src/output/stream_output.rs index 43cee3a8..14565012 100644 --- a/crates/shirabe-symfony-console/src/output/stream_output.rs +++ b/crates/shirabe-symfony-console/src/output/stream_output.rs @@ -120,14 +120,13 @@ impl StreamOutput { } // See https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L157 - let mut matches: Vec> = Vec::new(); preg_match( php_regex!( "/^((screen|xterm|vt100|vt220|putty|rxvt|ansi|cygwin|linux).*)|(.*-256(color)?(-bce)?)$/" ), &term, - &mut matches, ) + .is_some() } } diff --git a/crates/shirabe-symfony-console/src/question/choice_question.rs b/crates/shirabe-symfony-console/src/question/choice_question.rs index b8ac16d8..84cba360 100644 --- a/crates/shirabe-symfony-console/src/question/choice_question.rs +++ b/crates/shirabe-symfony-console/src/question/choice_question.rs @@ -122,12 +122,12 @@ impl ChoiceQuestion { let selected_choices: Vec = if multiselect { // Check for a separated comma values - let mut matches: Vec> = Vec::new(); - if !preg_match( + if preg_match( php_regex!("/^[^,]+(?:,[^,]+)*$/"), &shirabe_php_shim::strval(&selected), - &mut matches, - ) { + ) + .is_none() + { return Err(InvalidArgumentException::new(shirabe_php_shim::sprintf( &error_message, std::slice::from_ref(&selected), diff --git a/crates/shirabe-symfony-console/src/question/confirmation_question.rs b/crates/shirabe-symfony-console/src/question/confirmation_question.rs index 6ec9281f..5a18a045 100644 --- a/crates/shirabe-symfony-console/src/question/confirmation_question.rs +++ b/crates/shirabe-symfony-console/src/question/confirmation_question.rs @@ -38,10 +38,7 @@ impl ConfirmationQuestion { return answer; } - let answer_is_true = { - let mut matches: Vec> = Vec::new(); - preg_match(®ex, &shirabe_php_shim::strval(&answer), &mut matches) - }; + let answer_is_true = preg_match(®ex, &shirabe_php_shim::strval(&answer)).is_some(); // false === $default if matches!(default, PhpMixed::Bool(false)) { diff --git a/crates/shirabe-symfony-console/src/terminal.rs b/crates/shirabe-symfony-console/src/terminal.rs index 8ff0431a..8db6fd93 100644 --- a/crates/shirabe-symfony-console/src/terminal.rs +++ b/crates/shirabe-symfony-console/src/terminal.rs @@ -79,12 +79,10 @@ impl Terminal { fn init_dimensions() { if cfg!(windows) { let ansicon = shirabe_php_shim::getenv("ANSICON"); - let mut matches: Vec> = Vec::new(); if let Some(ansicon) = &ansicon - && preg_match( + && let Some(matches) = preg_match( php_regex!("/^(\\d+)x(\\d+)(?: \\((\\d+)x(\\d+)\\))?$/"), &shirabe_php_shim::trim(&ansicon.to_string_lossy(), None), - &mut matches, ) { // extract [w, H] from "wxh (WxH)" @@ -137,12 +135,9 @@ impl Terminal { if stty_string.is_empty() { return; } - let mut matches: Vec> = Vec::new(); - if preg_match( - php_regex!("/rows.(\\d+);.columns.(\\d+);/i"), - &stty_string, - &mut matches, - ) { + if let Some(matches) = + preg_match(php_regex!("/rows.(\\d+);.columns.(\\d+);/i"), &stty_string) + { // extract [w, h] from "rows h; columns w;" WIDTH.with(|w| { w.set(Some(shirabe_php_shim::intval(&PhpMixed::String( @@ -154,11 +149,9 @@ impl Terminal { matches[1].clone().unwrap_or_default(), )))) }); - } else if preg_match( - php_regex!("/;.(\\d+).rows;.(\\d+).columns/i"), - &stty_string, - &mut matches, - ) { + } else if let Some(matches) = + preg_match(php_regex!("/;.(\\d+).rows;.(\\d+).columns/i"), &stty_string) + { // extract [w, h] from "; h rows; w columns" WIDTH.with(|w| { w.set(Some(shirabe_php_shim::intval(&PhpMixed::String( @@ -181,14 +174,10 @@ impl Terminal { let info = Self::read_from_process("mode CON"); let info = info?; - let mut matches: Vec> = Vec::new(); - if !preg_match( + let matches = preg_match( php_regex!("/--------+\\r?\\n.+?(\\d+)\\r?\\n.+?(\\d+)\\r?\\n/"), &info, - &mut matches, - ) { - return None; - } + )?; Some(vec![ shirabe_php_shim::intval(&PhpMixed::String(matches[2].clone().unwrap_or_default())), diff --git a/crates/shirabe-symfony-process/src/process.rs b/crates/shirabe-symfony-process/src/process.rs index 6fea07c8..96853e90 100644 --- a/crates/shirabe-symfony-process/src/process.rs +++ b/crates/shirabe-symfony-process/src/process.rs @@ -1043,11 +1043,7 @@ impl Process { if argument.contains('\0') { argument = argument.replace('\0', "?"); } - if !preg_match( - php_regex!(r#"/[()%!^"<>&|\s\[\]=;*?'$]/"#), - &argument, - &mut Vec::new(), - ) { + if preg_match(php_regex!(r#"/[()%!^"<>&|\s\[\]=;*?'$]/"#), &argument).is_none() { return argument; } argument = preg_replace(php_regex!(r"/(\\+)$/"), "$1$1", &argument); diff --git a/crates/shirabe/src/console/application.rs b/crates/shirabe/src/console/application.rs index 43a2597b..5385f790 100644 --- a/crates/shirabe/src/console/application.rs +++ b/crates/shirabe/src/console/application.rs @@ -1790,13 +1790,8 @@ impl Application { let mut line = String::new(); let mut offset = 0i64; - let mut m = shirabe_php_shim::PregMatches::new(); - while preg_match2( - php_regex!(r"/.{1,10000}/u"), - &utf8_string, - &mut m, - offset as usize, - ) { + while let Some(m) = preg_match2(php_regex!(r"/.{1,10000}/u"), &utf8_string, offset as usize) + { let m0 = m[&shirabe_php_shim::CaptureKey::ByIndex(0)] .as_deref() .unwrap_or(""); -- cgit v1.3.1-4-g156e