includes/diffengine/Renderer.php
changeset 1 fe660c52c48f
child 1227 bdac73ed481e
equal deleted inserted replaced
0:902822492a68 1:fe660c52c48f
       
     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.12 2005/12/16 11:07:33 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     var $_leading_context_lines = 0;
       
    21 
       
    22     /**
       
    23      * Number of trailing context "lines" to preserve.
       
    24      *
       
    25      * This should be left at zero for this class, but subclasses may want to
       
    26      * set this to other values.
       
    27      */
       
    28     var $_trailing_context_lines = 0;
       
    29 
       
    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     /**
       
    44      * Get any renderer parameters.
       
    45      *
       
    46      * @return array  All parameters of this renderer object.
       
    47      */
       
    48     function getParams()
       
    49     {
       
    50         $params = array();
       
    51         foreach (get_object_vars($this) as $k => $v) {
       
    52             if ($k[0] == '_') {
       
    53                 $params[substr($k, 1)] = $v;
       
    54             }
       
    55         }
       
    56 
       
    57         return $params;
       
    58     }
       
    59 
       
    60     /**
       
    61      * Renders a diff.
       
    62      *
       
    63      * @param Text_Diff $diff  A Text_Diff object.
       
    64      *
       
    65      * @return string  The formatted output.
       
    66      */
       
    67     function render($diff)
       
    68     {
       
    69         $xi = $yi = 1;
       
    70         $block = false;
       
    71         $context = array();
       
    72 
       
    73         $nlead = $this->_leading_context_lines;
       
    74         $ntrail = $this->_trailing_context_lines;
       
    75 
       
    76         $output = $this->_startDiff();
       
    77 
       
    78         $diffs = $diff->getDiff();
       
    79         foreach ($diffs as $i => $edit) {
       
    80             if (is_a($edit, 'Text_Diff_Op_copy')) {
       
    81                 if (is_array($block)) {
       
    82                     $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
       
    83                     if (count($edit->orig) <= $keep) {
       
    84                         $block[] = $edit;
       
    85                     } else {
       
    86                         if ($ntrail) {
       
    87                             $context = array_slice($edit->orig, 0, $ntrail);
       
    88                             $block[] = &new Text_Diff_Op_copy($context);
       
    89                         }
       
    90                         $output .= $this->_block($x0, $ntrail + $xi - $x0,
       
    91                                                  $y0, $ntrail + $yi - $y0,
       
    92                                                  $block);
       
    93                         $block = false;
       
    94                     }
       
    95                 }
       
    96                 $context = $edit->orig;
       
    97             } else {
       
    98                 if (!is_array($block)) {
       
    99                     $context = array_slice($context, count($context) - $nlead);
       
   100                     $x0 = $xi - count($context);
       
   101                     $y0 = $yi - count($context);
       
   102                     $block = array();
       
   103                     if ($context) {
       
   104                         $block[] = &new Text_Diff_Op_copy($context);
       
   105                     }
       
   106                 }
       
   107                 $block[] = $edit;
       
   108             }
       
   109 
       
   110             if ($edit->orig) {
       
   111                 $xi += count($edit->orig);
       
   112             }
       
   113             if ($edit->final) {
       
   114                 $yi += count($edit->final);
       
   115             }
       
   116         }
       
   117 
       
   118         if (is_array($block)) {
       
   119             $output .= $this->_block($x0, $xi - $x0,
       
   120                                      $y0, $yi - $y0,
       
   121                                      $block);
       
   122         }
       
   123 
       
   124         return $output . $this->_endDiff();
       
   125     }
       
   126 
       
   127     function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
       
   128     {
       
   129         $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
       
   130 
       
   131         foreach ($edits as $edit) {
       
   132             switch (strtolower(get_class($edit))) {
       
   133             case 'text_diff_op_copy':
       
   134                 $output .= $this->_context($edit->orig);
       
   135                 break;
       
   136 
       
   137             case 'text_diff_op_add':
       
   138                 $output .= $this->_added($edit->final);
       
   139                 break;
       
   140 
       
   141             case 'text_diff_op_delete':
       
   142                 $output .= $this->_deleted($edit->orig);
       
   143                 break;
       
   144 
       
   145             case 'text_diff_op_change':
       
   146                 $output .= $this->_changed($edit->orig, $edit->final);
       
   147                 break;
       
   148             }
       
   149         }
       
   150 
       
   151         return $output . $this->_endBlock();
       
   152     }
       
   153 
       
   154     function _startDiff()
       
   155     {
       
   156         return '';
       
   157     }
       
   158 
       
   159     function _endDiff()
       
   160     {
       
   161         return '';
       
   162     }
       
   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 
       
   173         return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
       
   174     }
       
   175 
       
   176     function _startBlock($header)
       
   177     {
       
   178         return $header . "\n";
       
   179     }
       
   180 
       
   181     function _endBlock()
       
   182     {
       
   183         return '';
       
   184     }
       
   185 
       
   186     function _lines($lines, $prefix = ' ')
       
   187     {
       
   188         return $prefix . implode("\n$prefix", $lines) . "\n";
       
   189     }
       
   190 
       
   191     function _context($lines)
       
   192     {
       
   193         return $this->_lines($lines);
       
   194     }
       
   195 
       
   196     function _added($lines)
       
   197     {
       
   198         return $this->_lines($lines, '>');
       
   199     }
       
   200 
       
   201     function _deleted($lines)
       
   202     {
       
   203         return $this->_lines($lines, '<');
       
   204     }
       
   205 
       
   206     function _changed($orig, $final)
       
   207     {
       
   208         return $this->_deleted($orig) . "---\n" . $this->_added($final);
       
   209     }
       
   210 
       
   211 }