PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/4.6/includes/PEAR/Text/Diff/Renderer.php

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