use crate::{replace_data::ReplaceData, ErrorKind};
use regex::{Regex, RegexBuilder};
use std::borrow::Cow;
pub struct ReplaceCommand<'a> {
expr: Regex,
with: Cow<'a, str>,
is_global: bool,
}
impl<'a> ReplaceCommand<'a> {
pub fn new(command: &'a str) -> Result<Self, ErrorKind> {
ReplaceData::new(command).and_then(ReplaceCommand::from_replace_data)
}
pub fn execute<'b>(&self, text: impl Into<Cow<'b, str>>) -> Cow<'b, str> {
let text = text.into();
if self.is_global {
regex_cow(text, &self.expr, Regex::replace_all, self.with.as_ref())
} else {
regex_cow(text, &self.expr, Regex::replace, self.with.as_ref())
}
}
pub(crate) fn from_replace_data(data: ReplaceData<'a>) -> Result<Self, ErrorKind> {
let mut builder = RegexBuilder::new(&data.pattern);
data.flags.apply(&mut builder);
let regex = builder.build().map_err(ErrorKind::RegexError)?;
Ok(ReplaceCommand {
expr: regex,
with: data.with,
is_global: data.flags.is_global(),
})
}
}
fn regex_cow<'a, R, F>(s: Cow<'a, str>, re: &Regex, f: F, rep: R) -> Cow<'a, str>
where
for<'r, 't> F: FnOnce(&'r Regex, &'t str, R) -> Cow<'t, str>,
R: regex::Replacer,
{
match s {
Cow::Borrowed(b) => f(re, b, rep),
Cow::Owned(o) => Cow::Owned(f(re, &o, rep).into_owned()),
}
}