Skip to content

Commit af38b58

Browse files
committed
Refactor MyersDiff to simplify line-by-line comparison
This commit simplifies the `MyersDiff.kt` implementation. Instead of using the traditional Myers algorithm for line-level diffing, it now performs a simpler line-by-line comparison. Key changes: - Removed the complex Myers algorithm logic (trace, v-array, buildDiff) from `MyersDiff.kt`. - `calculateDiff` now iterates through the maximum number of lines in the old and new texts. - For each line index, it compares `oldLines.getOrNull(i)` and `newLines.getOrNull(i)`: - If `oldLine` is null and `newLine` is not, it's an `ADDED` line. - If `oldLine` is not null and `newLine` is null, it's a `DELETED` line. - If both lines are equal, it's an `UNCHANGED` line. - If lines differ, it's marked as `CHANGED`, and `charLevelDiff` is used to find character differences. - Removed the `mergeChangedEntries` method as the new approach directly identifies `CHANGED` lines without needing a separate merge step. - Updated `MyersDiffTest.kt` by removing tests related to `mergeChangedEntries` and tests that were specific to the previous Myers algorithm behavior (e.g., `calculateDiff with all lines changed`, `calculateDiff with lines containing only whitespace`). - Removed `border` modifier from `CharDiffText.kt` as it's no longer used.
1 parent 92e3ee5 commit af38b58

3 files changed

Lines changed: 34 additions & 319 deletions

File tree

app/src/main/java/dev/jahidhasanco/diffly/domain/util/MyersDiff.kt

Lines changed: 34 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -11,146 +11,55 @@ class MyersDiff {
1111
fun calculateDiff(
1212
oldLines: List<String>,
1313
newLines: List<String>
14-
): List<DiffEntry> {
15-
val n = oldLines.size
16-
val m = newLines.size
17-
val max = n + m
18-
val v = mutableMapOf<Int, Int>()
19-
v[1] = 0
20-
val trace = mutableListOf<Map<Int, Int>>()
21-
22-
for (d in 0..max) {
23-
val vCopy = v.toMutableMap()
24-
trace.add(vCopy)
25-
26-
for (k in -d..d step 2) {
27-
val x = when {
28-
k == -d -> v[k + 1]!!
29-
k != d && v[k - 1]!! < v[k + 1]!! -> v[k + 1]!!
30-
else -> v[k - 1]!! + 1
31-
}
32-
33-
var y = x - k
34-
var xCopy = x
35-
36-
while (xCopy < n && y < m && oldLines[xCopy] == newLines[y]) {
37-
xCopy++
38-
y++
39-
}
40-
41-
v[k] = xCopy
42-
43-
if (xCopy >= n && y >= m) {
44-
val rawDiff = buildDiff(trace, oldLines, newLines)
45-
return mergeChangedEntries(rawDiff)
46-
}
47-
}
48-
}
49-
50-
throw IllegalStateException("Diff computation failed")
51-
}
52-
53-
private fun buildDiff(
54-
trace: List<Map<Int, Int>>,
55-
oldLines: List<String>,
56-
newLines: List<String>
5714
): List<DiffEntry> {
5815
val result = mutableListOf<DiffEntry>()
59-
var x = oldLines.size
60-
var y = newLines.size
16+
val maxLines = maxOf(oldLines.size, newLines.size)
6117

62-
for (d in trace.size - 1 downTo 0) {
63-
val v = trace[d]
64-
val k = x - y
65-
val prevK = when {
66-
k == -d || (k != d && v[k - 1]!! < v[k + 1]!!) -> k + 1
67-
else -> k - 1
68-
}
69-
val prevX = v[prevK]!!
70-
val prevY = prevX - prevK
18+
for (i in 0 until maxLines) {
19+
val oldLine = oldLines.getOrNull(i)
20+
val newLine = newLines.getOrNull(i)
7121

72-
// Handle unchanged lines
73-
while (x > prevX && y > prevY) {
74-
result.add(
22+
val entry = when {
23+
oldLine == null && newLine != null -> {
7524
DiffEntry(
76-
oldLine = oldLines[x - 1],
77-
newLine = newLines[y - 1],
78-
type = DiffType.UNCHANGED,
79-
charDiffs = null
25+
oldLine = null,
26+
newLine = newLine,
27+
type = DiffType.ADDED
8028
)
81-
)
82-
x--
83-
y--
84-
}
29+
}
8530

86-
// Handle inserted or deleted lines (only if d > 0)
87-
if (d > 0) {
88-
if (x == prevX) {
89-
// Inserted line(s)
90-
result.add(
91-
DiffEntry(
92-
oldLine = null,
93-
newLine = newLines[y - 1],
94-
type = DiffType.ADDED,
95-
charDiffs = null
96-
)
97-
)
98-
y--
99-
} else if (y == prevY) {
100-
// Deleted line(s)
101-
result.add(
102-
DiffEntry(
103-
oldLine = oldLines[x - 1],
104-
newLine = null,
105-
type = DiffType.DELETED,
106-
charDiffs = null
107-
)
31+
oldLine != null && newLine == null -> {
32+
DiffEntry(
33+
oldLine = oldLine,
34+
newLine = null,
35+
type = DiffType.DELETED
10836
)
109-
x--
110-
} else {
111-
// Changed line: Both old and new lines exist but differ
112-
val oldLine = oldLines[x - 1]
113-
val newLine = newLines[y - 1]
114-
115-
val charDiffs = charLevelDiff.diff(oldLine, newLine)
37+
}
11638

117-
result.add(
118-
DiffEntry(
119-
oldLine = oldLine,
120-
newLine = newLine,
121-
type = DiffType.CHANGED,
122-
charDiffs = charDiffs
123-
)
39+
oldLine == newLine -> {
40+
DiffEntry(
41+
oldLine = oldLine,
42+
newLine = newLine,
43+
type = DiffType.UNCHANGED
12444
)
125-
x--
126-
y--
12745
}
128-
}
129-
}
130-
131-
return result.reversed()
132-
}
13346

134-
fun mergeChangedEntries(diffEntries: List<DiffEntry>): List<DiffEntry> {
135-
val merged = mutableListOf<DiffEntry>()
136-
var i = 0
137-
while (i < diffEntries.size) {
138-
if (i < diffEntries.size - 1) {
139-
val curr = diffEntries[i]
140-
val next = diffEntries[i + 1]
141-
if (curr.type == DiffType.DELETED && next.type == DiffType.ADDED) {
142-
val oldLine = curr.oldLine ?: ""
143-
val newLine = next.newLine ?: ""
144-
val charDiffs = charLevelDiff.diff(oldLine, newLine)
145-
merged.add(DiffEntry(oldLine, newLine, DiffType.CHANGED, charDiffs))
146-
i += 2
147-
continue
47+
else -> {
48+
// Lines differ: compute char-level diff
49+
val charDiffs = charLevelDiff.diff(oldLine!!, newLine!!)
50+
DiffEntry(
51+
oldLine = oldLine,
52+
newLine = newLine,
53+
type = DiffType.CHANGED,
54+
charDiffs = charDiffs
55+
)
14856
}
14957
}
150-
merged.add(diffEntries[i])
151-
i++
58+
59+
result.add(entry)
15260
}
153-
return merged
61+
62+
return result
15463
}
15564

15665
}

app/src/main/java/dev/jahidhasanco/diffly/presentation/component/CharDiffText.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package dev.jahidhasanco.diffly.presentation.component
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.border
54
import androidx.compose.foundation.layout.Box
65
import androidx.compose.foundation.layout.Row
76
import androidx.compose.foundation.layout.Spacer

0 commit comments

Comments
 (0)