Implement text diffing for proper CRDT operations
This commit is contained in:
parent
925c7a3c0d
commit
4d6ecf78cd
1 changed files with 33 additions and 5 deletions
|
|
@ -61,19 +61,47 @@ function connect(roomName: string) {
|
|||
};
|
||||
}
|
||||
|
||||
// compute minimal edit operations using LCS-based diff
|
||||
function computeDiff(oldText: string, newText: string) {
|
||||
// find common prefix
|
||||
let prefixLen = 0;
|
||||
while (prefixLen < oldText.length && prefixLen < newText.length &&
|
||||
oldText[prefixLen] === newText[prefixLen]) {
|
||||
prefixLen++;
|
||||
}
|
||||
|
||||
// find common suffix
|
||||
let suffixLen = 0;
|
||||
while (suffixLen < oldText.length - prefixLen &&
|
||||
suffixLen < newText.length - prefixLen &&
|
||||
oldText[oldText.length - 1 - suffixLen] === newText[newText.length - 1 - suffixLen]) {
|
||||
suffixLen++;
|
||||
}
|
||||
|
||||
const deleteStart = prefixLen;
|
||||
const deleteLen = oldText.length - prefixLen - suffixLen;
|
||||
const insertText = newText.slice(prefixLen, newText.length - suffixLen);
|
||||
|
||||
return { deleteStart, deleteLen, insertText };
|
||||
}
|
||||
|
||||
function setContent(newContent: string) {
|
||||
if (!doc || !text || !ws) return;
|
||||
|
||||
const oldContent = text.toString();
|
||||
if (oldContent === newContent) return;
|
||||
|
||||
// compute diff and apply
|
||||
// simple approach: delete all, insert all
|
||||
// TODO: proper diff for efficiency
|
||||
// compute minimal diff and apply
|
||||
const { deleteStart, deleteLen, insertText } = computeDiff(oldContent, newContent);
|
||||
|
||||
const t = text;
|
||||
doc.transact(() => {
|
||||
t.delete(0, t.length);
|
||||
t.insert(0, newContent);
|
||||
if (deleteLen > 0) {
|
||||
t.delete(deleteStart, deleteLen);
|
||||
}
|
||||
if (insertText.length > 0) {
|
||||
t.insert(deleteStart, insertText);
|
||||
}
|
||||
});
|
||||
|
||||
// send update to daemon
|
||||
|
|
|
|||
Loading…
Reference in a new issue