From 7d258d93af359eaf6ac5acff74d3b9e934689ffb Mon Sep 17 00:00:00 2001 From: nacin Date: Fri, 19 Feb 2010 01:25:26 +0000 Subject: [PATCH] Update Text_Diff. Props simek. Fixes #9467 git-svn-id: http://svn.automattic.com/wordpress/trunk@13211 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/Text/Diff.php | 42 +++++++++++++-- wp-includes/Text/Diff/Engine/native.php | 7 ++- wp-includes/Text/Diff/Engine/shell.php | 4 +- wp-includes/Text/Diff/Engine/string.php | 30 ++++++++--- wp-includes/Text/Diff/Engine/xdiff.php | 7 +-- wp-includes/Text/Diff/Renderer.php | 4 +- wp-includes/Text/Diff/Renderer/inline.php | 66 +++++++++++++++++------ 7 files changed, 120 insertions(+), 40 deletions(-) diff --git a/wp-includes/Text/Diff.php b/wp-includes/Text/Diff.php index 06d1c6c764..3ba7b4c7ea 100644 --- a/wp-includes/Text/Diff.php +++ b/wp-includes/Text/Diff.php @@ -6,10 +6,8 @@ * The original PHP version of this code was written by Geoffrey T. Dairiki * , and is used/adapted with his permission. * - * $Horde: framework/Text_Diff/Diff.php,v 1.26 2008/01/04 10:07:49 jan Exp $ - * * Copyright 2004 Geoffrey T. Dairiki - * Copyright 2004-2008 The Horde Project (http://www.horde.org/) + * Copyright 2004-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. @@ -65,6 +63,44 @@ class Text_Diff { return $this->_edits; } + /** + * returns the number of new (added) lines in a given diff. + * + * @since Text_Diff 1.1.0 + * + * @return integer The number of new lines + */ + function countAddedLines() + { + $count = 0; + foreach ($this->_edits as $edit) { + if (is_a($edit, 'Text_Diff_Op_add') || + is_a($edit, 'Text_Diff_Op_change')) { + $count += $edit->nfinal(); + } + } + return $count; + } + + /** + * Returns the number of deleted (removed) lines in a given diff. + * + * @since Text_Diff 1.1.0 + * + * @return integer The number of deleted lines + */ + function countDeletedLines() + { + $count = 0; + foreach ($this->_edits as $edit) { + if (is_a($edit, 'Text_Diff_Op_delete') || + is_a($edit, 'Text_Diff_Op_change')) { + $count += $edit->norig(); + } + } + return $count; + } + /** * Computes a reversed diff. * diff --git a/wp-includes/Text/Diff/Engine/native.php b/wp-includes/Text/Diff/Engine/native.php index aa5bca5b04..93eaef220d 100644 --- a/wp-includes/Text/Diff/Engine/native.php +++ b/wp-includes/Text/Diff/Engine/native.php @@ -1,9 +1,8 @@ . The original PHP version of this * code was written by him, and is used/adapted with his permission. * - * Copyright 2004-2008 The Horde Project (http://www.horde.org/) + * Copyright 2004-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. diff --git a/wp-includes/Text/Diff/Engine/shell.php b/wp-includes/Text/Diff/Engine/shell.php index 7e9629f506..faf387032d 100644 --- a/wp-includes/Text/Diff/Engine/shell.php +++ b/wp-includes/Text/Diff/Engine/shell.php @@ -5,9 +5,7 @@ * This class uses the Unix `diff` program via shell_exec to compute the * differences between the two input arrays. * - * $Horde: framework/Text_Diff/Diff/Engine/shell.php,v 1.8 2008/01/04 10:07:50 jan Exp $ - * - * Copyright 2007-2008 The Horde Project (http://www.horde.org/) + * Copyright 2007-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. diff --git a/wp-includes/Text/Diff/Engine/string.php b/wp-includes/Text/Diff/Engine/string.php index 1a0bd3f37f..59eb8adb45 100644 --- a/wp-includes/Text/Diff/Engine/string.php +++ b/wp-includes/Text/Diff/Engine/string.php @@ -10,10 +10,8 @@ * echo $renderer->render($diff); * * - * $Horde: framework/Text_Diff/Diff/Engine/string.php,v 1.7 2008/01/04 10:07:50 jan Exp $ - * * Copyright 2005 Örjan Persson - * Copyright 2005-2008 The Horde Project (http://www.horde.org/) + * Copyright 2005-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. @@ -39,6 +37,19 @@ class Text_Diff_Engine_string { */ function diff($diff, $mode = 'autodetect') { + // Detect line breaks. + $lnbr = "\n"; + if (strpos($diff, "\r\n") !== false) { + $lnbr = "\r\n"; + } elseif (strpos($diff, "\r") !== false) { + $lnbr = "\r"; + } + + // Make sure we have a line break at the EOF. + if (substr($diff, -strlen($lnbr)) != $lnbr) { + $diff .= $lnbr; + } + if ($mode != 'autodetect' && $mode != 'context' && $mode != 'unified') { return PEAR::raiseError('Type of diff is unsupported'); } @@ -48,17 +59,20 @@ class Text_Diff_Engine_string { $unified = strpos($diff, '---'); if ($context === $unified) { return PEAR::raiseError('Type of diff could not be detected'); - } elseif ($context === false || $context === false) { + } elseif ($context === false || $unified === false) { $mode = $context !== false ? 'context' : 'unified'; } else { $mode = $context < $unified ? 'context' : 'unified'; } } - // split by new line and remove the diff header - $diff = explode("\n", $diff); - array_shift($diff); - array_shift($diff); + // Split by new line and remove the diff header, if there is one. + $diff = explode($lnbr, $diff); + if (($mode == 'context' && strpos($diff[0], '***') === 0) || + ($mode == 'unified' && strpos($diff[0], '---') === 0)) { + array_shift($diff); + array_shift($diff); + } if ($mode == 'context') { return $this->parseContextDiff($diff); diff --git a/wp-includes/Text/Diff/Engine/xdiff.php b/wp-includes/Text/Diff/Engine/xdiff.php index a39a4be176..b9f1736045 100644 --- a/wp-includes/Text/Diff/Engine/xdiff.php +++ b/wp-includes/Text/Diff/Engine/xdiff.php @@ -5,9 +5,7 @@ * This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff) * to compute the differences between the two input arrays. * - * $Horde: framework/Text_Diff/Diff/Engine/xdiff.php,v 1.6 2008/01/04 10:07:50 jan Exp $ - * - * Copyright 2004-2008 The Horde Project (http://www.horde.org/) + * Copyright 2004-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. @@ -42,6 +40,9 @@ class Text_Diff_Engine_xdiff { * valid, albeit a little less descriptive and efficient. */ $edits = array(); foreach ($diff as $line) { + if (!strlen($line)) { + continue; + } switch ($line[0]) { case ' ': $edits[] = &new Text_Diff_Op_copy(array(substr($line, 1))); diff --git a/wp-includes/Text/Diff/Renderer.php b/wp-includes/Text/Diff/Renderer.php index 5d226b4e21..922f4c09cc 100644 --- a/wp-includes/Text/Diff/Renderer.php +++ b/wp-includes/Text/Diff/Renderer.php @@ -5,9 +5,7 @@ * This class renders the diff in classic diff format. It is intended that * this class be customized via inheritance, to obtain fancier outputs. * - * $Horde: framework/Text_Diff/Diff/Renderer.php,v 1.21 2008/01/04 10:07:50 jan Exp $ - * - * Copyright 2004-2008 The Horde Project (http://www.horde.org/) + * Copyright 2004-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. diff --git a/wp-includes/Text/Diff/Renderer/inline.php b/wp-includes/Text/Diff/Renderer/inline.php index 1493eaa04e..392bd57cff 100644 --- a/wp-includes/Text/Diff/Renderer/inline.php +++ b/wp-includes/Text/Diff/Renderer/inline.php @@ -2,9 +2,7 @@ /** * "Inline" diff renderer. * - * $Horde: framework/Text_Diff/Diff/Renderer/inline.php,v 1.21 2008/01/04 10:07:51 jan Exp $ - * - * Copyright 2004-2008 The Horde Project (http://www.horde.org/) + * Copyright 2004-2010 The Horde Project (http://www.horde.org/) * * See the enclosed file COPYING for license information (LGPL). If you did * not receive this file, see http://opensource.org/licenses/lgpl-license.php. @@ -30,42 +28,65 @@ class Text_Diff_Renderer_inline extends Text_Diff_Renderer { /** * Number of leading context "lines" to preserve. + * + * @var integer */ var $_leading_context_lines = 10000; /** * Number of trailing context "lines" to preserve. + * + * @var integer */ var $_trailing_context_lines = 10000; /** * Prefix for inserted text. + * + * @var string */ var $_ins_prefix = ''; /** * Suffix for inserted text. + * + * @var string */ var $_ins_suffix = ''; /** * Prefix for deleted text. + * + * @var string */ var $_del_prefix = ''; /** * Suffix for deleted text. + * + * @var string */ var $_del_suffix = ''; /** * Header for each change block. + * + * @var string */ var $_block_header = ''; + /** + * Whether to split down to character-level. + * + * @var boolean + */ + var $_split_characters = false; + /** * What are we currently splitting on? Used to recurse to show word-level - * changes. + * or character-level changes. + * + * @var string */ var $_split_level = 'lines'; @@ -85,10 +106,10 @@ class Text_Diff_Renderer_inline extends Text_Diff_Renderer { array_walk($lines, array(&$this, '_encode')); } - if ($this->_split_level == 'words') { - return implode('', $lines); - } else { + if ($this->_split_level == 'lines') { return implode("\n", $lines) . "\n"; + } else { + return implode('', $lines); } } @@ -110,8 +131,13 @@ class Text_Diff_Renderer_inline extends Text_Diff_Renderer { function _changed($orig, $final) { - /* If we've already split on words, don't try to do so again - just - * display. */ + /* If we've already split on characters, just display. */ + if ($this->_split_level == 'characters') { + return $this->_deleted($orig) + . $this->_added($final); + } + + /* If we've already split on words, just display. */ if ($this->_split_level == 'words') { $prefix = ''; while ($orig[0] !== false && $final[0] !== false && @@ -130,15 +156,23 @@ class Text_Diff_Renderer_inline extends Text_Diff_Renderer { /* Non-printing newline marker. */ $nl = "\0"; - /* We want to split on word boundaries, but we need to - * preserve whitespace as well. Therefore we split on words, - * but include all blocks of whitespace in the wordlist. */ - $diff = new Text_Diff($this->_splitOnWords($text1, $nl), - $this->_splitOnWords($text2, $nl)); + if ($this->_split_characters) { + $diff = new Text_Diff('native', + array(preg_split('//', $text1), + preg_split('//', $text2))); + } else { + /* We want to split on word boundaries, but we need to preserve + * whitespace as well. Therefore we split on words, but include + * all blocks of whitespace in the wordlist. */ + $diff = new Text_Diff('native', + array($this->_splitOnWords($text1, $nl), + $this->_splitOnWords($text2, $nl))); + } /* Get the diff in inline format. */ - $renderer = new Text_Diff_Renderer_inline(array_merge($this->getParams(), - array('split_level' => 'words'))); + $renderer = new Text_Diff_Renderer_inline + (array_merge($this->getParams(), + array('split_level' => $this->_split_characters ? 'characters' : 'words'))); /* Run the diff and get the output. */ return str_replace($nl, "\n", $renderer->render($diff)) . "\n";