Skip to content

Commit c7a7330

Browse files
SpacePossumsebastianbergmann
authored andcommitted
Add DifferOutputBuilderInterface.
1 parent 9eda8de commit c7a7330

File tree

6 files changed

+248
-144
lines changed

6 files changed

+248
-144
lines changed

src/Differ.php

Lines changed: 8 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,22 @@
1010

1111
namespace SebastianBergmann\Diff;
1212

13+
use SebastianBergmann\Diff\Output\DiffOutputBuilderInterface;
14+
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
15+
1316
/**
1417
* Diff implementation.
1518
*/
1619
final class Differ
1720
{
1821
/**
19-
* @var string
20-
*/
21-
private $header;
22-
23-
/**
24-
* @var bool
22+
* @var DiffOutputBuilderInterface
2523
*/
26-
private $showNonDiffLines;
24+
private $outputBuilder;
2725

28-
public function __construct(string $header = "--- Original\n+++ New\n", bool $showNonDiffLines = true)
26+
public function __construct(DiffOutputBuilderInterface $outputBuilder = null)
2927
{
30-
$this->header = $header;
31-
$this->showNonDiffLines = $showNonDiffLines;
28+
$this->outputBuilder = $outputBuilder ?? new UnifiedDiffOutputBuilder();
3229
}
3330

3431
/**
@@ -46,7 +43,7 @@ public function diff($from, $to, LongestCommonSubsequenceCalculator $lcs = null)
4643
$to = $this->validateDiffInput($to);
4744
$diff = $this->diffToArray($from, $to, $lcs);
4845

49-
return $this->getDiff($diff);
46+
return $this->outputBuilder->getDiff($diff);
5047
}
5148

5249
/**
@@ -65,129 +62,6 @@ private function validateDiffInput($input): string
6562
return $input;
6663
}
6764

68-
/**
69-
* Takes input of the diff array and returns the common parts.
70-
* Iterates through diff line by line.
71-
*
72-
* @param array $diff
73-
* @param int $lineThreshold
74-
*
75-
* @return array
76-
*/
77-
private function getCommonChunks(array $diff, int $lineThreshold = 5): array
78-
{
79-
$diffSize = \count($diff);
80-
$capturing = false;
81-
$chunkStart = 0;
82-
$chunkSize = 0;
83-
$commonChunks = [];
84-
85-
for ($i = 0; $i < $diffSize; ++$i) {
86-
if ($diff[$i][1] === 0 /* OLD */) {
87-
if ($capturing === false) {
88-
$capturing = true;
89-
$chunkStart = $i;
90-
$chunkSize = 0;
91-
} else {
92-
++$chunkSize;
93-
}
94-
} elseif ($capturing !== false) {
95-
if ($chunkSize >= $lineThreshold) {
96-
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
97-
}
98-
99-
$capturing = false;
100-
}
101-
}
102-
103-
if ($capturing !== false && $chunkSize >= $lineThreshold) {
104-
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
105-
}
106-
107-
return $commonChunks;
108-
}
109-
110-
/**
111-
* Generates buffer in string format, returning the patch.
112-
*
113-
* @param array $diff
114-
*
115-
* @return string
116-
*/
117-
private function getDiff(array $diff): string
118-
{
119-
$old = $this->getCommonChunks($diff, 5);
120-
$start = isset($old[0]) ? $old[0] : 0;
121-
$end = \count($diff);
122-
123-
if (\count($old)) {
124-
\end($old);
125-
$tmp = \key($old);
126-
\reset($old);
127-
if ($old[$tmp] === $end - 1) {
128-
$end = $tmp;
129-
}
130-
}
131-
132-
$buffer = $this->header;
133-
134-
if (!isset($old[$start])) {
135-
$buffer = $this->getDiffBufferElementNew($diff, $buffer, $start);
136-
++$start;
137-
}
138-
139-
for ($i = $start; $i < $end; $i++) {
140-
if (isset($old[$i])) {
141-
$i = $old[$i];
142-
$buffer = $this->getDiffBufferElementNew($diff, $buffer, $i);
143-
} else {
144-
$buffer = $this->getDiffBufferElement($diff, $buffer, $i);
145-
}
146-
}
147-
148-
return $buffer;
149-
}
150-
151-
/**
152-
* Gets individual buffer element.
153-
*
154-
* @param array $diff
155-
* @param string $buffer
156-
* @param int $diffIndex
157-
*
158-
* @return string
159-
*/
160-
private function getDiffBufferElement(array $diff, string $buffer, int $diffIndex): string
161-
{
162-
if ($diff[$diffIndex][1] === 1 /* ADDED */) {
163-
$buffer .= '+' . $diff[$diffIndex][0] . "\n";
164-
} elseif ($diff[$diffIndex][1] === 2 /* REMOVED */) {
165-
$buffer .= '-' . $diff[$diffIndex][0] . "\n";
166-
} elseif ($this->showNonDiffLines === true) {
167-
$buffer .= ' ' . $diff[$diffIndex][0] . "\n";
168-
}
169-
170-
return $buffer;
171-
}
172-
173-
/**
174-
* Gets individual buffer element with opening.
175-
*
176-
* @param array $diff
177-
* @param string $buffer
178-
* @param int $diffIndex
179-
*
180-
* @return string
181-
*/
182-
private function getDiffBufferElementNew(array $diff, string $buffer, int $diffIndex): string
183-
{
184-
if ($this->showNonDiffLines === true) {
185-
$buffer .= "@@ @@\n";
186-
}
187-
188-
return $this->getDiffBufferElement($diff, $buffer, $diffIndex);
189-
}
190-
19165
/**
19266
* Returns the diff between two arrays or strings as array.
19367
*
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of sebastian/diff.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace SebastianBergmann\Diff\Output;
12+
13+
abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface
14+
{
15+
/**
16+
* Takes input of the diff array and returns the common parts.
17+
* Iterates through diff line by line.
18+
*
19+
* @param array $diff
20+
* @param int $lineThreshold
21+
*
22+
* @return array
23+
*/
24+
protected function getCommonChunks(array $diff, int $lineThreshold = 5): array
25+
{
26+
$diffSize = \count($diff);
27+
$capturing = false;
28+
$chunkStart = 0;
29+
$chunkSize = 0;
30+
$commonChunks = [];
31+
32+
for ($i = 0; $i < $diffSize; ++$i) {
33+
if ($diff[$i][1] === 0 /* OLD */) {
34+
if ($capturing === false) {
35+
$capturing = true;
36+
$chunkStart = $i;
37+
$chunkSize = 0;
38+
} else {
39+
++$chunkSize;
40+
}
41+
} elseif ($capturing !== false) {
42+
if ($chunkSize >= $lineThreshold) {
43+
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
44+
}
45+
46+
$capturing = false;
47+
}
48+
}
49+
50+
if ($capturing !== false && $chunkSize >= $lineThreshold) {
51+
$commonChunks[$chunkStart] = $chunkStart + $chunkSize;
52+
}
53+
54+
return $commonChunks;
55+
}
56+
}

