aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-16 17:58:11 +0900
committernsfisis <nsfisis@gmail.com>2026-08-16 17:58:11 +0900
commit24a4f39bd981768cc299121b506f6bba584cb31d (patch)
tree39c9de717f5ca374e2c4df9b7eaeb0f86b11da0b /crates
parent224d3e8262ed6156ea3374fe91dfb5b66d6f0d3a (diff)
downloadphp-shirabe-24a4f39bd981768cc299121b506f6bba584cb31d.tar.gz
php-shirabe-24a4f39bd981768cc299121b506f6bba584cb31d.tar.zst
php-shirabe-24a4f39bd981768cc299121b506f6bba584cb31d.zip
refactor(preg): merge preg_replace_callback2 into preg_replace_callback
preg_replace_callback2 had one caller, Preg::replace_callback6, which was itself reached only from Preg::replace_callback with the default limit, count and flags. Fold the two shim functions into one and drop those parameters along with replace_callback6. The surviving callback takes callback2's IndexMap of matches: it can be keyed by group name, and it omits trailing non-participating groups the way PHP does, which is what the callbacks in Process and ProgressBar test for.
Diffstat (limited to 'crates')
-rw-r--r--crates/shirabe-pcre/src/preg.rs18
-rw-r--r--crates/shirabe-php-shim/src/preg.rs56
-rw-r--r--crates/shirabe-symfony-console/src/helper/progress_bar.rs9
-rw-r--r--crates/shirabe-symfony-process/src/process.rs16
4 files changed, 26 insertions, 73 deletions
diff --git a/crates/shirabe-pcre/src/preg.rs b/crates/shirabe-pcre/src/preg.rs
index 06586d2c..1c6fbfc1 100644
--- a/crates/shirabe-pcre/src/preg.rs
+++ b/crates/shirabe-pcre/src/preg.rs
@@ -156,25 +156,15 @@ impl Preg {
pub fn replace_callback<F: FnMut(&IndexMap<CaptureKey, String>) -> String>(
pattern: impl PregPattern,
- replacement: F,
- subject: &str,
- ) -> String {
- Self::replace_callback6(pattern, replacement, subject, -1, None, 0)
- }
-
- pub fn replace_callback6<F: FnMut(&IndexMap<CaptureKey, String>) -> String>(
- pattern: impl PregPattern,
mut replacement: F,
subject: &str,
- limit: i64,
- count: Option<&mut usize>,
- flags: i64,
) -> String {
- let adapter = |internal: &IndexMap<CaptureKey, Option<String>>| -> String {
- replacement(&drop_null_matches_ref(internal))
+ let adapter = |internal: &IndexMap<CaptureKey, Option<String>>| {
+ Ok(replacement(&drop_null_matches_ref(internal)))
};
- shirabe_php_shim::preg_replace_callback2(pattern, adapter, subject, limit, count, flags)
+ shirabe_php_shim::preg_replace_callback(pattern, adapter, subject)
+ .expect("$replacement cannot fail")
}
pub fn split(pattern: impl PregPattern, subject: &str) -> Vec<String> {
diff --git a/crates/shirabe-php-shim/src/preg.rs b/crates/shirabe-php-shim/src/preg.rs
index b0828667..56801ca9 100644
--- a/crates/shirabe-php-shim/src/preg.rs
+++ b/crates/shirabe-php-shim/src/preg.rs
@@ -154,23 +154,23 @@ pub fn preg_replace_callback<F>(
subject: &str,
) -> anyhow::Result<String>
where
- F: FnMut(&[Option<String>]) -> anyhow::Result<String>,
+ F: FnMut(&indexmap::IndexMap<CaptureKey, Option<String>>) -> anyhow::Result<String>,
{
let __resolved = pattern.resolve();
let (re, _anchored) = __resolved.parts();
+ let names: Vec<Option<&str>> = re.capture_names().collect();
+
let mut out: Vec<u8> = Vec::new();
- let mut last = 0;
+ let mut last = 0usize;
for caps in re.captures_iter(subject) {
let m = caps.get(0).unwrap();
out.extend_from_slice(&subject.as_bytes()[last..m.start()]);
- let groups: Vec<Option<String>> = (0..caps.len())
- .map(|g| caps.get(g).map(|x| x.as_str().to_string()))
- .collect();
- let replaced = callback(&groups)?;
- out.extend_from_slice(replaced.as_bytes());
+ let map = single_match_map(&caps, &names, false);
+ out.extend_from_slice(callback(&map)?.as_bytes());
last = m.end();
}
out.extend_from_slice(&subject.as_bytes()[last..]);
+
Ok(String::from_utf8_lossy(&out).into_owned())
}
@@ -318,48 +318,6 @@ pub fn preg_replace2(
String::from_utf8_lossy(&out).into_owned()
}
-pub fn preg_replace_callback2<
- F: FnMut(&indexmap::IndexMap<CaptureKey, Option<String>>) -> String,
->(
- pattern: impl PregPattern,
- mut callback: F,
- subject: &str,
- limit: i64,
- count: Option<&mut usize>,
- flags: i64,
-) -> String {
- let __resolved = pattern.resolve();
- let (re, _anchored) = __resolved.parts();
- let unmatched_as_null = flags & PREG_UNMATCHED_AS_NULL != 0;
- let names: Vec<Option<&str>> = re.capture_names().collect();
- let limit = if limit < 0 {
- usize::MAX
- } else {
- limit as usize
- };
-
- let mut out: Vec<u8> = Vec::new();
- let mut last = 0usize;
- let mut n = 0usize;
- for caps in re.captures_iter(subject) {
- if n >= limit {
- break;
- }
- let m = caps.get(0).unwrap();
- out.extend_from_slice(&subject.as_bytes()[last..m.start()]);
- let map = single_match_map(&caps, &names, unmatched_as_null);
- out.extend_from_slice(callback(&map).as_bytes());
- last = m.end();
- n += 1;
- }
- out.extend_from_slice(&subject.as_bytes()[last..]);
-
- if let Some(count) = count {
- *count = n;
- }
- String::from_utf8_lossy(&out).into_owned()
-}
-
pub fn preg_split2(
pattern: impl PregPattern,
subject: &str,
diff --git a/crates/shirabe-symfony-console/src/helper/progress_bar.rs b/crates/shirabe-symfony-console/src/helper/progress_bar.rs
index b0124419..dea1c3ad 100644
--- a/crates/shirabe-symfony-console/src/helper/progress_bar.rs
+++ b/crates/shirabe-symfony-console/src/helper/progress_bar.rs
@@ -9,6 +9,7 @@ use crate::output::OutputInterface;
use crate::output::output_interface;
use crate::terminal::Terminal;
use indexmap::IndexMap;
+use shirabe_php_shim::CaptureKey;
pub const FORMAT_VERBOSE: &str = "verbose";
pub const FORMAT_VERY_VERBOSE: &str = "very_verbose";
@@ -797,8 +798,8 @@ impl ProgressBar {
let format = self.format.clone().unwrap_or_default();
// $callback in PHP, expressed as a closure over $this and the matches.
- let callback = |matches: &[Option<String>]| -> anyhow::Result<String> {
- let name = matches[1].clone().unwrap_or_default();
+ let callback = |matches: &IndexMap<CaptureKey, Option<String>>| -> anyhow::Result<String> {
+ let name = matches[&CaptureKey::ByIndex(1)].clone().unwrap_or_default();
let text: shirabe_php_shim::PhpMixed =
if Self::get_placeholder_formatter_definition(&name).is_some() {
@@ -812,10 +813,10 @@ impl ProgressBar {
} else if let Some(message) = self.messages.get(&name) {
shirabe_php_shim::PhpMixed::String(message.clone())
} else {
- return Ok(matches[0].clone().unwrap_or_default());
+ return Ok(matches[&CaptureKey::ByIndex(0)].clone().unwrap_or_default());
};
- if let Some(modifier) = matches.get(2).and_then(|m| m.clone()) {
+ if let Some(modifier) = matches.get(&CaptureKey::ByIndex(2)).and_then(|m| m.clone()) {
return Ok(shirabe_php_shim::sprintf(&format!("%{modifier}"), &[text]));
}
diff --git a/crates/shirabe-symfony-process/src/process.rs b/crates/shirabe-symfony-process/src/process.rs
index 87c6c68d..556238cf 100644
--- a/crates/shirabe-symfony-process/src/process.rs
+++ b/crates/shirabe-symfony-process/src/process.rs
@@ -11,7 +11,7 @@ use crate::pipes::unix_pipes::UnixPipes;
use crate::pipes::windows_pipes::WindowsPipes;
use crate::process_utils::ProcessUtils;
use indexmap::IndexMap;
-use shirabe_php_shim::{Descriptor, PhpMixed, PhpResource, php_regex};
+use shirabe_php_shim::{CaptureKey, Descriptor, PhpMixed, PhpResource, php_regex};
use std::sync::OnceLock;
/// A user-supplied callback invoked with the output type ("out"/"err") and a chunk of output.
@@ -935,9 +935,9 @@ impl Process {
)++
) | [^"]*+ )"/x"#
),
- |m: &[Option<String>]| -> anyhow::Result<String> {
- let m0 = m.first().cloned().flatten().unwrap_or_default();
- let m1 = m.get(1).cloned().flatten();
+ |m: &IndexMap<CaptureKey, Option<String>>| -> anyhow::Result<String> {
+ let m0 = m[&CaptureKey::ByIndex(0)].clone().unwrap_or_default();
+ let m1 = m.get(&CaptureKey::ByIndex(1)).cloned().flatten();
if m1.is_none() {
return Ok(m0);
}
@@ -1073,8 +1073,12 @@ impl Process {
) -> anyhow::Result<String> {
shirabe_php_shim::preg_replace_callback(
php_regex!(r#"/"\$\{:([_a-zA-Z]+[_a-zA-Z0-9]*)\}"/"#),
- |matches: &[Option<String>]| -> anyhow::Result<String> {
- let key = matches.get(1).cloned().flatten().unwrap_or_default();
+ |matches: &IndexMap<CaptureKey, Option<String>>| -> anyhow::Result<String> {
+ let key = matches
+ .get(&CaptureKey::ByIndex(1))
+ .cloned()
+ .flatten()
+ .unwrap_or_default();
match env.get(&key) {
None => Err(InvalidArgumentException::new(format!(
"Command line is missing a value for parameter \"{}\": {}",