Skip to content

Commit bed5cdd

Browse files
committed
WIP
1 parent 6f59c0e commit bed5cdd

2 files changed

Lines changed: 279 additions & 27 deletions

File tree

Tool/Sources/CodeDiff/CodeDiff.swift

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,29 @@ import SuggestionBasic
44
public struct CodeDiff {
55
public typealias LineDiff = CollectionDifference<String>
66

7-
public struct SnippetDiff {
8-
public struct Change {
7+
public struct SnippetDiff: Equatable {
8+
public struct Change: Equatable {
99
public var offset: Int
1010
public var element: String
1111
}
1212

13-
public struct Line {
13+
public struct Line: Equatable {
14+
public enum Diff: Equatable {
15+
case unchanged
16+
case mutated(changes: [Change])
17+
}
18+
1419
public var text: String
15-
public var diff: [Change]?
20+
public var diff: Diff = .unchanged
1621
}
1722

18-
public struct Section {
23+
public struct Section: Equatable {
1924
public var oldSnippet: [Line]
2025
public var newSnippet: [Line]
26+
27+
public var isEmpty: Bool {
28+
oldSnippet.isEmpty && newSnippet.isEmpty
29+
}
2130
}
2231

2332
public var sections: [Section]
@@ -82,8 +91,8 @@ public struct CodeDiff {
8291
}
8392

8493
public func diff(snippet: String, from oldSnippet: String) -> SnippetDiff {
85-
let newLines = snippet.breakLines()
86-
let oldLines = oldSnippet.breakLines()
94+
let newLines = snippet.splitByNewLine(omittingEmptySubsequences: false)
95+
let oldLines = oldSnippet.splitByNewLine(omittingEmptySubsequences: false)
8796
let diffByLine = newLines.difference(from: oldLines)
8897

8998
struct DiffSection: Equatable {
@@ -94,15 +103,15 @@ public struct CodeDiff {
94103

95104
func collect(
96105
into all: inout [DiffSection],
97-
changes: [CollectionDifference<String>.Change],
98-
extract: (CollectionDifference<String>.Change) -> (offset: Int, line: String)?
106+
changes: [CollectionDifference<Substring>.Change],
107+
extract: (CollectionDifference<Substring>.Change) -> (offset: Int, line: Substring)?
99108
) {
100109
var current: DiffSection?
101110
for change in changes {
102111
guard let (offset, element) = extract(change) else { continue }
103112
if var section = current {
104113
if offset == section.end + 1 {
105-
section.lines.append(element)
114+
section.lines.append(String(element))
106115
section.end = offset
107116
current = section
108117
continue
@@ -111,7 +120,7 @@ public struct CodeDiff {
111120
}
112121
}
113122

114-
current = DiffSection(offset: offset, end: offset, lines: [element])
123+
current = DiffSection(offset: offset, end: offset, lines: [String(element)])
115124
}
116125

117126
if let current {
@@ -144,16 +153,28 @@ public struct CodeDiff {
144153
// handle lines before sections
145154
var beforeSection = SnippetDiff.Section(oldSnippet: [], newSnippet: [])
146155

147-
while oldLineIndex < (removalSection?.offset ?? .max) {
148-
beforeSection.oldSnippet.append(.init(text: oldLines[oldLineIndex], diff: nil))
156+
while oldLineIndex < (removalSection?.offset ?? oldLines.endIndex) {
157+
if oldLineIndex < oldLines.endIndex {
158+
beforeSection.oldSnippet.append(.init(
159+
text: String(oldLines[oldLineIndex]),
160+
diff: .unchanged
161+
))
162+
}
149163
oldLineIndex += 1
150164
}
151-
while newLineIndex < (insertionSection?.offset ?? .max) {
152-
beforeSection.newSnippet.append(.init(text: newLines[newLineIndex], diff: nil))
165+
while newLineIndex < (insertionSection?.offset ?? newLines.endIndex) {
166+
if newLineIndex < newLines.endIndex {
167+
beforeSection.newSnippet.append(.init(
168+
text: String(newLines[newLineIndex]),
169+
diff: .unchanged
170+
))
171+
}
153172
newLineIndex += 1
154173
}
155174

156-
result.sections.append(beforeSection)
175+
if !beforeSection.isEmpty {
176+
result.sections.append(beforeSection)
177+
}
157178

158179
// handle lines inside sections
159180

@@ -166,24 +187,26 @@ public struct CodeDiff {
166187
if let oldLine {
167188
insideSection.oldSnippet.append(.init(
168189
text: oldLine,
169-
diff: diff.removals.compactMap { change in
190+
diff: .mutated(changes: diff.removals.compactMap { change in
170191
guard case let .remove(offset, element, _) = change else { return nil }
171192
return .init(offset: offset, element: element)
172-
}
193+
})
173194
))
174195
}
175196
if let newLine {
176197
insideSection.newSnippet.append(.init(
177198
text: newLine,
178-
diff: diff.insertions.compactMap { change in
199+
diff: .mutated(changes: diff.insertions.compactMap { change in
179200
guard case let .insert(offset, element, _) = change else { return nil }
180201
return .init(offset: offset, element: element)
181-
}
202+
})
182203
))
183204
}
184205
}
185206

186-
result.sections.append(insideSection)
207+
if !insideSection.isEmpty {
208+
result.sections.append(insideSection)
209+
}
187210

188211
oldLineIndex += removalSection?.lines.count ?? 0
189212
newLineIndex += insertionSection?.lines.count ?? 0
@@ -250,20 +273,23 @@ struct SnippetDiffPreview: View {
250273
$0.newSnippet.map {
251274
let text = $0.text.trimmingCharacters(in: .newlines)
252275
let string = NSMutableAttributedString(string: text)
253-
if let diff = $0.diff {
276+
if case let .mutated(changes) = $0.diff {
254277
string.addAttribute(
255278
.backgroundColor,
256279
value: NSColor.green.withAlphaComponent(0.1),
257280
range: NSRange(location: 0, length: text.count)
258281
)
259282

260-
for diffItem in diff {
283+
for diffItem in changes {
261284
string.addAttribute(
262285
.backgroundColor,
263286
value: NSColor.green.withAlphaComponent(0.5),
264287
range: NSRange(
265288
location: diffItem.offset,
266-
length: min(text.count - diffItem.offset, diffItem.element.count)
289+
length: min(
290+
text.count - diffItem.offset,
291+
diffItem.element.count
292+
)
267293
)
268294
)
269295
}
@@ -276,14 +302,14 @@ struct SnippetDiffPreview: View {
276302
$0.oldSnippet.map {
277303
let text = $0.text.trimmingCharacters(in: .newlines)
278304
let string = NSMutableAttributedString(string: text)
279-
if let diff = $0.diff {
305+
if case let .mutated(changes) = $0.diff {
280306
string.addAttribute(
281307
.backgroundColor,
282308
value: NSColor.red.withAlphaComponent(0.1),
283309
range: NSRange(location: 0, length: text.count)
284310
)
285311

286-
for diffItem in diff {
312+
for diffItem in changes {
287313
string.addAttribute(
288314
.backgroundColor,
289315
value: NSColor.red.withAlphaComponent(0.5),

0 commit comments

Comments
 (0)