/lib/diff/Renderer.php

https://gitlab.com/ElvisAns/tiki · PHP · 208 lines · 147 code · 27 blank · 34 comment · 15 complexity · 67d75f99e28a93b21a3c4eaee3c553b1 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. * $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.5 2004/10/13 09:30:20 jan Exp $
  9. *
  10. * @package Text_Diff
  11. */
  12. class Text_Diff_Renderer
  13. {
  14. /**
  15. * Number of leading context "lines" to preserve.
  16. *
  17. * This should be left at zero for this class, but subclasses may want to
  18. * set this to other values.
  19. */
  20. protected $_leading_context_lines = 0;
  21. /**
  22. * Number of trailing context "lines" to preserve.
  23. *
  24. * This should be left at zero for this class, but subclasses may want to
  25. * set this to other values.
  26. */
  27. protected $_trailing_context_lines = 0;
  28. /**
  29. * Constructor.
  30. */
  31. public function __construct($params = [])
  32. {
  33. foreach ($params as $param => $value) {
  34. $v = '_' . $param;
  35. if (isset($this->$v)) {
  36. $this->$v = $value;
  37. }
  38. }
  39. }
  40. /**
  41. * Renders a diff.
  42. *
  43. * @param Text_Diff $diff A Text_Diff object.
  44. *
  45. * @return string The formatted output.
  46. */
  47. public function render($diff)
  48. {
  49. $xi = $yi = 1;
  50. $block = false;
  51. $context = [];
  52. $nlead = $this->_leading_context_lines;
  53. $ntrail = $this->_trailing_context_lines;
  54. $this->_startDiff();
  55. foreach ($diff->getDiff() as $edit) {
  56. if (is_a($edit, 'Text_Diff_Op_copy')) {
  57. if (is_array($block)) {
  58. if (count($edit->orig) <= $nlead + $ntrail) {
  59. $block[] = $edit;
  60. } else {
  61. if ($ntrail) {
  62. $context = array_slice($edit->orig, 0, $ntrail);
  63. $block[] = new Text_Diff_Op_copy($context);
  64. }
  65. $this->_block(
  66. $x0,
  67. $ntrail + $xi - $x0,
  68. $y0,
  69. $ntrail + $yi - $y0,
  70. $block
  71. );
  72. $block = false;
  73. }
  74. }
  75. $context = $edit->orig;
  76. } else {
  77. if (! is_array($block)) {
  78. $context = array_slice($context, count($context) - $nlead);
  79. $x0 = $xi - count($context);
  80. $y0 = $yi - count($context);
  81. $block = [];
  82. if ($context) {
  83. $block[] = new Text_Diff_Op_copy($context);
  84. }
  85. }
  86. $block[] = $edit;
  87. }
  88. if ($edit->orig) {
  89. $xi += count($edit->orig);
  90. }
  91. if ($edit->final) {
  92. $yi += count($edit->final);
  93. }
  94. }
  95. if (is_array($block)) {
  96. $this->_block(
  97. $x0,
  98. $xi - $x0,
  99. $y0,
  100. $yi - $y0,
  101. $block
  102. );
  103. }
  104. return $this->_endDiff();
  105. }
  106. protected function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
  107. {
  108. $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
  109. foreach ($edits as $edit) {
  110. switch (strtolower(get_class($edit))) {
  111. case 'text_diff_op_copy':
  112. $this->_context($edit->orig);
  113. break;
  114. case 'text_diff_op_add':
  115. $this->_added($edit->final);
  116. break;
  117. case 'text_diff_op_delete':
  118. $this->_deleted($edit->orig);
  119. break;
  120. case 'text_diff_op_change':
  121. $this->_changed($edit->orig, $edit->final);
  122. break;
  123. default:
  124. trigger_error("Unknown edit type", E_USER_ERROR);
  125. }
  126. $this->_endBlock();
  127. }
  128. }
  129. protected function _startDiff()
  130. {
  131. ob_start();
  132. }
  133. protected function _endDiff()
  134. {
  135. $val = ob_get_contents();
  136. ob_end_clean();
  137. return $val;
  138. }
  139. protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
  140. {
  141. if ($xlen > 1) {
  142. $xbeg .= ',' . ($xbeg + $xlen - 1);
  143. }
  144. if ($ylen > 1) {
  145. $ybeg .= ',' . ($ybeg + $ylen - 1);
  146. }
  147. return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
  148. }
  149. protected function _startBlock($header)
  150. {
  151. // TODO: What's this output for? It breaks XML pages
  152. // echo $header . "\n";
  153. }
  154. protected function _endBlock()
  155. {
  156. }
  157. protected function _lines($lines, $prefix = '', $suffix = '', $type = '')
  158. {
  159. foreach ($lines as $line) {
  160. echo "$prefix$line$suffix\n";
  161. }
  162. }
  163. protected function _context($lines)
  164. {
  165. $this->_lines($lines, ' ');
  166. }
  167. protected function _added($lines)
  168. {
  169. $this->_lines($lines, '>');
  170. }
  171. protected function _deleted($lines)
  172. {
  173. $this->_lines($lines, '<');
  174. }
  175. protected function _changed($orig, $final)
  176. {
  177. $this->_deleted($orig);
  178. echo "---\n";
  179. $this->_added($final);
  180. }
  181. }