Skip to content

Commit e4b4935

Browse files
SpacePossumsebastianbergmann
authored andcommitted
Add linenumbers
1 parent 5bf53e7 commit e4b4935

File tree

2 files changed

+407
-55
lines changed

2 files changed

+407
-55
lines changed

src/Output/UnifiedDiffOutputBuilder.php

Lines changed: 97 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@ final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
2020
*/
2121
private $header;
2222

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)
2429
{
25-
$this->header = $header;
30+
$this->header = $header;
31+
$this->addLineNumbers = $addLineNumbers;
2632
}
2733

2834
public function getDiff(array $diff): string
@@ -49,71 +55,111 @@ public function getDiff(array $diff): string
4955
// of a list of elements all containing `same` (0) entries.
5056
private function writeDiffChunked($output, array $diff, array $old)
5157
{
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);
5474

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`
5786
$tmp = \key($old);
5887
\reset($old);
59-
if ($old[$tmp] === $end - 1) {
60-
$end = $tmp;
88+
if ($old[$tmp] === $upperLimit - 1) {
89+
$upperLimit = $tmp;
6190
}
6291
}
6392

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);
67101
}
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+
}
68120

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);
75124
}
125+
126+
\fwrite($output, " @@\n");
127+
} else {
128+
\fwrite($output, "@@ @@\n");
76129
}
77-
}
78130

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+
}
89139

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+
}
91145
}
92146

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
101148
{
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+
}
112161
}
113162

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];
118164
}
119165
}

0 commit comments

Comments
 (0)