use std::path::{Component, Path, PathBuf};
use similar::TextDiff;
#[cfg(feature = "script")]
use crate::error::Result;
use crate::pattern::CompiledPattern;
#[cfg(feature = "script")]
use crate::script::ScriptRewriter;
#[derive(Debug, Clone)]
pub struct RewriteOutcome {
pub before: String,
pub after: String,
pub matches: usize,
}
impl RewriteOutcome {
pub fn changed(&self) -> bool {
self.before != self.after
}
}
pub fn rewrite_text(pattern: &CompiledPattern, before: &str) -> RewriteOutcome {
let matches = pattern.regex().find_iter(before).count();
let after = pattern.regex().replace_all(before, pattern.replacement()).into_owned();
RewriteOutcome { before: before.to_owned(), after, matches }
}
#[cfg(feature = "script")]
pub fn rewrite_text_scripted(
pattern: &CompiledPattern,
script: &ScriptRewriter,
before: &str,
) -> Result<RewriteOutcome> {
use std::cell::RefCell;
let regex = pattern.regex();
let matches = regex.find_iter(before).count();
let err_slot: RefCell<Option<crate::error::Error>> = RefCell::new(None);
let after = regex.replace_all(before, |caps: ®ex::Captures<'_>| {
if err_slot.borrow().is_some() {
return String::new();
}
let caps_vec: Vec<&str> =
caps.iter().map(|m| m.map(|m| m.as_str()).unwrap_or("")).collect();
match script.replace(&caps_vec) {
Ok(s) => s,
Err(e) => {
*err_slot.borrow_mut() = Some(e);
String::new()
}
}
});
if let Some(e) = err_slot.into_inner() {
return Err(e);
}
Ok(RewriteOutcome { before: before.to_owned(), after: after.into_owned(), matches })
}
pub fn label_for_path(path: &Path) -> String {
let mut buf = PathBuf::new();
let mut leading = true;
for c in path.components() {
if leading && matches!(c, Component::CurDir) {
continue;
}
leading = false;
buf.push(c.as_os_str());
}
if buf.as_os_str().is_empty() {
".".to_owned()
} else {
buf.to_string_lossy().replace('\\', "/")
}
}
pub fn unified_diff(label: &str, before: &str, after: &str) -> String {
let diff = TextDiff::from_lines(before, after);
let mut out = diff
.unified_diff()
.context_radius(3)
.header(&format!("a/{label}"), &format!("b/{label}"))
.to_string();
if !out.ends_with('\n') {
out.push('\n');
}
out
}
#[cfg(test)]
#[path = "rewrite_tests.rs"]
mod tests;