feat: moved TextChange into api, added from diff

This commit is contained in:
əlemi 2023-11-17 05:45:31 +01:00
parent 5208ff65c0
commit 2ccb5c936b
6 changed files with 66 additions and 19 deletions

56
src/api/change.rs Normal file
View file

@ -0,0 +1,56 @@
//! # TextChange
//! this represent a range in the previous state of the string and a new content which should be
//! replaced to it, allowing to represent any combination of deletions, insertions or replacements
//!
//! bulk and widespread operations will result in a TextChange effectively sending the whole new
//! buffer, but small changes are efficient and easy to create or apply
//!
//! ### examples
//! to insert 'a' after 4th character we should send a
//! `TextChange { span: 4..4, content: "a".into() }`
//!
//! to delete a the fourth character we should send a
//! `TextChange { span: 3..4, content: "".into() }`
//!
/// an editor-friendly representation of a text change in a buffer
/// span refers to previous text content
#[derive(Clone, Debug, Default)]
pub struct TextChange {
/// range of text change, as char indexes in buffer previous state
pub span: std::ops::Range<usize>,
/// new content of text inside span
pub content: String,
}
impl TextChange {
/// create a new TextChange from the difference of given strings
pub fn from_diff(before: &str, after: &str) -> TextChange {
let diff = similar::TextDiff::from_chars(before, after);
let mut start = 0;
let mut end = 0;
let mut from_beginning = true;
for op in diff.ops() {
match op {
similar::DiffOp::Equal { .. } => {
if from_beginning {
start += 1
} else {
end += 1
}
},
_ => {
end = 0;
from_beginning = false;
}
}
}
let end_before = before.len() - end;
let end_after = after.len() - end;
TextChange {
span: start..end_before,
content: after[start..end_after].to_string(),
}
}
}

View file

@ -7,4 +7,8 @@
/// a generic async provider for bidirectional communication
pub mod controller;
/// a generic representation of a text change
pub mod change;
pub use controller::Controller;
pub use change::TextChange;

View file

@ -11,7 +11,7 @@ use tonic::async_trait;
use crate::errors::IgnorableError;
use crate::{api::Controller, Error};
use super::TextChange;
use crate::api::TextChange;
/// the buffer controller implementation
///

View file

@ -12,18 +12,3 @@ pub mod controller;
pub(crate) mod worker;
pub use controller::BufferController as Controller;
/// an editor-friendly representation of a text change in a buffer
///
/// TODO move in proto
#[derive(Clone, Debug, Default)]
pub struct TextChange {
/// range of text change, as byte indexes in buffer
pub span: std::ops::Range<usize>,
/// content of text change, as string
pub content: String,
/// content after this text change
/// note that this field will probably be dropped, don't rely on it
pub after: String
}

View file

@ -12,8 +12,8 @@ use crate::errors::IgnorableError;
use crate::proto::{OperationRequest, RawOp};
use crate::proto::buffer_client::BufferClient;
use crate::api::controller::ControllerWorker;
use crate::api::TextChange;
use super::TextChange;
use super::controller::BufferController;

View file

@ -11,14 +11,16 @@ pub use crate::{
pub use crate::ot::OperationSeq as CodempOperationSeq;
#[cfg(feature = "api")]
pub use crate::api::Controller as CodempController;
pub use crate::api::{
Controller as CodempController,
TextChange as CodempTextChange,
};
#[cfg(feature = "client")]
pub use crate::{
client::Client as CodempClient,
cursor::Controller as CodempCursorController,
buffer::Controller as CodempBufferController,
buffer::TextChange as CodempTextChange,
Instance as CodempInstance,
};