bekoedit_markdown/
patch.rs1use serde::{Deserialize, Serialize};
9
10use crate::range::{ByteRange, RangeError};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14pub enum PatchOrigin {
15 TextMode,
16 FormMode,
17 RawIsland,
18 FileRecovery,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23pub struct SourcePatch {
24 pub base_revision: u64,
26 pub range: ByteRange,
27 pub replacement: String,
28 pub origin: PatchOrigin,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct PatchResult {
34 pub affected_range: ByteRange,
36 pub reparse_required: bool,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
42pub enum PatchError {
43 #[error("document revision mismatch: patch base {base}, current {current}")]
44 DocumentRevisionMismatch { base: u64, current: u64 },
45 #[error("invalid patch range: {0}")]
46 InvalidRange(#[from] RangeError),
47}
48
49pub fn apply_patch(
53 text: &mut String,
54 current_revision: u64,
55 patch: &SourcePatch,
56) -> Result<PatchResult, PatchError> {
57 if patch.base_revision != current_revision {
58 return Err(PatchError::DocumentRevisionMismatch {
59 base: patch.base_revision,
60 current: current_revision,
61 });
62 }
63 patch.range.validate(text)?;
64 text.replace_range(patch.range.start..patch.range.end, &patch.replacement);
65 Ok(PatchResult {
66 affected_range: ByteRange::new(
67 patch.range.start,
68 patch.range.start + patch.replacement.len(),
69 ),
70 reparse_required: true,
71 })
72}