/wp-includes/Text/Diff/Renderer.php

https://bitbucket.org/jstroschein/wordpress-3.5.1-clean · PHP · 235 lines · 149 code · 31 blank · 55 comment · 20 complexity · 8fb9dc67143f8780f65762e97b0cf1c4 MD5 · raw file

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