Character.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. /**
  3. * "Character" diff renderer.
  4. *
  5. * This class renders the diff in "Character" format
  6. *
  7. * @package Text_Diff
  8. */
  9. class Horde_Text_Diff_Renderer_Character extends Horde_Text_Diff_Renderer {
  10. public $orig;
  11. public $final;
  12. public function __construct($context_lines = 0) {
  13. parent::__construct();
  14. $this->_leading_context_lines = $context_lines;
  15. $this->_trailing_context_lines = $context_lines;
  16. $this->orig = "";
  17. $this->final = "";
  18. }
  19. /**
  20. * Renders a diff.
  21. *
  22. * @param Text_Diff $diff A Text_Diff object.
  23. *
  24. * @return string The formatted output.
  25. */
  26. public function render($diff) {
  27. $xi = $yi = 1;
  28. $block = false;
  29. $context = [];
  30. $nlead = $this->_leading_context_lines;
  31. $ntrail = $this->_trailing_context_lines;
  32. $diffs = $diff->getDiff();
  33. foreach ($diffs as $i => $edit) {
  34. /* If these are unchanged (copied) lines, and we want to keep
  35. * leading or trailing context lines, extract them from the copy
  36. * block. */
  37. if (is_a($edit, 'Text_Diff_Op_copy')) {
  38. /* Do we have any diff blocks yet? */
  39. if (is_array($block)) {
  40. /* How many lines to keep as context from the copy
  41. * block. */
  42. $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
  43. if (count($edit->orig) <= $keep) {
  44. /* We have less lines in the block than we want for
  45. * context => keep the whole block. */
  46. $block[] = $edit;
  47. } else {
  48. if ($ntrail) {
  49. /* Create a new block with as many lines as we need
  50. * for the trailing context. */
  51. $context = array_slice($edit->orig, 0, $ntrail);
  52. $block[] = &new Text_Diff_Op_copy($context);
  53. }
  54. /* @todo */
  55. $output = $this->_block($x0, $ntrail + $xi - $x0, $y0, $ntrail + $yi - $y0, $block);
  56. $block = false;
  57. }
  58. }
  59. /* Keep the copy block as the context for the next block. */
  60. $context = $edit->orig;
  61. } else {
  62. /* Don't we have any diff blocks yet? */
  63. if (!is_array($block)) {
  64. /* Extract context lines from the preceding copy block. */
  65. $context = array_slice($context, count($context) - (int)$nlead);
  66. $x0 = $xi - count($context);
  67. $y0 = $yi - count($context);
  68. $block = [];
  69. if ($context) {
  70. $block[] = &new Text_Diff_Op_copy($context);
  71. }
  72. }
  73. $block[] = $edit;
  74. }
  75. if ($edit->orig) {
  76. $xi += count($edit->orig);
  77. }
  78. if ($edit->final) {
  79. $yi += count($edit->final);
  80. }
  81. }
  82. if (is_array($block)) {
  83. $output = $this->_block($x0, $xi - $x0, $y0, $yi - $y0, $block);
  84. }
  85. return $output;
  86. }
  87. protected function _startDiff() {
  88. }
  89. protected function _endDiff() {
  90. return [$this->orig, $this->final];
  91. }
  92. protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen) {
  93. }
  94. protected function _startBlock($header) {
  95. echo $header;
  96. }
  97. protected function _endBlock() {
  98. }
  99. protected function _lines($type, $lines, $prefix = '') {
  100. if ($type == 'context') {
  101. foreach ($lines as $line) {
  102. $this->orig .= $line;
  103. $this->final .= $line;
  104. }
  105. } elseif ($type == 'added' || $type == 'change-added') {
  106. $l = "";
  107. foreach ($lines as $line) {
  108. $l .= $line;
  109. }
  110. if (!empty($l))
  111. $this->final .= '<span class="diffchar">' . $l . "</span>";
  112. } elseif ($type == 'deleted' || $type == 'change-deleted') {
  113. $l = "";
  114. foreach ($lines as $line)
  115. $l .= $line;
  116. if (!empty($l))
  117. $this->orig .= '<span class="diffchar">' . $l . "</span>";
  118. }
  119. }
  120. protected function _block($xbeg, $xlen, $ybeg, $ylen, &$edits) {
  121. foreach ($edits as $edit) {
  122. switch (strtolower(get_class($edit))) {
  123. case 'text_diff_op_copy':
  124. $this->_context($edit->orig);
  125. break;
  126. case 'text_diff_op_add':
  127. $this->_added($edit->final);
  128. break;
  129. case 'text_diff_op_delete':
  130. $this->_deleted($edit->orig);
  131. break;
  132. case 'text_diff_op_change':
  133. $this->_changed($edit->orig, $edit->final);
  134. break;
  135. }
  136. }
  137. return [$this->orig, $this->final];
  138. }
  139. protected function _context($lines) {
  140. $this->_lines('context', $lines);
  141. }
  142. protected function _added($lines, $changemode = false) {
  143. if ($changemode) {
  144. $this->_lines('change-added', $lines, '+');
  145. } else {
  146. $this->_lines('added', $lines, '+');
  147. }
  148. }
  149. protected function _deleted($lines, $changemode = false) {
  150. if ($changemode) {
  151. $this->_lines('change-deleted', $lines, '-');
  152. } else {
  153. $this->_lines('deleted', $lines, '-');
  154. }
  155. }
  156. protected function _changed($orig, $final) {
  157. $this->_deleted($orig, true);
  158. $this->_added($final, true);
  159. }
  160. }