Skip to content

Instantly share code, notes, and snippets.

@siliconjungle
Created December 10, 2023 19:49
Show Gist options
  • Save siliconjungle/b028885947713b7c0753e0eade4c17de to your computer and use it in GitHub Desktop.
Save siliconjungle/b028885947713b7c0753e0eade4c17de to your computer and use it in GitHub Desktop.
Simple diff
// This is a basic diff mechanism, it is not going to work for characters that take up more than
// one byte. It is also not going to normalise text.
// these are things that *should happen* in the future, but for now they are going to be ignored.
// returns the insert position & the text to insert as well as the delete position & the text to delete
// one of the problems with this kind of diff is that you can't tell in some cases where the insert
// actually occurred.
// for this you will need to take into account the cursor start & end.
export const diff = (a, b) => {
if (a === b) {
return []
}
const ops = []
// Handle the case where one string is empty
if (!a.length || !b.length) {
return [{
type: a.length ? 'remove' : 'insert',
pos: 0,
text: a.length ? a : b,
}]
}
// Find the start of the change
let start = 0
while (start < a.length && start < b.length && a[start] === b[start]) {
start++
}
// Find the end of the change
let endA = a.length, endB = b.length
while (endA > start && endB > start && a[endA - 1] === b[endB - 1]) {
endA--
endB--
}
// Determine removal operation
if (endA - start > 0) {
ops.push({
type: 'remove',
pos: start,
amount: endA - start,
})
}
// Determine insertion operation
if (endB - start > 0) {
ops.push({
type: 'insert',
pos: start,
text: b.substring(start, endB),
})
}
return ops
}
console.log(diff('Hello world', 'Hello!'))
console.log(diff('Hello!', 'Hello world'))
console.log(diff('abc', ''))
console.log(diff('', 'abc'))
console.log(diff('Hello world', 'Hello brave world'))
console.log(diff('Hello brave world', 'Hello beautiful world'))
console.log(diff('abc', 'cba'))
console.log(diff('The quick brown fox', 'The slow red fox jumps over'))
console.log(diff('Hello world', 'Hello world'))
console.log(diff('Hello World', 'hello world'))
console.log(diff('Hello\nWorld', 'Hello World'))
console.log(diff('Café', 'Cafe'))
console.log(diff('こんにちは', 'こんばんは'))
console.log(diff('', ''))
// These cases are weird.
// Not going to bother with them *yet*.
console.log(diff('👍', '👍🏽'))
console.log(diff('👨‍👩‍👦', '👨‍👩‍👧'))
console.log(diff('🇫🇷', '🇩🇪'))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment