run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
6.65 KB
2026-03-11 16:18:51
R W Run
error_log
📄Renderer.php
1<?php
2/**
3 * A class to render Diffs in different formats.
4 *
5 * This class renders the diff in classic diff format. It is intended that
6 * this class be customized via inheritance, to obtain fancier outputs.
7 *
8 * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
9 *
10 * See the enclosed file COPYING for license information (LGPL). If you did
11 * not receive this file, see https://opensource.org/license/lgpl-2-1/.
12 *
13 * @package Text_Diff
14 */
15class Text_Diff_Renderer {
16
17 /**
18 * Number of leading context "lines" to preserve.
19 *
20 * This should be left at zero for this class, but subclasses may want to
21 * set this to other values.
22 */
23 var $_leading_context_lines = 0;
24
25 /**
26 * Number of trailing context "lines" to preserve.
27 *
28 * This should be left at zero for this class, but subclasses may want to
29 * set this to other values.
30 */
31 var $_trailing_context_lines = 0;
32
33 /**
34 * Constructor.
35 */
36 function __construct( $params = array() )
37 {
38 foreach ($params as $param => $value) {
39 $v = '_' . $param;
40 if (isset($this->$v)) {
41 $this->$v = $value;
42 }
43 }
44 }
45
46 /**
47 * PHP4 constructor.
48 */
49 public function Text_Diff_Renderer( $params = array() ) {
50 self::__construct( $params );
51 }
52
53 /**
54 * Get any renderer parameters.
55 *
56 * @return array All parameters of this renderer object.
57 */
58 function getParams()
59 {
60 $params = array();
61 foreach (get_object_vars($this) as $k => $v) {
62 if ($k[0] == '_') {
63 $params[substr($k, 1)] = $v;
64 }
65 }
66
67 return $params;
68 }
69
70 /**
71 * Renders a diff.
72 *
73 * @param Text_Diff $diff A Text_Diff object.
74 *
75 * @return string The formatted output.
76 */
77 function render($diff)
78 {
79 $xi = $yi = 1;
80 $block = false;
81 $context = array();
82
83 $nlead = $this->_leading_context_lines;
84 $ntrail = $this->_trailing_context_lines;
85
86 $output = $this->_startDiff();
87
88 $diffs = $diff->getDiff();
89 foreach ($diffs as $i => $edit) {
90 /* If these are unchanged (copied) lines, and we want to keep
91 * leading or trailing context lines, extract them from the copy
92 * block. */
93 if (is_a($edit, 'Text_Diff_Op_copy')) {
94 /* Do we have any diff blocks yet? */
95 if (is_array($block)) {
96 /* How many lines to keep as context from the copy
97 * block. */
98 $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
99 if (count($edit->orig) <= $keep) {
100 /* We have less lines in the block than we want for
101 * context => keep the whole block. */
102 $block[] = $edit;
103 } else {
104 if ($ntrail) {
105 /* Create a new block with as many lines as we need
106 * for the trailing context. */
107 $context = array_slice($edit->orig, 0, $ntrail);
108 $block[] = new Text_Diff_Op_copy($context);
109 }
110 /* @todo */
111 $output .= $this->_block($x0, $ntrail + $xi - $x0,
112 $y0, $ntrail + $yi - $y0,
113 $block);
114 $block = false;
115 }
116 }
117 /* Keep the copy block as the context for the next block. */
118 $context = $edit->orig;
119 } else {
120 /* Don't we have any diff blocks yet? */
121 if (!is_array($block)) {
122 /* Extract context lines from the preceding copy block. */
123 $context = array_slice($context, count($context) - $nlead);
124 $x0 = $xi - count($context);
125 $y0 = $yi - count($context);
126 $block = array();
127 if ($context) {
128 $block[] = new Text_Diff_Op_copy($context);
129 }
130 }
131 $block[] = $edit;
132 }
133
134 if ($edit->orig) {
135 $xi += count($edit->orig);
136 }
137 if ($edit->final) {
138 $yi += count($edit->final);
139 }
140 }
141
142 if (is_array($block)) {
143 $output .= $this->_block($x0, $xi - $x0,
144 $y0, $yi - $y0,
145 $block);
146 }
147
148 return $output . $this->_endDiff();
149 }
150
151 function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
152 {
153 $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
154
155 foreach ($edits as $edit) {
156 switch (strtolower(get_class($edit))) {
157 case 'text_diff_op_copy':
158 $output .= $this->_context($edit->orig);
159 break;
160
161 case 'text_diff_op_add':
162 $output .= $this->_added($edit->final);
163 break;
164
165 case 'text_diff_op_delete':
166 $output .= $this->_deleted($edit->orig);
167 break;
168
169 case 'text_diff_op_change':
170 $output .= $this->_changed($edit->orig, $edit->final);
171 break;
172 }
173 }
174
175 return $output . $this->_endBlock();
176 }
177
178 function _startDiff()
179 {
180 return '';
181 }
182
183 function _endDiff()
184 {
185 return '';
186 }
187
188 function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
189 {
190 if ($xlen > 1) {
191 $xbeg .= ',' . ($xbeg + $xlen - 1);
192 }
193 if ($ylen > 1) {
194 $ybeg .= ',' . ($ybeg + $ylen - 1);
195 }
196
197 // this matches the GNU Diff behaviour
198 if ($xlen && !$ylen) {
199 $ybeg--;
200 } elseif (!$xlen) {
201 $xbeg--;
202 }
203
204 return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
205 }
206
207 function _startBlock($header)
208 {
209 return $header . "\n";
210 }
211
212 function _endBlock()
213 {
214 return '';
215 }
216
217 function _lines($lines, $prefix = ' ')
218 {
219 return $prefix . implode("\n$prefix", $lines) . "\n";
220 }
221
222 function _context($lines)
223 {
224 return $this->_lines($lines, ' ');
225 }
226
227 function _added($lines)
228 {
229 return $this->_lines($lines, '> ');
230 }
231
232 function _deleted($lines)
233 {
234 return $this->_lines($lines, '< ');
235 }
236
237 function _changed($orig, $final)
238 {
239 return $this->_deleted($orig) . "---\n" . $this->_added($final);
240 }
241
242}
243