Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Component\Diff;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Diff\Engine\DiffOpCopy;
|
Chris@0
|
6
|
Chris@0
|
7 /**
|
Chris@0
|
8 * A class to format Diffs
|
Chris@0
|
9 *
|
Chris@0
|
10 * This class formats the diff in classic diff format.
|
Chris@0
|
11 * It is intended that this class be customized via inheritance,
|
Chris@0
|
12 * to obtain fancier outputs.
|
Chris@0
|
13 * @todo document
|
Chris@0
|
14 * @private
|
Chris@0
|
15 * @subpackage DifferenceEngine
|
Chris@0
|
16 */
|
Chris@0
|
17 class DiffFormatter {
|
Chris@0
|
18 /**
|
Chris@0
|
19 * Should a block header be shown?
|
Chris@0
|
20 */
|
Chris@0
|
21 public $show_header = TRUE;
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@0
|
24 * Number of leading context "lines" to preserve.
|
Chris@0
|
25 *
|
Chris@0
|
26 * This should be left at zero for this class, but subclasses
|
Chris@0
|
27 * may want to set this to other values.
|
Chris@0
|
28 */
|
Chris@0
|
29 public $leading_context_lines = 0;
|
Chris@0
|
30
|
Chris@0
|
31 /**
|
Chris@0
|
32 * Number of trailing context "lines" to preserve.
|
Chris@0
|
33 *
|
Chris@0
|
34 * This should be left at zero for this class, but subclasses
|
Chris@0
|
35 * may want to set this to other values.
|
Chris@0
|
36 */
|
Chris@0
|
37 public $trailing_context_lines = 0;
|
Chris@0
|
38
|
Chris@0
|
39 /**
|
Chris@0
|
40 * The line stats.
|
Chris@0
|
41 *
|
Chris@0
|
42 * @var array
|
Chris@0
|
43 */
|
Chris@0
|
44 protected $line_stats = [
|
Chris@0
|
45 'counter' => ['x' => 0, 'y' => 0],
|
Chris@0
|
46 'offset' => ['x' => 0, 'y' => 0],
|
Chris@0
|
47 ];
|
Chris@0
|
48
|
Chris@0
|
49 /**
|
Chris@0
|
50 * Format a diff.
|
Chris@0
|
51 *
|
Chris@0
|
52 * @param \Drupal\Component\Diff\Diff $diff
|
Chris@0
|
53 * A Diff object.
|
Chris@0
|
54 *
|
Chris@0
|
55 * @return string
|
Chris@0
|
56 * The formatted output.
|
Chris@0
|
57 */
|
Chris@0
|
58 public function format(Diff $diff) {
|
Chris@0
|
59 $xi = $yi = 1;
|
Chris@0
|
60 $block = FALSE;
|
Chris@0
|
61 $context = [];
|
Chris@0
|
62
|
Chris@0
|
63 $nlead = $this->leading_context_lines;
|
Chris@0
|
64 $ntrail = $this->trailing_context_lines;
|
Chris@0
|
65
|
Chris@0
|
66 $this->_start_diff();
|
Chris@0
|
67
|
Chris@0
|
68 foreach ($diff->getEdits() as $edit) {
|
Chris@0
|
69 if ($edit->type == 'copy') {
|
Chris@0
|
70 if (is_array($block)) {
|
Chris@0
|
71 if (sizeof($edit->orig) <= $nlead + $ntrail) {
|
Chris@0
|
72 $block[] = $edit;
|
Chris@0
|
73 }
|
Chris@0
|
74 else {
|
Chris@0
|
75 if ($ntrail) {
|
Chris@0
|
76 $context = array_slice($edit->orig, 0, $ntrail);
|
Chris@0
|
77 $block[] = new DiffOpCopy($context);
|
Chris@0
|
78 }
|
Chris@0
|
79 $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
|
Chris@0
|
80 $block = FALSE;
|
Chris@0
|
81 }
|
Chris@0
|
82 }
|
Chris@0
|
83 $context = $edit->orig;
|
Chris@0
|
84 }
|
Chris@0
|
85 else {
|
Chris@0
|
86 if (!is_array($block)) {
|
Chris@0
|
87 $context = array_slice($context, sizeof($context) - $nlead);
|
Chris@0
|
88 $x0 = $xi - sizeof($context);
|
Chris@0
|
89 $y0 = $yi - sizeof($context);
|
Chris@0
|
90 $block = [];
|
Chris@0
|
91 if ($context) {
|
Chris@0
|
92 $block[] = new DiffOpCopy($context);
|
Chris@0
|
93 }
|
Chris@0
|
94 }
|
Chris@0
|
95 $block[] = $edit;
|
Chris@0
|
96 }
|
Chris@0
|
97
|
Chris@0
|
98 if ($edit->orig) {
|
Chris@0
|
99 $xi += sizeof($edit->orig);
|
Chris@0
|
100 }
|
Chris@0
|
101 if ($edit->closing) {
|
Chris@0
|
102 $yi += sizeof($edit->closing);
|
Chris@0
|
103 }
|
Chris@0
|
104 }
|
Chris@0
|
105
|
Chris@0
|
106 if (is_array($block)) {
|
Chris@0
|
107 $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
|
Chris@0
|
108 }
|
Chris@0
|
109 $end = $this->_end_diff();
|
Chris@0
|
110
|
Chris@0
|
111 if (!empty($xi)) {
|
Chris@0
|
112 $this->line_stats['counter']['x'] += $xi;
|
Chris@0
|
113 }
|
Chris@0
|
114 if (!empty($yi)) {
|
Chris@0
|
115 $this->line_stats['counter']['y'] += $yi;
|
Chris@0
|
116 }
|
Chris@0
|
117
|
Chris@0
|
118 return $end;
|
Chris@0
|
119 }
|
Chris@0
|
120
|
Chris@0
|
121 protected function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) {
|
Chris@0
|
122 $this->_start_block($this->_block_header($xbeg, $xlen, $ybeg, $ylen));
|
Chris@0
|
123 foreach ($edits as $edit) {
|
Chris@0
|
124 if ($edit->type == 'copy') {
|
Chris@0
|
125 $this->_context($edit->orig);
|
Chris@0
|
126 }
|
Chris@0
|
127 elseif ($edit->type == 'add') {
|
Chris@0
|
128 $this->_added($edit->closing);
|
Chris@0
|
129 }
|
Chris@0
|
130 elseif ($edit->type == 'delete') {
|
Chris@0
|
131 $this->_deleted($edit->orig);
|
Chris@0
|
132 }
|
Chris@0
|
133 elseif ($edit->type == 'change') {
|
Chris@0
|
134 $this->_changed($edit->orig, $edit->closing);
|
Chris@0
|
135 }
|
Chris@0
|
136 else {
|
Chris@0
|
137 trigger_error('Unknown edit type', E_USER_ERROR);
|
Chris@0
|
138 }
|
Chris@0
|
139 }
|
Chris@0
|
140 $this->_end_block();
|
Chris@0
|
141 }
|
Chris@0
|
142
|
Chris@0
|
143 protected function _start_diff() {
|
Chris@0
|
144 ob_start();
|
Chris@0
|
145 }
|
Chris@0
|
146
|
Chris@0
|
147 protected function _end_diff() {
|
Chris@0
|
148 $val = ob_get_contents();
|
Chris@0
|
149 ob_end_clean();
|
Chris@0
|
150 return $val;
|
Chris@0
|
151 }
|
Chris@0
|
152
|
Chris@0
|
153 protected function _block_header($xbeg, $xlen, $ybeg, $ylen) {
|
Chris@0
|
154 if ($xlen > 1) {
|
Chris@0
|
155 $xbeg .= "," . ($xbeg + $xlen - 1);
|
Chris@0
|
156 }
|
Chris@0
|
157 if ($ylen > 1) {
|
Chris@0
|
158 $ybeg .= "," . ($ybeg + $ylen - 1);
|
Chris@0
|
159 }
|
Chris@0
|
160
|
Chris@0
|
161 return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
|
Chris@0
|
162 }
|
Chris@0
|
163
|
Chris@0
|
164 protected function _start_block($header) {
|
Chris@0
|
165 if ($this->show_header) {
|
Chris@0
|
166 echo $header . "\n";
|
Chris@0
|
167 }
|
Chris@0
|
168 }
|
Chris@0
|
169
|
Chris@0
|
170 protected function _end_block() {
|
Chris@0
|
171 }
|
Chris@0
|
172
|
Chris@0
|
173 protected function _lines($lines, $prefix = ' ') {
|
Chris@0
|
174 foreach ($lines as $line) {
|
Chris@0
|
175 echo "$prefix $line\n";
|
Chris@0
|
176 }
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@0
|
179 protected function _context($lines) {
|
Chris@0
|
180 $this->_lines($lines);
|
Chris@0
|
181 }
|
Chris@0
|
182
|
Chris@0
|
183 protected function _added($lines) {
|
Chris@0
|
184 $this->_lines($lines, '>');
|
Chris@0
|
185 }
|
Chris@0
|
186
|
Chris@0
|
187 protected function _deleted($lines) {
|
Chris@0
|
188 $this->_lines($lines, '<');
|
Chris@0
|
189 }
|
Chris@0
|
190
|
Chris@0
|
191 protected function _changed($orig, $closing) {
|
Chris@0
|
192 $this->_deleted($orig);
|
Chris@0
|
193 echo "---\n";
|
Chris@0
|
194 $this->_added($closing);
|
Chris@0
|
195 }
|
Chris@0
|
196
|
Chris@0
|
197 }
|