3
* A class to render Diffs in different formats.
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.
8
* Copyright 2004-2010 The Horde Project (http://www.horde.org/)
10
* See the enclosed file COPYING for license information (LGPL). If you did
11
* not receive this file, see http://opensource.org/licenses/lgpl-license.php.
15
class Text_Diff_Renderer {
18
* Number of leading context "lines" to preserve.
20
* This should be left at zero for this class, but subclasses may want to
21
* set this to other values.
23
var $_leading_context_lines = 0;
26
* Number of trailing context "lines" to preserve.
28
* This should be left at zero for this class, but subclasses may want to
29
* set this to other values.
31
var $_trailing_context_lines = 0;
36
function Text_Diff_Renderer($params = array())
38
foreach ($params as $param => $value) {
40
if (isset($this->$v)) {
47
* Get any renderer parameters.
49
* @return array All parameters of this renderer object.
54
foreach (get_object_vars($this) as $k => $v) {
56
$params[substr($k, 1)] = $v;
66
* @param Text_Diff $diff A Text_Diff object.
68
* @return string The formatted output.
70
function render($diff)
76
$nlead = $this->_leading_context_lines;
77
$ntrail = $this->_trailing_context_lines;
79
$output = $this->_startDiff();
81
$diffs = $diff->getDiff();
82
foreach ($diffs as $i => $edit) {
83
/* If these are unchanged (copied) lines, and we want to keep
84
* leading or trailing context lines, extract them from the copy
86
if (is_a($edit, 'Text_Diff_Op_copy')) {
87
/* Do we have any diff blocks yet? */
88
if (is_array($block)) {
89
/* How many lines to keep as context from the copy
91
$keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
92
if (count($edit->orig) <= $keep) {
93
/* We have less lines in the block than we want for
94
* context => keep the whole block. */
98
/* Create a new block with as many lines as we need
99
* for the trailing context. */
100
$context = array_slice($edit->orig, 0, $ntrail);
101
$block[] = new Text_Diff_Op_copy($context);
104
$output .= $this->_block($x0, $ntrail + $xi - $x0,
105
$y0, $ntrail + $yi - $y0,
110
/* Keep the copy block as the context for the next block. */
111
$context = $edit->orig;
113
/* Don't we have any diff blocks yet? */
114
if (!is_array($block)) {
115
/* Extract context lines from the preceding copy block. */
116
$context = array_slice($context, count($context) - $nlead);
117
$x0 = $xi - count($context);
118
$y0 = $yi - count($context);
121
$block[] = new Text_Diff_Op_copy($context);
128
$xi += count($edit->orig);
131
$yi += count($edit->final);
135
if (is_array($block)) {
136
$output .= $this->_block($x0, $xi - $x0,
141
return $output . $this->_endDiff();
144
function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
146
$output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
148
foreach ($edits as $edit) {
149
switch (strtolower(get_class($edit))) {
150
case 'text_diff_op_copy':
151
$output .= $this->_context($edit->orig);
154
case 'text_diff_op_add':
155
$output .= $this->_added($edit->final);
158
case 'text_diff_op_delete':
159
$output .= $this->_deleted($edit->orig);
162
case 'text_diff_op_change':
163
$output .= $this->_changed($edit->orig, $edit->final);
168
return $output . $this->_endBlock();
171
function _startDiff()
181
function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
184
$xbeg .= ',' . ($xbeg + $xlen - 1);
187
$ybeg .= ',' . ($ybeg + $ylen - 1);
190
// this matches the GNU Diff behaviour
191
if ($xlen && !$ylen) {
197
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
200
function _startBlock($header)
202
return $header . "\n";
210
function _lines($lines, $prefix = ' ')
212
return $prefix . implode("\n$prefix", $lines) . "\n";
215
function _context($lines)
217
return $this->_lines($lines, ' ');
220
function _added($lines)
222
return $this->_lines($lines, '> ');
225
function _deleted($lines)
227
return $this->_lines($lines, '< ');
230
function _changed($orig, $final)
232
return $this->_deleted($orig) . "---\n" . $this->_added($final);