wp/wp-includes/Text/Diff/Renderer.php
changeset 0 d970ebf37754
child 7 cf61fcea0001
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     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-2010 The Horde Project (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://opensource.org/licenses/lgpl-license.php.
       
    12  *
       
    13  * @package Text_Diff
       
    14  */
       
    15 class 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     var $_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     var $_trailing_context_lines = 0;
       
    32 
       
    33     /**
       
    34      * Constructor.
       
    35      */
       
    36     function Text_Diff_Renderer($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     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 Text_Diff $diff  A Text_Diff object.
       
    67      *
       
    68      * @return string  The formatted output.
       
    69      */
       
    70     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 (is_a($edit, '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 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 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     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 (strtolower(get_class($edit))) {
       
   150             case 'text_diff_op_copy':
       
   151                 $output .= $this->_context($edit->orig);
       
   152                 break;
       
   153 
       
   154             case 'text_diff_op_add':
       
   155                 $output .= $this->_added($edit->final);
       
   156                 break;
       
   157 
       
   158             case 'text_diff_op_delete':
       
   159                 $output .= $this->_deleted($edit->orig);
       
   160                 break;
       
   161 
       
   162             case '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     function _startDiff()
       
   172     {
       
   173         return '';
       
   174     }
       
   175 
       
   176     function _endDiff()
       
   177     {
       
   178         return '';
       
   179     }
       
   180 
       
   181     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     function _startBlock($header)
       
   201     {
       
   202         return $header . "\n";
       
   203     }
       
   204 
       
   205     function _endBlock()
       
   206     {
       
   207         return '';
       
   208     }
       
   209 
       
   210     function _lines($lines, $prefix = ' ')
       
   211     {
       
   212         return $prefix . implode("\n$prefix", $lines) . "\n";
       
   213     }
       
   214 
       
   215     function _context($lines)
       
   216     {
       
   217         return $this->_lines($lines, '  ');
       
   218     }
       
   219 
       
   220     function _added($lines)
       
   221     {
       
   222         return $this->_lines($lines, '> ');
       
   223     }
       
   224 
       
   225     function _deleted($lines)
       
   226     {
       
   227         return $this->_lines($lines, '< ');
       
   228     }
       
   229 
       
   230     function _changed($orig, $final)
       
   231     {
       
   232         return $this->_deleted($orig) . "---\n" . $this->_added($final);
       
   233     }
       
   234 
       
   235 }