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