@@ -20,9 +20,15 @@ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
20
20
*/
21
21
private $ header ;
22
22
23
- public function __construct (string $ header = "--- Original \n+++ New \n" )
23
+ /**
24
+ * @var bool
25
+ */
26
+ private $ addLineNumbers ;
27
+
28
+ public function __construct (string $ header = "--- Original \n+++ New \n" , bool $ addLineNumbers = false )
24
29
{
25
- $ this ->header = $ header ;
30
+ $ this ->header = $ header ;
31
+ $ this ->addLineNumbers = $ addLineNumbers ;
26
32
}
27
33
28
34
public function getDiff (array $ diff ): string
@@ -49,71 +55,111 @@ public function getDiff(array $diff): string
49
55
// of a list of elements all containing `same` (0) entries.
50
56
private function writeDiffChunked ($ output , array $ diff , array $ old )
51
57
{
52
- $ start = isset ($ old [0 ]) ? $ old [0 ] : 0 ;
53
- $ end = \count ($ diff );
58
+ $ upperLimit = \count ($ diff );
59
+ $ start = 0 ;
60
+ $ fromStart = 0 ;
61
+ $ toStart = 0 ;
62
+
63
+ if (\count ($ old )) { // no common parts, list all diff entries
64
+ \reset ($ old );
65
+
66
+ // iterate the diff, go from chunk to chunk skipping common chunk of lines between those
67
+ do {
68
+ $ commonStart = \key ($ old );
69
+ $ commonEnd = \current ($ old );
70
+
71
+ if ($ commonStart !== $ start ) {
72
+ list ($ fromRange , $ toRange ) = $ this ->getChunkRange ($ diff , $ start , $ commonStart );
73
+ $ this ->writeChunk ($ output , $ diff , $ start , $ commonStart , $ fromStart , $ fromRange , $ toStart , $ toRange );
54
74
55
- if (\count ($ old )) {
56
- \end ($ old );
75
+ $ fromStart += $ fromRange ;
76
+ $ toStart += $ toRange ;
77
+ }
78
+
79
+ $ start = $ commonEnd + 1 ;
80
+ $ commonLength = $ commonEnd - $ commonStart + 1 ; // calculate number of non-change lines in the common part
81
+ $ fromStart += $ commonLength ;
82
+ $ toStart += $ commonLength ;
83
+ } while (false !== \next ($ old ));
84
+
85
+ \end ($ old ); // short cut for finding possible last `change entry`
57
86
$ tmp = \key ($ old );
58
87
\reset ($ old );
59
- if ($ old [$ tmp ] === $ end - 1 ) {
60
- $ end = $ tmp ;
88
+ if ($ old [$ tmp ] === $ upperLimit - 1 ) {
89
+ $ upperLimit = $ tmp ;
61
90
}
62
91
}
63
92
64
- if (!isset ($ old [$ start ])) {
65
- $ this ->writeDiffBufferElementNew ($ diff , $ output , $ start );
66
- ++$ start ;
93
+ if ($ start < $ upperLimit - 1 ) { // check for trailing (non) diff entries
94
+ do {
95
+ --$ upperLimit ;
96
+ } while (isset ($ diff [$ upperLimit ][1 ]) && $ diff [$ upperLimit ][1 ] === 0 );
97
+ ++$ upperLimit ;
98
+
99
+ list ($ fromRange , $ toRange ) = $ this ->getChunkRange ($ diff , $ start , $ upperLimit );
100
+ $ this ->writeChunk ($ output , $ diff , $ start , $ upperLimit , $ fromStart , $ fromRange , $ toStart , $ toRange );
67
101
}
102
+ }
103
+
104
+ private function writeChunk (
105
+ $ output ,
106
+ array $ diff ,
107
+ int $ diffStartIndex ,
108
+ int $ diffEndIndex ,
109
+ int $ fromStart ,
110
+ int $ fromRange ,
111
+ int $ toStart ,
112
+ int $ toRange
113
+ ) {
114
+ if ($ this ->addLineNumbers ) {
115
+ \fwrite ($ output , '@@ - ' . (1 + $ fromStart ));
116
+
117
+ if ($ fromRange > 1 ) {
118
+ \fwrite ($ output , ', ' . $ fromRange );
119
+ }
68
120
69
- for ($ i = $ start ; $ i < $ end ; $ i ++) {
70
- if (isset ($ old [$ i ])) {
71
- $ i = $ old [$ i ];
72
- $ this ->writeDiffBufferElementNew ($ diff , $ output , $ i );
73
- } else {
74
- $ this ->writeDiffBufferElement ($ diff , $ output , $ i );
121
+ \fwrite ($ output , ' + ' . (1 + $ toStart ));
122
+ if ($ toRange > 1 ) {
123
+ \fwrite ($ output , ', ' . $ toRange );
75
124
}
125
+
126
+ \fwrite ($ output , " @@ \n" );
127
+ } else {
128
+ \fwrite ($ output , "@@ @@ \n" );
76
129
}
77
- }
78
130
79
- /**
80
- * Gets individual buffer element with opening.
81
- *
82
- * @param array $diff
83
- * @param resource $buffer
84
- * @param int $diffIndex
85
- */
86
- private function writeDiffBufferElementNew (array $ diff , $ buffer , int $ diffIndex )
87
- {
88
- \fwrite ($ buffer , "@@ @@ \n" );
131
+ for ($ i = $ diffStartIndex ; $ i < $ diffEndIndex ; ++$ i ) {
132
+ if ($ diff [$ i ][1 ] === 1 /* ADDED */ ) {
133
+ \fwrite ($ output , '+ ' . $ diff [$ i ][0 ]);
134
+ } elseif ($ diff [$ i ][1 ] === 2 /* REMOVED */ ) {
135
+ \fwrite ($ output , '- ' . $ diff [$ i ][0 ]);
136
+ } else { /* Not changed (old) 0 or Warning 3 */
137
+ \fwrite ($ output , ' ' . $ diff [$ i ][0 ]);
138
+ }
89
139
90
- $ this ->writeDiffBufferElement ($ diff , $ buffer , $ diffIndex );
140
+ $ lc = \substr ($ diff [$ i ][0 ], -1 );
141
+ if ($ lc !== "\n" && $ lc !== "\r" ) {
142
+ \fwrite ($ output , "\n" ); // \No newline at end of file
143
+ }
144
+ }
91
145
}
92
146
93
- /**
94
- * Gets individual buffer element.
95
- *
96
- * @param array $diff
97
- * @param resource $buffer
98
- * @param int $diffIndex
99
- */
100
- private function writeDiffBufferElement (array $ diff , $ buffer , int $ diffIndex )
147
+ private function getChunkRange (array $ diff , int $ diffStartIndex , int $ diffEndIndex ): array
101
148
{
102
- if ($ diff [$ diffIndex ][1 ] === 1 /* ADDED */ ) {
103
- \fwrite ($ buffer , '+ ' . $ diff [$ diffIndex ][0 ]);
104
- } elseif ($ diff [$ diffIndex ][1 ] === 2 /* REMOVED */ ) {
105
- \fwrite ($ buffer , '- ' . $ diff [$ diffIndex ][0 ]);
106
- } elseif ($ diff [$ diffIndex ][1 ] === 3 /* WARNING */ ) {
107
- \fwrite ($ buffer , ' ' . $ diff [$ diffIndex ][0 ]);
108
-
109
- return ; // Warnings should not be tested for line break, it will always be there
110
- } else { /* OLD Not changed (0) */
111
- \fwrite ($ buffer , ' ' . $ diff [$ diffIndex ][0 ]);
149
+ $ toRange = 0 ;
150
+ $ fromRange = 0 ;
151
+
152
+ for ($ i = $ diffStartIndex ; $ i < $ diffEndIndex ; ++$ i ) {
153
+ if ($ diff [$ i ][1 ] === 1 ) { // added
154
+ ++$ toRange ;
155
+ } elseif ($ diff [$ i ][1 ] === 2 ) { // removed
156
+ ++$ fromRange ;
157
+ } elseif ($ diff [$ i ][1 ] === 0 ) { // same
158
+ ++$ fromRange ;
159
+ ++$ toRange ;
160
+ }
112
161
}
113
162
114
- $ lc = \substr ($ diff [$ diffIndex ][0 ], -1 );
115
- if ($ lc !== "\n" && $ lc !== "\r" ) {
116
- \fwrite ($ buffer , "\n" ); // \No newline at end of file
117
- }
163
+ return [$ fromRange , $ toRange ];
118
164
}
119
165
}
0 commit comments