From 4d6ecf78cda5d4d09f75db45162f9fe23a4663a2 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Tue, 27 Jan 2026 16:16:34 -0500 Subject: [PATCH] Implement text diffing for proper CRDT operations --- adapters/vim/bridge.ts | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/adapters/vim/bridge.ts b/adapters/vim/bridge.ts index 6b2a764..2223506 100644 --- a/adapters/vim/bridge.ts +++ b/adapters/vim/bridge.ts @@ -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