use std::error::Error;
use std::fmt;
use log::{debug, info};
use unescape::unescape;
use variables::{VariableExpressionError, inject_variables};
use super::{Action, ActionError};
use crate::scoping::scope::ScopeContext;
pub mod variables;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Replacement(String);
impl TryFrom<String> for Replacement {
type Error = ReplacementError;
fn try_from(replacement: String) -> Result<Self, Self::Error> {
let unescaped =
unescape(&replacement).ok_or(ReplacementError::InvalidEscapeSequences(replacement))?;
Ok(Self(unescaped))
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ReplacementError {
InvalidEscapeSequences(String),
VariableError(VariableExpressionError),
}
impl fmt::Display for ReplacementError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidEscapeSequences(replacement) => {
write!(f, "Contains invalid escape sequences: '{replacement}'")
}
Self::VariableError(err) => {
write!(f, "Error in variable expressions: {err}")
}
}
}
}
impl Error for ReplacementError {}
impl From<VariableExpressionError> for ReplacementError {
fn from(value: VariableExpressionError) -> Self {
Self::VariableError(value)
}
}
impl Action for Replacement {
fn act(&self, input: &str) -> String {
info!("Substituting '{}' with '{}'", input, self.0);
info!("This substitution is verbatim and does not take into account variables");
self.0.clone()
}
fn act_with_context(
&self,
_input: &str,
context: &ScopeContext<'_>,
) -> Result<String, ActionError> {
match context {
ScopeContext::CaptureGroups(cgs) => {
debug!("Available capture group variables: {cgs:?}");
Ok(inject_variables(self.0.as_str(), cgs)?)
}
}
}
}
impl From<VariableExpressionError> for ActionError {
fn from(value: VariableExpressionError) -> Self {
Self::ReplacementError(value.into())
}
}
impl From<ReplacementError> for ActionError {
fn from(value: ReplacementError) -> Self {
Self::ReplacementError(value)
}
}