src/Output/DiffOnlyOutputBuilder.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of sebastian/diff.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\Diff\Output;
11+
12+
/**
13+
* Builds a diff string representation in a loose unified diff format
14+
* listing only changes lines. Does not include line numbers.
15+
*/
16+
final class DiffOnlyOutputBuilder implements DiffOutputBuilderInterface
17+
{
18+
/**
19+
* @var string
20+
*/
21+
private $header;
22+
23+
public function __construct(string $header = "--- Original\n+++ New\n")
24+
{
25+
$this->header = $header;
26+
}
27+
28+
public function getDiff(array $diff): string
29+
{
30+
$buffer = \fopen('php://memory', 'r+b');
31+
\fwrite($buffer, $this->header);
32+
33+
foreach ($diff as $diffEntry) {
34+
if ($diffEntry[1] === 1 /* ADDED */) {
35+
\fwrite($buffer, '+' . $diffEntry[0] . "\n");
36+
} elseif ($diffEntry[1] === 2 /* REMOVED */) {
37+
\fwrite($buffer, '-' . $diffEntry[0] . "\n");
38+
}
39+
}
40+
41+
$diff = \stream_get_contents($buffer, -1, 0);
42+
\fclose($buffer);
43+
44+
return $diff;
45+
}
46+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of sebastian/diff.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
namespace SebastianBergmann\Diff\Output;
11+
12+
/**
13+
* Defines how an output builder should take a generated
14+
* diff array and return a string representation of that diff.
15+
*/
16+
interface DiffOutputBuilderInterface
17+
{
18+
public function getDiff(array $diff): string;
19+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php declare(strict_types=1);
2+
/*
3+
* This file is part of sebastian/diff.
4+
*
5+
* (c) Sebastian Bergmann <[email protected]>
6+
*
7+
* For the full copyright and license information, please view the LICENSE
8+
* file that was distributed with this source code.
9+
*/
10+
11+
namespace SebastianBergmann\Diff\Output;
12+
13+
/**
14+
* Builds a diff string representation in unified diff format in chunks.
15+
*/
16+
final class UnifiedDiffOutputBuilder extends AbstractChunkOutputBuilder
17+
{
18+
/**
19+
* @var string
20+
*/
21+
private $header;
22+
23+
public function __construct(string $header = "--- Original\n+++ New\n")
24+
{
25+
$this->header = $header;
26+
}
27+
28+
public function getDiff(array $diff): string
29+
{
30+
$old = $this->getCommonChunks($diff, 5);
31+
$start = isset($old[0]) ? $old[0] : 0;
32+
$end = \count($diff);
33+
34+
if (\count($old)) {
35+
\end($old);
36+
$tmp = \key($old);
37+
\reset($old);
38+
if ($old[$tmp] === $end - 1) {
39+
$end = $tmp;
40+
}
41+
}
42+
43+
$buffer = $this->header;
44+
45+
if (!isset($old[$start])) {
46+
$buffer = $this->getDiffBufferElementNew($diff, $buffer, $start);
47+
++$start;
48+
}
49+
50+
for ($i = $start; $i < $end; $i++) {
51+
if (isset($old[$i])) {
52+
$i = $old[$i];
53+
$buffer = $this->getDiffBufferElementNew($diff, $buffer, $i);
54+
} else {
55+
$buffer = $this->getDiffBufferElement($diff, $buffer, $i);
56+
}
57+
}
58+
59+
return $buffer;
60+
}
61+
62+
/**
63+
* Gets individual buffer element with opening.
64+
*
65+
* @param array $diff
66+
* @param string $buffer
67+
* @param int $diffIndex
68+
*
69+
* @return string
70+
*/
71+
private function getDiffBufferElementNew(array $diff, string $buffer, int $diffIndex): string
72+
{
73+
return $this->getDiffBufferElement($diff, $buffer . "@@ @@\n", $diffIndex);
74+
}
75+
76+
/**
77+
* Gets individual buffer element.
78+
*
79+
* @param array $diff
80+
* @param string $buffer
81+
* @param int $diffIndex
82+
*
83+
* @return string
84+
*/
85+
private function getDiffBufferElement(array $diff, string $buffer, int $diffIndex): string
86+
{
87+
if ($diff[$diffIndex][1] === 1 /* ADDED */) {
88+
$buffer .= '+' . $diff[$diffIndex][0] . "\n";
89+
} elseif ($diff[$diffIndex][1] === 2 /* REMOVED */) {
90+
$buffer .= '-' . $diff[$diffIndex][0] . "\n";
91+
} else {
92+
$buffer .= ' ' . $diff[$diffIndex][0] . "\n";
93+
}
94+
95+
return $buffer;
96+
}
97+
}

0 commit comments

Comments
 (0)