use serde::{Deserialize, Serialize};
use crate::range::{ByteRange, RangeError};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PatchOrigin {
TextMode,
FormMode,
RawIsland,
FileRecovery,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SourcePatch {
pub base_revision: u64,
pub range: ByteRange,
pub replacement: String,
pub origin: PatchOrigin,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PatchResult {
pub affected_range: ByteRange,
pub reparse_required: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
pub enum PatchError {
#[error("document revision mismatch: patch base {base}, current {current}")]
DocumentRevisionMismatch { base: u64, current: u64 },
#[error("invalid patch range: {0}")]
InvalidRange(#[from] RangeError),
}
pub fn apply_patch(
text: &mut String,
current_revision: u64,
patch: &SourcePatch,
) -> Result<PatchResult, PatchError> {
if patch.base_revision != current_revision {
return Err(PatchError::DocumentRevisionMismatch {
base: patch.base_revision,
current: current_revision,
});
}
patch.range.validate(text)?;
text.replace_range(patch.range.start..patch.range.end, &patch.replacement);
Ok(PatchResult {
affected_range: ByteRange::new(
patch.range.start,
patch.range.start + patch.replacement.len(),
),
reparse_required: true,
})
}