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