@@ -59,13 +59,13 @@ final class UnifiedDiffOutputBuilder implements DiffOutputBuilderInterface
59
59
private $ contextLines ;
60
60
61
61
private static $ default = [
62
- 'contextLines ' => 3 , // like `diff: -u, -U NUM, --unified[=NUM]`, for patch/git apply compatibility best to keep at least @ 3
63
- 'collapseRanges ' => true , // ranges of length one are rendered with the trailing `,1`
62
+ 'collapseRanges ' => true , // ranges of length one are rendered with the trailing `,1`
63
+ 'commonLineThreshold ' => 6 , // number of same lines before ending a new hunk and creating a new one (if needed)
64
+ 'contextLines ' => 3 , // like `diff: -u, -U NUM, --unified[=NUM]`, for patch/git apply compatibility best to keep at least @ 3
64
65
'fromFile ' => null ,
65
66
'fromFileDate ' => null ,
66
67
'toFile ' => null ,
67
68
'toFileDate ' => null ,
68
- 'commonLineThreshold ' => 6 , // number of same lines before ending a new hunk and creating a new one (if needed)
69
69
];
70
70
71
71
public function __construct (array $ options = [])
@@ -122,15 +122,24 @@ public function getDiff(array $diff): string
122
122
123
123
$ this ->writeDiffHunks ($ buffer , $ diff );
124
124
125
+ if (!$ this ->changed ) {
126
+ \fclose ($ buffer );
127
+
128
+ return '' ;
129
+ }
130
+
125
131
$ diff = \stream_get_contents ($ buffer , -1 , 0 );
126
132
127
133
\fclose ($ buffer );
128
134
129
- if (! $ this -> changed ) {
130
- return '' ;
131
- }
135
+ // If the last char is not a linebreak: add it.
136
+ // This might happen when both the `from` and `to` do not have a trailing linebreak
137
+ $ last = \substr ( $ diff , - 1 );
132
138
133
- return $ diff ;
139
+ return "\n" !== $ last && "\r" !== $ last
140
+ ? $ diff ."\n"
141
+ : $ diff
142
+ ;
134
143
}
135
144
136
145
private function writeDiffHunks ($ output , array $ diff )
@@ -139,7 +148,6 @@ private function writeDiffHunks($output, array $diff)
139
148
140
149
$ upperLimit = \count ($ diff );
141
150
142
- // append "\ No newline at end of file" if needed
143
151
if (0 === $ diff [$ upperLimit - 1 ][1 ]) {
144
152
$ lc = \substr ($ diff [$ upperLimit - 1 ][0 ], -1 );
145
153
if ("\n" !== $ lc ) {
@@ -185,24 +193,30 @@ private function writeDiffHunks($output, array $diff)
185
193
++$ fromRange ;
186
194
187
195
if ($ sameCount === $ cutOff ) {
188
- $ contextStartOffset = $ hunkCapture - $ this ->contextLines < 0
196
+ $ contextStartOffset = ( $ hunkCapture - $ this ->contextLines ) < 0
189
197
? $ hunkCapture
190
198
: $ this ->contextLines
191
199
;
192
200
193
- $ contextEndOffset = $ i + $ this ->contextLines >= \count ($ diff )
194
- ? \count ($ diff ) - $ i
195
- : $ this ->contextLines
196
- ;
201
+ // note: $contextEndOffset = $this->contextLines;
202
+ //
203
+ // because we never go beyond the end of the diff.
204
+ // with the cutoff/contextlines here the follow is never true;
205
+ //
206
+ // if ($i - $cutOff + $this->contextLines + 1 > \count($diff)) {
207
+ // $contextEndOffset = count($diff) - 1;
208
+ // }
209
+ //
210
+ // ; that would be true for a trailing incomplete hunk case which is dealt with after this loop
197
211
198
212
$ this ->writeHunk (
199
213
$ diff ,
200
214
$ hunkCapture - $ contextStartOffset ,
201
- $ i - $ cutOff + $ contextEndOffset + 1 ,
215
+ $ i - $ cutOff + $ this -> contextLines + 1 ,
202
216
$ fromStart - $ contextStartOffset ,
203
- $ fromRange - $ cutOff + $ contextStartOffset + $ contextEndOffset ,
217
+ $ fromRange - $ cutOff + $ contextStartOffset + $ this -> contextLines ,
204
218
$ toStart - $ contextStartOffset ,
205
- $ toRange - $ cutOff + $ contextStartOffset + $ contextEndOffset ,
219
+ $ toRange - $ cutOff + $ contextStartOffset + $ this -> contextLines ,
206
220
$ output
207
221
);
208
222
@@ -237,23 +251,35 @@ private function writeDiffHunks($output, array $diff)
237
251
}
238
252
}
239
253
240
- if (false !== $ hunkCapture ) {
241
- $ contextStartOffset = $ hunkCapture - $ this ->contextLines < 0
242
- ? $ hunkCapture
243
- : $ this ->contextLines
244
- ;
245
-
246
- $ this ->writeHunk (
247
- $ diff ,
248
- $ hunkCapture - $ contextStartOffset ,
249
- \count ($ diff ),
250
- $ fromStart - $ contextStartOffset ,
251
- $ fromRange + $ contextStartOffset ,
252
- $ toStart - $ contextStartOffset ,
253
- $ toRange + $ contextStartOffset ,
254
- $ output
255
- );
254
+ if (false === $ hunkCapture ) {
255
+ return ;
256
256
}
257
+
258
+ // we end here when cutoff (commonLineThreshold) was not reached, but we where capturing a hunk,
259
+ // do not render hunk till end automatically because the number of context lines might be less than the commonLineThreshold
260
+
261
+ $ contextStartOffset = $ hunkCapture - $ this ->contextLines < 0
262
+ ? $ hunkCapture
263
+ : $ this ->contextLines
264
+ ;
265
+
266
+ // prevent trying to write out more common lines than there are in the diff _and_
267
+ // do not write more than configured through the context lines
268
+ $ contextEndOffset = \min ($ sameCount , $ this ->contextLines );
269
+
270
+ $ fromRange -= $ sameCount ;
271
+ $ toRange -= $ sameCount ;
272
+
273
+ $ this ->writeHunk (
274
+ $ diff ,
275
+ $ hunkCapture - $ contextStartOffset ,
276
+ $ i - $ sameCount + $ contextEndOffset + 1 ,
277
+ $ fromStart - $ contextStartOffset ,
278
+ $ fromRange + $ contextStartOffset + $ contextEndOffset ,
279
+ $ toStart - $ contextStartOffset ,
280
+ $ toRange + $ contextStartOffset + $ contextEndOffset ,
281
+ $ output
282
+ );
257
283
}
258
284
259
285
private function writeHunk (
@@ -292,6 +318,11 @@ private function writeHunk(
292
318
$ this ->changed = true ;
293
319
\fwrite ($ output , $ diff [$ i ][0 ]);
294
320
}
321
+ //} elseif ($diff[$i][1] === 3) { // custom comment inserted by PHPUnit/diff package
322
+ // skip
323
+ //} else {
324
+ // unknown/invalid
325
+ //}
295
326
}
296
327
}
297
328
}
0 commit comments