Spaces:
Sleeping
Sleeping
/** | |
* A class to render Diffs in different formats. | |
* | |
* This class renders the diff in classic diff format. It is intended that | |
* this class be customized via inheritance, to obtain fancier outputs. | |
* | |
* Copyright 2004-2010 The Horde Project (http://www.horde.org/) | |
* | |
* See the enclosed file COPYING for license information (LGPL). If you did | |
* not receive this file, see https://opensource.org/license/lgpl-2-1/. | |
* | |
* @package Text_Diff | |
*/ | |
class Text_Diff_Renderer { | |
/** | |
* Number of leading context "lines" to preserve. | |
* | |
* This should be left at zero for this class, but subclasses may want to | |
* set this to other values. | |
*/ | |
var $_leading_context_lines = 0; | |
/** | |
* Number of trailing context "lines" to preserve. | |
* | |
* This should be left at zero for this class, but subclasses may want to | |
* set this to other values. | |
*/ | |
var $_trailing_context_lines = 0; | |
/** | |
* Constructor. | |
*/ | |
function __construct( $params = array() ) | |
{ | |
foreach ($params as $param => $value) { | |
$v = '_' . $param; | |
if (isset($this->$v)) { | |
$this->$v = $value; | |
} | |
} | |
} | |
/** | |
* PHP4 constructor. | |
*/ | |
public function Text_Diff_Renderer( $params = array() ) { | |
self::__construct( $params ); | |
} | |
/** | |
* Get any renderer parameters. | |
* | |
* @return array All parameters of this renderer object. | |
*/ | |
function getParams() | |
{ | |
$params = array(); | |
foreach (get_object_vars($this) as $k => $v) { | |
if ($k[0] == '_') { | |
$params[substr($k, 1)] = $v; | |
} | |
} | |
return $params; | |
} | |
/** | |
* Renders a diff. | |
* | |
* @param Text_Diff $diff A Text_Diff object. | |
* | |
* @return string The formatted output. | |
*/ | |
function render($diff) | |
{ | |
$xi = $yi = 1; | |
$block = false; | |
$context = array(); | |
$nlead = $this->_leading_context_lines; | |
$ntrail = $this->_trailing_context_lines; | |
$output = $this->_startDiff(); | |
$diffs = $diff->getDiff(); | |
foreach ($diffs as $i => $edit) { | |
/* If these are unchanged (copied) lines, and we want to keep | |
* leading or trailing context lines, extract them from the copy | |
* block. */ | |
if (is_a($edit, 'Text_Diff_Op_copy')) { | |
/* Do we have any diff blocks yet? */ | |
if (is_array($block)) { | |
/* How many lines to keep as context from the copy | |
* block. */ | |
$keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail; | |
if (count($edit->orig) <= $keep) { | |
/* We have less lines in the block than we want for | |
* context => keep the whole block. */ | |
$block[] = $edit; | |
} else { | |
if ($ntrail) { | |
/* Create a new block with as many lines as we need | |
* for the trailing context. */ | |
$context = array_slice($edit->orig, 0, $ntrail); | |
$block[] = new Text_Diff_Op_copy($context); | |
} | |
/* @todo */ | |
$output .= $this->_block($x0, $ntrail + $xi - $x0, | |
$y0, $ntrail + $yi - $y0, | |
$block); | |
$block = false; | |
} | |
} | |
/* Keep the copy block as the context for the next block. */ | |
$context = $edit->orig; | |
} else { | |
/* Don't we have any diff blocks yet? */ | |
if (!is_array($block)) { | |
/* Extract context lines from the preceding copy block. */ | |
$context = array_slice($context, count($context) - $nlead); | |
$x0 = $xi - count($context); | |
$y0 = $yi - count($context); | |
$block = array(); | |
if ($context) { | |
$block[] = new Text_Diff_Op_copy($context); | |
} | |
} | |
$block[] = $edit; | |
} | |
if ($edit->orig) { | |
$xi += count($edit->orig); | |
} | |
if ($edit->final) { | |
$yi += count($edit->final); | |
} | |
} | |
if (is_array($block)) { | |
$output .= $this->_block($x0, $xi - $x0, | |
$y0, $yi - $y0, | |
$block); | |
} | |
return $output . $this->_endDiff(); | |
} | |
function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) | |
{ | |
$output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen)); | |
foreach ($edits as $edit) { | |
switch (strtolower(get_class($edit))) { | |
case 'text_diff_op_copy': | |
$output .= $this->_context($edit->orig); | |
break; | |
case 'text_diff_op_add': | |
$output .= $this->_added($edit->final); | |
break; | |
case 'text_diff_op_delete': | |
$output .= $this->_deleted($edit->orig); | |
break; | |
case 'text_diff_op_change': | |
$output .= $this->_changed($edit->orig, $edit->final); | |
break; | |
} | |
} | |
return $output . $this->_endBlock(); | |
} | |
function _startDiff() | |
{ | |
return ''; | |
} | |
function _endDiff() | |
{ | |
return ''; | |
} | |
function _blockHeader($xbeg, $xlen, $ybeg, $ylen) | |
{ | |
if ($xlen > 1) { | |
$xbeg .= ',' . ($xbeg + $xlen - 1); | |
} | |
if ($ylen > 1) { | |
$ybeg .= ',' . ($ybeg + $ylen - 1); | |
} | |
// this matches the GNU Diff behaviour | |
if ($xlen && !$ylen) { | |
$ybeg--; | |
} elseif (!$xlen) { | |
$xbeg--; | |
} | |
return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg; | |
} | |
function _startBlock($header) | |
{ | |
return $header . "\n"; | |
} | |
function _endBlock() | |
{ | |
return ''; | |
} | |
function _lines($lines, $prefix = ' ') | |
{ | |
return $prefix . implode("\n$prefix", $lines) . "\n"; | |
} | |
function _context($lines) | |
{ | |
return $this->_lines($lines, ' '); | |
} | |
function _added($lines) | |
{ | |
return $this->_lines($lines, '> '); | |
} | |
function _deleted($lines) | |
{ | |
return $this->_lines($lines, '< '); | |
} | |
function _changed($orig, $final) | |
{ | |
return $this->_deleted($orig) . "---\n" . $this->_added($final); | |
} | |
} | |