From 7efe41e227eae44f3ad443905957f9081cf05e3b Mon Sep 17 00:00:00 2001 From: Konstantin Kudryashov Date: Thu, 27 Sep 2012 02:00:35 +0300 Subject: [PATCH 01/12] Update composer.json Change namespace as this is a fork --- composer.json | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index a6b043bb..b81a45d5 100644 --- a/composer.json +++ b/composer.json @@ -1,16 +1,18 @@ { - "name": "chrisboulton/php-diff", - "type": "library", + "name": "phpspec/php-diff", + "type": "library", "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "authors": [ { "name": "Chris Boulton", "email": "@chrisboulton" } ], - "autoload": { - "psr-0": { - "Diff": "lib/" - } - } + + "autoload": { + "psr-0": { + "Diff": "lib/" + } + } } \ No newline at end of file From 9b736ac28341f8193627aafdb9929e3e798263f9 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Wed, 7 Nov 2012 16:08:40 -0500 Subject: [PATCH 02/12] Fix composer.json so that it validates --- composer.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index b81a45d5..5e91b0f9 100644 --- a/composer.json +++ b/composer.json @@ -2,11 +2,12 @@ "name": "phpspec/php-diff", "type": "library", "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", + "license": "BSD-3-Clause", "authors": [ { "name": "Chris Boulton", - "email": "@chrisboulton" + "homepage": "http://github.com/chrisboulton" } ], @@ -15,4 +16,4 @@ "Diff": "lib/" } } -} \ No newline at end of file +} From 29dc0029cc81193ac1e296770a9edaf7d8720857 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 15 Oct 2013 12:52:58 +0400 Subject: [PATCH 03/12] PHP 5.5 compatibility fix --- lib/Diff/Renderer/Html/Array.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Diff/Renderer/Html/Array.php b/lib/Diff/Renderer/Html/Array.php index 0b3f1d50..20a55162 100644 --- a/lib/Diff/Renderer/Html/Array.php +++ b/lib/Diff/Renderer/Html/Array.php @@ -177,7 +177,7 @@ private function formatLines($lines) $lines = array_map(array($this, 'ExpandTabs'), $lines); $lines = array_map(array($this, 'HtmlSafe'), $lines); foreach($lines as &$line) { - $line = preg_replace('# ( +)|^ #e', "\$this->fixSpaces('\\1')", $line); + $line = preg_replace_callback('# ( +)|^ #', __CLASS__."::fixSpaces", $line); } return $lines; } @@ -188,7 +188,7 @@ private function formatLines($lines) * @param string $spaces The string of spaces. * @return string The HTML representation of the string. */ - function fixSpaces($spaces='') + public static function fixSpaces($spaces='') { $count = strlen($spaces); if($count == 0) { From dd80390d67c2743c8e9872781b1adbd376fb6904 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 15 Oct 2013 12:53:16 +0400 Subject: [PATCH 04/12] phpdoc fixes --- lib/Diff.php | 3 ++- lib/Diff/SequenceMatcher.php | 14 ++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/Diff.php b/lib/Diff.php index 35305c03..d6cecb79 100644 --- a/lib/Diff.php +++ b/lib/Diff.php @@ -80,6 +80,7 @@ class Diff * * @param array $a Array containing the lines of the first string to compare. * @param array $b Array containing the lines for the second string to compare. + * @param array $options */ public function __construct($a, $b, $options=array()) { @@ -92,7 +93,7 @@ public function __construct($a, $b, $options=array()) /** * Render a diff using the supplied rendering class and return it. * - * @param object $renderer An instance of the rendering object to use for generating the diff. + * @param Diff_Renderer_Abstract $renderer An instance of the rendering object to use for generating the diff. * @return mixed The generated diff. Exact return value depends on the rendered. */ public function render(Diff_Renderer_Abstract $renderer) diff --git a/lib/Diff/SequenceMatcher.php b/lib/Diff/SequenceMatcher.php index e819e810..67a903b3 100644 --- a/lib/Diff/SequenceMatcher.php +++ b/lib/Diff/SequenceMatcher.php @@ -83,6 +83,7 @@ class Diff_SequenceMatcher * @param string|array $a A string or array containing the lines to compare against. * @param string|array $b A string or array containing the lines to compare. * @param string|array $junkCallback Either an array or string that references a callback function (if there is one) to determine 'junk' characters. + * @param array $options */ public function __construct($a, $b, $junkCallback=null, $options) { @@ -93,6 +94,11 @@ public function __construct($a, $b, $junkCallback=null, $options) $this->setSequences($a, $b); } + /** + * Set new options + * + * @param array $options + */ public function setOptions($options) { $this->options = array_merge($this->defaultOptions, $options); @@ -206,8 +212,8 @@ private function chainB() /** * Checks if a particular character is in the junk dictionary * for the list of junk characters. - * - * @return boolean $b True if the character is considered junk. False if not. + * @param $b + * @return boolean True if the character is considered junk. False if not. */ private function isBJunk($b) { @@ -631,7 +637,7 @@ private function quickRatio() { if($this->fullBCount === null) { $this->fullBCount = array(); - $bLength = count ($b); + $bLength = count ($this->b); for($i = 0; $i < $bLength; ++$i) { $char = $this->b[$i]; $this->fullBCount[$char] = $this->arrayGetDefault($this->fullBCount, $char, 0) + 1; @@ -729,7 +735,7 @@ private function tupleSort($a, $b) } } - if(count($a) == $count($b)) { + if(count($a) == count($b)) { return 0; } else if(count($a) < count($b)) { From 71cd475aef0b1ccda2c15f5c4766a221fb71fb49 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 15 Oct 2013 13:53:22 +0400 Subject: [PATCH 05/12] Fixed callback --- lib/Diff/Renderer/Html/Array.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Diff/Renderer/Html/Array.php b/lib/Diff/Renderer/Html/Array.php index 20a55162..7113a174 100644 --- a/lib/Diff/Renderer/Html/Array.php +++ b/lib/Diff/Renderer/Html/Array.php @@ -185,11 +185,12 @@ private function formatLines($lines) /** * Replace a string containing spaces with a HTML representation using  . * - * @param string $spaces The string of spaces. + * @param string $matches Regex matches array. * @return string The HTML representation of the string. */ - public static function fixSpaces($spaces='') + public static function fixSpaces($matches) { + $spaces = isset($matches[1]) ? $matches[1] : ''; $count = strlen($spaces); if($count == 0) { return ''; From e2ac602e8ae1d6198ce12515fdf9f1d24dfa9bf9 Mon Sep 17 00:00:00 2001 From: Anh Nhan Nguyen Date: Tue, 4 Feb 2014 11:52:30 +0100 Subject: [PATCH 06/12] Fixing line number placement for inline renderer --- lib/Diff/Renderer/Html/Inline.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Diff/Renderer/Html/Inline.php b/lib/Diff/Renderer/Html/Inline.php index 60e8005a..70cc9041 100644 --- a/lib/Diff/Renderer/Html/Inline.php +++ b/lib/Diff/Renderer/Html/Inline.php @@ -128,8 +128,8 @@ public function render() foreach($change['changed']['lines'] as $no => $line) { $toLine = $change['changed']['offset'] + $no + 1; $html .= ''; - $html .= ''.$toLine.''; $html .= ' '; + $html .= ''.$toLine.''; $html .= ''.$line.''; $html .= ''; } From cce18c8ea75735bb03de3222e4be07077233181b Mon Sep 17 00:00:00 2001 From: Anh Nhan Nguyen Date: Tue, 4 Feb 2014 12:00:10 +0100 Subject: [PATCH 07/12] Removing superfluous closing spans --- lib/Diff/Renderer/Html/SideBySide.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Diff/Renderer/Html/SideBySide.php b/lib/Diff/Renderer/Html/SideBySide.php index 307af1c3..eb438483 100644 --- a/lib/Diff/Renderer/Html/SideBySide.php +++ b/lib/Diff/Renderer/Html/SideBySide.php @@ -83,9 +83,9 @@ public function render() $toLine = $change['changed']['offset'] + $no + 1; $html .= ''; $html .= ''.$fromLine.''; - $html .= ''.$line.' '; + $html .= ''.$line.' '; $html .= ''.$toLine.''; - $html .= ''.$line.' '; + $html .= ''.$line.' '; $html .= ''; } } From e2ed4e816cf08ad27bb993a4577a04848c1977bc Mon Sep 17 00:00:00 2001 From: Actine Date: Thu, 8 May 2014 21:08:26 +0300 Subject: [PATCH 08/12] Fixed multi-byte support for HTML output (cherry picked from commit 89b351e) --- lib/Diff/Renderer/Html/Array.php | 56 ++++++++++++++++++-------------- lib/Diff/SequenceMatcher.php | 12 ++++--- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/lib/Diff/Renderer/Html/Array.php b/lib/Diff/Renderer/Html/Array.php index 7113a174..0fc135c2 100644 --- a/lib/Diff/Renderer/Html/Array.php +++ b/lib/Diff/Renderer/Html/Array.php @@ -5,10 +5,10 @@ * PHP version 5 * * Copyright (c) 2009 Chris Boulton - * + * * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without + * + * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, @@ -16,20 +16,20 @@ * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * - Neither the name of the Chris Boulton nor the names of its contributors - * may be used to endorse or promote products derived from this software + * - Neither the name of the Chris Boulton nor the names of its contributors + * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @package DiffLib @@ -82,12 +82,18 @@ public function render() list($start, $end) = $this->getChangeExtent($fromLine, $toLine); if($start != 0 || $end != 0) { - $last = $end + strlen($fromLine); - $fromLine = substr_replace($fromLine, "\0", $start, 0); - $fromLine = substr_replace($fromLine, "\1", $last + 1, 0); - $last = $end + strlen($toLine); - $toLine = substr_replace($toLine, "\0", $start, 0); - $toLine = substr_replace($toLine, "\1", $last + 1, 0); + $realEnd = mb_strlen($fromLine) + $end; + $fromLine = mb_substr($fromLine, 0, $start) + . "\0" + . mb_substr($fromLine, $start, $realEnd - $start) + . "\1" + . mb_substr($fromLine, $realEnd); + $realEnd = mb_strlen($toLine) + $end; + $toLine = mb_substr($toLine, 0, $start) + . "\0" + . mb_substr($toLine, $start, $realEnd - $start) + . "\1" + . mb_substr($toLine, $realEnd); $a[$i1 + $i] = $fromLine; $b[$j1 + $i] = $toLine; } @@ -149,13 +155,13 @@ public function render() private function getChangeExtent($fromLine, $toLine) { $start = 0; - $limit = min(strlen($fromLine), strlen($toLine)); - while($start < $limit && $fromLine{$start} == $toLine{$start}) { + $limit = min(mb_strlen($fromLine), mb_strlen($toLine)); + while($start < $limit && mb_substr($fromLine, $start, 1) == mb_substr($toLine, $start, 1)) { ++$start; } $end = -1; $limit = $limit - $start; - while(-$end <= $limit && substr($fromLine, $end, 1) == substr($toLine, $end, 1)) { + while(-$end <= $limit && mb_substr($fromLine, $end, 1) == mb_substr($toLine, $end, 1)) { --$end; } return array( @@ -222,4 +228,4 @@ private function htmlSafe($string) { return htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8'); } -} \ No newline at end of file +} diff --git a/lib/Diff/SequenceMatcher.php b/lib/Diff/SequenceMatcher.php index 67a903b3..9c84ee15 100644 --- a/lib/Diff/SequenceMatcher.php +++ b/lib/Diff/SequenceMatcher.php @@ -69,6 +69,10 @@ class Diff_SequenceMatcher private $options = array(); + private $matchingBlocks = null; + private $opCodes = null; + private $fullBCount = null; + private $defaultOptions = array( 'ignoreNewLines' => false, 'ignoreWhitespace' => false, @@ -217,7 +221,7 @@ private function chainB() */ private function isBJunk($b) { - if(isset($this->juncDict[$b])) { + if(isset($this->junkDict[$b])) { return true; } @@ -258,7 +262,7 @@ public function findLongestMatch($alo, $ahi, $blo, $bhi) for($i = $alo; $i < $ahi; ++$i) { $newJ2Len = array(); $jDict = $this->arrayGetDefault($this->b2j, $a[$i], $nothing); - foreach($jDict as $jKey => $j) { + foreach($jDict as $j) { if($j < $blo) { continue; } @@ -291,7 +295,7 @@ public function findLongestMatch($alo, $ahi, $blo, $bhi) } while($bestI > $alo && $bestJ > $blo && $this->isBJunk($b[$bestJ - 1]) && - !$this->isLineDifferent($bestI - 1, $bestJ - 1)) { + !$this->linesAreDifferent($bestI - 1, $bestJ - 1)) { --$bestI; --$bestJ; ++$bestSize; @@ -745,4 +749,4 @@ private function tupleSort($a, $b) return 1; } } -} \ No newline at end of file +} From 0200ecd42da7c3c8357e119876ca73d701c84751 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Sun, 18 Jan 2015 11:56:28 +0100 Subject: [PATCH 09/12] Add the branch-alias for master --- composer.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/composer.json b/composer.json index 5e91b0f9..145c6136 100644 --- a/composer.json +++ b/composer.json @@ -15,5 +15,11 @@ "psr-0": { "Diff": "lib/" } + }, + + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } } } From d1fc6fff854b4f6477a7c38632a89a7d3230eb41 Mon Sep 17 00:00:00 2001 From: MaximAL Date: Fri, 20 Mar 2015 13:14:08 +0300 Subject: [PATCH 10/12] Add ability not to expand tabs --- lib/Diff/Renderer/Html/Array.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Diff/Renderer/Html/Array.php b/lib/Diff/Renderer/Html/Array.php index 7113a174..a97e717e 100644 --- a/lib/Diff/Renderer/Html/Array.php +++ b/lib/Diff/Renderer/Html/Array.php @@ -174,7 +174,9 @@ private function getChangeExtent($fromLine, $toLine) */ private function formatLines($lines) { - $lines = array_map(array($this, 'ExpandTabs'), $lines); + if ($this->options['tabSize'] !== false) { + $lines = array_map(array($this, 'ExpandTabs'), $lines); + } $lines = array_map(array($this, 'HtmlSafe'), $lines); foreach($lines as &$line) { $line = preg_replace_callback('# ( +)|^ #', __CLASS__."::fixSpaces", $line); @@ -222,4 +224,4 @@ private function htmlSafe($string) { return htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8'); } -} \ No newline at end of file +} From d9afff9013dc7f5b4f687c404a8b6bdb284bcf38 Mon Sep 17 00:00:00 2001 From: Shane Auckland Date: Tue, 22 Dec 2015 15:30:30 +0000 Subject: [PATCH 11/12] Use PHP_EOL constant to represent line endings --- lib/Diff/Renderer/Text/Context.php | 10 +++++----- lib/Diff/Renderer/Text/Unified.php | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/Diff/Renderer/Text/Context.php b/lib/Diff/Renderer/Text/Context.php index 1200b01c..241b965d 100644 --- a/lib/Diff/Renderer/Text/Context.php +++ b/lib/Diff/Renderer/Text/Context.php @@ -72,17 +72,17 @@ public function render() $j2 = $group[$lastItem][4]; if($i2 - $i1 >= 2) { - $diff .= '*** '.($group[0][1] + 1).','.$i2." ****\n"; + $diff .= '*** '.($group[0][1] + 1).','.$i2." ****".PHP_EOL; } else { $diff .= '*** '.$i2." ****\n"; } if($j2 - $j1 >= 2) { - $separator = '--- '.($j1 + 1).','.$j2." ----\n"; + $separator = '--- '.($j1 + 1).','.$j2." ----".PHP_EOL; } else { - $separator = '--- '.$j2." ----\n"; + $separator = '--- '.$j2." ----".PHP_EOL; } $hasVisible = false; @@ -99,7 +99,7 @@ public function render() if($tag == 'insert') { continue; } - $diff .= $this->tagMap[$tag].' '.implode("\n".$this->tagMap[$tag].' ', $this->diff->GetA($i1, $i2))."\n"; + $diff .= $this->tagMap[$tag].' '.implode(PHP_EOL.$this->tagMap[$tag].' ', $this->diff->GetA($i1, $i2)).PHP_EOL; } } @@ -119,7 +119,7 @@ public function render() if($tag == 'delete') { continue; } - $diff .= $this->tagMap[$tag].' '.implode("\n".$this->tagMap[$tag].' ', $this->diff->GetB($j1, $j2))."\n"; + $diff .= $this->tagMap[$tag].' '.implode(PHP_EOL.$this->tagMap[$tag].' ', $this->diff->GetB($j1, $j2)).PHP_EOL; } } } diff --git a/lib/Diff/Renderer/Text/Unified.php b/lib/Diff/Renderer/Text/Unified.php index e94d951d..084611c2 100644 --- a/lib/Diff/Renderer/Text/Unified.php +++ b/lib/Diff/Renderer/Text/Unified.php @@ -65,19 +65,19 @@ public function render() $i2 = -1; } - $diff .= '@@ -'.($i1 + 1).','.($i2 - $i1).' +'.($j1 + 1).','.($j2 - $j1)." @@\n"; + $diff .= '@@ -'.($i1 + 1).','.($i2 - $i1).' +'.($j1 + 1).','.($j2 - $j1)." @@".PHP_EOL; foreach($group as $code) { list($tag, $i1, $i2, $j1, $j2) = $code; if($tag == 'equal') { - $diff .= ' '.implode("\n ", $this->diff->GetA($i1, $i2))."\n"; + $diff .= ' '.implode(PHP_EOL." ", $this->diff->GetA($i1, $i2)).PHP_EOL; } else { if($tag == 'replace' || $tag == 'delete') { - $diff .= '-'.implode("\n-", $this->diff->GetA($i1, $i2))."\n"; + $diff .= '-'.implode(PHP_EOL."-", $this->diff->GetA($i1, $i2)).PHP_EOL; } if($tag == 'replace' || $tag == 'insert') { - $diff .= '+'.implode("\n+", $this->diff->GetB($j1, $j2))."\n"; + $diff .= '+'.implode(PHP_EOL."+", $this->diff->GetB($j1, $j2)).PHP_EOL; } } } From 0bbc54c4c8bfa2fc743867292fe5140666faf54e Mon Sep 17 00:00:00 2001 From: Ciaran McNulty Date: Fri, 18 Sep 2020 14:43:57 +0100 Subject: [PATCH 12/12] Fix optional arg for PHP8 --- lib/Diff/SequenceMatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Diff/SequenceMatcher.php b/lib/Diff/SequenceMatcher.php index 9c84ee15..71c9c630 100644 --- a/lib/Diff/SequenceMatcher.php +++ b/lib/Diff/SequenceMatcher.php @@ -89,7 +89,7 @@ class Diff_SequenceMatcher * @param string|array $junkCallback Either an array or string that references a callback function (if there is one) to determine 'junk' characters. * @param array $options */ - public function __construct($a, $b, $junkCallback=null, $options) + public function __construct($a, $b, $junkCallback=null, $options=[]) { $this->a = null; $this->b = null;