Skip to content

Commit 2d0145d

Browse files
authored
Merge pull request #93 from JBlond/php-diff-90
Fix #90 - Diff mode Merged shows result only partially
2 parents 9830fe0 + 7a67d32 commit 2d0145d

File tree

4 files changed

+116
-72
lines changed

4 files changed

+116
-72
lines changed

example/dark-theme.css

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ body {
66
}
77

88
pre {
9-
width: 100%;
109
overflow: auto;
10+
width: 100%;
1111
}
1212

1313
a, a:visited {
@@ -19,35 +19,35 @@ a, a:visited {
1919
*/
2020

2121
.Differences {
22-
width: 100%;
2322
border-collapse: collapse;
2423
border-spacing: 0;
2524
empty-cells: show;
25+
width: 100%;
2626
}
2727

2828
.Differences thead th {
29-
text-align: left;
30-
border-bottom: 1px solid #000000;
3129
background: #AAAAAA;
30+
border-bottom: 1px solid #000000;
3231
color: #000000;
3332
padding: 4px;
33+
text-align: left;
3434
}
3535

3636
.Differences tbody th {
37-
text-align: right;
3837
background: #AAAAAA;
38+
border-right: 1px solid #000000;
3939
color: #272822;
40-
width: 4em;
40+
font-size: 13px;
4141
padding: 1px 2px;
42-
border-right: 1px solid #000000;
42+
text-align: right;
4343
vertical-align: top;
44-
font-size: 13px;
44+
width: 4em;
4545
}
4646

4747
.Differences td {
48-
padding: 1px 2px;
4948
font-family: Consolas, monospace;
5049
font-size: 13px;
50+
padding: 1px 2px;
5151
}
5252

5353
.Differences .Skipped {
@@ -65,7 +65,7 @@ a, a:visited {
6565
* HTML Side by Side Diff
6666
*/
6767
.DifferencesSideBySide .ChangeInsert td.Left {
68-
background: #008000;
68+
background: #DDFFDD;
6969
}
7070

7171
.DifferencesSideBySide .ChangeInsert td.Right {
@@ -83,7 +83,7 @@ a, a:visited {
8383
}
8484

8585
.DifferencesSideBySide .ChangeReplace .Left {
86-
background: #FFEE99;
86+
background: #FFDD88;
8787
color: #272822;
8888
}
8989

@@ -114,10 +114,12 @@ a, a:visited {
114114
.DifferencesUnified .ChangeReplace .Right,
115115
.DifferencesUnified .ChangeInsert .Right {
116116
background: #DDFFDD;
117+
color: #272822;
117118
}
118119

119120
.DifferencesUnified .ChangeReplace ins {
120121
background: #008000;
122+
color: #272822;
121123
}
122124

123125
.DifferencesUnified .ChangeReplace del {
@@ -128,13 +130,16 @@ a, a:visited {
128130
/*
129131
* HTML Merged Diff
130132
*/
131-
.DifferencesMerged .ChangeReplace .Left,
133+
.DifferencesMerged td.ChangeReplace {
134+
background: #FFDD88;
135+
color: #272822;
136+
}
137+
132138
.DifferencesMerged .ChangeDelete {
133139
background: #FFDDDD;
134140
color: #272822;
135141
}
136142

137-
.DifferencesMerged .ChangeReplace .Right,
138143
.DifferencesMerged .ChangeInsert {
139144
background: #DDFFDD;
140145
color: #272822;
@@ -153,3 +158,7 @@ a, a:visited {
153158
.DifferencesMerged th.ChangeDelete {
154159
background-image: linear-gradient(-45deg, #AAAAAA 0%, #EE9999 100%);
155160
}
161+
162+
.DifferencesMerged th.ChangeReplace {
163+
background-image: linear-gradient(-45deg, #CCCCCC 0%, #FFDD88 100%);
164+
}

example/styles.css

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,44 @@ body {
66
}
77

88
pre {
9-
width: 100%;
109
overflow: auto;
10+
width: 100%;
1111
}
1212

1313
/*
1414
* HTML Renderers - General
1515
*/
1616

1717
.Differences {
18-
width: 100%;
1918
border-collapse: collapse;
2019
border-spacing: 0;
2120
empty-cells: show;
21+
width: 100%;
2222
}
2323

2424
.Differences thead th {
25-
text-align: left;
26-
border-bottom: 1px solid #000000;
2725
background: #AAAAAA;
26+
border-bottom: 1px solid #000000;
2827
color: #000000;
2928
padding: 4px;
29+
text-align: left;
3030
}
3131

3232
.Differences tbody th {
33-
text-align: right;
3433
background: #CCCCCC;
35-
width: 4em;
36-
padding: 1px 2px;
3734
border-right: 1px solid #000000;
38-
vertical-align: top;
3935
font-size: 13px;
36+
padding: 1px 2px;
37+
text-align: right;
38+
vertical-align: top;
39+
width: 4em;
4040
}
4141

4242
.Differences td {
43-
padding: 1px 2px;
44-
font-family: Consolas, monospace;
45-
font-size: 13px;
43+
font-family: Consolas, monospace;
44+
font-size: 13px;
45+
padding: 1px 2px;
46+
vertical-align: top;
4647
}
4748

4849
.Differences .Skipped {
@@ -111,12 +112,14 @@ pre {
111112
/*
112113
* HTML Merged Diff
113114
*/
114-
.DifferencesMerged .ChangeReplace .Left,
115+
.DifferencesMerged td.ChangeReplace {
116+
background: #FFDD88;
117+
}
118+
115119
.DifferencesMerged .ChangeDelete {
116120
background: #FFDDDD;
117121
}
118122

119-
.DifferencesMerged .ChangeReplace .Right,
120123
.DifferencesMerged .ChangeInsert {
121124
background: #DDFFDD;
122125
}
@@ -132,3 +135,7 @@ pre {
132135
.DifferencesMerged th.ChangeDelete {
133136
background-image: linear-gradient(-45deg, #CCCCCC 0%, #EE9999 100%);
134137
}
138+
139+
.DifferencesMerged th.ChangeReplace {
140+
background-image: linear-gradient(-45deg, #CCCCCC 0%, #FFDD88 100%);
141+
}

lib/jblond/Diff/Renderer/Html/Merged.php

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public function generateSkippedLines(): string
112112

113113
return <<<HTML
114114
<tr>
115-
<th class="$headerClass" title="{$this->lastDeleted}">$marker</th>
115+
<th class="$headerClass" title="$this->lastDeleted">$marker</th>
116116
<td class="Skipped">&hellip;</td>
117117
</tr>
118118
HTML;
@@ -125,18 +125,19 @@ public function generateSkippedLines(): string
125125
*/
126126
public function generateLinesEqual(array $changes): string
127127
{
128-
$html = '';
129-
$headerClass = '';
128+
$html = '';
130129

131130
foreach ($changes['base']['lines'] as $lineNo => $line) {
132-
$fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset;
131+
$fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset;
132+
$headerClass = '';
133+
133134
if (!$lineNo && $this->lastDeleted !== null) {
134135
$headerClass = 'ChangeDelete';
135136
}
136137

137138
$html .= <<<HTML
138139
<tr>
139-
<th class="$headerClass" title="{$this->lastDeleted}">$fromLine</th>
140+
<th class="$headerClass" title="$this->lastDeleted">$fromLine</th>
140141
<td>$line</td>
141142
</tr>
142143
HTML;
@@ -153,19 +154,19 @@ public function generateLinesEqual(array $changes): string
153154
*/
154155
public function generateLinesInsert(array $changes): string
155156
{
156-
$html = '';
157-
$headerClass = '';
157+
$html = '';
158158

159159
foreach ($changes['changed']['lines'] as $lineNo => $line) {
160160
$this->lineOffset++;
161-
$toLine = $changes['base']['offset'] + $this->lineOffset;
161+
$toLine = $changes['base']['offset'] + $this->lineOffset;
162+
$headerClass = '';
162163
if (!$lineNo && $this->lastDeleted !== null) {
163164
$headerClass = 'ChangeDelete';
164165
}
165166

166167
$html .= <<<HTML
167168
<tr>
168-
<th class="$headerClass" title="{$this->lastDeleted}">$toLine</th>
169+
<th class="$headerClass" title="$this->lastDeleted">$toLine</th>
169170
<td><ins>$line</ins></td>
170171
</tr>
171172
HTML;
@@ -185,7 +186,7 @@ public function generateLinesDelete(array $changes): string
185186
{
186187
$this->lineOffset -= count($changes['base']['lines']);
187188

188-
$title = "Lines deleted at {$this->options['title2']}:\n";
189+
$title = "Lines of {$this->options['title1']} deleted at {$this->options['title2']}:\n";
189190

190191
foreach ($changes['base']['lines'] as $lineNo => $line) {
191192
$fromLine = $changes['base']['offset'] + $lineNo + 1;
@@ -196,7 +197,7 @@ public function generateLinesDelete(array $changes): string
196197
TEXT;
197198
}
198199

199-
$this->lastDeleted = $title;
200+
$this->lastDeleted = htmlentities($title);
200201

201202
return '';
202203
}
@@ -208,41 +209,68 @@ public function generateLinesDelete(array $changes): string
208209
*/
209210
public function generateLinesReplace(array $changes): string
210211
{
211-
$html = '';
212-
$headerClass = '';
213-
214-
foreach ($changes['base']['lines'] as $lineNo => $line) {
215-
$fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset;
216-
if (!$lineNo && $this->lastDeleted !== null) {
217-
$headerClass = 'ChangeDelete';
212+
$html = '';
213+
$baseLineCount = count($changes['base']['lines']);
214+
$changedLineCount = count($changes['changed']['lines']);
215+
216+
if (count($changes['base']['lines']) == $changedLineCount) {
217+
// Lines of Version 1 are modified at version 2.
218+
foreach ($changes['base']['lines'] as $lineNo => $line) {
219+
$fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset;
220+
221+
// Capture line-parts which are added to the same line at version 2.
222+
$addedParts = [];
223+
preg_match_all('/\x0.*?\x1/', $changes['changed']['lines'][$lineNo], $addedParts, PREG_PATTERN_ORDER);
224+
array_unshift($addedParts[0], '');
225+
226+
// Inline Replacement:
227+
// Concatenate line-parts which are removed at version2 with line-parts which are added at version 2.
228+
$line = preg_replace_callback(
229+
'/\x0.*?\x1/',
230+
function ($removedParts) use ($addedParts) {
231+
$addedPart = str_replace(["\0", "\1"], $this->options['insertMarkers'], next($addedParts[0]));
232+
$removedPart = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $removedParts[0]);
233+
234+
return "$removedPart$addedPart";
235+
},
236+
$line
237+
);
238+
239+
$html .= <<<HTML
240+
<tr>
241+
<th>$fromLine</th>
242+
<td>$line</td>
243+
</tr>
244+
HTML;
218245
}
219246

220-
// Capture added parts.
221-
$addedParts = [];
222-
preg_match_all('/\x0.*?\x1/', $changes['changed']['lines'][$lineNo], $addedParts, PREG_PATTERN_ORDER);
223-
array_unshift($addedParts[0], '');
247+
return $html;
248+
}
224249

225-
// Concatenate removed parts with added parts.
226-
$line = preg_replace_callback(
227-
'/\x0.*?\x1/',
228-
function ($removedParts) use ($addedParts) {
229-
$addedPart = str_replace(["\0", "\1"], $this->options['insertMarkers'], next($addedParts[0]));
230-
$removedPart = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $removedParts[0]);
250+
// More or less lines at version 2. Block of version 1 is replaced by block of version 2.
251+
$title = '';
231252

232-
return "$removedPart$addedPart";
233-
},
234-
$line
235-
);
253+
foreach ($changes['changed']['lines'] as $lineNo => $line) {
254+
$toLine = $changes['changed']['offset'] + $lineNo + 1;
236255

237-
$html .= <<<HTML
256+
if (!$lineNo) {
257+
$title = "Lines replaced at {$this->options['title1']}:\n";
258+
foreach ($changes['base']['lines'] as $baseLineNo => $baseLine) {
259+
$title .= $changes['base']['offset'] + $baseLineNo + 1 . ": $baseLine\n";
260+
}
261+
}
262+
263+
$title = htmlentities($title);
264+
$html .= <<<HTML
238265
<tr>
239-
<th class="$headerClass" title="{$this->lastDeleted}">$fromLine</th>
240-
<td>$line</td>
266+
<th class="ChangeReplace" title="$title">$toLine</th>
267+
<td class="ChangeReplace">$line</td>
241268
</tr>
242269
HTML;
243-
$this->lastDeleted = null;
244270
}
245271

272+
$this->lineOffset = $this->lineOffset + $changedLineCount - $baseLineCount;
273+
246274
return $html;
247275
}
248276

0 commit comments

Comments
 (0)