Implement text diffing for proper CRDT operations

This commit is contained in:
Jared Miller 2026-01-27 16:16:34 -05:00
parent 925c7a3c0d
commit 4d6ecf78cd
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C

View file

@ -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