mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-26 02:51:57 +03:00
check size when applying operations
This commit is contained in:
parent
887b676acb
commit
f78d5b104f
@ -1,3 +1,4 @@
|
|||||||
|
use anyhow::Result;
|
||||||
use difference::{Changeset, Difference};
|
use difference::{Changeset, Difference};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -11,13 +12,40 @@ pub enum Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
pub fn apply(&self, text: &mut Vec<char>) {
|
pub fn apply(&self, text: &mut Vec<char>) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Operation::Insert((index, chunk)) => {
|
Operation::Insert((index, chunk)) => {
|
||||||
text.splice(*index as usize..*index as usize, chunk.chars());
|
if *index as usize > text.len() {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Index out of bounds, {} > {}",
|
||||||
|
index,
|
||||||
|
text.len()
|
||||||
|
))
|
||||||
|
} else if *index as usize == text.len() {
|
||||||
|
text.extend(chunk.chars());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
text.splice(*index as usize..*index as usize, chunk.chars());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Operation::Delete((index, len)) => {
|
Operation::Delete((index, len)) => {
|
||||||
text.splice(*index as usize..(*index + *len) as usize, "".chars());
|
if *index as usize > text.len() {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Index out of bounds, {} > {}",
|
||||||
|
index,
|
||||||
|
text.len()
|
||||||
|
))
|
||||||
|
} else if *index as usize + *len as usize > text.len() {
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Index + length out of bounds, {} > {}",
|
||||||
|
index + len,
|
||||||
|
text.len()
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
text.splice(*index as usize..(*index + *len) as usize, "".chars());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::time::SystemTime;
|
|
||||||
|
|
||||||
use super::{deltas, operations};
|
use super::{deltas, operations};
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::time::SystemTime;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct TextDocument {
|
pub struct TextDocument {
|
||||||
@ -8,20 +8,21 @@ pub struct TextDocument {
|
|||||||
deltas: Vec<deltas::Delta>,
|
deltas: Vec<deltas::Delta>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_deltas(doc: &mut Vec<char>, deltas: &Vec<deltas::Delta>) {
|
fn apply_deltas(doc: &mut Vec<char>, deltas: &Vec<deltas::Delta>) -> Result<()> {
|
||||||
for delta in deltas {
|
for delta in deltas {
|
||||||
for operation in &delta.operations {
|
for operation in &delta.operations {
|
||||||
operation.apply(doc);
|
operation.apply(doc)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextDocument {
|
impl TextDocument {
|
||||||
// creates a new text document from a deltas.
|
// creates a new text document from a deltas.
|
||||||
pub fn from_deltas(deltas: Vec<deltas::Delta>) -> TextDocument {
|
pub fn from_deltas(deltas: Vec<deltas::Delta>) -> Result<TextDocument> {
|
||||||
let mut doc = vec![];
|
let mut doc = vec![];
|
||||||
apply_deltas(&mut doc, &deltas);
|
apply_deltas(&mut doc, &deltas)?;
|
||||||
TextDocument { doc, deltas }
|
Ok(TextDocument { doc, deltas })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_deltas(&self) -> Vec<deltas::Delta> {
|
pub fn get_deltas(&self) -> Vec<deltas::Delta> {
|
||||||
@ -29,18 +30,18 @@ impl TextDocument {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns a text document where internal state is seeded with value, and deltas are applied.
|
// returns a text document where internal state is seeded with value, and deltas are applied.
|
||||||
pub fn new(value: &str, deltas: Vec<deltas::Delta>) -> TextDocument {
|
pub fn new(value: &str, deltas: Vec<deltas::Delta>) -> Result<TextDocument> {
|
||||||
let mut all_deltas = vec![deltas::Delta {
|
let mut all_deltas = vec![deltas::Delta {
|
||||||
operations: operations::get_delta_operations("", value),
|
operations: operations::get_delta_operations("", value),
|
||||||
timestamp_ms: 0,
|
timestamp_ms: 0,
|
||||||
}];
|
}];
|
||||||
all_deltas.append(&mut deltas.clone());
|
all_deltas.append(&mut deltas.clone());
|
||||||
let mut doc = vec![];
|
let mut doc = vec![];
|
||||||
apply_deltas(&mut doc, &all_deltas);
|
apply_deltas(&mut doc, &all_deltas)?;
|
||||||
TextDocument { doc, deltas }
|
Ok(TextDocument { doc, deltas })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, value: &str) -> bool {
|
pub fn update(&mut self, value: &str) -> Result<bool> {
|
||||||
let diffs = operations::get_delta_operations(&self.to_string(), value);
|
let diffs = operations::get_delta_operations(&self.to_string(), value);
|
||||||
let event = deltas::Delta {
|
let event = deltas::Delta {
|
||||||
operations: diffs,
|
operations: diffs,
|
||||||
@ -50,11 +51,11 @@ impl TextDocument {
|
|||||||
.as_millis(),
|
.as_millis(),
|
||||||
};
|
};
|
||||||
if event.operations.len() == 0 {
|
if event.operations.len() == 0 {
|
||||||
return false;
|
return Ok(false);
|
||||||
}
|
}
|
||||||
apply_deltas(&mut self.doc, &vec![event.clone()]);
|
apply_deltas(&mut self.doc, &vec![event.clone()])?;
|
||||||
self.deltas.push(event);
|
self.deltas.push(event);
|
||||||
return true;
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
|
@ -3,14 +3,18 @@ use crate::deltas::{operations::Operation, text_document::TextDocument, Delta};
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_new() {
|
fn test_new() {
|
||||||
let document = TextDocument::new("hello world", vec![]);
|
let document = TextDocument::new("hello world", vec![]);
|
||||||
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let document = document.unwrap();
|
||||||
assert_eq!(document.to_string(), "hello world");
|
assert_eq!(document.to_string(), "hello world");
|
||||||
assert_eq!(document.get_deltas().len(), 0);
|
assert_eq!(document.get_deltas().len(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update() {
|
fn test_update() {
|
||||||
let mut document = TextDocument::new("hello world", vec![]);
|
let document = TextDocument::new("hello world", vec![]);
|
||||||
document.update("hello world!");
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let mut document = document.unwrap();
|
||||||
|
document.update("hello world!").unwrap();
|
||||||
assert_eq!(document.to_string(), "hello world!");
|
assert_eq!(document.to_string(), "hello world!");
|
||||||
assert_eq!(document.get_deltas().len(), 1);
|
assert_eq!(document.get_deltas().len(), 1);
|
||||||
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
||||||
@ -22,8 +26,10 @@ fn test_update() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty() {
|
fn test_empty() {
|
||||||
let mut document = TextDocument::from_deltas(vec![]);
|
let document = TextDocument::from_deltas(vec![]);
|
||||||
document.update("hello world!");
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let mut document = document.unwrap();
|
||||||
|
document.update("hello world!").unwrap();
|
||||||
assert_eq!(document.to_string(), "hello world!");
|
assert_eq!(document.to_string(), "hello world!");
|
||||||
assert_eq!(document.get_deltas().len(), 1);
|
assert_eq!(document.get_deltas().len(), 1);
|
||||||
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
||||||
@ -52,14 +58,18 @@ fn test_from_deltas() {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let document = document.unwrap();
|
||||||
assert_eq!(document.to_string(), "held!");
|
assert_eq!(document.to_string(), "held!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_complex_line() {
|
fn test_complex_line() {
|
||||||
let mut document = TextDocument::from_deltas(vec![]);
|
let document = TextDocument::from_deltas(vec![]);
|
||||||
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let mut document = document.unwrap();
|
||||||
|
|
||||||
document.update("hello");
|
document.update("hello").unwrap();
|
||||||
assert_eq!(document.to_string(), "hello");
|
assert_eq!(document.to_string(), "hello");
|
||||||
assert_eq!(document.get_deltas().len(), 1);
|
assert_eq!(document.get_deltas().len(), 1);
|
||||||
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
||||||
@ -68,7 +78,7 @@ fn test_complex_line() {
|
|||||||
Operation::Insert((0, "hello".to_string()))
|
Operation::Insert((0, "hello".to_string()))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("hello world");
|
document.update("hello world").unwrap();
|
||||||
assert_eq!(document.to_string(), "hello world");
|
assert_eq!(document.to_string(), "hello world");
|
||||||
assert_eq!(document.get_deltas().len(), 2);
|
assert_eq!(document.get_deltas().len(), 2);
|
||||||
assert_eq!(document.get_deltas()[1].operations.len(), 1);
|
assert_eq!(document.get_deltas()[1].operations.len(), 1);
|
||||||
@ -77,7 +87,7 @@ fn test_complex_line() {
|
|||||||
Operation::Insert((5, " world".to_string()))
|
Operation::Insert((5, " world".to_string()))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("held!");
|
document.update("held!").unwrap();
|
||||||
assert_eq!(document.to_string(), "held!");
|
assert_eq!(document.to_string(), "held!");
|
||||||
assert_eq!(document.get_deltas().len(), 3);
|
assert_eq!(document.get_deltas().len(), 3);
|
||||||
assert_eq!(document.get_deltas()[2].operations.len(), 2);
|
assert_eq!(document.get_deltas()[2].operations.len(), 2);
|
||||||
@ -93,9 +103,11 @@ fn test_complex_line() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiline_add() {
|
fn test_multiline_add() {
|
||||||
let mut document = TextDocument::from_deltas(vec![]);
|
let document = TextDocument::from_deltas(vec![]);
|
||||||
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let mut document = document.unwrap();
|
||||||
|
|
||||||
document.update("first");
|
document.update("first").unwrap();
|
||||||
assert_eq!(document.to_string(), "first");
|
assert_eq!(document.to_string(), "first");
|
||||||
assert_eq!(document.get_deltas().len(), 1);
|
assert_eq!(document.get_deltas().len(), 1);
|
||||||
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
||||||
@ -104,7 +116,7 @@ fn test_multiline_add() {
|
|||||||
Operation::Insert((0, "first".to_string()))
|
Operation::Insert((0, "first".to_string()))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("first\ntwo");
|
document.update("first\ntwo").unwrap();
|
||||||
assert_eq!(document.to_string(), "first\ntwo");
|
assert_eq!(document.to_string(), "first\ntwo");
|
||||||
assert_eq!(document.get_deltas().len(), 2);
|
assert_eq!(document.get_deltas().len(), 2);
|
||||||
assert_eq!(document.get_deltas()[1].operations.len(), 1);
|
assert_eq!(document.get_deltas()[1].operations.len(), 1);
|
||||||
@ -113,7 +125,7 @@ fn test_multiline_add() {
|
|||||||
Operation::Insert((5, "\ntwo".to_string()))
|
Operation::Insert((5, "\ntwo".to_string()))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("first line\nline two");
|
document.update("first line\nline two").unwrap();
|
||||||
assert_eq!(document.to_string(), "first line\nline two");
|
assert_eq!(document.to_string(), "first line\nline two");
|
||||||
assert_eq!(document.get_deltas().len(), 3);
|
assert_eq!(document.get_deltas().len(), 3);
|
||||||
assert_eq!(document.get_deltas()[2].operations.len(), 2);
|
assert_eq!(document.get_deltas()[2].operations.len(), 2);
|
||||||
@ -129,9 +141,11 @@ fn test_multiline_add() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_multiline_remove() {
|
fn test_multiline_remove() {
|
||||||
let mut document = TextDocument::from_deltas(vec![]);
|
let document = TextDocument::from_deltas(vec![]);
|
||||||
|
assert_eq!(document.is_ok(), true);
|
||||||
|
let mut document = document.unwrap();
|
||||||
|
|
||||||
document.update("first line\nline two");
|
document.update("first line\nline two").unwrap();
|
||||||
assert_eq!(document.to_string(), "first line\nline two");
|
assert_eq!(document.to_string(), "first line\nline two");
|
||||||
assert_eq!(document.get_deltas().len(), 1);
|
assert_eq!(document.get_deltas().len(), 1);
|
||||||
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
assert_eq!(document.get_deltas()[0].operations.len(), 1);
|
||||||
@ -140,7 +154,7 @@ fn test_multiline_remove() {
|
|||||||
Operation::Insert((0, "first line\nline two".to_string()))
|
Operation::Insert((0, "first line\nline two".to_string()))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("first\ntwo");
|
document.update("first\ntwo").unwrap();
|
||||||
assert_eq!(document.to_string(), "first\ntwo");
|
assert_eq!(document.to_string(), "first\ntwo");
|
||||||
assert_eq!(document.get_deltas().len(), 2);
|
assert_eq!(document.get_deltas().len(), 2);
|
||||||
assert_eq!(document.get_deltas()[1].operations.len(), 2);
|
assert_eq!(document.get_deltas()[1].operations.len(), 2);
|
||||||
@ -153,7 +167,7 @@ fn test_multiline_remove() {
|
|||||||
Operation::Delete((6, 5))
|
Operation::Delete((6, 5))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("first");
|
document.update("first").unwrap();
|
||||||
assert_eq!(document.to_string(), "first");
|
assert_eq!(document.to_string(), "first");
|
||||||
assert_eq!(document.get_deltas().len(), 3);
|
assert_eq!(document.get_deltas().len(), 3);
|
||||||
assert_eq!(document.get_deltas()[2].operations.len(), 1);
|
assert_eq!(document.get_deltas()[2].operations.len(), 1);
|
||||||
@ -162,7 +176,7 @@ fn test_multiline_remove() {
|
|||||||
Operation::Delete((5, 4))
|
Operation::Delete((5, 4))
|
||||||
);
|
);
|
||||||
|
|
||||||
document.update("");
|
document.update("").unwrap();
|
||||||
assert_eq!(document.to_string(), "");
|
assert_eq!(document.to_string(), "");
|
||||||
assert_eq!(document.get_deltas().len(), 4);
|
assert_eq!(document.get_deltas().len(), 4);
|
||||||
assert_eq!(document.get_deltas()[3].operations.len(), 1);
|
assert_eq!(document.get_deltas()[3].operations.len(), 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user