@@ -4,20 +4,29 @@ import SuggestionBasic
44public 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