balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

inline.php (5535B)


      1 <?php
      2 /**
      3  * "Inline" diff renderer.
      4  *
      5  * Copyright 2004-2010 The Horde Project (http://www.horde.org/)
      6  *
      7  * See the enclosed file COPYING for license information (LGPL). If you did
      8  * not receive this file, see http://opensource.org/licenses/lgpl-license.php.
      9  *
     10  * @author  Ciprian Popovici
     11  * @package Text_Diff
     12  */
     13 
     14 /** Text_Diff_Renderer */
     15 
     16 // WP #7391
     17 require_once dirname(dirname(__FILE__)) . '/Renderer.php';
     18 
     19 /**
     20  * "Inline" diff renderer.
     21  *
     22  * This class renders diffs in the Wiki-style "inline" format.
     23  *
     24  * @author  Ciprian Popovici
     25  * @package Text_Diff
     26  */
     27 class Text_Diff_Renderer_inline extends Text_Diff_Renderer {
     28 
     29     /**
     30      * Number of leading context "lines" to preserve.
     31      *
     32      * @var integer
     33      */
     34     var $_leading_context_lines = 10000;
     35 
     36     /**
     37      * Number of trailing context "lines" to preserve.
     38      *
     39      * @var integer
     40      */
     41     var $_trailing_context_lines = 10000;
     42 
     43     /**
     44      * Prefix for inserted text.
     45      *
     46      * @var string
     47      */
     48     var $_ins_prefix = '<ins>';
     49 
     50     /**
     51      * Suffix for inserted text.
     52      *
     53      * @var string
     54      */
     55     var $_ins_suffix = '</ins>';
     56 
     57     /**
     58      * Prefix for deleted text.
     59      *
     60      * @var string
     61      */
     62     var $_del_prefix = '<del>';
     63 
     64     /**
     65      * Suffix for deleted text.
     66      *
     67      * @var string
     68      */
     69     var $_del_suffix = '</del>';
     70 
     71     /**
     72      * Header for each change block.
     73      *
     74      * @var string
     75      */
     76     var $_block_header = '';
     77 
     78     /**
     79      * Whether to split down to character-level.
     80      *
     81      * @var boolean
     82      */
     83     var $_split_characters = false;
     84 
     85     /**
     86      * What are we currently splitting on? Used to recurse to show word-level
     87      * or character-level changes.
     88      *
     89      * @var string
     90      */
     91     var $_split_level = 'lines';
     92 
     93     function _blockHeader($xbeg, $xlen, $ybeg, $ylen)
     94     {
     95         return $this->_block_header;
     96     }
     97 
     98     function _startBlock($header)
     99     {
    100         return $header;
    101     }
    102 
    103     function _lines($lines, $prefix = ' ', $encode = true)
    104     {
    105         if ($encode) {
    106             array_walk($lines, array(&$this, '_encode'));
    107         }
    108 
    109         if ($this->_split_level == 'lines') {
    110             return implode("\n", $lines) . "\n";
    111         } else {
    112             return implode('', $lines);
    113         }
    114     }
    115 
    116     function _added($lines)
    117     {
    118         array_walk($lines, array(&$this, '_encode'));
    119         $lines[0] = $this->_ins_prefix . $lines[0];
    120         $lines[count($lines) - 1] .= $this->_ins_suffix;
    121         return $this->_lines($lines, ' ', false);
    122     }
    123 
    124     function _deleted($lines, $words = false)
    125     {
    126         array_walk($lines, array(&$this, '_encode'));
    127         $lines[0] = $this->_del_prefix . $lines[0];
    128         $lines[count($lines) - 1] .= $this->_del_suffix;
    129         return $this->_lines($lines, ' ', false);
    130     }
    131 
    132     function _changed($orig, $final)
    133     {
    134         /* If we've already split on characters, just display. */
    135         if ($this->_split_level == 'characters') {
    136             return $this->_deleted($orig)
    137                 . $this->_added($final);
    138         }
    139 
    140         /* If we've already split on words, just display. */
    141         if ($this->_split_level == 'words') {
    142             $prefix = '';
    143             while ($orig[0] !== false && $final[0] !== false &&
    144                    substr($orig[0], 0, 1) == ' ' &&
    145                    substr($final[0], 0, 1) == ' ') {
    146                 $prefix .= substr($orig[0], 0, 1);
    147                 $orig[0] = substr($orig[0], 1);
    148                 $final[0] = substr($final[0], 1);
    149             }
    150             return $prefix . $this->_deleted($orig) . $this->_added($final);
    151         }
    152 
    153         $text1 = implode("\n", $orig);
    154         $text2 = implode("\n", $final);
    155 
    156         /* Non-printing newline marker. */
    157         $nl = "\0";
    158 
    159         if ($this->_split_characters) {
    160             $diff = new Text_Diff('native',
    161                                   array(preg_split('//', $text1),
    162                                         preg_split('//', $text2)));
    163         } else {
    164             /* We want to split on word boundaries, but we need to preserve
    165              * whitespace as well. Therefore we split on words, but include
    166              * all blocks of whitespace in the wordlist. */
    167             $diff = new Text_Diff('native',
    168                                   array($this->_splitOnWords($text1, $nl),
    169                                         $this->_splitOnWords($text2, $nl)));
    170         }
    171 
    172         /* Get the diff in inline format. */
    173         $renderer = new Text_Diff_Renderer_inline
    174             (array_merge($this->getParams(),
    175                          array('split_level' => $this->_split_characters ? 'characters' : 'words')));
    176 
    177         /* Run the diff and get the output. */
    178         return str_replace($nl, "\n", $renderer->render($diff)) . "\n";
    179     }
    180 
    181     function _splitOnWords($string, $newlineEscape = "\n")
    182     {
    183         // Ignore \0; otherwise the while loop will never finish.
    184         $string = str_replace("\0", '', $string);
    185 
    186         $words = array();
    187         $length = strlen($string);
    188         $pos = 0;
    189 
    190         while ($pos < $length) {
    191             // Eat a word with any preceding whitespace.
    192             $spaces = strspn(substr($string, $pos), " \n");
    193             $nextpos = strcspn(substr($string, $pos + $spaces), " \n");
    194             $words[] = str_replace("\n", $newlineEscape, substr($string, $pos, $spaces + $nextpos));
    195             $pos += $spaces + $nextpos;
    196         }
    197 
    198         return $words;
    199     }
    200 
    201     function _encode(&$string)
    202     {
    203         $string = htmlspecialchars($string);
    204     }
    205 
    206 }