Overview

Packages

  • Text
    • Diff

Classes

  • Horde_Text_Diff
  • Horde_Text_Diff_Engine_Native
  • Horde_Text_Diff_Engine_Shell
  • Horde_Text_Diff_Engine_String
  • Horde_Text_Diff_Engine_Xdiff
  • Horde_Text_Diff_Exception
  • Horde_Text_Diff_Mapped
  • Horde_Text_Diff_Op_Add
  • Horde_Text_Diff_Op_Base
  • Horde_Text_Diff_Op_Change
  • Horde_Text_Diff_Op_Copy
  • Horde_Text_Diff_Op_Delete
  • Horde_Text_Diff_Renderer
  • Horde_Text_Diff_Renderer_Context
  • Horde_Text_Diff_Renderer_Inline
  • Horde_Text_Diff_Renderer_Unified
  • Horde_Text_Diff_ThreeWay
  • Horde_Text_Diff_ThreeWay_BlockBuilder
  • Horde_Text_Diff_ThreeWay_Op_Base
  • Horde_Text_Diff_ThreeWay_Op_Copy
  • Overview
  • Package
  • Class
  • Tree
  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-2012 Horde LLC (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://www.horde.org/licenses/lgpl21.
 12:  *
 13:  * @package Text_Diff
 14:  */
 15: class Horde_Text_Diff_Renderer
 16: {
 17:     /**
 18:      * Number of leading context "lines" to preserve.
 19:      *
 20:      * This should be left at zero for this class, but subclasses may want to
 21:      * set this to other values.
 22:      */
 23:     protected $_leading_context_lines = 0;
 24: 
 25:     /**
 26:      * Number of trailing context "lines" to preserve.
 27:      *
 28:      * This should be left at zero for this class, but subclasses may want to
 29:      * set this to other values.
 30:      */
 31:     protected $_trailing_context_lines = 0;
 32: 
 33:     /**
 34:      * Constructor.
 35:      */
 36:     public function __construct($params = array())
 37:     {
 38:         foreach ($params as $param => $value) {
 39:             $v = '_' . $param;
 40:             if (isset($this->$v)) {
 41:                 $this->$v = $value;
 42:             }
 43:         }
 44:     }
 45: 
 46:     /**
 47:      * Get any renderer parameters.
 48:      *
 49:      * @return array  All parameters of this renderer object.
 50:      */
 51:     public 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: 
 60:         return $params;
 61:     }
 62: 
 63:     /**
 64:      * Renders a diff.
 65:      *
 66:      * @param Horde_Text_Diff $diff  A Horde_Text_Diff object.
 67:      *
 68:      * @return string  The formatted output.
 69:      */
 70:     public function render($diff)
 71:     {
 72:         $xi = $yi = 1;
 73:         $block = false;
 74:         $context = array();
 75: 
 76:         $nlead = $this->_leading_context_lines;
 77:         $ntrail = $this->_trailing_context_lines;
 78: 
 79:         $output = $this->_startDiff();
 80: 
 81:         $diffs = $diff->getDiff();
 82:         foreach ($diffs as $i => $edit) {
 83:             /* If these are unchanged (copied) lines, and we want to keep
 84:              * leading or trailing context lines, extract them from the copy
 85:              * block. */
 86:             if ($edit instanceof Horde_Text_Diff_Op_Copy) {
 87:                 /* Do we have any diff blocks yet? */
 88:                 if (is_array($block)) {
 89:                     /* How many lines to keep as context from the copy
 90:                      * block. */
 91:                     $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
 92:                     if (count($edit->orig) <= $keep) {
 93:                         /* We have less lines in the block than we want for
 94:                          * context => keep the whole block. */
 95:                         $block[] = $edit;
 96:                     } else {
 97:                         if ($ntrail) {
 98:                             /* Create a new block with as many lines as we need
 99:                              * for the trailing context. */
100:                             $context = array_slice($edit->orig, 0, $ntrail);
101:                             $block[] = new Horde_Text_Diff_Op_Copy($context);
102:                         }
103:                         /* @todo */
104:                         $output .= $this->_block($x0, $ntrail + $xi - $x0,
105:                                                  $y0, $ntrail + $yi - $y0,
106:                                                  $block);
107:                         $block = false;
108:                     }
109:                 }
110:                 /* Keep the copy block as the context for the next block. */
111:                 $context = $edit->orig;
112:             } else {
113:                 /* Don't we have any diff blocks yet? */
114:                 if (!is_array($block)) {
115:                     /* Extract context lines from the preceding copy block. */
116:                     $context = array_slice($context, count($context) - $nlead);
117:                     $x0 = $xi - count($context);
118:                     $y0 = $yi - count($context);
119:                     $block = array();
120:                     if ($context) {
121:                         $block[] = new Horde_Text_Diff_Op_Copy($context);
122:                     }
123:                 }
124:                 $block[] = $edit;
125:             }
126: 
127:             if ($edit->orig) {
128:                 $xi += count($edit->orig);
129:             }
130:             if ($edit->final) {
131:                 $yi += count($edit->final);
132:             }
133:         }
134: 
135:         if (is_array($block)) {
136:             $output .= $this->_block($x0, $xi - $x0,
137:                                      $y0, $yi - $y0,
138:                                      $block);
139:         }
140: 
141:         return $output . $this->_endDiff();
142:     }
143: 
144:     protected function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
145:     {
146:         $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
147: 
148:         foreach ($edits as $edit) {
149:             switch (get_class($edit)) {
150:             case 'Horde_Text_Diff_Op_Copy':
151:                 $output .= $this->_context($edit->orig);
152:                 break;
153: 
154:             case 'Horde_Text_Diff_Op_Add':
155:                 $output .= $this->_added($edit->final);
156:                 break;
157: 
158:             case 'Horde_Text_Diff_Op_Delete':
159:                 $output .= $this->_deleted($edit->orig);
160:                 break;
161: 
162:             case 'Horde_Text_Diff_Op_Change':
163:                 $output .= $this->_changed($edit->orig, $edit->final);
164:                 break;
165:             }
166:         }
167: 
168:         return $output . $this->_endBlock();
169:     }
170: 
171:     protected function _startDiff()
172:     {
173:         return '';
174:     }
175: 
176:     protected function _endDiff()
177:     {
178:         return '';
179:     }
180: 
181:     protected function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
182:     {
183:         if ($xlen > 1) {
184:             $xbeg .= ',' . ($xbeg + $xlen - 1);
185:         }
186:         if ($ylen > 1) {
187:             $ybeg .= ',' . ($ybeg + $ylen - 1);
188:         }
189: 
190:         // this matches the GNU Diff behaviour
191:         if ($xlen && !$ylen) {
192:             $ybeg--;
193:         } elseif (!$xlen) {
194:             $xbeg--;
195:         }
196: 
197:         return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
198:     }
199: 
200:     protected function _startBlock($header)
201:     {
202:         return $header . "\n";
203:     }
204: 
205:     protected function _endBlock()
206:     {
207:         return '';
208:     }
209: 
210:     protected function _lines($lines, $prefix = ' ')
211:     {
212:         return $prefix . implode("\n$prefix", $lines) . "\n";
213:     }
214: 
215:     protected function _context($lines)
216:     {
217:         return $this->_lines($lines, '  ');
218:     }
219: 
220:     protected function _added($lines)
221:     {
222:         return $this->_lines($lines, '> ');
223:     }
224: 
225:     protected function _deleted($lines)
226:     {
227:         return $this->_lines($lines, '< ');
228:     }
229: 
230:     protected function _changed($orig, $final)
231:     {
232:         return $this->_deleted($orig) . "---\n" . $this->_added($final);
233:     }
234: }
235: 
API documentation generated by ApiGen