use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ChangeKind {
Insert,
Delete,
Replace,
Equal,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ChangeSpan {
pub kind: ChangeKind,
pub text: String,
pub new_text: Option<String>,
pub old_line: Option<usize>,
pub new_line: Option<usize>,
}
impl ChangeSpan {
pub fn new(kind: ChangeKind, text: impl Into<String>) -> Self {
Self {
kind,
text: text.into(),
new_text: None,
old_line: None,
new_line: None,
}
}
pub fn insert(text: impl Into<String>) -> Self {
Self::new(ChangeKind::Insert, text)
}
pub fn delete(text: impl Into<String>) -> Self {
Self::new(ChangeKind::Delete, text)
}
pub fn equal(text: impl Into<String>) -> Self {
Self::new(ChangeKind::Equal, text)
}
pub fn replace(old: impl Into<String>, new: impl Into<String>) -> Self {
Self {
kind: ChangeKind::Replace,
text: old.into(),
new_text: Some(new.into()),
old_line: None,
new_line: None,
}
}
pub fn with_lines(mut self, old_line: Option<usize>, new_line: Option<usize>) -> Self {
self.old_line = old_line;
self.new_line = new_line;
self
}
pub fn is_change(&self) -> bool {
self.kind != ChangeKind::Equal
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Change {
pub id: usize,
pub spans: Vec<ChangeSpan>,
pub description: Option<String>,
}
impl Change {
pub fn new(id: usize, spans: Vec<ChangeSpan>) -> Self {
Self {
id,
spans,
description: None,
}
}
pub fn single(id: usize, span: ChangeSpan) -> Self {
Self::new(id, vec![span])
}
pub fn with_description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn changes(&self) -> impl Iterator<Item = &ChangeSpan> {
self.spans.iter().filter(|s| s.is_change())
}
pub fn has_changes(&self) -> bool {
self.spans.iter().any(|s| s.is_change())
}
}