home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / Text / Diff / Renderer.php
Encoding:
PHP Script  |  2015-06-28  |  6.7 KB  |  243 lines

  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 __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.      * PHP4 constructor.
  48.      */
  49.     public function Text_Diff_Renderer( $params = array() ) {
  50.         self::__construct( $params );
  51.     }
  52.  
  53.     /**
  54.      * Get any renderer parameters.
  55.      *
  56.      * @return array  All parameters of this renderer object.
  57.      */
  58.     function getParams()
  59.     {
  60.         $params = array();
  61.         foreach (get_object_vars($this) as $k => $v) {
  62.             if ($k[0] == '_') {
  63.                 $params[substr($k, 1)] = $v;
  64.             }
  65.         }
  66.  
  67.         return $params;
  68.     }
  69.  
  70.     /**
  71.      * Renders a diff.
  72.      *
  73.      * @param Text_Diff $diff  A Text_Diff object.
  74.      *
  75.      * @return string  The formatted output.
  76.      */
  77.     function render($diff)
  78.     {
  79.         $xi = $yi = 1;
  80.         $block = false;
  81.         $context = array();
  82.  
  83.         $nlead = $this->_leading_context_lines;
  84.         $ntrail = $this->_trailing_context_lines;
  85.  
  86.         $output = $this->_startDiff();
  87.  
  88.         $diffs = $diff->getDiff();
  89.         foreach ($diffs as $i => $edit) {
  90.             /* If these are unchanged (copied) lines, and we want to keep
  91.              * leading or trailing context lines, extract them from the copy
  92.              * block. */
  93.             if (is_a($edit, 'Text_Diff_Op_copy')) {
  94.                 /* Do we have any diff blocks yet? */
  95.                 if (is_array($block)) {
  96.                     /* How many lines to keep as context from the copy
  97.                      * block. */
  98.                     $keep = $i == count($diffs) - 1 ? $ntrail : $nlead + $ntrail;
  99.                     if (count($edit->orig) <= $keep) {
  100.                         /* We have less lines in the block than we want for
  101.                          * context => keep the whole block. */
  102.                         $block[] = $edit;
  103.                     } else {
  104.                         if ($ntrail) {
  105.                             /* Create a new block with as many lines as we need
  106.                              * for the trailing context. */
  107.                             $context = array_slice($edit->orig, 0, $ntrail);
  108.                             $block[] = new Text_Diff_Op_copy($context);
  109.                         }
  110.                         /* @todo */
  111.                         $output .= $this->_block($x0, $ntrail + $xi - $x0,
  112.                                                  $y0, $ntrail + $yi - $y0,
  113.                                                  $block);
  114.                         $block = false;
  115.                     }
  116.                 }
  117.                 /* Keep the copy block as the context for the next block. */
  118.                 $context = $edit->orig;
  119.             } else {
  120.                 /* Don't we have any diff blocks yet? */
  121.                 if (!is_array($block)) {
  122.                     /* Extract context lines from the preceding copy block. */
  123.                     $context = array_slice($context, count($context) - $nlead);
  124.                     $x0 = $xi - count($context);
  125.                     $y0 = $yi - count($context);
  126.                     $block = array();
  127.                     if ($context) {
  128.                         $block[] = new Text_Diff_Op_copy($context);
  129.                     }
  130.                 }
  131.                 $block[] = $edit;
  132.             }
  133.  
  134.             if ($edit->orig) {
  135.                 $xi += count($edit->orig);
  136.             }
  137.             if ($edit->final) {
  138.                 $yi += count($edit->final);
  139.             }
  140.         }
  141.  
  142.         if (is_array($block)) {
  143.             $output .= $this->_block($x0, $xi - $x0,
  144.                                      $y0, $yi - $y0,
  145.                                      $block);
  146.         }
  147.  
  148.         return $output . $this->_endDiff();
  149.     }
  150.  
  151.     function _block($xbeg, $xlen, $ybeg, $ylen, &$edits)
  152.     {
  153.         $output = $this->_startBlock($this->_blockHeader($xbeg, $xlen, $ybeg, $ylen));
  154.  
  155.         foreach ($edits as $edit) {
  156.             switch (strtolower(get_class($edit))) {
  157.             case 'text_diff_op_copy':
  158.                 $output .= $this->_context($edit->orig);
  159.                 break;
  160.  
  161.             case 'text_diff_op_add':
  162.                 $output .= $this->_added($edit->final);
  163.                 break;
  164.  
  165.             case 'text_diff_op_delete':
  166.                 $output .= $this->_deleted($edit->orig);
  167.                 break;
  168.  
  169.             case 'text_diff_op_change':
  170.                 $output .= $this->_changed($edit->orig, $edit->final);
  171.                 break;
  172.             }
  173.         }
  174.  
  175.         return $output . $this->_endBlock();
  176.     }
  177.  
  178.     function _startDiff()
  179.     {
  180.         return '';
  181.     }
  182.  
  183.     function _endDiff()
  184.     {
  185.         return '';
  186.     }
  187.  
  188.     function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
  189.     {
  190.         if ($xlen > 1) {
  191.             $xbeg .= ',' . ($xbeg + $xlen - 1);
  192.         }
  193.         if ($ylen > 1) {
  194.             $ybeg .= ',' . ($ybeg + $ylen - 1);
  195.         }
  196.  
  197.         // this matches the GNU Diff behaviour
  198.         if ($xlen && !$ylen) {
  199.             $ybeg--;
  200.         } elseif (!$xlen) {
  201.             $xbeg--;
  202.         }
  203.  
  204.         return $xbeg . ($xlen ? ($ylen ? 'c' : 'd') : 'a') . $ybeg;
  205.     }
  206.  
  207.     function _startBlock($header)
  208.     {
  209.         return $header . "\n";
  210.     }
  211.  
  212.     function _endBlock()
  213.     {
  214.         return '';
  215.     }
  216.  
  217.     function _lines($lines, $prefix = ' ')
  218.     {
  219.         return $prefix . implode("\n$prefix", $lines) . "\n";
  220.     }
  221.  
  222.     function _context($lines)
  223.     {
  224.         return $this->_lines($lines, '  ');
  225.     }
  226.  
  227.     function _added($lines)
  228.     {
  229.         return $this->_lines($lines, '> ');
  230.     }
  231.  
  232.     function _deleted($lines)
  233.     {
  234.         return $this->_lines($lines, '< ');
  235.     }
  236.  
  237.     function _changed($orig, $final)
  238.     {
  239.         return $this->_deleted($orig) . "---\n" . $this->_added($final);
  240.     }
  241.  
  242. }
  243.