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