From 9c4e77c85bb3d88878a93083dd1906a2411a1988 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 2 Jul 2020 14:36:25 +0200 Subject: [PATCH 001/206] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 67be32fa..eb4a95fa 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ composer require jblond/php-diff ## Example Use +
 
+ ```PHP Render($renderer); ``` +
+ ### Example Output A quick usage example can be found in the `example/` directory and under example.php. From bae640ee9faf3c684a15cab19facc98d4a412842 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 2 Jul 2020 14:39:07 +0200 Subject: [PATCH 002/206] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb4a95fa..d152b408 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ echo $diff->Render($renderer); ### Example Output -A quick usage example can be found in the `example/` directory and under example.php. +A quick usage example can be found in the `example/` directory and under example.php. Included is a light theme and a dark theme. #### HTML Side By Side Example ![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example") From 5cd911342c8709c26d5b5fe14ba879648aaf7e90 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 2 Jul 2020 14:41:08 +0200 Subject: [PATCH 003/206] Hide images by default, to have a shorter readme --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index d152b408..985ed230 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ echo $diff->Render($renderer); ### Example Output A quick usage example can be found in the `example/` directory and under example.php. Included is a light theme and a dark theme. +
Example Pictures
+ #### HTML Side By Side Example ![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example") #### HTML Inline Example @@ -79,6 +81,8 @@ A quick usage example can be found in the `example/` directory and under example #### Text Context Example ![Text Context Example](textContext.png "Text Context Example") +
+ ## Requirements * PHP 7.2 or greater From 99150a4f515bf1e50c47c6c8c0c8babfc93f078e Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 3 Jul 2020 08:00:04 +0200 Subject: [PATCH 004/206] Correct typo in wording --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 985ed230..576fe7c7 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ composer require jblond/php-diff ## Example Use -
 
+
Example Code
```PHP Render($renderer); ### Example Output A quick usage example can be found in the `example/` directory and under example.php. Included is a light theme and a dark theme. -
Example Pictures
+
Example Pictures
#### HTML Side By Side Example ![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example") From 7a49d76408eaf0417c6fb83d10939152b35cc557 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 08:16:55 +0200 Subject: [PATCH 005/206] remove Autoloader.php and have only the one from composer --- README.md | 4 ---- example/example.php | 5 ++--- lib/Autoloader.php | 39 --------------------------------------- 3 files changed, 2 insertions(+), 46 deletions(-) delete mode 100644 lib/Autoloader.php diff --git a/README.md b/README.md index 67be32fa..1b480d5a 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,6 @@ use jblond\Diff\Renderer\Html\SideBySide; // Installed via composer... require 'vendor/autoload.php'; -// ...or installed manually. -require dirname(__FILE__).'/../lib/Autoloader.php'; - -new Autoloader(); $a = file_get_contents(dirname(__FILE__).'/a.txt'); $b = file_get_contents(dirname(__FILE__).'/b.txt'); diff --git a/example/example.php b/example/example.php index 681f6869..0f2d430a 100644 --- a/example/example.php +++ b/example/example.php @@ -1,6 +1,5 @@ 'Custom title for version2', ]); echo $diff->Render($renderer); + $cli = new \jblond\cli\Cli(); ?>

HTML Inline Diff

diff --git a/lib/Autoloader.php b/lib/Autoloader.php deleted file mode 100644 index d2820528..00000000 --- a/lib/Autoloader.php +++ /dev/null @@ -1,39 +0,0 @@ - - * @copyright (c) 2015 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 - * @link https://github.com/JBlond/php-diff - */ -class Autoloader -{ - - /** - * Constructor. - * - * A function is registered as an __autoload() implementation to include and evaluate the class file when this class - * is called. - */ - public function __construct() - { - spl_autoload_register(function ($class) { - $class = str_replace('\\', '/', $class); // revert path for old PHP on Linux - $dir = str_replace('\\', '/', __DIR__); - if (file_exists($dir . '/' . $class . '.php')) { - /** @noinspection PhpIncludeInspection */ - require_once $dir . '/' . $class . '.php'; - } - }); - } -} From 4192d8b7d411e492e02f855094b557b0b114cbe1 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 08:45:43 +0200 Subject: [PATCH 006/206] Add Cli color support --- composer.json | 3 +- example/cli.php | 29 +++++++ lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 90 ++++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 example/cli.php create mode 100644 lib/jblond/Diff/Renderer/Text/UnifiedCli.php diff --git a/composer.json b/composer.json index 818e62eb..511eb3e8 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ ], "require": { "php": ">=7.2", - "ext-mbstring": "*" + "ext-mbstring": "*", + "jblond/php-cli": "*" }, "require-dev": { "phpunit/phpunit": "8.*", diff --git a/example/cli.php b/example/cli.php new file mode 100644 index 00000000..783b37da --- /dev/null +++ b/example/cli.php @@ -0,0 +1,29 @@ + 2, + 'trimEqual' => false, + 'ignoreWhitespace' => true, + 'ignoreCase' => true, +]; + +// Choose one of the initializations. +$diff = new Diff($a, $b); + + +// Generate a unified diff. +// \jblond\Diff\Renderer\Text +$renderer = new UnifiedCli(); +$cli = new Cli(); +$cli->output($diff->render($renderer)); diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php new file mode 100644 index 00000000..c9ee1b15 --- /dev/null +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -0,0 +1,90 @@ + + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 1.18 + * @link https://github.com/JBlond/php-diff + */ + +class UnifiedCli extends RendererAbstract +{ + + /** + * @var CliColors + */ + private $colors; + + /** + * UnifiedCli constructor. + * @param array $options + */ + public function __construct(array $options = []) + { + parent::__construct($options); + $this->colors = new CliColors(); + } + + /** + * Render and return a unified diff. + * + * @return string Direct Output to the console + */ + public function render(): string + { + $diff = ''; + $opCodes = $this->diff->getGroupedOpCodes(); + foreach ($opCodes as $group) { + $lastItem = count($group) - 1; + $i1 = $group['0']['1']; + $i2 = $group[$lastItem]['2']; + $j1 = $group['0']['3']; + $j2 = $group[$lastItem]['4']; + + if ($i1 == 0 && $i2 == 0) { + $i1 = -1; + $i2 = -1; + } + + $diff .= $this->colors->getColoredString( + '@@ -' . ($i1 + 1) . ',' . ($i2 - $i1) . ' +' . ($j1 + 1) . ',' . ($j2 - $j1) . " @@\n", + 'purple' + ); + foreach ($group as [$tag, $i1, $i2, $j1, $j2]) { + if ($tag == 'equal') { + $diff .= $this->colors->getColoredString(' ' . + implode( + "\n ", + $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + ) . "\n", 'grey'); + continue; + } + if ($tag == 'replace' || $tag == 'delete') { + $diff .= $this->colors->getColoredString('-' . + implode( + "\n- ", + $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + ) . "\n", 'red'); + } + if ($tag == 'replace' || $tag == 'insert') { + $diff .= $this->colors->getColoredString('+' . + implode( + "\n+", + $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) + ) . "\n", 'green'); + } + } + } + return $diff; + } +} From 37088ab2932824803b928ead1e10df69208429ff Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 08:52:50 +0200 Subject: [PATCH 007/206] update example with full class path --- example/cli.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example/cli.php b/example/cli.php index 783b37da..189ab2a0 100644 --- a/example/cli.php +++ b/example/cli.php @@ -25,5 +25,7 @@ // Generate a unified diff. // \jblond\Diff\Renderer\Text $renderer = new UnifiedCli(); + +// jblond\cli\Cli $cli = new Cli(); $cli->output($diff->render($renderer)); From 7e6e1257aa0bf86583699cdd5487ff5d1c61988a Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 08:56:59 +0200 Subject: [PATCH 008/206] update Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1b480d5a..5972b5b2 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Generated differences can be rendered in all of the standard formats including: * Inline HTML * Side by Side HTML * Unified HTML +* Unified Commandline colored output The logic behind the core of the diff engine (ie, the sequence matcher) is primarily based on the Python difflib package. The reason for doing so is primarily because of its high degree of accuracy. @@ -27,7 +28,6 @@ composer require jblond/php-diff ```PHP Date: Fri, 3 Jul 2020 09:15:14 +0200 Subject: [PATCH 009/206] a new line for each change --- lib/jblond/Diff/Renderer/Html/Unified.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 6a60b11b..3991d685 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -102,7 +102,7 @@ public function generateLinesEqual(array $change): string $html = ''; foreach ($change['base']['lines'] as $line) { - $html .= '' . $line . '
'; + $html .= '' . $line . '
' . "\n"; } return $html; @@ -120,7 +120,7 @@ public function generateLinesInsert(array $change): string $html = ''; foreach ($change['changed']['lines'] as $line) { - $html .= '' . $line . '
'; + $html .= '' . $line . '
' . "\n"; } return $html; @@ -137,7 +137,7 @@ public function generateLinesDelete(array $change): string { $html = ''; foreach ($change['base']['lines'] as $line) { - $html .= '' . $line . '
'; + $html .= '' . $line . '
' . "\n"; } return $html; @@ -156,12 +156,12 @@ public function generateLinesReplace(array $change): string // Lines with characters removed. foreach ($change['base']['lines'] as $line) { - $html .= '' . $line . '
'; + $html .= '' . $line . '
' . "\n"; } // Lines with characters added. foreach ($change['changed']['lines'] as $line) { - $html .= '' . $line . '
'; + $html .= '' . $line . '
' . "\n"; } return $html; From 12950b2ed61b2adac96d453724525d57c3198dfb Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 09:17:50 +0200 Subject: [PATCH 010/206] a new line for each change --- lib/jblond/Diff/Renderer/Html/Unified.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 3991d685..b6f89802 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -81,10 +81,10 @@ public function renderHtml($changes, $object = null): string $html .= $this->generateLinesReplace($change); break; } - $html .= ''; + $html .= '' . "\n"; } } - $html .= ''; + $html .= '' . "\n"; return $html; } From ee37a28cbebfce735419bd8ca169daa379a163c7 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 09:50:53 +0200 Subject: [PATCH 011/206] Add example picture --- README.md | 6 ++++++ textUnifiedCli.png | Bin 0 -> 165501 bytes 2 files changed, 6 insertions(+) create mode 100644 textUnifiedCli.png diff --git a/README.md b/README.md index 5972b5b2..3bdf0b14 100644 --- a/README.md +++ b/README.md @@ -62,15 +62,21 @@ A quick usage example can be found in the `example/` directory and under example #### HTML Side By Side Example ![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example") + #### HTML Inline Example ![HTML Inline Example](htmlInline.png "HTML Inline Example") #### HTML Unified Example ![HTML Unified Example](htmlUnified.png "HTML Unified Example") + #### Text Unified Example ![Text Unified Example](textUnified.png "Text Unified Example") + #### Text Context Example ![Text Context Example](textContext.png "Text Context Example") +#### Text Unified Console Example +![Text Unified Console Example](textUnifiedCli.png "Text Unified Console Example") + ## Requirements * PHP 7.2 or greater diff --git a/textUnifiedCli.png b/textUnifiedCli.png new file mode 100644 index 0000000000000000000000000000000000000000..7cfd27a6bb50c7457bce9cefa7edea548bf568a8 GIT binary patch literal 165501 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
+ ## Requirements * PHP 7.2 or greater From d00d224ca299116f9847584106af720fa7feb58a Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 10:09:08 +0200 Subject: [PATCH 016/206] remove from merge conflict --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index ee1d9e9f..5db74883 100644 --- a/README.md +++ b/README.md @@ -89,9 +89,6 @@ A quick usage example can be found in the `example/` directory and under example #### Text Unified Console Example -![Text Unified Console Example](textUnifiedCli.png "Text Unified Console Example") -#### Text Unified Console Example - ![Text Unified Console Example](textUnifiedCli.png "Text Unified Console Example")
From 606ff22e6829aca6fe139d6ac9fbe8ac61fa74c7 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 10:10:33 +0200 Subject: [PATCH 017/206] show one picture as a preview --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5db74883..ebbb9a15 100644 --- a/README.md +++ b/README.md @@ -65,11 +65,11 @@ echo $diff->Render($renderer); ### Example Output A quick usage example can be found in the `example/` directory and under example.php. Included is a light theme and a dark theme. -
Example Pictures
- #### HTML Side By Side Example -![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example") +![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example" + +
More Example Pictures
#### HTML Inline Example From ab6eb2808ceca528da995e806c8940816cdbdb1d Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 10:11:05 +0200 Subject: [PATCH 018/206] show one picture as a preview --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ebbb9a15..7c34574b 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ A quick usage example can be found in the `example/` directory and under example #### HTML Side By Side Example -![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example" +![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example")
More Example Pictures
From 6f41894d851efec06bad7eff3236b781e1d4355b Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 10:14:56 +0200 Subject: [PATCH 019/206] Add dark theme example --- README.md | 7 +++++++ htmlSidebySideDarkTheme.png | Bin 0 -> 89507 bytes 2 files changed, 7 insertions(+) create mode 100644 htmlSidebySideDarkTheme.png diff --git a/README.md b/README.md index 7c34574b..4314dbc9 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,13 @@ A quick usage example can be found in the `example/` directory and under example
+
HTML Side By Side Dark Theme Example
+ + +![HTML Side By Side Dark Theme Example](htmlSidebySideDarkTheme.png "HTML Side By Side Dark Theme Example") + +
+ ## Requirements * PHP 7.2 or greater diff --git a/htmlSidebySideDarkTheme.png b/htmlSidebySideDarkTheme.png new file mode 100644 index 0000000000000000000000000000000000000000..a1144e92733047908d3b5442cc7662bee39d125f GIT binary patch literal 89507 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 z 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⁣}$8Hgx6JltEavjkr$7<_Y{iBs==k_f;@ z)~g-i(02m{Gpby_Vd%5GkgH*Iz4tkCtD2Erq2KElM+ofFl{$XNNY8%z#+##~U?pt_ z8Cs>0Jel~u!$%+5AZnsJn~F4%yXX$keYl~uZ^1uc=HMe8I}}Kacx!uTpbJS`|EV$ zRkbazj$Y(87>(ZYk^gd7ZGY;IS#M5KIVHdGJQd1aHOf{(IIdw_JY*nk! zyzicu(XL%av}AVFFJgERkEbw&D2tyUg+F2AIi@t^=|X2OlQ&kih-o`rfZqdLp`|R zUpyRwsW|FkG<@u}m5sAEFyt}t7roJ5C~{vCAbP1iPgdJcWlMn_>~C{`lk%(tFmJbP zseS(COE>@h67?a@NbL*6wrh3-(fIQ_wrrs~-N+2sd>!ye@Rx}KspOVdQovUm0nF0C zkDFt^1pn}}EVg)ngRG;+)LO(?LSG@V9nQaBDSyAlr}|73@|AbNnTeAU`D+T+S@D<5 zshvjL$dOg!Z04p`AGz=Y##D%@$bLmcqXOGyHc>vw;ZC{I!ez-adU+YXT_r}eLpDNM zJ50ffbK=$fF<(_)YsW4HkF;zfjQ>ltITLl$VPRhVuz$9W@ctP@EN`)i!+g}iSI4nW;KQ|gXXd8pqXI`)WwG7ttQeah7R9uMI1Zh0B`A#OQXBiNJ)KXkBxHxpX8TokUM zE5w<$s|D83I4035rz{`!V9tq)R}P3fSI_gmZYA}0Nx&ViyEeAk3@|qk+AOiRxYoTW z!u?x1c%bW3atTjKU1P2h*L#XHOx5w3Lb?#ir;)^U{2iv~dYK_hc}NUHEvbviq;(Sx zYH@&}r`W(SozQD)47#t-fRT)n;|ye*u#p}e<`ggdA&?{KGQ;S@R2=0+nD!C$Pgx1e zrn8xPHgiP+qDEvaXIIy|t_^z8oUd#i)B$Ukc=BsbKz6&i%DSX#HI~GMc7D=ILUDXh z4jo0^=R_YnbC(8|9TFF}+OWEK1CT|OG@0}UxuiikEjC<

~=B1Q{sbm!s_0upa1| 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 V(^%tj^l9ibN{={S{~rVz+9Ut~ From f1d90c2d857a96c1c85dbf5166083bf2545312b1 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 10:31:42 +0200 Subject: [PATCH 021/206] revert that change --- lib/jblond/Diff/Renderer/Html/Unified.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index b6f89802..a21c12bc 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -102,7 +102,7 @@ public function generateLinesEqual(array $change): string $html = ''; foreach ($change['base']['lines'] as $line) { - $html .= '' . $line . '
' . "\n"; + $html .= '' . $line . '
'; } return $html; @@ -120,7 +120,7 @@ public function generateLinesInsert(array $change): string $html = ''; foreach ($change['changed']['lines'] as $line) { - $html .= '' . $line . '
' . "\n"; + $html .= '' . $line . '
'; } return $html; @@ -137,7 +137,7 @@ public function generateLinesDelete(array $change): string { $html = ''; foreach ($change['base']['lines'] as $line) { - $html .= '' . $line . '
' . "\n"; + $html .= '' . $line . '
'; } return $html; @@ -156,12 +156,12 @@ public function generateLinesReplace(array $change): string // Lines with characters removed. foreach ($change['base']['lines'] as $line) { - $html .= '' . $line . '
' . "\n"; + $html .= '' . $line . '
'; } // Lines with characters added. foreach ($change['changed']['lines'] as $line) { - $html .= '' . $line . '
' . "\n"; + $html .= '' . $line . '
'; } return $html; From e93d249a48a0774f6f01bfb02bbfa8852fc248de Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 11:00:11 +0200 Subject: [PATCH 022/206] revert that change --- lib/jblond/Diff/Renderer/Html/Unified.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index a21c12bc..6a60b11b 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -81,10 +81,10 @@ public function renderHtml($changes, $object = null): string $html .= $this->generateLinesReplace($change); break; } - $html .= '' . "\n"; + $html .= ''; } } - $html .= '' . "\n"; + $html .= ''; return $html; } From ae6cfe453e9ae8f5e50995309013a5ff8a0ef643 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 13:26:33 +0200 Subject: [PATCH 023/206] adjust color --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index c9ee1b15..e1ef4538 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -74,14 +74,14 @@ public function render(): string implode( "\n- ", $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) - ) . "\n", 'red'); + ) . "\n", 'light_red'); } if ($tag == 'replace' || $tag == 'insert') { $diff .= $this->colors->getColoredString('+' . implode( "\n+", $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) - ) . "\n", 'green'); + ) . "\n", 'light_green'); } } } From 6bfd4f9696e949fbab21c375fca82d488a064773 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 8 Jul 2020 11:23:33 +0200 Subject: [PATCH 024/206] add composer scripts descriptions. Update key words --- composer.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 818e62eb..c5948fb7 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,9 @@ "license": "BSD-3-Clause", "keywords": [ "php", - "diff" + "diff", + "side-by-sidediff", + "unified" ], "authors": [ { @@ -43,5 +45,11 @@ "php_src": "phpcs --standard=phpcs.xml -s -p --colors ./lib/", "php_test": "phpcs --standard=phpcs.xml -s -p --colors ./tests/", "phpmd": "phpmd ./ ansi cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor" + }, + "scripts-descriptions": { + "phpunit": "Run PHPUnit tests", + "php_src": "Run code sniffer on lib directory", + "php_test": "Run code sniffer on tests directory", + "phpmd": "Run php mess detector" } } From ede59fbb40896da454f8b491d15e19ce1b5bd9f0 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 8 Jul 2020 21:59:43 +0200 Subject: [PATCH 025/206] change composer require for package --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 25ec6c2b..17a3e90c 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "require": { "php": ">=7.2", "ext-mbstring": "*", - "jblond/php-cli": "*" + "jblond/php-cli": "^1.0" }, "require-dev": { "phpunit/phpunit": "8.*", From 8fcc5fbd08b514ef066d6a9a55096104cb996f33 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 8 Jul 2020 22:00:18 +0200 Subject: [PATCH 026/206] reduce Cyclomatic Complexity --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index e1ef4538..029a80a0 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -62,26 +62,26 @@ public function render(): string ); foreach ($group as [$tag, $i1, $i2, $j1, $j2]) { if ($tag == 'equal') { - $diff .= $this->colors->getColoredString(' ' . - implode( - "\n ", - $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) - ) . "\n", 'grey'); + $string = implode( + "\n ", + $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + ); + $diff .= $this->colors->getColoredString(' ' . $string . "\n", 'grey'); continue; } if ($tag == 'replace' || $tag == 'delete') { - $diff .= $this->colors->getColoredString('-' . - implode( - "\n- ", - $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) - ) . "\n", 'light_red'); + $string = implode( + "\n- ", + $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + ); + $diff .= $this->colors->getColoredString('-' . $string . "\n", 'light_red'); } if ($tag == 'replace' || $tag == 'insert') { - $diff .= $this->colors->getColoredString('+' . - implode( - "\n+", - $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) - ) . "\n", 'light_green'); + $string = implode( + "\n+", + $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) + ); + $diff .= $this->colors->getColoredString('+' . $string . "\n", 'light_green'); } } } From f44ee814834aeaadfc459a6c4c2ec8f14aa75668 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 9 Jul 2020 12:16:35 +0200 Subject: [PATCH 027/206] increase version number --- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/Renderer/Html/HtmlArray.php | 2 +- lib/jblond/Diff/Renderer/Html/Inline.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/RendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 4a77269f..feb5c8bd 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -27,7 +27,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/Renderer/Html/HtmlArray.php b/lib/jblond/Diff/Renderer/Html/HtmlArray.php index 0cd0d53c..ca3cb5d3 100644 --- a/lib/jblond/Diff/Renderer/Html/HtmlArray.php +++ b/lib/jblond/Diff/Renderer/Html/HtmlArray.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class HtmlArray extends RendererAbstract diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 0b421622..b32b5067 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class Inline extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 128e8c98..4acd7a98 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class SideBySide extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 6a60b11b..bfc38f08 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class Unified extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/RendererAbstract.php b/lib/jblond/Diff/Renderer/RendererAbstract.php index f33ddc1c..6e3bb23c 100644 --- a/lib/jblond/Diff/Renderer/RendererAbstract.php +++ b/lib/jblond/Diff/Renderer/RendererAbstract.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ abstract class RendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 91d2c98f..880f2be3 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class Context extends RendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index e1a8c616..89b8ff7e 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 029a80a0..32e879a6 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -13,7 +13,7 @@ * @package jblond\Diff\Renderer\Text * @author Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 2d7f0ce5..8b8aef0a 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 1.18 + * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher From a1e61fbeeb10001beaf84c57828cf1e489e506ca Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 10 Jul 2020 08:59:24 +0200 Subject: [PATCH 028/206] remove some complexity --- .../Diff/Renderer/SequenceMatcherHelper.php | 62 +++++++++++++++++++ lib/jblond/Diff/SequenceMatcher.php | 48 +------------- 2 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 lib/jblond/Diff/Renderer/SequenceMatcherHelper.php diff --git a/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php b/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php new file mode 100644 index 00000000..4be8f5d7 --- /dev/null +++ b/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php @@ -0,0 +1,62 @@ + + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff + */ +class SequenceMatcherHelper +{ + /** + * Helper function that provides the ability to return the value for a key + * in an array of it exists, or if it doesn't then return a default value. + * Essentially cleaner than doing a series of if (isset()) {} else {} calls. + * + * @param array $array The array to search. + * @param string|int $key The key to check that exists. + * @param mixed $default The value to return as the default value if the key doesn't exist. + * @return mixed The value from the array if the key exists or otherwise the default. + */ + protected function arrayGetDefault(array $array, $key, $default) + { + if (isset($array[$key])) { + return $array[$key]; + } + return $default; + } + + /** + * Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks + * + * @param array $aArray First array to compare. + * @param array $bArray Second array to compare. + * @return int -1, 0 or 1, as expected by the usort function. + */ + protected function tupleSort(array $aArray, array $bArray): int + { + $max = max(count($aArray), count($bArray)); + for ($counter = 0; $counter < $max; ++$counter) { + if ($aArray[$counter] < $bArray[$counter]) { + return -1; + } elseif ($aArray[$counter] > $bArray[$counter]) { + return 1; + } + } + + if (count($aArray) == count($bArray)) { + return 0; + } + if (count($aArray) < count($bArray)) { + return -1; + } + return 1; + } +} diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 8b8aef0a..7552a36c 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -5,6 +5,7 @@ namespace jblond\Diff; use InvalidArgumentException; +use jblond\Diff\Renderer\SequenceMatcherHelper; /** * Sequence matcher for Diff @@ -20,7 +21,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class SequenceMatcher +class SequenceMatcher extends SequenceMatcherHelper { /** * @var string|array Either a string or an array containing a callback function to determine @@ -614,49 +615,4 @@ public function getGroupedOpCodes(): array return $groups; } - - /** - * Helper function that provides the ability to return the value for a key - * in an array of it exists, or if it doesn't then return a default value. - * Essentially cleaner than doing a series of if (isset()) {} else {} calls. - * - * @param array $array The array to search. - * @param string|int $key The key to check that exists. - * @param mixed $default The value to return as the default value if the key doesn't exist. - * @return mixed The value from the array if the key exists or otherwise the default. - */ - private function arrayGetDefault(array $array, $key, $default) - { - if (isset($array[$key])) { - return $array[$key]; - } - return $default; - } - - /** - * Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks - * - * @param array $aArray First array to compare. - * @param array $bArray Second array to compare. - * @return int -1, 0 or 1, as expected by the usort function. - */ - private function tupleSort(array $aArray, array $bArray): int - { - $max = max(count($aArray), count($bArray)); - for ($counter = 0; $counter < $max; ++$counter) { - if ($aArray[$counter] < $bArray[$counter]) { - return -1; - } elseif ($aArray[$counter] > $bArray[$counter]) { - return 1; - } - } - - if (count($aArray) == count($bArray)) { - return 0; - } - if (count($aArray) < count($bArray)) { - return -1; - } - return 1; - } } From b48cbe6f6f76e82a0a0c6079380fcb3f335bcf83 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 10 Jul 2020 10:18:44 +0200 Subject: [PATCH 029/206] refactor variable names --- lib/jblond/Diff/SequenceMatcher.php | 52 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 7552a36c..14d03952 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -237,32 +237,32 @@ private function isBJunk(string $bString): bool * that the junk element appears in the block. Extend it as far as possible * by matching only junk elements in both $a and $b. * - * @param int $alo The lower constraint for the first sequence. - * @param int $ahi The upper constraint for the first sequence. - * @param int $blo The lower constraint for the second sequence. - * @param int $bhi The upper constraint for the second sequence. + * @param int $aLower The lower constraint for the first sequence. + * @param int $aUpper The upper constraint for the first sequence. + * @param int $bLower The lower constraint for the second sequence. + * @param int $bUpper The upper constraint for the second sequence. * @return array Array containing the longest match that includes the starting position in $a, * start in $b and the length/size. */ - public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array + public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUpper): array { $old = $this->old; $new = $this->new; - $bestI = $alo; - $bestJ = $blo; + $bestI = $aLower; + $bestJ = $bLower; $bestSize = 0; $j2Len = []; $nothing = []; - for ($i = $alo; $i < $ahi; ++$i) { + for ($i = $aLower; $i < $aUpper; ++$i) { $newJ2Len = []; $jDict = $this->arrayGetDefault($this->b2j, $old[$i], $nothing); foreach ($jDict as $j) { - if ($j < $blo) { + if ($j < $bLower) { continue; - } elseif ($j >= $bhi) { + } elseif ($j >= $bUpper) { break; } @@ -279,8 +279,8 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array } while ( - $bestI > $alo && - $bestJ > $blo && + $bestI > $aLower && + $bestJ > $bLower && !$this->isBJunk($new[$bestJ - 1]) && !$this->linesAreDifferent($bestI - 1, $bestJ - 1) ) { @@ -290,8 +290,8 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array } while ( - $bestI + $bestSize < $ahi && - ($bestJ + $bestSize) < $bhi && + $bestI + $bestSize < $aUpper && + ($bestJ + $bestSize) < $bUpper && !$this->isBJunk($new[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize) ) { @@ -299,8 +299,8 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array } while ( - $bestI > $alo && - $bestJ > $blo && + $bestI > $aLower && + $bestJ > $bLower && $this->isBJunk($new[$bestJ - 1]) && !$this->linesAreDifferent($bestI - 1, $bestJ - 1) ) { @@ -310,8 +310,8 @@ public function findLongestMatch(int $alo, int $ahi, int $blo, int $bhi): array } while ( - $bestI + $bestSize < $ahi && - $bestJ + $bestSize < $bhi && + $bestI + $bestSize < $aUpper && + $bestJ + $bestSize < $bUpper && $this->isBJunk($new[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize) ) { @@ -385,26 +385,26 @@ public function getMatchingBlocks(): array $matchingBlocks = []; while (!empty($queue)) { - [$alo, $ahi, $blo, $bhi] = array_pop($queue); - $longestMatch = $this->findLongestMatch($alo, $ahi, $blo, $bhi); + [$aLower, $aUpper, $bLower, $bUpper] = array_pop($queue); + $longestMatch = $this->findLongestMatch($aLower, $aUpper, $bLower, $bUpper); [$list1, $list2, $list3] = $longestMatch; if ($list3) { $matchingBlocks[] = $longestMatch; - if ($alo < $list1 && $blo < $list2) { + if ($aLower < $list1 && $bLower < $list2) { $queue[] = [ - $alo, + $aLower, $list1, - $blo, + $bLower, $list2 ]; } - if ($list1 + $list3 < $ahi && $list2 + $list3 < $bhi) { + if ($list1 + $list3 < $aUpper && $list2 + $list3 < $bUpper) { $queue[] = [ $list1 + $list3, - $ahi, + $aUpper, $list2 + $list3, - $bhi + $bUpper ]; } } From 8586225e4de8aa631e78f56047022d64c309cccf Mon Sep 17 00:00:00 2001 From: JBlond Date: Sat, 11 Jul 2020 11:06:12 +0200 Subject: [PATCH 030/206] follow up https://github.com/JBlond/php-diff/pull/42 --- lib/jblond/Diff/Renderer/SequenceMatcherHelper.php | 4 ++-- lib/jblond/Diff/SequenceMatcher.php | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php b/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php index 4be8f5d7..f191599b 100644 --- a/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php +++ b/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php @@ -25,7 +25,7 @@ class SequenceMatcherHelper * @param mixed $default The value to return as the default value if the key doesn't exist. * @return mixed The value from the array if the key exists or otherwise the default. */ - protected function arrayGetDefault(array $array, $key, $default) + public static function arrayGetDefault(array $array, $key, $default) { if (isset($array[$key])) { return $array[$key]; @@ -40,7 +40,7 @@ protected function arrayGetDefault(array $array, $key, $default) * @param array $bArray Second array to compare. * @return int -1, 0 or 1, as expected by the usort function. */ - protected function tupleSort(array $aArray, array $bArray): int + public static function tupleSort(array $aArray, array $bArray): int { $max = max(count($aArray), count($bArray)); for ($counter = 0; $counter < $max; ++$counter) { diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 14d03952..420e81dd 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -7,6 +7,7 @@ use InvalidArgumentException; use jblond\Diff\Renderer\SequenceMatcherHelper; + /** * Sequence matcher for Diff * @@ -21,7 +22,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class SequenceMatcher extends SequenceMatcherHelper +class SequenceMatcher { /** * @var string|array Either a string or an array containing a callback function to determine @@ -258,7 +259,7 @@ public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUp for ($i = $aLower; $i < $aUpper; ++$i) { $newJ2Len = []; - $jDict = $this->arrayGetDefault($this->b2j, $old[$i], $nothing); + $jDict = SequenceMatcherHelper::arrayGetDefault($this->b2j, $old[$i], $nothing); foreach ($jDict as $j) { if ($j < $bLower) { continue; @@ -266,7 +267,7 @@ public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUp break; } - $k = $this->arrayGetDefault($j2Len, $j - 1, 0) + 1; + $k = SequenceMatcherHelper::arrayGetDefault($j2Len, $j - 1, 0) + 1; $newJ2Len[$j] = $k; if ($k > $bestSize) { $bestI = $i - $k + 1; @@ -413,7 +414,7 @@ public function getMatchingBlocks(): array usort( $matchingBlocks, function ($aArray, $bArray) { - return $this->tupleSort($aArray, $bArray); + return SequenceMatcherHelper::tupleSort($aArray, $bArray); } ); From f3a8f0d54eee0594e7aeddb7d60910ebc0e2f4dd Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 11 Jul 2020 11:06:12 +0200 Subject: [PATCH 031/206] Following up #42. - Removed redundant method SequenceMatcherHelper::arrayGetDefault(). - Renamed SequenceMatcherHelper to more generic name DiffUtils. - Changed calls to SequenceMatcherHelper::arrayGetDefault() into comparison with null coalesce operator. - Moved helper class from renderer directory to Diff directory. - Changed namespaces to reflect above changes. --- ...equenceMatcherHelper.php => DiffUtils.php} | 24 +++---------------- lib/jblond/Diff/SequenceMatcher.php | 9 ++++--- 2 files changed, 7 insertions(+), 26 deletions(-) rename lib/jblond/Diff/{Renderer/SequenceMatcherHelper.php => DiffUtils.php} (55%) diff --git a/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php b/lib/jblond/Diff/DiffUtils.php similarity index 55% rename from lib/jblond/Diff/Renderer/SequenceMatcherHelper.php rename to lib/jblond/Diff/DiffUtils.php index 4be8f5d7..2fd26e8d 100644 --- a/lib/jblond/Diff/Renderer/SequenceMatcherHelper.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -1,6 +1,6 @@ arrayGetDefault($this->b2j, $old[$i], $nothing); + $jDict = $this->b2j[$old[$i]] ?? $nothing; foreach ($jDict as $j) { if ($j < $bLower) { continue; @@ -266,7 +265,7 @@ public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUp break; } - $k = $this->arrayGetDefault($j2Len, $j - 1, 0) + 1; + $k = ($j2Len[$j - 1] ?? 0) + 1; $newJ2Len[$j] = $k; if ($k > $bestSize) { $bestI = $i - $k + 1; @@ -413,7 +412,7 @@ public function getMatchingBlocks(): array usort( $matchingBlocks, function ($aArray, $bArray) { - return $this->tupleSort($aArray, $bArray); + return DiffUtils::tupleSort($aArray, $bArray); } ); From 1ecdac53e9112fbbf75824aa99f13d5bf6efa2cf Mon Sep 17 00:00:00 2001 From: JBlond Date: Sun, 12 Jul 2020 21:50:14 +0200 Subject: [PATCH 032/206] remove not used variable --- example/example.php | 1 - 1 file changed, 1 deletion(-) diff --git a/example/example.php b/example/example.php index 0f2d430a..f0546a2b 100644 --- a/example/example.php +++ b/example/example.php @@ -64,7 +64,6 @@ function changeCSS(cssFile, cssLinkIndex) { 'title2' => 'Custom title for version2', ]); echo $diff->Render($renderer); - $cli = new \jblond\cli\Cli(); ?>

HTML Inline Diff

From d7bbe128f3437cbf85508ce759f806faf97ab67f Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 13 Jul 2020 08:20:43 +0200 Subject: [PATCH 033/206] add plain output for cli --- README.md | 5 +-- example/cli.php | 17 +++++++- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 46 ++++++++++++++++++-- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4314dbc9..8ddbab70 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,6 @@ composer require jblond/php-diff ## Example Use -
Example Code
- ```PHP true, 'ignoreCase' => true, 'context' => 2, + 'cliColor' => 'simple' // for cli output ]; // Initialize the diff class. @@ -60,8 +59,6 @@ $renderer = new SideBySide([ echo $diff->Render($renderer); ``` -
- ### Example Output A quick usage example can be found in the `example/` directory and under example.php. Included is a light theme and a dark theme. diff --git a/example/cli.php b/example/cli.php index 189ab2a0..97a5b2cf 100644 --- a/example/cli.php +++ b/example/cli.php @@ -7,6 +7,10 @@ // Include and instantiate autoloader. require '../vendor/autoload.php'; +// jblond\cli\Cli +$cli = new Cli(); + + // Include two sample files for comparison. $a = file_get_contents(dirname(__FILE__) . '/a.txt'); $b = file_get_contents(dirname(__FILE__) . '/b.txt'); @@ -26,6 +30,15 @@ // \jblond\Diff\Renderer\Text $renderer = new UnifiedCli(); -// jblond\cli\Cli -$cli = new Cli(); + $cli->output($diff->render($renderer)); + +echo "\n\n Now Colored\n\n"; + +$coloredRenderer = new UnifiedCli(['cliColor'=>'simple']); + +$cli->output($diff->render($coloredRenderer)); + +$coloredWordBasedRenderer = new UnifiedCli(['cliColor'=>'wordBased']); + +$cli->output($diff->render($coloredWordBasedRenderer)); diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 32e879a6..3e85bf68 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -2,9 +2,11 @@ namespace jblond\Diff\Renderer\Text; +use InvalidArgumentException; use jblond\cli\CliColors; use jblond\Diff\Renderer\RendererAbstract; + /** * Unified diff generator for PHP DiffLib. * @@ -25,6 +27,11 @@ class UnifiedCli extends RendererAbstract */ private $colors; + /** + * @var array + */ + protected $options; + /** * UnifiedCli constructor. * @param array $options @@ -33,14 +40,45 @@ public function __construct(array $options = []) { parent::__construct($options); $this->colors = new CliColors(); + $this->options = $options; } /** * Render and return a unified diff. * * @return string Direct Output to the console + * @throws InvalidArgumentException */ public function render(): string + { + if (!isset($this->options['cliColor'])) { + return $this->output(); + } + if (isset($this->options['cliColor']) && $this->options['cliColor'] == 'simple') { + return $this->output(); + } + throw new InvalidArgumentException('Invalid cliColor option'); + } + + + /** + * @param $string + * @param string $color + * @return string + */ + private function colorizeString($string, $color = ''): string + { + if (isset($this->options['cliColor']) && $this->options['cliColor'] == 'simple') { + return $this->colors->getColoredString($string, $color); + } + return $string; + } + + /** + * Render and return a unified colored diff. + * @return string + */ + private function output(): string { $diff = ''; $opCodes = $this->diff->getGroupedOpCodes(); @@ -56,7 +94,7 @@ public function render(): string $i2 = -1; } - $diff .= $this->colors->getColoredString( + $diff .= $this->colorizeString( '@@ -' . ($i1 + 1) . ',' . ($i2 - $i1) . ' +' . ($j1 + 1) . ',' . ($j2 - $j1) . " @@\n", 'purple' ); @@ -66,7 +104,7 @@ public function render(): string "\n ", $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) ); - $diff .= $this->colors->getColoredString(' ' . $string . "\n", 'grey'); + $diff .= $this->colorizeString(' ' . $string . "\n", 'grey'); continue; } if ($tag == 'replace' || $tag == 'delete') { @@ -74,14 +112,14 @@ public function render(): string "\n- ", $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) ); - $diff .= $this->colors->getColoredString('-' . $string . "\n", 'light_red'); + $diff .= $this->colorizeString('-' . $string . "\n", 'light_red'); } if ($tag == 'replace' || $tag == 'insert') { $string = implode( "\n+", $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) ); - $diff .= $this->colors->getColoredString('+' . $string . "\n", 'light_green'); + $diff .= $this->colorizeString('+' . $string . "\n", 'light_green'); } } } From 89602af6954d50b15c519cc5829686b5e7130e02 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 13 Jul 2020 11:32:16 +0200 Subject: [PATCH 034/206] remove output example --- example/cli.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/example/cli.php b/example/cli.php index 97a5b2cf..77cf8f50 100644 --- a/example/cli.php +++ b/example/cli.php @@ -38,7 +38,3 @@ $coloredRenderer = new UnifiedCli(['cliColor'=>'simple']); $cli->output($diff->render($coloredRenderer)); - -$coloredWordBasedRenderer = new UnifiedCli(['cliColor'=>'wordBased']); - -$cli->output($diff->render($coloredWordBasedRenderer)); From 0c75757bea37584a81bce7bdff273c14a2293f54 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 13 Jul 2020 15:14:06 +0200 Subject: [PATCH 035/206] add unit test for cli output --- .../Diff/Renderer/Text/TextRenderersTest.php | 16 +++++++ tests/resources/ab.diff | 42 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/resources/ab.diff diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index a08a0851..e52fb5f9 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -67,4 +67,20 @@ public function testUnified() $this->assertStringEqualsFile('tests/resources/textUnified.txt', $result); } + + public function testUnifiedCli() + { + $diff = new Diff( + file_get_contents('tests/resources/a.txt'), + file_get_contents('tests/resources/b.txt') + ); + + $renderer = new Diff\Renderer\Text\UnifiedCli(); + $result = $diff->render($renderer); + if ($this->genOutputFiles) { + file_put_contents('textUnifiedCli.txt', $result); + } + $this->assertStringEqualsFile('tests/resources/ab.diff', $result); + } } + diff --git a/tests/resources/ab.diff b/tests/resources/ab.diff new file mode 100644 index 00000000..c66e4752 --- /dev/null +++ b/tests/resources/ab.diff @@ -0,0 +1,42 @@ +@@ -1,22 +1,22 @@ + + + +- Hello World! ++ Hello You! + + +

This is demo content to show features of the php-diff package.

+-

This line is removed from version2.

+

This line is the same for both versions.

+-

This line has inline differences between both versions.

++

This line has differences between both versions.

+

This line is the same for both versions.

+-

This line also has inline differences between both versions.

++

This line also has InLine differences between both versions.

+

This line is the same for both versions.

++

This line is added to version2.

+ +

+ It's also compatible with multibyte characters (like Chinese and emoji) as shown below: +- 另外我覺得那個評價的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革” +- Do you know what "金槍魚罐頭" means in Chinese? +- 🍏🍎🙂 ++ 另外我覺得那個評鑑的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革” ++ Do you know what "魚の缶詰" means in Chinese? ++ 🍎🍏🙂 +

+ +

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+@@ -25,9 +25,9 @@ +

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+-

This line also has inline differences between both versions. It's the whitespace in front.

++

This line also has inline differences between both versions. It's the whitespace in front.

+

This line is the same for both versions.

+-

This line also has inline differences between both versions.

++

This line also has inline differences between both versions!

+ + + From 7ec0dbb22cac3612de212d603d2d96c96a9e72d4 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 13 Jul 2020 15:20:41 +0200 Subject: [PATCH 036/206] update doc in unit test --- tests/Diff/Renderer/Html/HtmlRenderersTest.php | 9 +++++++++ tests/Diff/Renderer/Text/TextRenderersTest.php | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 938008c7..d88b6a87 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -37,6 +37,9 @@ public function __construct($name = null, array $data = [], $dataName = '') parent::__construct($name, $data, $dataName); } + /** + * @covers \jblond\Diff\Renderer\Html\SideBySide + */ public function testSideBySide() { $diff = new Diff( @@ -53,6 +56,9 @@ public function testSideBySide() $this->assertStringEqualsFile('tests/resources/htmlSideBySide.txt', $result); } + /** + * @covers \jblond\Diff\Renderer\Html\Inline + */ public function testInline() { $diff = new Diff( @@ -69,6 +75,9 @@ public function testInline() $this->assertStringEqualsFile('tests/resources/htmlInline.txt', $result); } + /** + * @covers \jblond\Diff\Renderer\Html\Unified + */ public function testUnified() { $diff = new Diff( diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index e52fb5f9..63d61613 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -36,6 +36,10 @@ public function __construct($name = null, array $data = [], $dataName = '') parent::__construct($name, $data, $dataName); } + /** + * Test context + * @covers \jblond\Diff\Renderer\Text\Context + */ public function testContext() { $diff = new Diff( @@ -52,6 +56,10 @@ public function testContext() $this->assertStringEqualsFile('tests/resources/textContext.txt', $result); } + /** + * Test Unified + * @covers \jblond\Diff\Renderer\Text\Unified + */ public function testUnified() { $diff = new Diff( @@ -68,6 +76,10 @@ public function testUnified() $this->assertStringEqualsFile('tests/resources/textUnified.txt', $result); } + /** + * Test Unified Cli + * @covers \jblond\Diff\Renderer\Text\UnifiedCli + */ public function testUnifiedCli() { $diff = new Diff( From fbea75e2eb5683e57c9afb01542cd4bb2842bace Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 13 Jul 2020 19:53:20 +0200 Subject: [PATCH 037/206] move images to assets directory --- README.md | 14 +++++++------- htmlInline.png => assets/htmlInline.png | Bin htmlSideBySide.png => assets/htmlSideBySide.png | Bin .../htmlSidebySideDarkTheme.png | Bin htmlUnified.png => assets/htmlUnified.png | Bin textContext.png => assets/textContext.png | Bin textUnified.png => assets/textUnified.png | Bin textUnifiedCli.png => assets/textUnifiedCli.png | Bin 8 files changed, 7 insertions(+), 7 deletions(-) rename htmlInline.png => assets/htmlInline.png (100%) rename htmlSideBySide.png => assets/htmlSideBySide.png (100%) rename htmlSidebySideDarkTheme.png => assets/htmlSidebySideDarkTheme.png (100%) rename htmlUnified.png => assets/htmlUnified.png (100%) rename textContext.png => assets/textContext.png (100%) rename textUnified.png => assets/textUnified.png (100%) rename textUnifiedCli.png => assets/textUnifiedCli.png (100%) diff --git a/README.md b/README.md index 8ddbab70..9115a8c7 100644 --- a/README.md +++ b/README.md @@ -64,36 +64,36 @@ A quick usage example can be found in the `example/` directory and under example #### HTML Side By Side Example -![HTML Side By Side Example](htmlSideBySide.png "HTML Side By Side Example") +![HTML Side By Side Example](assets/htmlSideBySide.png "HTML Side By Side Example")
More Example Pictures
#### HTML Inline Example -![HTML Inline Example](htmlInline.png "HTML Inline Example") +![HTML Inline Example](assets/htmlInline.png "HTML Inline Example") #### HTML Unified Example -![HTML Unified Example](htmlUnified.png "HTML Unified Example") +![HTML Unified Example](assets/htmlUnified.png "HTML Unified Example") #### Text Unified Example -![Text Unified Example](textUnified.png "Text Unified Example") +![Text Unified Example](assets/textUnified.png "Text Unified Example") #### Text Context Example -![Text Context Example](textContext.png "Text Context Example") +![Text Context Example](assets/textContext.png "Text Context Example") #### Text Unified Console Example -![Text Unified Console Example](textUnifiedCli.png "Text Unified Console Example") +![Text Unified Console Example](assets/textUnifiedCli.png "Text Unified Console Example")
HTML Side By Side Dark Theme Example
-![HTML Side By Side Dark Theme Example](htmlSidebySideDarkTheme.png "HTML Side By Side Dark Theme Example") +![HTML Side By Side Dark Theme Example](assets/htmlSidebySideDarkTheme.png "HTML Side By Side Dark Theme Example")
diff --git a/htmlInline.png b/assets/htmlInline.png similarity index 100% rename from htmlInline.png rename to assets/htmlInline.png diff --git a/htmlSideBySide.png b/assets/htmlSideBySide.png similarity index 100% rename from htmlSideBySide.png rename to assets/htmlSideBySide.png diff --git a/htmlSidebySideDarkTheme.png b/assets/htmlSidebySideDarkTheme.png similarity index 100% rename from htmlSidebySideDarkTheme.png rename to assets/htmlSidebySideDarkTheme.png diff --git a/htmlUnified.png b/assets/htmlUnified.png similarity index 100% rename from htmlUnified.png rename to assets/htmlUnified.png diff --git a/textContext.png b/assets/textContext.png similarity index 100% rename from textContext.png rename to assets/textContext.png diff --git a/textUnified.png b/assets/textUnified.png similarity index 100% rename from textUnified.png rename to assets/textUnified.png diff --git a/textUnifiedCli.png b/assets/textUnifiedCli.png similarity index 100% rename from textUnifiedCli.png rename to assets/textUnifiedCli.png From 66e8de5a4427efe45808b154a2e0094fc7ae359b Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 14 Jul 2020 12:32:44 +0200 Subject: [PATCH 038/206] update doc --- LICENSE | 2 +- lib/jblond/Diff.php | 25 ++++++++++--------- lib/jblond/Diff/DiffUtils.php | 10 ++++---- lib/jblond/Diff/Renderer/Html/HtmlArray.php | 23 +++++++++-------- lib/jblond/Diff/Renderer/Html/Inline.php | 16 ++++++------ lib/jblond/Diff/Renderer/Html/SideBySide.php | 16 ++++++------ lib/jblond/Diff/Renderer/Html/Unified.php | 6 ++--- lib/jblond/Diff/Renderer/RendererAbstract.php | 22 ++++++++-------- lib/jblond/Diff/Renderer/Text/Context.php | 16 ++++++------ lib/jblond/Diff/Renderer/Text/Unified.php | 14 +++++------ lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 16 ++++++------ lib/jblond/Diff/SequenceMatcher.php | 24 +++++++++--------- 12 files changed, 96 insertions(+), 94 deletions(-) diff --git a/LICENSE b/LICENSE index 88d00098..78654c0d 100644 --- a/LICENSE +++ b/LICENSE @@ -12,7 +12,7 @@ modification, are permitted provided that the following conditions are met: - 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 + - Neither the name of the Mario Brandt nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index feb5c8bd..98deb1c9 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -21,14 +21,14 @@ * * PHP version 7.2 or greater * - * @package jblond - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class Diff { @@ -50,8 +50,9 @@ class Diff private $groupedCodes; /** - * @var array Associative array containing the default options available for the diff class and their default - * value. + * @var array Associative array containing the default options available + * for the diff class and their default value. + * * - context The amount of lines to include around blocks that differ. * - trimEqual Strip blocks of equal lines from the start and end of the text. * - ignoreWhitespace When true, tabs and spaces are ignored while comparing. @@ -111,8 +112,8 @@ public function __construct($version1, $version2, array $options = []) * * @param mixed $var Variable to get type from. * - * @return int Number indicating the type of the variable. 0 for array type and 1 for string type. - * @throws InvalidArgumentException When the type isn't 'array' or 'string'. + * @return int umber indicating the type of the variable. 0 for array type and 1 for string type. + * @throws InvalidArgumentException When the type isn't 'array' or 'string'. * */ public function getArgumentType($var): int diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 2fd26e8d..e054527a 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -7,11 +7,11 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff - * @author Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff + * @author Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class DiffUtils { diff --git a/lib/jblond/Diff/Renderer/Html/HtmlArray.php b/lib/jblond/Diff/Renderer/Html/HtmlArray.php index ca3cb5d3..67bd2b43 100644 --- a/lib/jblond/Diff/Renderer/Html/HtmlArray.php +++ b/lib/jblond/Diff/Renderer/Html/HtmlArray.php @@ -11,20 +11,21 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Html + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class HtmlArray extends RendererAbstract { /** - * @var array Associative array containing the default options available for this renderer and their default - * value. + * @var array Associative array containing the default options available + * for this renderer and their default value. + * * - tabSize The amount of spaces to replace a tab character with. * - title_a Title of the "old" version of text. * - title_b Title of the "new" version of text. @@ -46,7 +47,7 @@ class HtmlArray extends RendererAbstract * * This method is called by the renderers which extends this class. * - * @param array $changes Contains the op-codes about the differences between "old and "new". + * @param array $changes Contains the op-codes about the differences between "old and "new". * @param object|Inline|SideBySide|Unified $htmlRenderer Renderer which extends this class. * * @return string HTML representation of the differences. diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index b32b5067..77fd36fa 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -9,14 +9,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Html + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class Inline extends HtmlArray { diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 4acd7a98..6d1ae675 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -9,14 +9,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Html + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2009 Chris Boulton + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class SideBySide extends HtmlArray { diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index bfc38f08..2a60df86 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -10,11 +10,11 @@ * PHP version 7.2 or greater * * @package jblond\Diff\Renderer\Html - * @author Mario Brandt + * @author Mario Brandt * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton + * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.1.0 * @link https://github.com/JBlond/php-diff */ class Unified extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/RendererAbstract.php b/lib/jblond/Diff/Renderer/RendererAbstract.php index 6e3bb23c..b1e76704 100644 --- a/lib/jblond/Diff/Renderer/RendererAbstract.php +++ b/lib/jblond/Diff/Renderer/RendererAbstract.php @@ -11,14 +11,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ abstract class RendererAbstract { @@ -29,7 +29,7 @@ abstract class RendererAbstract public $diff; /** - * @var array Array of the default options that apply to this renderer. + * @var array Array of the default options that apply to this renderer. */ protected $defaultOptions = [ 'title1' => 'Version1', @@ -37,7 +37,7 @@ abstract class RendererAbstract ]; /** - * @var array Array containing the user applied and merged default options for the renderer. + * @var array Array containing the user applied and merged default options for the renderer. */ protected $options = []; @@ -57,7 +57,7 @@ public function __construct(array $options = []) * Options are merged with the default to ensure that there aren't any missing * options. * - * @param array $options Array of options to set. + * @param array $options Array of options to set. */ public function setOptions(array $options) { diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 880f2be3..455cb254 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -11,14 +11,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Text + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2009 Chris Boulton + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class Context extends RendererAbstract { diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 89b8ff7e..aa3d3a62 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -11,13 +11,13 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Chris Boulton - * @author Mario Brandt - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Text + * @author Chris Boulton + * @author Mario Brandt + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ /** diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 3e85bf68..196edfab 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -12,11 +12,11 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Text + * @author Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class UnifiedCli extends RendererAbstract @@ -34,7 +34,7 @@ class UnifiedCli extends RendererAbstract /** * UnifiedCli constructor. - * @param array $options + * @param array $options */ public function __construct(array $options = []) { @@ -62,11 +62,11 @@ public function render(): string /** - * @param $string + * @param string $string * @param string $color * @return string */ - private function colorizeString($string, $color = ''): string + private function colorizeString(string $string, string $color = ''): string { if (isset($this->options['cliColor']) && $this->options['cliColor'] == 'simple') { return $this->colors->getColoredString($string, $color); diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index c44b1ccc..2a90cd75 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -11,14 +11,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.0 + * @link https://github.com/JBlond/php-diff */ class SequenceMatcher { @@ -79,9 +79,9 @@ class SequenceMatcher * sequence matcher and it will perform a basic cleanup & calculate junk * elements. * - * @param string|array $old A string or array containing the lines to compare against. - * @param string|array $new A string or array containing the lines to compare. - * @param array $options + * @param string|array $old A string or array containing the lines to compare against. + * @param string|array $new A string or array containing the lines to compare. + * @param array $options * @param string|array|null $junkCallback Either an array or string that references a callback function * (if there is one) to determine 'junk' characters. */ @@ -212,7 +212,7 @@ private function chainB() * for the list of junk characters. * * @param string $bString - * @return bool $b True if the character is considered junk. False if not. + * @return bool True if the character is considered junk. False if not. */ private function isBJunk(string $bString): bool { From 4f2b31a5e43aaa11e3f9d7a0209cf8e652a10711 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 15 Jul 2020 21:41:14 +0200 Subject: [PATCH 039/206] correct typo --- lib/jblond/Diff.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 98deb1c9..aa02e18b 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -112,7 +112,7 @@ public function __construct($version1, $version2, array $options = []) * * @param mixed $var Variable to get type from. * - * @return int umber indicating the type of the variable. 0 for array type and 1 for string type. + * @return int Number indicating the type of the variable. 0 for array type and 1 for string type. * @throws InvalidArgumentException When the type isn't 'array' or 'string'. * */ From 8555fdd922fa8423aac371b99dfb83ed9f550c7b Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 16 Jul 2020 08:24:26 +0200 Subject: [PATCH 040/206] update doc --- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/Renderer/Html/HtmlArray.php | 2 +- lib/jblond/Diff/Renderer/RendererAbstract.php | 6 +++--- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index aa02e18b..acd0b888 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -50,7 +50,7 @@ class Diff private $groupedCodes; /** - * @var array Associative array containing the default options available + * @var array Associative array containing the default options available * for the diff class and their default value. * * - context The amount of lines to include around blocks that differ. diff --git a/lib/jblond/Diff/Renderer/Html/HtmlArray.php b/lib/jblond/Diff/Renderer/Html/HtmlArray.php index 67bd2b43..02cd0b8e 100644 --- a/lib/jblond/Diff/Renderer/Html/HtmlArray.php +++ b/lib/jblond/Diff/Renderer/Html/HtmlArray.php @@ -23,7 +23,7 @@ class HtmlArray extends RendererAbstract { /** - * @var array Associative array containing the default options available + * @var array Associative array containing the default options available * for this renderer and their default value. * * - tabSize The amount of spaces to replace a tab character with. diff --git a/lib/jblond/Diff/Renderer/RendererAbstract.php b/lib/jblond/Diff/Renderer/RendererAbstract.php index b1e76704..269323c2 100644 --- a/lib/jblond/Diff/Renderer/RendererAbstract.php +++ b/lib/jblond/Diff/Renderer/RendererAbstract.php @@ -29,7 +29,7 @@ abstract class RendererAbstract public $diff; /** - * @var array Array of the default options that apply to this renderer. + * @var array Array of the default options that apply to this renderer. */ protected $defaultOptions = [ 'title1' => 'Version1', @@ -37,7 +37,7 @@ abstract class RendererAbstract ]; /** - * @var array Array containing the user applied and merged default options for the renderer. + * @var array Array containing the user applied and merged default options for the renderer. */ protected $options = []; @@ -57,7 +57,7 @@ public function __construct(array $options = []) * Options are merged with the default to ensure that there aren't any missing * options. * - * @param array $options Array of options to set. + * @param array $options Array of options to set. */ public function setOptions(array $options) { diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 196edfab..24c6eeb2 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -34,7 +34,7 @@ class UnifiedCli extends RendererAbstract /** * UnifiedCli constructor. - * @param array $options + * @param array $options */ public function __construct(array $options = []) { From 65f2aa4925d0dbdb996d61ea5f642e8bcfbc2d11 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 16 Jul 2020 11:00:30 +0200 Subject: [PATCH 041/206] remove empty line --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 24c6eeb2..f465425d 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -6,7 +6,6 @@ use jblond\cli\CliColors; use jblond\Diff\Renderer\RendererAbstract; - /** * Unified diff generator for PHP DiffLib. * From c323f770e78dd6987f80306f41ba1eca60d59a78 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 15 Jul 2020 19:41:58 +0200 Subject: [PATCH 042/206] Change rendering flow. - Updated examples for cgi and cli output. - Renamed RendererAbstract.php to MainRendererAbstract.php. - Added default options to the abstract main Renderer. - Change: Custom options which where set before wil not be lost when setting new options. - Added a main renderer so custom (sub)renderers are easier to create. - Added a sub-renderer interface. - Merged HtmlArray.php into MainRenderer.php. - Updated HTML renderers so they act as a sub renderer of the new main renderer. - Updated existing text renderers so they make use of the renamed abstract renderer. - Added Unified CLI text renderer. - Renamed HtmlArrayTest.php to MainRenderersTest.php. - Updated MainRenderersTest to be compatible with the main renderer. - Added a PHPUnit test and resource for InlineCli. - Changed collapsed block from inline to block element for the HTML unified renderer. - Update PHPUnit resource to reflect above change. - Renamed PHPUnit resource of unified CLI text renderer to reflect other resource names. --- example/cli.php | 55 +++- example/example.php | 32 +-- lib/jblond/Diff/Renderer/Html/Inline.php | 116 ++++++-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 139 ++++++---- lib/jblond/Diff/Renderer/Html/Unified.php | 167 +++++++----- .../{Html/HtmlArray.php => MainRenderer.php} | 142 +++++----- .../Diff/Renderer/MainRendererAbstract.php | 83 ++++++ lib/jblond/Diff/Renderer/RendererAbstract.php | 66 ----- lib/jblond/Diff/Renderer/SubRenderer.php | 102 +++++++ lib/jblond/Diff/Renderer/Text/Context.php | 4 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 255 ++++++++++++++++++ lib/jblond/Diff/Renderer/Text/Unified.php | 4 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 21 +- tests/Diff/Renderer/Html/HtmlArrayTest.php | 91 ------- .../Diff/Renderer/Html/HtmlRenderersTest.php | 39 ++- tests/Diff/Renderer/MainRendererTest.php | 140 ++++++++++ .../Diff/Renderer/Text/TextRenderersTest.php | 61 +++-- tests/Diff/SequenceMatcherTest.php | 16 +- tests/resources/htmlUnified.txt | 2 +- tests/resources/textInlineCli.txt | 33 +++ .../resources/{ab.diff => textUnifiedCli.txt} | 0 21 files changed, 1125 insertions(+), 443 deletions(-) rename lib/jblond/Diff/Renderer/{Html/HtmlArray.php => MainRenderer.php} (73%) create mode 100644 lib/jblond/Diff/Renderer/MainRendererAbstract.php delete mode 100644 lib/jblond/Diff/Renderer/RendererAbstract.php create mode 100644 lib/jblond/Diff/Renderer/SubRenderer.php create mode 100644 lib/jblond/Diff/Renderer/Text/InlineCli.php delete mode 100644 tests/Diff/Renderer/Html/HtmlArrayTest.php create mode 100644 tests/Diff/Renderer/MainRendererTest.php create mode 100644 tests/resources/textInlineCli.txt rename tests/resources/{ab.diff => textUnifiedCli.txt} (100%) diff --git a/example/cli.php b/example/cli.php index 77cf8f50..3c826ed8 100644 --- a/example/cli.php +++ b/example/cli.php @@ -2,18 +2,23 @@ use jblond\cli\Cli; use jblond\Diff; +use jblond\Diff\Renderer\Text\InlineCli; use jblond\Diff\Renderer\Text\UnifiedCli; -// Include and instantiate autoloader. -require '../vendor/autoload.php'; +// Validate the interpreter. +if (php_sapi_name() !== 'cli') { + echo 'This script demonstrates console support for the php-diff package.
'; + echo 'Please execute it from a cli interpreter.'; + exit; +} -// jblond\cli\Cli -$cli = new Cli(); +// Include and instantiate autoloader. +require '../vendor/autoload.php'; // Include two sample files for comparison. -$a = file_get_contents(dirname(__FILE__) . '/a.txt'); -$b = file_get_contents(dirname(__FILE__) . '/b.txt'); +$sampleA = file_get_contents(dirname(__FILE__) . '/a.txt'); +$sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); $customOptions = [ 'context' => 2, @@ -23,18 +28,48 @@ ]; // Choose one of the initializations. -$diff = new Diff($a, $b); +$diff = new Diff($sampleA, $sampleB); +//$diff = new Diff($a, $b, $customOptions); // Initialize the diff class with custom options. +// Instantiate Cli wrapper +$cli = new Cli(); // Generate a unified diff. -// \jblond\Diff\Renderer\Text $renderer = new UnifiedCli(); +echo "-= Unified Default =-\n\n"; +$cli->output($diff->render($renderer)); + +echo "\n\n-= Unified Colored =-\n\n"; + +$renderer = new UnifiedCli( +// Define renderer options. + [ + 'cliColor' => 'simple', + ] +); + +$cli->output($diff->render($renderer)); +// Generate an inline diff. +$renderer = new InlineCli( +// Define renderer options. + [ + 'deleteMarkers' => ['-', '-'], + 'insertMarkers' => ['+', '+'], + 'equalityMarkers' => ['=', 'x'], + ] +); +echo "-= Inline Marked =-\n\n"; $cli->output($diff->render($renderer)); -echo "\n\n Now Colored\n\n"; +echo "-= Inline Colored =-\n\n"; -$coloredRenderer = new UnifiedCli(['cliColor'=>'simple']); +$coloredRenderer = new InlineCli( +// Define renderer options. + [ + 'cliColor' => true, + ] +); $cli->output($diff->render($coloredRenderer)); diff --git a/example/example.php b/example/example.php index f0546a2b..f3637528 100644 --- a/example/example.php +++ b/example/example.php @@ -2,8 +2,8 @@ use jblond\Diff; use jblond\Diff\Renderer\Html\Inline; -use jblond\Diff\Renderer\Html\Unified as HtmlUnified; use jblond\Diff\Renderer\Html\SideBySide; +use jblond\Diff\Renderer\Html\Unified as HtmlUnified; use jblond\Diff\Renderer\Text\Context; use jblond\Diff\Renderer\Text\Unified; @@ -11,8 +11,8 @@ require '../vendor/autoload.php'; // Include two sample files for comparison. -$a = file_get_contents(dirname(__FILE__) . '/a.txt'); -$b = file_get_contents(dirname(__FILE__) . '/b.txt'); +$sampleA = file_get_contents(dirname(__FILE__) . '/a.txt'); +$sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); // Options for generating the diff. $customOptions = [ @@ -23,7 +23,7 @@ ]; // Choose one of the initializations. -$diff = new Diff($a, $b); // Initialize the diff class with default options. +$diff = new Diff($sampleA, $sampleB); // Initialize the diff class with default options. //$diff = new Diff($a, $b, $customOptions); // Initialize the diff class with custom options. ?> @@ -34,14 +34,14 @@ @@ -52,17 +52,13 @@ function changeCSS(cssFile, cssLinkIndex) {
Light Theme
Dark Theme -
+

HTML Side by Side Diff

'Custom title for version1', - 'title2' => 'Custom title for version2', - ]); + $renderer = new SideBySide(); echo $diff->Render($renderer); ?> @@ -71,7 +67,6 @@ function changeCSS(cssFile, cssLinkIndex) { render($renderer); ?> @@ -79,7 +74,6 @@ function changeCSS(cssFile, cssLinkIndex) {

HTML Unified Diff

{$diff->render($renderer)}"; ?> @@ -87,7 +81,6 @@ function changeCSS(cssFile, cssLinkIndex) {

Text Unified Diff

' . htmlspecialchars($diff->render($renderer)) . ''; ?> @@ -95,7 +88,6 @@ function changeCSS(cssFile, cssLinkIndex) {

Text Context Diff

' . htmlspecialchars($diff->render($renderer)) . ''; ?> diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index b32b5067..75200c5a 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -4,6 +4,9 @@ namespace jblond\Diff\Renderer\Html; +use jblond\Diff\Renderer\MainRenderer; +use jblond\Diff\Renderer\SubRenderer; + /** * Inline HTML diff generator for PHP DiffLib. * @@ -11,34 +14,65 @@ * * @package jblond\Diff\Renderer\Html * @author Chris Boulton - * @author Mario Brandt + * @author Mario Brandt * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class Inline extends HtmlArray +class Inline extends MainRenderer implements SubRenderer { /** - * Render a and return diff-view with changes between the two sequences displayed side by side. (under each other) + * @var array Associative array containing the default options available for this renderer and their default + * value. + * - format Format of the texts. + * - insertMarkers Markers for inserted text. + * - deleteMarkers Markers for removed text. + * - title1 Title of the 1st version of text. + * - title2 Title of the 2nd version of text. + */ + protected $subOptions = [ + 'format' => 'html', + 'insertMarkers' => ['', ''], + 'deleteMarkers' => ['', ''], + 'title1' => 'Version1', + 'title2' => 'Version2', + ]; + + /** + * Inline constructor. + * + * @param array $options Custom defined options for the inline diff renderer. + * + * @see Inline::$subOptions + */ + public function __construct(array $options = []) + { + parent::__construct(); + $this->setOptions($this->subOptions); + $this->setOptions($options); + } + + /** + * Render and return a diff-view with changes between the two sequences displayed inline (under each other). * * @return string The generated inline diff-view. */ public function render(): string { - $changes = parent::render(); + $changes = parent::renderSequences(); - return parent::renderHtml($changes, $this); + return parent::renderOutput($changes, $this); } - /** - * Generates a string representation of the opening of a predefined table and its header with titles from options. + * Generates a string representation of the opening of a table and its header with titles from the sub renderer's + * options. * * @return string HTML code representation of a table's header. */ - public function generateTableHeader(): string + public function generateDiffHeader(): string { return << @@ -53,11 +87,11 @@ public function generateTableHeader(): string } /** - * Generates a string representation of table rows showing lines are skipped. + * Generates a string representation of table rows with lines that are skipped. * - * @return string HTML code representation of a table's header. + * @return string HTML code representation of skipped lines. */ - public function generateTableRowsSkipped(): string + public function generateSkippedLines(): string { return << @@ -69,13 +103,13 @@ public function generateTableRowsSkipped(): string } /** - * Generates a string representation of table rows showing text with no difference. + * Generate a string representation of table rows with lines without differences between both versions. * * @param array $changes Contains the op-codes about the changes between two blocks. * - * @return string HTML code representing table rows showing text with no difference. + * @return string HTML code representing table rows showing text without differences. */ - public function generateTableRowsEqual(array $changes): string + public function generateLinesEqual(array $changes): string { $html = ''; @@ -96,13 +130,13 @@ public function generateTableRowsEqual(array $changes): string } /** - * Generates a string representation of table rows showing added text. + * Generates a string representation of table rows with lines that are added to the 2nd version. * * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string HTML code representing table rows showing with added text. */ - public function generateTableRowsInsert(array $changes): string + public function generateLinesInsert(array $changes): string { $html = ''; @@ -125,13 +159,13 @@ public function generateTableRowsInsert(array $changes): string } /** - * Generates a string representation of table rows showing removed text. + * Generates a string representation of table rows with lines that are removed from the 2nd version. * * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string HTML code representing table rows showing removed text. */ - public function generateTableRowsDelete(array $changes): string + public function generateLinesDelete(array $changes): string { $html = ''; @@ -154,20 +188,20 @@ public function generateTableRowsDelete(array $changes): string } /** - * Generates a string representation of table rows showing partially modified text. + * Generates a string representation of table rows with lines that are partially modified. * * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Html code representing table rows showing modified text. */ - public function generateTableRowsReplace(array $changes): string + public function generateLinesReplace(array $changes): string { $html = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1; - - $html .= <<options['deleteMarkers'], $line); + $html .= << $fromLine   @@ -180,8 +214,8 @@ public function generateTableRowsReplace(array $changes): string foreach ($changes['changed']['lines'] as $lineNo => $line) { $toLine = $changes['changed']['offset'] + $lineNo + 1; - - $html .= <<options['insertMarkers'], $line); + $html .= <<   $toLine @@ -194,4 +228,38 @@ public function generateTableRowsReplace(array $changes): string return $html; } + + /** + * Generate a string representation of the start of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Start of the diff view. + */ + public function generateBlockHeader(array $changes): string + { + return ''; + } + + /** + * Generate a string representation of the end of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string End of the block. + */ + public function generateBlockFooter(array $changes): string + { + return ''; + } + + /** + * Generate a string representation of the end of a diff view. + * + * @return string End of the diff view. + */ + public function generateDiffFooter(): string + { + return ''; + } } diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 4acd7a98..3eae1bc5 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -4,22 +4,56 @@ namespace jblond\Diff\Renderer\Html; +use jblond\Diff\Renderer\MainRenderer; +use jblond\Diff\Renderer\SubRenderer; + /** * Side by Side HTML diff generator for PHP DiffLib. * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Html + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2009 Chris Boulton + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff */ -class SideBySide extends HtmlArray +class SideBySide extends MainRenderer implements SubRenderer { + /** + * @var array Associative array containing the default options available for this renderer and their default + * value. + * - format Format of the texts. + * - insertMarkers Markers for inserted text. + * - deleteMarkers Markers for removed text. + * - title1 Title of the 1st version of text. + * - title2 Title of the 2nd version of text. + */ + protected $subOptions = [ + 'format' => 'html', + 'insertMarkers' => ['', ''], + 'deleteMarkers' => ['', ''], + 'title1' => 'Version1', + 'title2' => 'Version2', + ]; + + /** + * SideBySide constructor. + * + * @param array $options Custom defined options for the inline diff renderer. + * + * @see Inline::$subOptions + */ + public function __construct(array $options = []) + { + parent::__construct(); + $this->setOptions($this->subOptions); + $this->setOptions($options); + } + /** * Render a and return diff-view with changes between the two sequences displayed side by side. * @@ -27,9 +61,9 @@ class SideBySide extends HtmlArray */ public function render(): string { - $changes = parent::render(); + $changes = parent::renderSequences(); - return parent::renderHtml($changes, $this); + return parent::renderOutput($changes, $this); } /** @@ -37,7 +71,7 @@ public function render(): string * * @return string HTML code representation of a table's header. */ - public function generateTableHeader(): string + public function generateDiffHeader(): string { return << @@ -51,11 +85,11 @@ public function generateTableHeader(): string } /** - * Generates a string representation of table rows showing lines are skipped. + * Generates a string representation of table rows with lines that are skipped. * * @return string HTML code representation of a table's header. */ - public function generateTableRowsSkipped(): string + public function generateSkippedLines(): string { return << @@ -68,13 +102,13 @@ public function generateTableRowsSkipped(): string } /** - * Generates a string representation of table rows showing text with no difference. + * Generate a string representation of table rows with lines without differences between both versions. * * @param array $changes Contains the op-codes about the changes between two blocks. * * @return string HTML code representing table rows showing text with no difference. */ - public function generateTableRowsEqual(array $changes): string + public function generateLinesEqual(array $changes): string { $html = ''; @@ -100,13 +134,13 @@ public function generateTableRowsEqual(array $changes): string } /** - * Generates a string representation of table rows showing added text. + * Generates a string representation of table rows with lines that are added to the 2nd version. * * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string HTML code representing table rows showing with added text. */ - public function generateTableRowsInsert(array $changes): string + public function generateLinesInsert(array $changes): string { $html = ''; @@ -129,13 +163,13 @@ public function generateTableRowsInsert(array $changes): string } /** - * Generates a string representation of table rows showing removed text. + * Generates a string representation of table rows with lines that are removed from the 2nd version. * * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string HTML code representing table rows showing removed text. */ - public function generateTableRowsDelete(array $changes): string + public function generateLinesDelete(array $changes): string { $html = ''; @@ -158,13 +192,13 @@ public function generateTableRowsDelete(array $changes): string } /** - * Generates a string representation of table rows showing partially modified text. + * Generates a string representation of table rows with lines that are partially modified. * * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Html code representing table rows showing modified text. */ - public function generateTableRowsReplace(array $changes): string + public function generateLinesReplace(array $changes): string { $html = ''; @@ -174,11 +208,15 @@ public function generateTableRowsReplace(array $changes): string $fromLine = $changes['base']['offset'] + $lineNo + 1; $toLine = " "; $changedLine = " "; + if (isset($changes['changed']['lines'][$lineNo])) { $toLine = $changes['changed']['offset'] + $lineNo + 1; $changedLine = $changes['changed']['lines'][$lineNo]; } + $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); + $changedLine = str_replace(["\0", "\1"], $this->options['insertMarkers'], $changedLine); + $html .= << $fromLine @@ -192,33 +230,42 @@ public function generateTableRowsReplace(array $changes): string HTML; } - - return $html; } - foreach ($changes['changed']['lines'] as $lineNo => $changedLine) { - $toLine = $changes['changed']['offset'] + $lineNo + 1; - $fromLine = " "; - $line = " "; - if (isset($changes['base']['lines'][$lineNo])) { - $fromLine = $changes['base']['offset'] + $lineNo + 1; - $line = $changes['base']['lines'][$lineNo]; - } + return $html; + } - $html .= << - $fromLine - - $line - - $toLine - - $changedLine - - -HTML; - } + /** + * Generate a string representation of the start of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Start of the diff view. + */ + public function generateBlockHeader(array $changes): string + { + return ''; + } - return $html; + /** + * Generate a string representation of the end of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string End of the block. + */ + public function generateBlockFooter(array $changes): string + { + return ''; + } + + /** + * Generate a string representation of the end of a diff view. + * + * @return string End of the diff view. + */ + public function generateDiffFooter(): string + { + return ''; } } diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index bfc38f08..15b9061a 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -4,94 +4,91 @@ namespace jblond\Diff\Renderer\Html; +use jblond\Diff\Renderer\MainRenderer; +use jblond\Diff\Renderer\SubRenderer; + /** * Unified HTML diff generator for PHP DiffLib. * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Html + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2009 Chris Boulton + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff */ -class Unified extends HtmlArray +class Unified extends MainRenderer implements SubRenderer { /** - * Render and return a unified diff-view with changes between the two sequences displayed inline (under each other). + * @var array Associative array containing the default options available for this renderer and their default + * value. + * - format Format of the texts. + * - insertMarkers Markers for inserted text. + * - deleteMarkers Markers for removed text. + * - title1 Title of the "old" version of text. + * - title2 Title of the "new" version of text. + */ + protected $subOptions = [ + 'format' => 'html', + 'insertMarkers' => ['', ''], + 'deleteMarkers' => ['', ''], + 'title1' => 'Version1', + 'title2' => 'Version2', + ]; + + /** + * Unified constructor. + * + * @param array $options Custom defined options for the inline diff renderer. + * + * @see Inline::$subOptions + */ + public function __construct(array $options = []) + { + parent::__construct(); + $this->setOptions($this->subOptions); + $this->setOptions($options); + } + + /** + * Render a and return diff-view with changes between the two sequences (under each other). * - * @return string The generated inline diff-view. + * @return string The generated unified diff-view. */ public function render(): string { - $changes = parent::render(); + $changes = parent::renderSequences(); - return $this->renderHtml($changes); + return parent::renderOutput($changes, $this); } /** - * Render the unified diff-view as html. + * Generates a string representation of the opening of a predefined table and its header with titles from options. * - * Since this class extends the "HtmlArray" class which in turn extends "RendererAbstract" class, this method needs - * to match the signature of RendererAbstract::renderHTML(). However the second parameter isn't used and can be - * omitted. - * - * @param array $changes Contains the op-codes about the differences between "old and "new". - * @param null $object Unused. - * - * @return string HTML code containing the unified differences. + * @return string HTML code representation of the diff-view header. */ - public function renderHtml($changes, $object = null): string + public function generateDiffHeader(): string { - if (empty($changes)) { - //No changes between "old" and "new" - return 'No differences found.'; - } - - $html = ''; - - foreach ($changes as $i => $blocks) { - if ($i > 0) { - // If this is a separate block, we're condensing code to output …, - // indicating a significant portion of the code has been collapsed as it did not change. - $html .= <<… -HTML; - } - - foreach ($blocks as $change) { - $html .= ''; - switch ($change['tag']) { - case 'equal': - // Add unmodified lines. - $html .= $this->generateLinesEqual($change); - break; - case 'insert': - // Add Added lines. - $html .= $this->generateLinesInsert($change); - break; - case 'delete': - // Add deleted lines. - $html .= $this->generateLinesDelete($change); - break; - case 'replace': - // Add modified lines. - $html .= $this->generateLinesReplace($change); - break; - } - $html .= ''; - } - } - $html .= ''; + return ''; + } - return $html; + /** + * Generates a string representation of lines that are skipped. + * + * @return string HTML code representation of a table's header. + */ + public function generateSkippedLines(): string + { + return '
'; } /** - * Generates a string representation of blocks of text with no difference. + * Generate a string representation of lines without differences between both versions. * * @param array $change Contains the op-codes about the changes between two blocks. * @@ -109,7 +106,7 @@ public function generateLinesEqual(array $change): string } /** - * Generates a string representation of a block of text, where new text was added. + * Generates a string representation of lines that are added to the 2nd version. * * @param array $change Contains the op-codes about the changes between two blocks. * @@ -127,7 +124,7 @@ public function generateLinesInsert(array $change): string } /** - * Generates a string representation of a block of text, where text was removed. + * Generates a string representation of lines that are removed from the 2nd version. * * @param array $change Contains the op-codes about the changes between two blocks. * @@ -144,7 +141,7 @@ public function generateLinesDelete(array $change): string } /** - * Generates a string representation of a block of text, where text was partially modified. + * Generates a string representation of a lines that are partially modified. * * @param array $change Contains the op-codes about the changes between two blocks. * @@ -156,14 +153,50 @@ public function generateLinesReplace(array $change): string // Lines with characters removed. foreach ($change['base']['lines'] as $line) { + $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); $html .= '' . $line . '
'; } // Lines with characters added. foreach ($change['changed']['lines'] as $line) { + $line = str_replace(["\0", "\1"], $this->options['insertMarkers'], $line); $html .= '' . $line . '
'; } return $html; } + + /** + * Generate a string representation of the start of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Start of the diff view. + */ + public function generateBlockHeader(array $changes): string + { + return ''; + } + + /** + * Generate a string representation of the end of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string End of the block. + */ + public function generateBlockFooter(array $changes): string + { + return ''; + } + + /** + * Generate a string representation of the end of a diff view. + * + * @return string End of the diff view. + */ + public function generateDiffFooter(): string + { + return '
'; + } } diff --git a/lib/jblond/Diff/Renderer/Html/HtmlArray.php b/lib/jblond/Diff/Renderer/MainRenderer.php similarity index 73% rename from lib/jblond/Diff/Renderer/Html/HtmlArray.php rename to lib/jblond/Diff/Renderer/MainRenderer.php index ca3cb5d3..c44c1b15 100644 --- a/lib/jblond/Diff/Renderer/Html/HtmlArray.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -2,42 +2,31 @@ declare(strict_types=1); -namespace jblond\Diff\Renderer\Html; - -use jblond\Diff\Renderer\RendererAbstract; +namespace jblond\Diff\Renderer; /** - * Base renderer for rendering HTML based diffs for PHP DiffLib. + * Base renderer for rendering diffs for PHP DiffLib. * * PHP version 7.2 or greater * * @package jblond\Diff\Renderer\Html * @author Chris Boulton - * @author Mario Brandt + * @author Mario Brandt * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class HtmlArray extends RendererAbstract +class MainRenderer extends MainRendererAbstract { /** - * @var array Associative array containing the default options available for this renderer and their default - * value. - * - tabSize The amount of spaces to replace a tab character with. - * - title_a Title of the "old" version of text. - * - title_b Title of the "new" version of text. + * @var int */ - protected $defaultOptions = [ - 'tabSize' => 4, - 'title1' => 'Version1', - 'title2' => 'Version2', - ]; - + protected $maxLineMarkerWidth = 0; /** * @var string The last operation which was recorded in the array which contains the changes, used by the renderer. - * @see HtmlArray::appendChangesArray() + * @see MainRenderer::appendChangesArray() */ private $lastTag; @@ -46,66 +35,74 @@ class HtmlArray extends RendererAbstract * * This method is called by the renderers which extends this class. * - * @param array $changes Contains the op-codes about the differences between "old and "new". - * @param object|Inline|SideBySide|Unified $htmlRenderer Renderer which extends this class. + * @param array $changes Contains the op-codes about the differences between "old and "new". + * @param object $subRenderer Renderer which is subClass of this class. * - * @return string HTML representation of the differences. + * @return string Representation of the differences. */ - public function renderHtml(array $changes, object $htmlRenderer): string + public function renderOutput(array $changes, object $subRenderer): string { - if (empty($changes)) { + if (!$changes) { //No changes between "old" and "new" return 'No differences found.'; } - $html = $htmlRenderer->generateTableHeader(); + $output = $subRenderer->generateDiffHeader(); - foreach ($changes as $i => $blocks) { - if ($i > 0) { - // If this is a separate block, we're condensing code to output …, - // indicating a significant portion of the code has been collapsed as it did not change. - $html .= $htmlRenderer->generateTableRowsSkipped(); + foreach ($changes as $iterator => $blocks) { + if ($iterator > 0) { + // If this is a separate block, we're condensing code to indicate a significant portion of the code + // has been collapsed as it did not change. + $output .= $subRenderer->generateSkippedLines(); + } + + if ($this->options['format'] == 'plain') { + $this->maxLineMarkerWidth = + max( + strlen($this->options['insertMarkers'][0]), + strlen($this->options['deleteMarkers'][0]), + strlen($this->options['equalityMarkers'][0]), + strlen($this->options['equalityMarkers'][1]) + ); } foreach ($blocks as $change) { - $html .= ''; + $output .= $subRenderer->generateBlockHeader($change); switch ($change['tag']) { - // Equal changes should be shown on both sides of the diff case 'equal': - $html .= $htmlRenderer->generateTableRowsEqual($change); + $output .= $subRenderer->generateLinesEqual($change); break; - // Added lines only on the right side case 'insert': - $html .= $htmlRenderer->generateTableRowsInsert($change); + $output .= $subRenderer->generateLinesInsert($change); break; - // Show deleted lines only on the left side case 'delete': - $html .= $htmlRenderer->generateTableRowsDelete($change); + $output .= $subRenderer->generateLinesDelete($change); break; - // Show modified lines on both sides case 'replace': - $html .= $htmlRenderer->generateTableRowsReplace($change); + $output .= $subRenderer->generateLinesReplace($change); break; } - $html .= ''; + $output .= $subRenderer->generateBlockFooter($change); } } - $html .= ''; + $output .= $subRenderer->generateDiffFooter(); - return $html; + return $output; } /** - * Render and return an array structure suitable for generating HTML based differences. + * Render the sequences where differences between them are marked. + * + * The marked sequences are returned as array which is suitable for rendering the final output. * - * Generally called by classes which extend this class and that generate a HTML based diff by returning an array of - * the changes to show in the diff. + * Generally called by classes which extend this class and that generate a diff by returning an array of the changes + * to show in the diff. * - * @return array An array of the generated changes, suitable for presentation in HTML. + * @return array An array of marked sequences. */ - public function render() + protected function renderSequences(): array { // The old and New texts are copied so change markers can be added without modifying the original sequences. $oldText = $this->diff->getVersion1(); @@ -159,15 +156,11 @@ public function render() if ($tag == 'replace' || $tag == 'delete') { // Inline differences or old block doesn't exist in the new text. - // Replace the markers, which where added above, by HTML delete tags. - $oldBlock = str_replace(["\0", "\1"], ['', ''], $oldBlock); $blocks[$lastBlock]['base']['lines'] += $oldBlock; } if ($tag == 'replace' || $tag == 'insert') { // Inline differences or the new block doesn't exist in the old text. - // Replace the markers, which where added above, by HTML insert tags. - $newBlock = str_replace(["\0", "\1"], ['', ''], $newBlock); $blocks[$lastBlock]['changed']['lines'] += $newBlock; } } @@ -199,10 +192,10 @@ public function render() */ private function markInlineChange(array &$oldText, array &$newText, $startOld, $endOld, $startNew) { - for ($i = 0; $i < ($endOld - $startOld); ++$i) { + for ($iterator = 0; $iterator < ($endOld - $startOld); ++$iterator) { // Check each line in the block for differences. - $oldString = $oldText[$startOld + $i]; - $newString = $newText[$startNew + $i]; + $oldString = $oldText[$startOld + $iterator]; + $newString = $newText[$startNew + $iterator]; // Determine the start and end position of the line difference. [$start, $end] = $this->getInlineChange($oldString, $newString); @@ -223,8 +216,8 @@ private function markInlineChange(array &$oldText, array &$newText, $startOld, $ mb_substr($newString, $sequenceEnd); // Overwrite the strings in the old and new text so the changed lines include the markers. - $oldText[$startOld + $i] = $oldString; - $newText[$startNew + $i] = $newString; + $oldText[$startOld + $iterator] = $oldString; + $newText[$startNew + $iterator] = $newString; } } } @@ -303,6 +296,7 @@ private function appendChangesArray(array &$blocks, string $tag, int $lineInOld, ]; $this->lastTag = $tag; + return count($blocks) - 1; } @@ -321,32 +315,34 @@ protected function formatLines(array $strings): array if ($this->options['tabSize'] !== false) { // Replace tabs with spaces. $strings = array_map( - function ($item) { - return str_replace("\t", str_repeat(' ', $this->options['tabSize']), $item); + function ($line) { + return str_replace("\t", str_repeat(' ', $this->options['tabSize']), $line); }, $strings ); } - // Convert special characters to HTML entities - $strings = array_map( - function ($item) { - return htmlspecialchars($item, ENT_NOQUOTES, 'UTF-8'); - }, - $strings - ); - - // Replace leading spaces of a line with HTML entities. - foreach ($strings as &$line) { - $line = preg_replace_callback( - '/(^[ \0\1]*)/', - function ($matches) { - return str_replace(' ', " ", $matches[0]); + if (strtolower($this->options['format']) == 'html') { + // Convert special characters to HTML entities + $strings = array_map( + function ($line) { + return htmlspecialchars($line, ENT_NOQUOTES, 'UTF-8'); }, - $line + $strings ); + + // Replace leading spaces of a line with HTML entities. + foreach ($strings as &$line) { + $line = preg_replace_callback( + '/(^[ \0\1]*)/', + function ($matches) { + return str_replace(' ', " ", $matches[0]); + }, + $line + ); + } + unset($line); } - unset($line); return $strings; } diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php new file mode 100644 index 00000000..be7b86c4 --- /dev/null +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -0,0 +1,83 @@ + + * @author Ferry Cools + * @copyright (c) 2009 Chris Boulton + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff + */ +abstract class MainRendererAbstract +{ + + /** + * @var Diff $diff Instance of the diff class that this renderer is generating the rendered diff for. + */ + public $diff; + + /** + * @var array Associative array containing the default options available for this renderer and their default + * value. + * - tabSize The amount of spaces to replace a tab character with. + * - format The format of the input texts. + * - cliColor Colorized output for cli. + * - deleteMarkers Markers for removed text. + * - insertMarkers Markers for inserted text. + * - equalityMarkers Markers for unchanged and changed lines. + * - insertColors Fore- and background color for inserted text. Only when cloColor = true. + * - deleteColors Fore- and background color for removed text. Only when cloColor = true. + */ + protected $mainOptions = [ + 'tabSize' => 4, + 'format' => 'plain', + 'cliColor' => false, + 'deleteMarkers' => ['', ''], + 'insertMarkers' => ['', ''], + 'equalityMarkers' => ['', ''], + 'insertColors' => ['black', 'green'], + 'deleteColors' => ['black', 'red'], + ]; + + /** + * @var array Array containing a merge between the default options and user applied options for the renderer. + * @see MainRendererAbstract::$mainOptions + */ + protected $options = []; + + /** + * The constructor. Instantiates the rendering engine and if options are passed, + * sets the options for the renderer. + * + * @param array $options Optionally, an array of the options for the renderer. + */ + public function __construct(array $options = []) + { + $this->setOptions($options); + } + + /** + * Set the options of the main renderer to the supplied options. + * + * Options are merged with the default to ensure that there aren't any missing options. + * When custom options are added to the default ones, they can be overwritten, but they can't be removed. + * @see MainRendererAbstract::$mainOptions + * + * @param array $options Array of options to set. + */ + public function setOptions(array $options) + { + $this->options = array_merge($this->mainOptions, $this->options, $options); + } +} diff --git a/lib/jblond/Diff/Renderer/RendererAbstract.php b/lib/jblond/Diff/Renderer/RendererAbstract.php deleted file mode 100644 index 6e3bb23c..00000000 --- a/lib/jblond/Diff/Renderer/RendererAbstract.php +++ /dev/null @@ -1,66 +0,0 @@ - - * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff - */ -abstract class RendererAbstract -{ - - /** - * @var Diff $diff Instance of the diff class that this renderer is generating the rendered diff for. - */ - public $diff; - - /** - * @var array Array of the default options that apply to this renderer. - */ - protected $defaultOptions = [ - 'title1' => 'Version1', - 'title2' => 'Version2', - ]; - - /** - * @var array Array containing the user applied and merged default options for the renderer. - */ - protected $options = []; - - /** - * The constructor. Instantiates the rendering engine and if options are passed, - * sets the options for the renderer. - * - * @param array $options Optionally, an array of the options for the renderer. - */ - public function __construct(array $options = []) - { - $this->setOptions($options); - } - - /** - * Set the options of the renderer to those supplied in the passed in array. - * Options are merged with the default to ensure that there aren't any missing - * options. - * - * @param array $options Array of options to set. - */ - public function setOptions(array $options) - { - $this->options = array_merge($this->defaultOptions, $options); - } -} diff --git a/lib/jblond/Diff/Renderer/SubRenderer.php b/lib/jblond/Diff/Renderer/SubRenderer.php new file mode 100644 index 00000000..383c1a2a --- /dev/null +++ b/lib/jblond/Diff/Renderer/SubRenderer.php @@ -0,0 +1,102 @@ + + * @copyright (c) 2020 Ferry Cools + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff + */ +interface SubRenderer +{ + /** + * Render and return a diff-view with changes between two sequences. + * + * @return string The generated diff-view. + */ + public function render(): string; + + /** + * Generate a string representation of the start of a diff view. + * + * @return string Start of the diff view. + */ + public function generateDiffHeader(): string; + + /** + * Generate a string representation of the start of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Start of the diff view. + */ + public function generateBlockHeader(array $changes): string; + + /** + * Generate a string representation of lines that are skipped in the diff view. + * + * @return string Representation of skipped lines. + */ + public function generateSkippedLines(): string; + + /** + * Generate a string representation of lines without differences between both versions. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Text with no difference. + */ + public function generateLinesEqual(array $changes): string; + + /** + * Generate a string representation of lines that are added to the 2nd version. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Added text. + */ + public function generateLinesInsert(array $changes): string; + + /** + * Generate a string representation of lines that are removed from the 2nd version. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Removed text. + */ + public function generateLinesDelete(array $changes): string; + + /** + * Generate a string representation of lines that are partially modified. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Modified text. + */ + public function generateLinesReplace(array $changes): string; + + /** + * Generate a string representation of the end of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string End of the block. + */ + public function generateBlockFooter(array $changes): string; + + /** + * Generate a string representation of the end of a diff view. + * + * @return string End of the diff view. + */ + public function generateDiffFooter(): string; +} diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 880f2be3..aedc5611 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -4,7 +4,7 @@ namespace jblond\Diff\Renderer\Text; -use jblond\Diff\Renderer\RendererAbstract; +use jblond\Diff\Renderer\MainRendererAbstract; /** * Context diff generator for PHP DiffLib. @@ -20,7 +20,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class Context extends RendererAbstract +class Context extends MainRendererAbstract { /** * @var array Array of the different op-code tags and how they map to the context diff-view equivalent. diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php new file mode 100644 index 00000000..a66d9144 --- /dev/null +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -0,0 +1,255 @@ + + * @copyright (c) 2020 Ferry Cools + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff + */ +class InlineCli extends MainRenderer implements SubRenderer +{ + /** + * @var array Associative array containing the default options available for this renderer and their default + * value. + */ + protected $subOptions = []; + + /** + * InlineCli constructor. + * + * @param array $options Custom defined options for the inline diff renderer. + * + * @see Inline::$subOptions + */ + public function __construct(array $options = []) + { + parent::__construct(); + $this->setOptions($this->subOptions); + $this->setOptions($options); + } + + /** + * Render a and return diff-view with changes between the two sequences displayed inline. + * + * @return string The generated diff-view. + */ + public function render(): string + { + $changes = parent::renderSequences(); + + return parent::renderOutput($changes, $this); + } + + + /** + * Generate a string representation of the start of a diff view. + * + * @return string Start of the diff view. + */ + public function generateDiffHeader(): string + { + return ''; + } + + /** + * Generate a string representation of the start of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of lines. + * + * @return string Start of the diff view. + */ + public function generateBlockHeader($changes): string + { + return ''; + } + + /** + * Generate a string representation of the lines that are skipped in the diff view. + * + * @return string Representation of skipped lines. + */ + public function generateSkippedLines(): string + { + return '...' . PHP_EOL; + } + + /** + * Generate a string representation lines without differences between the two versions. + * + * @param array $changes Contains the op-codes about the changes between two blocks of lines. + * + * @return string Text with no difference. + */ + public function generateLinesEqual(array $changes): string + { + $returnValue = ''; + $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][0])); + + foreach ($changes['base']['lines'] as $line) { + $returnValue .= $this->options['equalityMarkers'][0] . $padding . '|' . $line . PHP_EOL; + } + + return $returnValue; + } + + /** + * Generate a string representation of lines that are added to the 2nd version. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Added text. + */ + public function generateLinesInsert(array $changes): string + { + $colorize = new CliColors(); + $returnValue = ''; + $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['insertMarkers'][0])); + + foreach ($changes['changed']['lines'] as $line) { + if ($this->options['cliColor']) { + [$fgColor, $bgColor] = $this->options['insertColors']; + $line = $colorize->getColoredString($line, $fgColor, $bgColor); + } + $returnValue .= $this->options['insertMarkers'][0] . $padding . '|' . $line . PHP_EOL; + } + + return $returnValue; + } + + /** + * Generate a string representation of lines that are removed from the 2nd version. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Removed text. + */ + public function generateLinesDelete(array $changes): string + { + $colorize = new CliColors(); + $returnValue = ''; + $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['deleteMarkers'][0])); + + foreach ($changes['base']['lines'] as $line) { + if ($this->options['cliColor']) { + [$fgColor, $bgColor] = $this->options['deleteColors']; + $line = $colorize->getColoredString($line, $fgColor, $bgColor); + } + $returnValue .= $this->options['deleteMarkers'][0] . $padding . '|' . $line . PHP_EOL; + } + + return $returnValue; + } + + /** + * Generate a string representation of lines that are partially modified. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Modified text. + */ + public function generateLinesReplace(array $changes): string + { + $returnValue = ''; + + $changes['base']['lines'] = $this->mergeChanges( + $changes['base']['lines'], + $changes['changed']['lines'], + $this->options['deleteColors'], + $this->options['insertColors'] + ); + + $returnValue .= implode(PHP_EOL, $changes['base']['lines']) . PHP_EOL; + + return $returnValue; + } + + /** + * Merge the changes between two lines together and mark these changes. + * + * @param array $baseLines Lines of version 1. + * @param array $changedLines Lines of version 2. + * @param array|null[] $deleteColors Fore- and background colors of part that is removed from the 2nd version. + * @param array|null[] $insertColors Fore- and background colors of part that is added to the 2nd version. + * + * Option $deleteColors and $insertColors only have affect when this class's cliColors option is set to true. + * + * @return array + */ + private function mergeChanges( + array $baseLines, + array $changedLines, + array $deleteColors = [null, null], + array $insertColors = [null, null] + ): array { + $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][1])); + if ($this->options['cliColor']) { + $colorize = new CliColors(); + } + + foreach ($baseLines as $lineKey => $line) { + $iterator = 0; + $baselineParts = preg_split('/\x00(.*?)\x01/', $line, -1, PREG_SPLIT_DELIM_CAPTURE); + $changedLineParts = preg_split('/\x00(.*?)\x01/', $changedLines[$lineKey], -1, PREG_SPLIT_DELIM_CAPTURE); + + foreach ($baselineParts as $partKey => &$part) { + if ($iterator++ % 2) { + // This part of the line has been changed. Surround it with user defied markers. + $basePart = $this->options['deleteMarkers'][0] . $part . $this->options['deleteMarkers'][1]; + $changedPart = + $this->options['insertMarkers'][0] . + $changedLineParts[$partKey] . + $this->options['insertMarkers'][1]; + + if ($this->options['cliColor']) { + // Colorize the changed part. + [$fgColor, $bgColor] = $deleteColors; + $basePart = $colorize->getColoredString($basePart, $fgColor, $bgColor); + [$fgColor, $bgColor] = $insertColors; + $changedPart = $colorize->getColoredString($changedPart, $fgColor, $bgColor); + } + $part = $basePart . $changedPart; + } + } + unset($part); + $baseLines[$lineKey] = $this->options['equalityMarkers'][1] . $padding . '|' . implode('', $baselineParts); + } + + return $baseLines; + } + + /** + * Generate a string representation of the end of a block. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string End of the block + */ + public function generateBlockFooter(array $changes): string + { + return ''; + } + + /** + * Generate a string representation of the end of a diff view. + * + * @return string End of the diff view. + */ + public function generateDiffFooter(): string + { + return ''; + } +} diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 89b8ff7e..cf82dd4a 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -4,7 +4,7 @@ namespace jblond\Diff\Renderer\Text; -use jblond\Diff\Renderer\RendererAbstract; +use jblond\Diff\Renderer\MainRendererAbstract; /** * Unified diff generator for PHP DiffLib. @@ -23,7 +23,7 @@ /** * Class Diff_Renderer_Text_Unified */ -class Unified extends RendererAbstract +class Unified extends MainRendererAbstract { /** * Render and return a unified diff. diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 3e85bf68..3949bbea 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -4,22 +4,22 @@ use InvalidArgumentException; use jblond\cli\CliColors; -use jblond\Diff\Renderer\RendererAbstract; - +use jblond\Diff\Renderer\MainRendererAbstract; /** * Unified diff generator for PHP DiffLib. * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff\Renderer\Text + * @author Mario Brandt + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff */ -class UnifiedCli extends RendererAbstract +class UnifiedCli extends MainRendererAbstract { /** @@ -27,11 +27,6 @@ class UnifiedCli extends RendererAbstract */ private $colors; - /** - * @var array - */ - protected $options; - /** * UnifiedCli constructor. * @param array $options diff --git a/tests/Diff/Renderer/Html/HtmlArrayTest.php b/tests/Diff/Renderer/Html/HtmlArrayTest.php deleted file mode 100644 index 5b7313b5..00000000 --- a/tests/Diff/Renderer/Html/HtmlArrayTest.php +++ /dev/null @@ -1,91 +0,0 @@ -diff = new Diff( - ['a'], - [] - ); - $result = $htmlRenderer->render(); - static::assertEquals([ - [ - [ - 'tag' => 'delete', - 'base' => [ - 'offset' => 0, - 'lines' => [ - 'a' - ] - ], - 'changed' => [ - 'offset' => 0, - 'lines' => [] - ] - ] - ] - ], $result); - } - - /** - * - */ - public function testRenderFixesSpaces() - { - $htmlRenderer = new HtmlArray(); - $htmlRenderer->diff = new Diff( - [' a'], - ['a'] - ); - $result = $htmlRenderer->render(); - static::assertEquals([ - [ - [ - 'tag' => 'replace', - 'base' => [ - 'offset' => 0, - 'lines' => [ - "    a", - ] - ], - 'changed' => [ - 'offset' => 0, - 'lines' => [ - 'a' - ] - ] - ] - ] - ], $result); - } -} diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index d88b6a87..a3fff39a 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -13,11 +13,17 @@ /** * Class HtmlRendererTest * - * PHPUnit tests to verify the output of the HTML renderers hasn't change by code changes. + * PHPUnit tests to verify that the output of the HTML renderers did not change due to code changes. * - * @package Tests\Diff\Renderer\Html + * @package Tests\Diff\Renderer\Html + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff */ -class HtmlRendererTest extends TestCase +class HtmlRenderersTest extends TestCase { /** * @var bool Store the renderer's output in a file, when set to true. @@ -27,9 +33,9 @@ class HtmlRendererTest extends TestCase /** * Constructor. * - * @param null $name - * @param array $data - * @param string $dataName + * @param null $name + * @param array $data + * @param string $dataName */ public function __construct($name = null, array $data = [], $dataName = '') { @@ -38,6 +44,7 @@ public function __construct($name = null, array $data = [], $dataName = '') } /** + * Test the output of the HTML Side by Side renderer. * @covers \jblond\Diff\Renderer\Html\SideBySide */ public function testSideBySide() @@ -47,8 +54,8 @@ public function testSideBySide() file_get_contents('tests/resources/b.txt') ); - $renderer = new SideBySide(); - $result = $diff->render($renderer); + $renderer = new SideBySide(); + $result = $diff->render($renderer); if ($this->genOutputFiles) { file_put_contents('htmlSideBySide.txt', $result); } @@ -57,6 +64,7 @@ public function testSideBySide() } /** + * Test the output of the HTML Inline renderer. * @covers \jblond\Diff\Renderer\Html\Inline */ public function testInline() @@ -66,8 +74,14 @@ public function testInline() file_get_contents('tests/resources/b.txt') ); - $renderer = new Inline(); - $result = $diff->render($renderer); + $renderer = new Inline( + [ + 'format' => 'html', + 'insertMarkers' => ['', ''], + 'deleteMarkers' => ['', ''], + ] + ); + $result = $diff->render($renderer); if ($this->genOutputFiles) { file_put_contents('htmlInline.txt', $result); } @@ -76,6 +90,7 @@ public function testInline() } /** + * Test the output of the HTML Unified renderer. * @covers \jblond\Diff\Renderer\Html\Unified */ public function testUnified() @@ -85,8 +100,8 @@ public function testUnified() file_get_contents('tests/resources/b.txt') ); - $renderer = new Unified(); - $result = $diff->render($renderer); + $renderer = new Unified(); + $result = $diff->render($renderer); if ($this->genOutputFiles) { file_put_contents('htmlUnified.txt', $result); } diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php new file mode 100644 index 00000000..f07ff7a5 --- /dev/null +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -0,0 +1,140 @@ + + * @author Ferry Cools + * @copyright (c) 2009 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff + */ + +/** + * Class MainRendererTest + * @package Tests\Diff\Renderer\Html + */ +class MainRendererTest extends TestCase +{ + + /** + * @var string[] Defines the main renderer options. + */ + public $rendererOptions = [ + 'format' => 'html', + ]; + + /** + * MainRendererTest constructor. + * + * @param null $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = null, array $data = [], $dataName = '') + { + //new \jblond\Autoloader(); + parent::__construct($name, $data, $dataName); + } + + /** + * + */ + public function testRenderSimpleDelete() + { + $renderer = new MainRenderer(); + $renderer->diff = new Diff( + ['a'], + [] + ); + $result = $this->invokeMethod($renderer, 'renderSequences'); + static::assertEquals( + [ + [ + [ + 'tag' => 'delete', + 'base' => [ + 'offset' => 0, + 'lines' => [ + 'a', + ], + ], + 'changed' => [ + 'offset' => 0, + 'lines' => [], + ], + ], + ], + ], + $result + ); + } + + /** + * Call protected/private method of a class. + * + * @param object &$object Instantiated object that we will run method on. + * @param string $methodName Method name to call + * @param array $parameters Array of parameters to pass into method. + * + * @return mixed Method return. + * @throws \ReflectionException If the class doesn't exist. + */ + public function invokeMethod(&$object, $methodName, array $parameters = []) + { + $reflection = new ReflectionClass(get_class($object)); + $method = $reflection->getMethod($methodName); + $method->setAccessible(true); + + return $method->invokeArgs($object, $parameters); + } + + /** + * + */ + public function testRenderFixesSpaces() + { + $renderer = new MainRenderer($this->rendererOptions); + $renderer->diff = new Diff( + [' a'], + ['a'] + ); + $result = $this->invokeMethod($renderer, 'renderSequences'); + + static::assertEquals( + [ + [ + [ + 'tag' => 'replace', + 'base' => [ + 'offset' => 0, + 'lines' => [ + "\0    \1a", + ], + ], + 'changed' => [ + 'offset' => 0, + 'lines' => [ + "\0\1a", + ], + ], + ], + ], + ], + $result + ); + } +} diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 63d61613..c3489b0c 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -12,9 +12,15 @@ /** * Class TextRendererTest * - * PHPUnit tests to verify the output of the text renderers hasn't change by code changes. + * PHPUnit tests to verify that the output of the text renderers did not change due to code changes. * - * @package Tests\Diff\Renderer\Text + * @package Tests\Diff\Renderer\Text + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2019 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff */ class TextRendererTest extends TestCase { @@ -24,11 +30,11 @@ class TextRendererTest extends TestCase private $genOutputFiles = false; /** - * Constructor. + * TextRendererTest constructor. * - * @param null $name - * @param array $data - * @param string $dataName + * @param null $name + * @param array $data + * @param string $dataName */ public function __construct($name = null, array $data = [], $dataName = '') { @@ -37,7 +43,7 @@ public function __construct($name = null, array $data = [], $dataName = '') } /** - * Test context + * Test the output of the text-context renderer. * @covers \jblond\Diff\Renderer\Text\Context */ public function testContext() @@ -47,8 +53,8 @@ public function testContext() file_get_contents('tests/resources/b.txt') ); - $renderer = new Context(); - $result = $diff->render($renderer); + $renderer = new Context(); + $result = $diff->render($renderer); if ($this->genOutputFiles) { file_put_contents('textContext.txt', $result); } @@ -57,7 +63,7 @@ public function testContext() } /** - * Test Unified + * Test the output of the text-unified renderer. * @covers \jblond\Diff\Renderer\Text\Unified */ public function testUnified() @@ -67,8 +73,8 @@ public function testUnified() file_get_contents('tests/resources/b.txt') ); - $renderer = new Unified(); - $result = $diff->render($renderer); + $renderer = new Unified(); + $result = $diff->render($renderer); if ($this->genOutputFiles) { file_put_contents('textUnified.txt', $result); } @@ -77,7 +83,7 @@ public function testUnified() } /** - * Test Unified Cli + * Test the output of the CLI text-context renderer. * @covers \jblond\Diff\Renderer\Text\UnifiedCli */ public function testUnifiedCli() @@ -92,7 +98,32 @@ public function testUnifiedCli() if ($this->genOutputFiles) { file_put_contents('textUnifiedCli.txt', $result); } - $this->assertStringEqualsFile('tests/resources/ab.diff', $result); + $this->assertStringEqualsFile('tests/resources/textUnifiedCli.txt', $result); } -} + /** + * Test the output of the CLI text-inline renderer. + * @covers \jblond\Diff\Renderer\Text\InlineCli + */ + public function testInlineCli() + { + $diff = new Diff( + file_get_contents('tests/resources/a.txt'), + file_get_contents('tests/resources/b.txt') + ); + + $renderer = new Diff\Renderer\Text\InlineCli( + [ + 'cliColor' => true, + 'deleteMarkers' => ['-', '-'], + 'insertMarkers' => ['+', '+'], + 'equalityMarkers' => ['=', 'x'], + ] + ); + $result = $diff->render($renderer); + if ($this->genOutputFiles) { + file_put_contents('textInlineCli.txt', $result); + } + $this->assertStringEqualsFile('tests/resources/textInlineCli.txt', $result); + } +} diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index f3cb0c00..f97fb5b1 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -5,11 +5,25 @@ use jblond\Diff\SequenceMatcher; use PHPUnit\Framework\TestCase; +/** + * PHPUnit Test for the main renderer of PHP DiffLib. + * + * PHP version 7.2 or greater + * + * @package Tests\Diff + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2009 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.0.0 + * @link https://github.com/JBlond/php-diff + */ + class SequenceMatcherTest extends TestCase { /** - * Constructor. + * SequenceMatcherTest constructor. * * @param null $name * @param array $data diff --git a/tests/resources/htmlUnified.txt b/tests/resources/htmlUnified.txt index 35b0c9e9..2da3bdd7 100644 --- a/tests/resources/htmlUnified.txt +++ b/tests/resources/htmlUnified.txt @@ -1 +1 @@ -<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file +<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file diff --git a/tests/resources/textInlineCli.txt b/tests/resources/textInlineCli.txt new file mode 100644 index 00000000..3678f6f4 --- /dev/null +++ b/tests/resources/textInlineCli.txt @@ -0,0 +1,33 @@ +=| +=| +=| +x| Hello -World-+You+! +=| +=| +=|

This is demo content to show features of the php-diff package.

+-|

This line is removed from version2.

 +=|

This line is the same for both versions.

+x|

This line has -inline -++differences between both versions.

+=|

This line is the same for both versions.

+x|

This line also has -inl-+InL+ine differences between both versions.

+=|

This line is the same for both versions.

++|

This line is added to version2.

 +=| +=|

+=| It's also compatible with multibyte characters (like Chinese and emoji) as shown below: +x| 另外我覺得那個評-價-+鑑+的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革” +x| Do you know what "-金槍魚罐頭-+魚の缶詰+" means in Chinese? +x| -🍏🍎-+🍎🍏+🙂 +=|

+=| +=|

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+... +=|

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+=|

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+=|

Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.

+x|- -+ +

This line also has inline differences between both versions. It's the whitespace in front.

+=|

This line is the same for both versions.

+x|

This line also has inline differences between both versions-.-+!+

+=| +=| +=| diff --git a/tests/resources/ab.diff b/tests/resources/textUnifiedCli.txt similarity index 100% rename from tests/resources/ab.diff rename to tests/resources/textUnifiedCli.txt From 0ef6def8a0c8b310a0b64a3a71da21e7f85c2974 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 16 Jul 2020 16:26:53 +0200 Subject: [PATCH 043/206] Fix code quality. - Rename interface SubRenderer to SubRendererInterface. - Throw exception instead of aborting script execution with exit at cli example. - Changed line-endings from LF to CRLF of PHPUnit resource textInlineCli.txt (Check if these are changed by git!). --- example/cli.php | 2 +- lib/jblond/Diff/Renderer/Html/Inline.php | 4 ++-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 4 ++-- lib/jblond/Diff/Renderer/Html/Unified.php | 4 ++-- .../Renderer/{SubRenderer.php => SubRendererInterface.php} | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) rename lib/jblond/Diff/Renderer/{SubRenderer.php => SubRendererInterface.php} (99%) diff --git a/example/cli.php b/example/cli.php index 3c826ed8..18054cf2 100644 --- a/example/cli.php +++ b/example/cli.php @@ -9,7 +9,7 @@ if (php_sapi_name() !== 'cli') { echo 'This script demonstrates console support for the php-diff package.
'; echo 'Please execute it from a cli interpreter.'; - exit; + throw new RuntimeException('Script for CLI use only!'); } diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 75200c5a..9937c51a 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -5,7 +5,7 @@ namespace jblond\Diff\Renderer\Html; use jblond\Diff\Renderer\MainRenderer; -use jblond\Diff\Renderer\SubRenderer; +use jblond\Diff\Renderer\SubRendererInterface; /** * Inline HTML diff generator for PHP DiffLib. @@ -21,7 +21,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class Inline extends MainRenderer implements SubRenderer +class Inline extends MainRenderer implements SubRendererInterface { /** * @var array Associative array containing the default options available for this renderer and their default diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 3eae1bc5..d406ce89 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -5,7 +5,7 @@ namespace jblond\Diff\Renderer\Html; use jblond\Diff\Renderer\MainRenderer; -use jblond\Diff\Renderer\SubRenderer; +use jblond\Diff\Renderer\SubRendererInterface; /** * Side by Side HTML diff generator for PHP DiffLib. @@ -21,7 +21,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class SideBySide extends MainRenderer implements SubRenderer +class SideBySide extends MainRenderer implements SubRendererInterface { /** * @var array Associative array containing the default options available for this renderer and their default diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 15b9061a..42164d59 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -5,7 +5,7 @@ namespace jblond\Diff\Renderer\Html; use jblond\Diff\Renderer\MainRenderer; -use jblond\Diff\Renderer\SubRenderer; +use jblond\Diff\Renderer\SubRendererInterface; /** * Unified HTML diff generator for PHP DiffLib. @@ -21,7 +21,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class Unified extends MainRenderer implements SubRenderer +class Unified extends MainRenderer implements SubRendererInterface { /** * @var array Associative array containing the default options available for this renderer and their default diff --git a/lib/jblond/Diff/Renderer/SubRenderer.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php similarity index 99% rename from lib/jblond/Diff/Renderer/SubRenderer.php rename to lib/jblond/Diff/Renderer/SubRendererInterface.php index 383c1a2a..f9c84e68 100644 --- a/lib/jblond/Diff/Renderer/SubRenderer.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -16,7 +16,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -interface SubRenderer +interface SubRendererInterface { /** * Render and return a diff-view with changes between two sequences. diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index a66d9144..5629fac2 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -6,7 +6,7 @@ use jblond\cli\CliColors; use jblond\Diff\Renderer\MainRenderer; -use jblond\Diff\Renderer\SubRenderer; +use jblond\Diff\Renderer\SubRendererInterface; /** * Inline diff generator for PHP DiffLib. @@ -20,7 +20,7 @@ * @version 2.0.0 * @link https://github.com/JBlond/php-diff */ -class InlineCli extends MainRenderer implements SubRenderer +class InlineCli extends MainRenderer implements SubRendererInterface { /** * @var array Associative array containing the default options available for this renderer and their default From 47d6288797d10b42acc7ae48db4f1f11822f7bc0 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Fri, 17 Jul 2020 08:06:20 +0200 Subject: [PATCH 044/206] Fix #50. First or last x lines of text are shown even when there's no difference between the two compared texts. --- lib/jblond/Diff/SequenceMatcher.php | 8 ++--- tests/Diff/SequenceMatcherTest.php | 53 +++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 2a90cd75..3ee19977 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -555,7 +555,7 @@ public function getGroupedOpCodes(): array if ($this->options['trimEqual']) { if ($opCodes['0']['0'] == 'equal') { - // Remove sequences at the start which are out of context. + // Remove sequences at the start of the text, but keep the context lines. $opCodes['0'] = [ $opCodes['0']['0'], max($opCodes['0']['1'], $opCodes['0']['2'] - $this->options['context']), @@ -568,7 +568,7 @@ public function getGroupedOpCodes(): array $lastItem = count($opCodes) - 1; if ($opCodes[$lastItem]['0'] == 'equal') { [$tag, $item1, $item2, $item3, $item4] = $opCodes[$lastItem]; - // Remove sequences at the end which are out of context. + // Remove sequences at the end of the text, but keep the context lines. $opCodes[$lastItem] = [ $tag, $item1, @@ -607,8 +607,8 @@ public function getGroupedOpCodes(): array ]; } - if ($this->options['trimEqual'] || (!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal'))) { - //Do not add the last sequences. They're out of context. + if (!$this->options['trimEqual'] || (!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal'))) { + // Add the last sequences when !trimEqual || When there are no differences between both versions. $groups[] = $group; } diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index f3cb0c00..f443741e 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -20,23 +20,47 @@ public function __construct($name = null, array $data = [], $dataName = '') parent::__construct($name, $data, $dataName); } - public function testGetGroupedOpCodes() + public function testGetGroupedOpCodesDefault() { // Test with default options. - $sequenceMatcher = new SequenceMatcher('54321ABXDE12345', '54321ABxDE12345'); + $sequenceMatcher = new SequenceMatcher( + '54321ABXDE12345', + '54321ABxDE12345' + ); + $this->assertEquals( - [[['equal', 4, 7, 4, 7], ['replace', 7, 8, 7, 8], ['equal', 8, 11, 8, 11]]], + [ + [ + ['equal', 4, 7, 4, 7], ['replace', 7, 8, 7, 8], ['equal', 8, 11, 8, 11] + ] + ], $sequenceMatcher->getGroupedOpCodes() ); + } + public function testGetGroupedOpCodesTrimEqualFalse() + { // Test with trimEqual disabled. - $sequenceMatcher = new SequenceMatcher('54321ABXDE12345', '54321ABxDE12345', ['trimEqual' => false]); + // First and last context lines of the sequences are included. + $sequenceMatcher = new SequenceMatcher( + '54321ABXDE12345', + '54321ABxDE12345', + ['trimEqual' => false] + ); + $this->assertEquals( - [[['equal', 0, 3, 0, 3]], [['equal', 4, 7, 4, 7], ['replace', 7, 8, 7, 8], ['equal', 8, 11, 8, 11]]], + [ + [['equal', 0, 3, 0, 3]], + [['equal', 4, 7, 4, 7], ['replace', 7, 8, 7, 8], ['equal', 8, 11, 8, 11]], + [['equal', 12, 15, 12, 15]], + ], $sequenceMatcher->getGroupedOpCodes() ); + } - // Test with ignoreWhitespace enabled. + public function testGetGroupedOpCodesIgnoreWhitespaceTrue() + { + // Test with ignoreWhitespace enabled. Both sequences are considered to be the same. // Note: The sequenceMatcher evaluates the string character by character. Option ignoreWhitespace will ignore // if the difference if the character is a tab in one sequence and a space in the other. $sequenceMatcher = new SequenceMatcher( @@ -44,15 +68,24 @@ public function testGetGroupedOpCodes() " 54321ABXDE12345\t", ['ignoreWhitespace' => true] ); + $this->assertEquals( - [[['equal', 14, 17, 14, 17]]], + [], $sequenceMatcher->getGroupedOpCodes() ); + } + + public function testGetGroupedOpCodesIgnoreCaseTrue() + { + // Test with ignoreCase enabled. Both sequences are considered to be the same. + $sequenceMatcher = new SequenceMatcher( + '54321ABXDE12345', + '54321ABxDE12345', + ['ignoreCase' => true] + ); - // Test with ignoreCase enabled. - $sequenceMatcher = new SequenceMatcher('54321ABXDE12345', '54321ABxDE12345', ['ignoreCase' => true]); $this->assertEquals( - [[['equal', 12, 15, 12, 15]]], + [], $sequenceMatcher->getGroupedOpCodes() ); } From af5b2c57a05a5c71b8748ceb95d4dcf6067fdb68 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 17 Jul 2020 09:22:13 +0200 Subject: [PATCH 045/206] remove second empty last line --- tests/Diff/Renderer/Text/TextRenderersTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 63d61613..eb5abdb5 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -95,4 +95,3 @@ public function testUnifiedCli() $this->assertStringEqualsFile('tests/resources/ab.diff', $result); } } - From eda111b59cf6dab66ab9d6c875d29235ac1fc353 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 17 Jul 2020 09:25:28 +0200 Subject: [PATCH 046/206] increase version number for #50 bug fix release --- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/HtmlArray.php | 2 +- lib/jblond/Diff/Renderer/Html/Inline.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/RendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index acd0b888..f35001f4 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -27,7 +27,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index e054527a..d2bc3544 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -10,7 +10,7 @@ * @package jblond\Diff * @author Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/HtmlArray.php b/lib/jblond/Diff/Renderer/Html/HtmlArray.php index 02cd0b8e..d906ff04 100644 --- a/lib/jblond/Diff/Renderer/Html/HtmlArray.php +++ b/lib/jblond/Diff/Renderer/Html/HtmlArray.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class HtmlArray extends RendererAbstract diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 77fd36fa..49ba0ec8 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class Inline extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 6d1ae675..56336539 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class SideBySide extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 2a60df86..33977de0 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class Unified extends HtmlArray diff --git a/lib/jblond/Diff/Renderer/RendererAbstract.php b/lib/jblond/Diff/Renderer/RendererAbstract.php index 269323c2..500f4ecf 100644 --- a/lib/jblond/Diff/Renderer/RendererAbstract.php +++ b/lib/jblond/Diff/Renderer/RendererAbstract.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ abstract class RendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 455cb254..71ae5f5e 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class Context extends RendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index aa3d3a62..6e84218e 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index f465425d..877ab5f9 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -14,7 +14,7 @@ * @package jblond\Diff\Renderer\Text * @author Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 3ee19977..b1359428 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.0 + * @version 2.1.1 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher From fda4852a92a7cb6f2d51e0292d9bb13bbf560d2c Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 22 Jul 2020 21:26:28 +0200 Subject: [PATCH 047/206] Resolve #52 and fixes. - HTML renderer Inline, SideBySide and Unified return false when there's nothing to render. - Text renderer Context, InlineCli and Unified return false when there's nothing to render. Main renderer returns false when there's nothing to render. - Text renderer InlineCli renders line-ending `\n` instead of `PHP_EOL`. - Added missing docBlock content. - Updated docBlock of the SubRenderer Interface. - Added method Diff::isIdentical(). - Updated README.md to reflect Diff::isIdentical(). --- README.md | 22 ++-- example/example.php | 106 +++++++++--------- lib/jblond/Diff.php | 38 +++++-- lib/jblond/Diff/Renderer/Html/Inline.php | 4 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 4 +- lib/jblond/Diff/Renderer/Html/Unified.php | 4 +- lib/jblond/Diff/Renderer/MainRenderer.php | 14 +-- .../Diff/Renderer/SubRendererInterface.php | 4 +- lib/jblond/Diff/Renderer/Text/Context.php | 6 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 14 +-- lib/jblond/Diff/Renderer/Text/Unified.php | 6 +- lib/jblond/Diff/SequenceMatcher.php | 1 + 12 files changed, 125 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index 9115a8c7..f2374221 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ## Introduction A comprehensive library for generating differences between two hashable objects (strings or arrays). -Generated differences can be rendered in all of the standard formats including: +Generated differences can be rendered in all the standard formats including: * Unified * Context @@ -35,8 +35,8 @@ use jblond\Diff\Renderer\Html\SideBySide; // Installed via composer... require 'vendor/autoload.php'; -$a = file_get_contents(dirname(__FILE__).'/a.txt'); -$b = file_get_contents(dirname(__FILE__).'/b.txt'); +$sampleA = file_get_contents(dirname(__FILE__).'/a.txt'); +$sampleB = file_get_contents(dirname(__FILE__).'/b.txt'); // Options for generating the diff. $options = [ @@ -47,20 +47,26 @@ $options = [ ]; // Initialize the diff class. -$diff = new Diff($a, $b /*, $options */); +$diff = new Diff($sampleA, $sampleB /*, $options */); // Choose Renderer. $renderer = new SideBySide([ - 'title1' => 'Custom title for OLD version', - 'title2' => 'Custom title for NEW version', + 'title1' => 'Custom title for sample A', + 'title2' => 'Custom title for sample B', ]); -// Show it. +// Show the output of the difference renderer. echo $diff->Render($renderer); + +// Alternative +// Show the differences or a message. +echo $diff->isIdentical() ? 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
' ; + ``` ### Example Output -A quick usage example can be found in the `example/` directory and under example.php. Included is a light theme and a dark theme. +File `example.php` contains a quick demo and can be found in the `example/` directory. +Included is a light and a dark theme. #### HTML Side By Side Example diff --git a/example/example.php b/example/example.php index f3637528..caebc983 100644 --- a/example/example.php +++ b/example/example.php @@ -23,73 +23,73 @@ ]; // Choose one of the initializations. -$diff = new Diff($sampleA, $sampleB); // Initialize the diff class with default options. -//$diff = new Diff($a, $b, $customOptions); // Initialize the diff class with custom options. +$diff = new Diff($sampleA, $sampleB); // Initialize the diff class with default options. +//$diff = new Diff($sampleA, $sampleB, $customOptions); // Initialize the diff class with custom options. ?> - - - PHP LibDiff - Examples - - - - -

PHP LibDiff - Examples

- -
- -

HTML Side by Side Diff

- - + + PHP LibDiff - Examples + + + + +

PHP LibDiff - Examples

+ +
+ +

HTML Side by Side Diff

+ + Render($renderer); - ?> - -

HTML Inline Diff

- - isIdentical() ? 'No differences found.' : $diff->Render($renderer); + ?> +

HTML Inline Diff

+ render($renderer); - ?> + echo $diff->isIdentical() ? 'No differences found.' : $diff->Render($renderer); + ?> -

HTML Unified Diff

- HTML Unified Diff + {$diff->render($renderer)}"; - ?> + echo $diff->isIdentical() ? 'No differences found.' : '
' . $diff->Render($renderer) . '
'; + ?> -

Text Unified Diff

- Text Unified Diff + ' . htmlspecialchars($diff->render($renderer)) . ''; - ?> + echo $diff->isIdentical() ? + 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; + ?> -

Text Context Diff

- Text Context Diff + ' . htmlspecialchars($diff->render($renderer)) . ''; - ?> - + echo $diff->isIdentical() ? + 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; + ?> + diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index f35001f4..63868c96 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -21,14 +21,14 @@ * * PHP version 7.2 or greater * - * @package jblond - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools + * @package jblond + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2020 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.1 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.1.1 + * @link https://github.com/JBlond/php-diff */ class Diff { @@ -73,6 +73,10 @@ class Diff * @see Diff::setOptions() */ private $options = []; + /** + * @var bool True when compared versions are identical, False otherwise. + */ + private $identical; /** * The constructor. @@ -169,9 +173,9 @@ public function getVersion2(): array * Render a diff-view using a rendering class and get its results. * * @param object|Context|Unified|UnifiedHtml|Inline|SideBySide $renderer An instance of the rendering object, - * used for generating the diff-view. + * used for generating the diff-view. * - * @return mixed The generated diff-view. The type of the return value depends on the applied rendereder. + * @return mixed The generated diff-view. The type of the return value depends on the applied renderer. */ public function render(object $renderer) { @@ -221,6 +225,20 @@ public function getArrayRange(array $array, int $start = 0, $end = null): array return array_slice($array, $start, $length); } + /** + * Get if the compared versions are identical or have differences. + * + * @return bool True when identical. + */ + public function isIdentical(): bool + { + if ($this->getGroupedOpCodes() === null) { + $this->getGroupedOpCodes(); + } + + return $this->identical; + } + /** * Generate a list of the compiled and grouped op-codes for the differences between two strings. * @@ -240,6 +258,8 @@ public function getGroupedOpCodes(): array //Get and cache the grouped op-codes. $sequenceMatcher = new SequenceMatcher($this->version1, $this->version2, $this->options); $this->groupedCodes = $sequenceMatcher->getGroupedOpCodes(); + $opCodes = $sequenceMatcher->getOpCodes(); + $this->identical = count($opCodes) == 1 && $opCodes[0][0] == 'equal'; return $this->groupedCodes; } diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 9937c51a..767d5f7c 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -57,9 +57,9 @@ public function __construct(array $options = []) /** * Render and return a diff-view with changes between the two sequences displayed inline (under each other). * - * @return string The generated inline diff-view. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string + public function render() { $changes = parent::renderSequences(); diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index d406ce89..4dcd829b 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -57,9 +57,9 @@ public function __construct(array $options = []) /** * Render a and return diff-view with changes between the two sequences displayed side by side. * - * @return string The generated side by side diff-view. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string + public function render() { $changes = parent::renderSequences(); diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 42164d59..bb971822 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -57,9 +57,9 @@ public function __construct(array $options = []) /** * Render a and return diff-view with changes between the two sequences (under each other). * - * @return string The generated unified diff-view. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string + public function render() { $changes = parent::renderSequences(); diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index c44c1b15..942eaafe 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -21,7 +21,7 @@ class MainRenderer extends MainRendererAbstract { /** - * @var int + * @var int Character count of the line marker with the most characters. */ protected $maxLineMarkerWidth = 0; /** @@ -31,20 +31,20 @@ class MainRenderer extends MainRendererAbstract private $lastTag; /** - * Generate a string representation of changes between the "old and "new" sequences. + * Generate a string representation of changes between version1 and version2. * * This method is called by the renderers which extends this class. * - * @param array $changes Contains the op-codes about the differences between "old and "new". + * @param array $changes Contains the op-codes about the differences between version1 and version2. * @param object $subRenderer Renderer which is subClass of this class. * - * @return string Representation of the differences. + * @return string|false String representation of the differences or false when versions are identical. */ - public function renderOutput(array $changes, object $subRenderer): string + public function renderOutput(array $changes, object $subRenderer) { if (!$changes) { - //No changes between "old" and "new" - return 'No differences found.'; + //No changes between version1 and version2 + return false; } $output = $subRenderer->generateDiffHeader(); diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index f9c84e68..cad6f87e 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -21,9 +21,9 @@ interface SubRendererInterface /** * Render and return a diff-view with changes between two sequences. * - * @return string The generated diff-view. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string; + public function render(); /** * Generate a string representation of the start of a diff view. diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 63f086f7..ed9d52ec 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -37,11 +37,11 @@ class Context extends MainRendererAbstract * * @link https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Context.html#Detailed-Context * - * @return string The generated context diff-view. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string + public function render() { - $diff = ''; + $diff = false; $opCodes = $this->diff->getGroupedOpCodes(); foreach ($opCodes as $group) { diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 5629fac2..cb411989 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -45,9 +45,9 @@ public function __construct(array $options = []) /** * Render a and return diff-view with changes between the two sequences displayed inline. * - * @return string The generated diff-view. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string + public function render() { $changes = parent::renderSequences(); @@ -84,7 +84,7 @@ public function generateBlockHeader($changes): string */ public function generateSkippedLines(): string { - return '...' . PHP_EOL; + return "...\n"; } /** @@ -100,7 +100,7 @@ public function generateLinesEqual(array $changes): string $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][0])); foreach ($changes['base']['lines'] as $line) { - $returnValue .= $this->options['equalityMarkers'][0] . $padding . '|' . $line . PHP_EOL; + $returnValue .= $this->options['equalityMarkers'][0] . $padding . '|' . $line . "\n"; } return $returnValue; @@ -124,7 +124,7 @@ public function generateLinesInsert(array $changes): string [$fgColor, $bgColor] = $this->options['insertColors']; $line = $colorize->getColoredString($line, $fgColor, $bgColor); } - $returnValue .= $this->options['insertMarkers'][0] . $padding . '|' . $line . PHP_EOL; + $returnValue .= $this->options['insertMarkers'][0] . $padding . '|' . $line . "\n"; } return $returnValue; @@ -148,7 +148,7 @@ public function generateLinesDelete(array $changes): string [$fgColor, $bgColor] = $this->options['deleteColors']; $line = $colorize->getColoredString($line, $fgColor, $bgColor); } - $returnValue .= $this->options['deleteMarkers'][0] . $padding . '|' . $line . PHP_EOL; + $returnValue .= $this->options['deleteMarkers'][0] . $padding . '|' . $line . "\n"; } return $returnValue; @@ -172,7 +172,7 @@ public function generateLinesReplace(array $changes): string $this->options['insertColors'] ); - $returnValue .= implode(PHP_EOL, $changes['base']['lines']) . PHP_EOL; + $returnValue .= implode("\n", $changes['base']['lines']) . "\n"; return $returnValue; } diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 50a1c58a..cbd00103 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -28,11 +28,11 @@ class Unified extends MainRendererAbstract /** * Render and return a unified diff. * - * @return string The unified diff. + * @return string|false The generated diff-view or false when there's no difference. */ - public function render(): string + public function render() { - $diff = ''; + $diff = false; $opCodes = $this->diff->getGroupedOpCodes(); foreach ($opCodes as $group) { $lastItem = count($group) - 1; diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index b1359428..62a6ffc4 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -481,6 +481,7 @@ function ($aArray, $bArray) { public function getOpCodes(): array { if (!empty($this->opCodes)) { + //Return the cached results. return $this->opCodes; } From 2be0c511e9243b363f16823217cfc4d71abc59de Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 23 Jul 2020 09:07:22 +0200 Subject: [PATCH 048/206] Resolve #52 and fixes. - Fixed calling Diff::getGroupedOpCodes() twice. --- lib/jblond/Diff.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 63868c96..83364c2a 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -70,6 +70,7 @@ class Diff /** * @var array Associative array containing the options that will be applied for generating the diff. * The key-value pairs are set at the constructor of this class. + * * @see Diff::setOptions() */ private $options = []; @@ -232,7 +233,7 @@ public function getArrayRange(array $array, int $start = 0, $end = null): array */ public function isIdentical(): bool { - if ($this->getGroupedOpCodes() === null) { + if ($this->groupedCodes === null) { $this->getGroupedOpCodes(); } From e28511b003fe2c3451de4f38c1776590ffe5351e Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 23 Jul 2020 09:17:42 +0200 Subject: [PATCH 049/206] add line for readabiltity --- lib/jblond/Diff.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 83364c2a..1b5a5f77 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -74,6 +74,7 @@ class Diff * @see Diff::setOptions() */ private $options = []; + /** * @var bool True when compared versions are identical, False otherwise. */ From 6acb81e38997cb378607ece0a4a37756aa4d161b Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 23 Jul 2020 09:21:08 +0200 Subject: [PATCH 050/206] increase version number for the next release --- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Inline.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- tests/Diff/Renderer/Html/HtmlRenderersTest.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- tests/Diff/Renderer/Text/TextRenderersTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 1b5a5f77..f162e519 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -27,7 +27,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.1 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index d2bc3544..6c2e25c5 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -10,7 +10,7 @@ * @package jblond\Diff * @author Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.1 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 767d5f7c..157063ad 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class Inline extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 4dcd829b..57c27be7 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index bb971822..07c8f3a2 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class Unified extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 942eaafe..57376675 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class MainRenderer extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index be7b86c4..c29a8922 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index cad6f87e..fc15ec51 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -13,7 +13,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index ed9d52ec..8b7b35c8 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.1 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index cb411989..651b2a18 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index cbd00103..19d3a6a3 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.1 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 3949bbea..6e34f637 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -15,7 +15,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 62a6ffc4..f83414b1 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.1.1 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index a3fff39a..4299b755 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -20,7 +20,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class HtmlRenderersTest extends TestCase diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index f07ff7a5..c882aa49 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index c3489b0c..5233bd53 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2019 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ class TextRendererTest extends TestCase diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 24c620c9..56f3bded 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.0.0 + * @version 2.2.0 * @link https://github.com/JBlond/php-diff */ From 147b89e964dc666e6b782f3f289204a8edb2eb66 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 23 Jul 2020 09:54:06 +0200 Subject: [PATCH 051/206] pcre is needed --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index 17a3e90c..8ce44a67 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "require": { "php": ">=7.2", "ext-mbstring": "*", + "ext-pcre": "*", "jblond/php-cli": "^1.0" }, "require-dev": { From 2bb7a09ec072ec8cb3a85c884746502b262dce54 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 23 Jul 2020 09:59:48 +0200 Subject: [PATCH 052/206] update readme file --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f2374221..17c0c5d0 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,12 @@ Included is a light and a dark theme. * PHP Multibyte String * [jblond/php-cli](https://github.com/jblond/php-cli) +## Issues and feature requests + +If you found a bug, or have an idea for new functionality, +feel free to report it on the issue tracker - just use search beforehand. +[Issue tracker](https://github.com/JBlond/php-diff/issues) + ## Merge files using jQuery Xiphe has build a jQuery plugin with that you can merge the compared files. @@ -126,7 +132,7 @@ Contributors since I forked the repo. * maxxer * Creris * jfcherng -* DigiLive +* [DigiLive](https://github.com/DigiLive) ### License (BSD License) From 0346948d1ed7943bd4f5c6a9ded3ecf7cc96c263 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 27 Jul 2020 09:24:28 +0200 Subject: [PATCH 053/206] make jblond/php-cli optional --- README.md | 6 +++++- composer.json | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 17c0c5d0..9781d298 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,10 @@ package. The reason for doing so is primarily because of its high degree of accu composer require jblond/php-diff ``` +### Install for cli support + +For cli usage you need to install the suggested `jblond/php-cli` package. + ## Example Use ```PHP @@ -107,7 +111,7 @@ Included is a light and a dark theme. * PHP 7.2 or greater * PHP Multibyte String -* [jblond/php-cli](https://github.com/jblond/php-cli) +* [jblond/php-cli](https://github.com/jblond/php-cli) (suggested) ## Issues and feature requests diff --git a/composer.json b/composer.json index 8ce44a67..2b7089f4 100644 --- a/composer.json +++ b/composer.json @@ -26,14 +26,16 @@ "require": { "php": ">=7.2", "ext-mbstring": "*", - "ext-pcre": "*", - "jblond/php-cli": "^1.0" + "ext-pcre": "*" }, "require-dev": { "phpunit/phpunit": "8.*", "squizlabs/php_codesniffer": "*", "phpmd/phpmd": "2.*" }, + "suggest": { + "jblond/php-cli": "^1.0" + }, "autoload": { "psr-4": { "jblond\\": "lib/jblond" From 08228048ab6d671c3f58b71cbb398f94e327956f Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 27 Jul 2020 09:34:22 +0200 Subject: [PATCH 054/206] return direct from isset --- lib/jblond/Diff/SequenceMatcher.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index f83414b1..e81d6926 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -216,11 +216,7 @@ private function chainB() */ private function isBJunk(string $bString): bool { - if (isset($this->junkDict[$bString])) { - return true; - } - - return false; + return isset($this->junkDict[$bString]); } /** From acd12cbf60c57cd2e9ccbe072caf395c5cd127b0 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 27 Jul 2020 15:08:58 +0200 Subject: [PATCH 055/206] add to dev for unit tests --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 2b7089f4..cc5bb674 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,8 @@ "require-dev": { "phpunit/phpunit": "8.*", "squizlabs/php_codesniffer": "*", - "phpmd/phpmd": "2.*" + "phpmd/phpmd": "2.*", + "jblond/php-cli": "^1.0" }, "suggest": { "jblond/php-cli": "^1.0" From 02695d5c2a5289aeb5c24d594204e877ce9c803e Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 5 Aug 2020 11:27:28 +0200 Subject: [PATCH 056/206] Fix #58 - Side by side diff shows empty diff --- lib/jblond/Diff/Renderer/Html/SideBySide.php | 29 +++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 57c27be7..95b0c73f 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -208,15 +208,11 @@ public function generateLinesReplace(array $changes): string $fromLine = $changes['base']['offset'] + $lineNo + 1; $toLine = " "; $changedLine = " "; - if (isset($changes['changed']['lines'][$lineNo])) { $toLine = $changes['changed']['offset'] + $lineNo + 1; $changedLine = $changes['changed']['lines'][$lineNo]; } - $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); - $changedLine = str_replace(["\0", "\1"], $this->options['insertMarkers'], $changedLine); - $html .= << $fromLine @@ -230,6 +226,31 @@ public function generateLinesReplace(array $changes): string HTML; } + + return $html; + } + + foreach ($changes['changed']['lines'] as $lineNo => $changedLine) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $fromLine = " "; + $line = " "; + if (isset($changes['base']['lines'][$lineNo])) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $line = $changes['base']['lines'][$lineNo]; + } + + $html .= << + $fromLine + + $line + + $toLine + + $changedLine + + +HTML; } return $html; From 369b1461d62b26268dbaeddeaf1919f5cab41738 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 5 Aug 2020 12:21:18 +0200 Subject: [PATCH 057/206] Fix #58 - Side by side diff shows empty diff --- example/example.php | 4 ++-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/example/example.php b/example/example.php index caebc983..94985a3b 100644 --- a/example/example.php +++ b/example/example.php @@ -11,8 +11,8 @@ require '../vendor/autoload.php'; // Include two sample files for comparison. -$sampleA = file_get_contents(dirname(__FILE__) . '/a.txt'); -$sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); +$sampleA = file_get_contents(dirname(__FILE__) . '/c.txt'); +$sampleB = file_get_contents(dirname(__FILE__) . '/d.txt'); // Options for generating the diff. $customOptions = [ diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 95b0c73f..992d029b 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -213,6 +213,9 @@ public function generateLinesReplace(array $changes): string $changedLine = $changes['changed']['lines'][$lineNo]; } + $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); + $changedLine = str_replace(["\0", "\1"], $this->options['insertMarkers'], $changedLine); + $html .= << $fromLine @@ -239,6 +242,9 @@ public function generateLinesReplace(array $changes): string $line = $changes['base']['lines'][$lineNo]; } + $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); + $changedLine = str_replace(["\0", "\1"], $this->options['insertMarkers'], $changedLine); + $html .= << $fromLine From 0946d5967ca435d81def7599061627761ce0357a Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 5 Aug 2020 16:16:39 +0200 Subject: [PATCH 058/206] Fix #58 - Side by side diff shows empty diff - Reverted used sample texts. --- example/example.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example/example.php b/example/example.php index 94985a3b..caebc983 100644 --- a/example/example.php +++ b/example/example.php @@ -11,8 +11,8 @@ require '../vendor/autoload.php'; // Include two sample files for comparison. -$sampleA = file_get_contents(dirname(__FILE__) . '/c.txt'); -$sampleB = file_get_contents(dirname(__FILE__) . '/d.txt'); +$sampleA = file_get_contents(dirname(__FILE__) . '/a.txt'); +$sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); // Options for generating the diff. $customOptions = [ From e6812d018163a60261136621c4cb05499ab995c9 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 6 Aug 2020 14:27:35 +0200 Subject: [PATCH 059/206] update version number --- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Inline.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- tests/Diff/Renderer/Html/HtmlRenderersTest.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- tests/Diff/Renderer/Text/TextRenderersTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index f162e519..2e469b35 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -27,7 +27,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 6c2e25c5..2937456d 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -10,7 +10,7 @@ * @package jblond\Diff * @author Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 157063ad..74d1933c 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class Inline extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 992d029b..a53f09b9 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 07c8f3a2..54ee60a4 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class Unified extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 57376675..a9716309 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class MainRenderer extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index c29a8922..fd204a04 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index fc15ec51..89496191 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -13,7 +13,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 8b7b35c8..5e616db5 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 651b2a18..e454cc30 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 19d3a6a3..dec25b84 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 6e34f637..2f5007d2 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -15,7 +15,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index e81d6926..70bb7a58 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 4299b755..00f8f0e5 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -20,7 +20,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class HtmlRenderersTest extends TestCase diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index c882aa49..34742164 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 5233bd53..1e80d17b 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2019 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ class TextRendererTest extends TestCase diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 56f3bded..35dcdc95 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.0 + * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ From df270f5840c257a4d3d8a6180ba281a44664ff73 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 6 Oct 2020 21:49:17 +0200 Subject: [PATCH 060/206] correct typos --- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index fd204a04..5a11e3e5 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -36,8 +36,8 @@ abstract class MainRendererAbstract * - deleteMarkers Markers for removed text. * - insertMarkers Markers for inserted text. * - equalityMarkers Markers for unchanged and changed lines. - * - insertColors Fore- and background color for inserted text. Only when cloColor = true. - * - deleteColors Fore- and background color for removed text. Only when cloColor = true. + * - insertColors Fore- and background color for inserted text. Only when cliColor = true. + * - deleteColors Fore- and background color for removed text. Only when cliColor = true. */ protected $mainOptions = [ 'tabSize' => 4, From 38864db2b5db077fd37a76a9237c02d6e3ec90e3 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 6 Oct 2020 21:51:58 +0200 Subject: [PATCH 061/206] change cli colors option from simple to true --- README.md | 2 +- example/cli.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9781d298..62b8a55a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ $options = [ 'ignoreWhitespace' => true, 'ignoreCase' => true, 'context' => 2, - 'cliColor' => 'simple' // for cli output + 'cliColor' => true // for cli output ]; // Initialize the diff class. diff --git a/example/cli.php b/example/cli.php index 18054cf2..8b3ea7de 100644 --- a/example/cli.php +++ b/example/cli.php @@ -44,7 +44,7 @@ $renderer = new UnifiedCli( // Define renderer options. [ - 'cliColor' => 'simple', + 'cliColor' => true, ] ); diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 2f5007d2..9d840dfa 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -49,7 +49,7 @@ public function render(): string if (!isset($this->options['cliColor'])) { return $this->output(); } - if (isset($this->options['cliColor']) && $this->options['cliColor'] == 'simple') { + if (isset($this->options['cliColor'])) { return $this->output(); } throw new InvalidArgumentException('Invalid cliColor option'); @@ -63,7 +63,7 @@ public function render(): string */ private function colorizeString($string, $color = ''): string { - if (isset($this->options['cliColor']) && $this->options['cliColor'] == 'simple') { + if (isset($this->options['cliColor'])) { return $this->colors->getColoredString($string, $color); } return $string; From fbccaf423326e0b9472f99c79e8f1d83136c4cd5 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 6 Oct 2020 21:56:52 +0200 Subject: [PATCH 062/206] check type of option --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 9d840dfa..bc9f0df1 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -49,7 +49,7 @@ public function render(): string if (!isset($this->options['cliColor'])) { return $this->output(); } - if (isset($this->options['cliColor'])) { + if (isset($this->options['cliColor']) && $this->options['cliColor'] === true) { return $this->output(); } throw new InvalidArgumentException('Invalid cliColor option'); @@ -63,7 +63,7 @@ public function render(): string */ private function colorizeString($string, $color = ''): string { - if (isset($this->options['cliColor'])) { + if (isset($this->options['cliColor']) && $this->options['cliColor'] === true) { return $this->colors->getColoredString($string, $color); } return $string; From eb382faa06284cd3b90d0e0d9486b5b0da6b5dde Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 6 Oct 2020 22:14:32 +0200 Subject: [PATCH 063/206] update README file --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 9781d298..5963b008 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,13 @@ Have a look at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge * Ability to ignore blank line changes * 3 way diff support +## Contribution + +You are welcome to contribute to this project. + +- Open an issue +- create a PR + ## Contributors Contributors since I forked the repo. From 98781fd8c290bb2960f8960c945c0d951f1b9e29 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 08:45:23 +0200 Subject: [PATCH 064/206] check only if option is set --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index bc9f0df1..93077e2c 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -49,10 +49,7 @@ public function render(): string if (!isset($this->options['cliColor'])) { return $this->output(); } - if (isset($this->options['cliColor']) && $this->options['cliColor'] === true) { - return $this->output(); - } - throw new InvalidArgumentException('Invalid cliColor option'); + return $this->output(); } @@ -63,7 +60,7 @@ public function render(): string */ private function colorizeString($string, $color = ''): string { - if (isset($this->options['cliColor']) && $this->options['cliColor'] === true) { + if (isset($this->options['cliColor'])) { return $this->colors->getColoredString($string, $color); } return $string; From cff7db14f67f430dbeb352266e422320de7996dc Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 09:41:38 +0200 Subject: [PATCH 065/206] add declaration --- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index a9716309..a967e35b 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -190,7 +190,7 @@ protected function renderSequences(): array * @param int $endOld last line of the block in old to replace. * @param int $startNew First line of the block in new to replace. */ - private function markInlineChange(array &$oldText, array &$newText, $startOld, $endOld, $startNew) + private function markInlineChange(array &$oldText, array &$newText, int $startOld, int $endOld, int $startNew) { for ($iterator = 0; $iterator < ($endOld - $startOld); ++$iterator) { // Check each line in the block for differences. diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index e454cc30..869b7578 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -72,7 +72,7 @@ public function generateDiffHeader(): string * * @return string Start of the diff view. */ - public function generateBlockHeader($changes): string + public function generateBlockHeader(array $changes): string { return ''; } From 0e3fd21254bc7eba09f1c4fdae8e85a0aec6b432 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 11:38:33 +0200 Subject: [PATCH 066/206] merge options instead of set them directly --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 93077e2c..414867f0 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -27,15 +27,23 @@ class UnifiedCli extends MainRendererAbstract */ private $colors; + /** + * @var array Associative array containing the default options available for this renderer and their default + * value. + */ + protected $subOptions = []; + /** * UnifiedCli constructor. * @param array $options + * */ public function __construct(array $options = []) { - parent::__construct($options); + parent::__construct(); + $this->setOptions($this->subOptions); + $this->setOptions($options); $this->colors = new CliColors(); - $this->options = $options; } /** From 0a16fd1f5ccac316103f4e969938fc95f9bbc9b2 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 11:41:22 +0200 Subject: [PATCH 067/206] update README file --- README.md | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5963b008..d8c37cfd 100644 --- a/README.md +++ b/README.md @@ -113,12 +113,14 @@ Included is a light and a dark theme. * PHP Multibyte String * [jblond/php-cli](https://github.com/jblond/php-cli) (suggested) -## Issues and feature requests +## Contribution, Issues and feature requests If you found a bug, or have an idea for new functionality, feel free to report it on the issue tracker - just use search beforehand. [Issue tracker](https://github.com/JBlond/php-diff/issues) +You can also fork this repository and open a PR. + ## Merge files using jQuery Xiphe has build a jQuery plugin with that you can merge the compared files. @@ -129,13 +131,6 @@ Have a look at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge * Ability to ignore blank line changes * 3 way diff support -## Contribution - -You are welcome to contribute to this project. - -- Open an issue -- create a PR - ## Contributors Contributors since I forked the repo. From 24c8bb936077565cae3d1cc0da75eaf395a8cb20 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 13:29:45 +0200 Subject: [PATCH 068/206] Simplify options merge --- lib/jblond/Diff/Renderer/Html/Inline.php | 3 +-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 3 +-- lib/jblond/Diff/Renderer/Html/Unified.php | 3 +-- lib/jblond/Diff/Renderer/Text/InlineCli.php | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 74d1933c..068b1177 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -49,8 +49,7 @@ class Inline extends MainRenderer implements SubRendererInterface */ public function __construct(array $options = []) { - parent::__construct(); - $this->setOptions($this->subOptions); + parent::__construct($this->subOptions); $this->setOptions($options); } diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index a53f09b9..5e1d937d 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -49,8 +49,7 @@ class SideBySide extends MainRenderer implements SubRendererInterface */ public function __construct(array $options = []) { - parent::__construct(); - $this->setOptions($this->subOptions); + parent::__construct($this->subOptions); $this->setOptions($options); } diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 54ee60a4..e9bba020 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -49,8 +49,7 @@ class Unified extends MainRenderer implements SubRendererInterface */ public function __construct(array $options = []) { - parent::__construct(); - $this->setOptions($this->subOptions); + parent::__construct($this->subOptions); $this->setOptions($options); } diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index e454cc30..1261a721 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -37,8 +37,7 @@ class InlineCli extends MainRenderer implements SubRendererInterface */ public function __construct(array $options = []) { - parent::__construct(); - $this->setOptions($this->subOptions); + parent::__construct($this->subOptions); $this->setOptions($options); } From 276d84d8a4eca1dc00dcf20d2b745adcae68f582 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 13:35:05 +0200 Subject: [PATCH 069/206] Simplify code --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 414867f0..0c1cec40 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -54,9 +54,6 @@ public function __construct(array $options = []) */ public function render(): string { - if (!isset($this->options['cliColor'])) { - return $this->output(); - } return $this->output(); } From ccd5a6d2ff6eddef0f69123134ad99f68192498e Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 13:49:49 +0200 Subject: [PATCH 070/206] add wiki links to README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d8c37cfd..7462fb5c 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,15 @@ composer require jblond/php-diff For cli usage you need to install the suggested `jblond/php-cli` package. +## Documentation + +See the [Wiki](https://github.com/JBlond/php-diff/wiki) for + +* [Getting started](https://github.com/JBlond/php-diff/wiki/a)-Getting-Started) +* [Parameters and Options](https://github.com/JBlond/php-diff/wiki/b)-Parameters-and-Options) +* [Custom Renderer](https://github.com/JBlond/php-diff/wiki/c)-Custom-Renderer) +* [Styling](https://github.com/JBlond/php-diff/wiki/d)-Styling) + ## Example Use ```PHP @@ -47,7 +56,7 @@ $options = [ 'ignoreWhitespace' => true, 'ignoreCase' => true, 'context' => 2, - 'cliColor' => 'simple' // for cli output + 'cliColor' => true // for cli output ]; // Initialize the diff class. From 1a7182255b1f444c781ac4d687ba2815482c9336 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 13:53:34 +0200 Subject: [PATCH 071/206] github markdown urls should not contain ")" --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7462fb5c..e7f75236 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,10 @@ For cli usage you need to install the suggested `jblond/php-cli` package. See the [Wiki](https://github.com/JBlond/php-diff/wiki) for -* [Getting started](https://github.com/JBlond/php-diff/wiki/a)-Getting-Started) -* [Parameters and Options](https://github.com/JBlond/php-diff/wiki/b)-Parameters-and-Options) -* [Custom Renderer](https://github.com/JBlond/php-diff/wiki/c)-Custom-Renderer) -* [Styling](https://github.com/JBlond/php-diff/wiki/d)-Styling) +* [Getting started](https://github.com/JBlond/php-diff/wiki/1.-Getting-Started) +* [Parameters and Options](https://github.com/JBlond/php-diff/wiki/2.-Parameters-and-Options) +* [Custom Renderer](https://github.com/JBlond/php-diff/wiki/3.-Custom-Renderer) +* [Styling](https://github.com/JBlond/php-diff/wiki/4.-Styling) ## Example Use From 8098c712490aec949828e844d43ce81ed9ee50f1 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 7 Oct 2020 14:16:13 +0200 Subject: [PATCH 072/206] if option is true, not only if it is set --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 0c1cec40..eb19a221 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -65,7 +65,7 @@ public function render(): string */ private function colorizeString($string, $color = ''): string { - if (isset($this->options['cliColor'])) { + if ($this->options['cliColor']) { return $this->colors->getColoredString($string, $color); } return $string; From 4b7a56ffc196245c8d6eb44a440a8912578648ad Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 8 Oct 2020 09:48:09 +0200 Subject: [PATCH 073/206] add changelog --- changelog.md | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 changelog.md diff --git a/changelog.md b/changelog.md new file mode 100644 index 00000000..82f74302 --- /dev/null +++ b/changelog.md @@ -0,0 +1,110 @@ +# changelog + +## 2.2.1 (2020-08-06) + +- This release fixed #58 - Side by side diff shows empty diff + +## 2.2.0 (2020-07-23) + +- adds an option for a custom override renderer. #53 +- add the feature to not have an output when there are not changes between the compared strings / files. #52 #54 + +## 2.1.1 (2020-07-17) + +- This release fixes #50 that equal text files produced an output, but shouldn't. + +## 2.1.0 (2020-07-13) + +- This release adds cli non colored output. This allows it to be piped. + +## 2.0.0 (2020-07-09) + +- This version mainly adds Unified Commandline colored output +- using semantic versioning + +## 1.18 (2020-07-01) + +- Added a dark theme to the example +- Fix: Avoid variables with short names (some) + +## 1.17 (2020-06-08) + +- Bugfix release for #32 + +## 1.16 (2020-03-02) + +- Features + - Add trimEqual option + +- Fixes + - Fix PHPMD Violation. + - Code Optimization, cleanup, refactoring and commenting. + +## 1.15 (2020-01-24) + +- Added new Unified HTML +- code clean up + +## 1.14 (2019-12-03) + +- Removed some old dead code + +## 1.13 (2019-10-08) + +- switched to PSR12 + +## 1.12 (2019-03-18) + +- Update composer +- PSR2 fixes + +## 1.11 (2019-02-22) + +- code clean up +- Corrected composer autoloader for unit tests + +## 1.10 (2019-02-20) + +- code clean up + +## 1.9 (2019-02-19) + +- code cleaning + +## 1.8 + +- Readme updates +- unit test fixes + +## 1.7 + +- PSR2 code alignment + +## 1.6 + +- php-diff requires now PHP 7.1 +- Added return type hinting + +## 1.5 (2019-01-15) + +- Fixed some autoloader naming issues + +## 1.4 (2019-01-14) + +- PSR4 namespace support added + +## 1.3 (2019-01-11) + +- PHP methods contained too much logic. That has been simplified. + +## 1.2 (2018-01-23) + +- Added support for custom titles + +## 1.1 (2017-05-06) + +- Some fixes with chinese characters + +## 1.0 + +- initial version From 09aea70e1290ed30ff65817afbcaf3852d0b5e1b Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 8 Oct 2020 09:49:51 +0200 Subject: [PATCH 074/206] add changelog to Readme file --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e7f75236..778ded8d 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,10 @@ See the [Wiki](https://github.com/JBlond/php-diff/wiki) for * [Custom Renderer](https://github.com/JBlond/php-diff/wiki/3.-Custom-Renderer) * [Styling](https://github.com/JBlond/php-diff/wiki/4.-Styling) +## Changelog + +[Changelog](changelog.md) + ## Example Use ```PHP From 98ac4c5b9841e5c9ce8debe7c6b5faae225d15b6 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 8 Oct 2020 10:01:02 +0200 Subject: [PATCH 075/206] update changelog --- changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.md b/changelog.md index 82f74302..9adbf646 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # changelog +## next + +- Fix: Unified Cli renderer options incompatible with Main renderer options +- added change log + ## 2.2.1 (2020-08-06) - This release fixed #58 - Side by side diff shows empty diff From c5f6d72e5e1866ae5280bc05b117fad215e1b8d5 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 13 Oct 2020 09:01:48 +0200 Subject: [PATCH 076/206] Fixes #64 - maxLineMarkerWidth only calculated for input format plain. - Calculation of maxLineMarkerWidth independent of input format. - Second parameter of string repeat function minimizes to 0. - Code cleanup. --- lib/jblond/Diff/Renderer/MainRenderer.php | 43 ++++++++--------- lib/jblond/Diff/Renderer/Text/InlineCli.php | 53 +++++++++++++-------- 2 files changed, 53 insertions(+), 43 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index a967e35b..0a00e637 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -35,8 +35,8 @@ class MainRenderer extends MainRendererAbstract * * This method is called by the renderers which extends this class. * - * @param array $changes Contains the op-codes about the differences between version1 and version2. - * @param object $subRenderer Renderer which is subClass of this class. + * @param array $changes Contains the op-codes about the differences between version1 and version2. + * @param object $subRenderer Renderer which is subClass of this class. * * @return string|false String representation of the differences or false when versions are identical. */ @@ -56,15 +56,12 @@ public function renderOutput(array $changes, object $subRenderer) $output .= $subRenderer->generateSkippedLines(); } - if ($this->options['format'] == 'plain') { - $this->maxLineMarkerWidth = - max( - strlen($this->options['insertMarkers'][0]), - strlen($this->options['deleteMarkers'][0]), - strlen($this->options['equalityMarkers'][0]), - strlen($this->options['equalityMarkers'][1]) - ); - } + $this->maxLineMarkerWidth = max( + strlen($this->options['insertMarkers'][0]), + strlen($this->options['deleteMarkers'][0]), + strlen($this->options['equalityMarkers'][0]), + strlen($this->options['equalityMarkers'][1]) + ); foreach ($blocks as $change) { $output .= $subRenderer->generateBlockHeader($change); @@ -184,11 +181,11 @@ protected function renderSequences(): array * New => "ab123fg" End marker inserted at position 6 * * - * @param array $oldText Collection of lines of old text. - * @param array $newText Collection of lines of new text. - * @param int $startOld First line of the block in old to replace. - * @param int $endOld last line of the block in old to replace. - * @param int $startNew First line of the block in new to replace. + * @param array $oldText Collection of lines of old text. + * @param array $newText Collection of lines of new text. + * @param int $startOld First line of the block in old to replace. + * @param int $endOld last line of the block in old to replace. + * @param int $startNew First line of the block in new to replace. */ private function markInlineChange(array &$oldText, array &$newText, int $startOld, int $endOld, int $startNew) { @@ -231,8 +228,8 @@ private function markInlineChange(array &$oldText, array &$newText, int $startOl * The second element defines the last (starting at -0) character from the end of the old string which is different. * * - * @param string $oldString The first string to compare. - * @param string $newString The second string to compare. + * @param string $oldString The first string to compare. + * @param string $newString The second string to compare. * * @return array Array containing the starting position (0 by default) and the ending position (-1 by default) */ @@ -270,10 +267,10 @@ private function getInlineChange(string $oldString, string $newString): array * * The index of the last element of the array is always returned. * - * @param array $blocks The array which keeps the changes for the HTML renderer. - * @param string $tag Kind of difference. - * @param integer $lineInOld Start of block in "old". - * @param integer $lineInNew Start of block in "new". + * @param array $blocks The array which keeps the changes for the HTML renderer. + * @param string $tag Kind of difference. + * @param integer $lineInOld Start of block in "old". + * @param integer $lineInNew Start of block in "new". * * @return int The index of the last element. */ @@ -306,7 +303,7 @@ private function appendChangesArray(array &$blocks, string $tag, int $lineInOld, * This involves replacing tab characters with spaces, making the HTML safe for output by ensuring that double * spaces are replaced with   etc. * - * @param array $strings Array of strings to format. + * @param array $strings Array of strings to format. * * @return array Array of formatted strings. */ diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index e86c9f82..1bcb9b6e 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -13,12 +13,12 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Ferry Cools + * @package jblond\Diff\Renderer\Text + * @author Ferry Cools * @copyright (c) 2020 Ferry Cools - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface { @@ -31,7 +31,7 @@ class InlineCli extends MainRenderer implements SubRendererInterface /** * InlineCli constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the inline diff renderer. * * @see Inline::$subOptions */ @@ -67,7 +67,7 @@ public function generateDiffHeader(): string /** * Generate a string representation of the start of a block. * - * @param array $changes Contains the op-codes about the changes between two blocks of lines. + * @param array $changes Contains the op-codes about the changes between two blocks of lines. * * @return string Start of the diff view. */ @@ -89,14 +89,17 @@ public function generateSkippedLines(): string /** * Generate a string representation lines without differences between the two versions. * - * @param array $changes Contains the op-codes about the changes between two blocks of lines. + * @param array $changes Contains the op-codes about the changes between two blocks of lines. * * @return string Text with no difference. */ public function generateLinesEqual(array $changes): string { $returnValue = ''; - $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][0])); + $padding = str_repeat( + ' ', + max($this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][0]), 0) + ); foreach ($changes['base']['lines'] as $line) { $returnValue .= $this->options['equalityMarkers'][0] . $padding . '|' . $line . "\n"; @@ -108,7 +111,7 @@ public function generateLinesEqual(array $changes): string /** * Generate a string representation of lines that are added to the 2nd version. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Added text. */ @@ -116,7 +119,10 @@ public function generateLinesInsert(array $changes): string { $colorize = new CliColors(); $returnValue = ''; - $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['insertMarkers'][0])); + $padding = str_repeat( + ' ', + max($this->maxLineMarkerWidth - strlen($this->options['insertMarkers'][0]), 0) + ); foreach ($changes['changed']['lines'] as $line) { if ($this->options['cliColor']) { @@ -132,7 +138,7 @@ public function generateLinesInsert(array $changes): string /** * Generate a string representation of lines that are removed from the 2nd version. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Removed text. */ @@ -140,7 +146,10 @@ public function generateLinesDelete(array $changes): string { $colorize = new CliColors(); $returnValue = ''; - $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['deleteMarkers'][0])); + $padding = str_repeat( + ' ', + max($this->maxLineMarkerWidth - strlen($this->options['deleteMarkers'][0]), 0) + ); foreach ($changes['base']['lines'] as $line) { if ($this->options['cliColor']) { @@ -156,7 +165,7 @@ public function generateLinesDelete(array $changes): string /** * Generate a string representation of lines that are partially modified. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Modified text. */ @@ -179,10 +188,10 @@ public function generateLinesReplace(array $changes): string /** * Merge the changes between two lines together and mark these changes. * - * @param array $baseLines Lines of version 1. - * @param array $changedLines Lines of version 2. - * @param array|null[] $deleteColors Fore- and background colors of part that is removed from the 2nd version. - * @param array|null[] $insertColors Fore- and background colors of part that is added to the 2nd version. + * @param array $baseLines Lines of version 1. + * @param array $changedLines Lines of version 2. + * @param array|null[] $deleteColors Fore- and background colors of part that is removed from the 2nd version. + * @param array|null[] $insertColors Fore- and background colors of part that is added to the 2nd version. * * Option $deleteColors and $insertColors only have affect when this class's cliColors option is set to true. * @@ -194,7 +203,11 @@ private function mergeChanges( array $deleteColors = [null, null], array $insertColors = [null, null] ): array { - $padding = str_repeat(' ', $this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][1])); + $padding = str_repeat( + ' ', + max($this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][1]), 0) + ); + if ($this->options['cliColor']) { $colorize = new CliColors(); } @@ -233,7 +246,7 @@ private function mergeChanges( /** * Generate a string representation of the end of a block. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string End of the block */ From 491d539abd81b522943210079a571b76aa4aa1d7 Mon Sep 17 00:00:00 2001 From: Ferry Cools <7613487+DigiLive@users.noreply.github.com> Date: Tue, 13 Oct 2020 16:57:30 +0200 Subject: [PATCH 077/206] Update changelog.md Add fixes for upcoming release. --- changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index 9adbf646..5720eee8 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,8 @@ ## next - Fix: Unified Cli renderer options incompatible with Main renderer options +- Fix: Calculation of maxLineMarkerWidth independent of input format. +- Fix: Second parameter of string repeat function minimizes to 0. - added change log ## 2.2.1 (2020-08-06) From ccfc4656f0f2cda01b12253a501a6b530c08ba32 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 14 Oct 2020 09:36:40 +0200 Subject: [PATCH 078/206] Fix: Html SideBySide renders equal lines of version 1 at both sides. When option ignoreCase is true, the renderer should show both versions. --- changelog.md | 71 ++++++++++---------- lib/jblond/Diff/Renderer/Html/SideBySide.php | 37 +++++----- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/changelog.md b/changelog.md index 5720eee8..7210c0b8 100644 --- a/changelog.md +++ b/changelog.md @@ -2,46 +2,47 @@ ## next -- Fix: Unified Cli renderer options incompatible with Main renderer options -- Fix: Calculation of maxLineMarkerWidth independent of input format. +- Add: Change log. +- Fix: Html SideBySide renders equal lines of version 1 at both sides (Option ignoreCase). - Fix: Second parameter of string repeat function minimizes to 0. -- added change log +- Fix: #60 - Unified Cli renderer options incompatible with Main renderer options +- Fix: #64 - Calculation of maxLineMarkerWidth independent of input format. ## 2.2.1 (2020-08-06) -- This release fixed #58 - Side by side diff shows empty diff +- Fix: #58 - Side by side diff shows empty diff ## 2.2.0 (2020-07-23) -- adds an option for a custom override renderer. #53 -- add the feature to not have an output when there are not changes between the compared strings / files. #52 #54 +- Add: Option for a custom override renderer. #53 +- Add: No output when there are no differences between the compared strings / files. #52 #54 ## 2.1.1 (2020-07-17) -- This release fixes #50 that equal text files produced an output, but shouldn't. +- Fix: #50 - Renderers produce output with equal texts, while they shouldn't. ## 2.1.0 (2020-07-13) -- This release adds cli non colored output. This allows it to be piped. +- Add: Cli uncolored output. This allows it to be piped. ## 2.0.0 (2020-07-09) -- This version mainly adds Unified Commandline colored output -- using semantic versioning +- Add: Unified Commandline colored output. +- Change: switch to semantic versioning. ## 1.18 (2020-07-01) -- Added a dark theme to the example -- Fix: Avoid variables with short names (some) +- Add: A dark theme to the example. +- Fix: Avoid variables with short names (some). ## 1.17 (2020-06-08) -- Bugfix release for #32 +- Fix #32 - Side by side diff shows only partially all deleted lines. ## 1.16 (2020-03-02) - Features - - Add trimEqual option + - Add: option trimEqual. - Fixes - Fix PHPMD Violation. @@ -49,69 +50,69 @@ ## 1.15 (2020-01-24) -- Added new Unified HTML -- code clean up +- Add: New Unified HTML. +- Fix: Code clean up. ## 1.14 (2019-12-03) -- Removed some old dead code +- Fix: Remove some old dead code. ## 1.13 (2019-10-08) -- switched to PSR12 +- Change: Switch to PSR12. ## 1.12 (2019-03-18) -- Update composer -- PSR2 fixes +- Change: Update Composer Configuration. +- Fix: PSR-2 conventions. ## 1.11 (2019-02-22) -- code clean up -- Corrected composer autoloader for unit tests +- Fix: Code clean up. +- Fix: Composer autoloader for unit tests. ## 1.10 (2019-02-20) -- code clean up +- Fix: Code clean up. ## 1.9 (2019-02-19) -- code cleaning +- Fix: Code clean up. ## 1.8 -- Readme updates -- unit test fixes +- Change: Update Readme and bumping versions. +- Fix: Moved include of Autoloader from the constructor to global space for HtmlArray unit test. ## 1.7 -- PSR2 code alignment +- Fix: PSR-2 code alignment. ## 1.6 -- php-diff requires now PHP 7.1 -- Added return type hinting +- Change: Bump required version of PHP to v7.1. +- Add: Return type hinting. ## 1.5 (2019-01-15) -- Fixed some autoloader naming issues +- Fix: Autoloader naming issues. ## 1.4 (2019-01-14) -- PSR4 namespace support added +- Add: PSR-4 namespace support. ## 1.3 (2019-01-11) -- PHP methods contained too much logic. That has been simplified. +- Fix: PHP methods contained too much logic. That has been simplified. ## 1.2 (2018-01-23) -- Added support for custom titles +- Add: Support for custom titles. ## 1.1 (2017-05-06) -- Some fixes with chinese characters +- Fix: Wrong highlight area for chinese characters. ## 1.0 -- initial version +- Initial version. diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 5e1d937d..850663c5 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -12,14 +12,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools + * @package jblond\Diff\Renderer\Html + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface { @@ -43,7 +43,7 @@ class SideBySide extends MainRenderer implements SubRendererInterface /** * SideBySide constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the inline diff renderer. * * @see Inline::$subOptions */ @@ -103,7 +103,10 @@ public function generateSkippedLines(): string /** * Generate a string representation of table rows with lines without differences between both versions. * - * @param array $changes Contains the op-codes about the changes between two blocks. + * Note: Depending on the options, lines can be marked as being equal, while the contents actually differ. + * (E.g. ignoreWhitespace and ignoreCase) + * + * @param array $changes Contains the op-codes about the changes between two blocks. * * @return string HTML code representing table rows showing text with no difference. */ @@ -111,7 +114,7 @@ public function generateLinesEqual(array $changes): string { $html = ''; - foreach ($changes['base']['lines'] as $lineNo => $line) { + foreach ($changes['base']['lines'] as $lineNo => $baseLine) { $fromLine = $changes['base']['offset'] + $lineNo + 1; $toLine = $changes['changed']['offset'] + $lineNo + 1; @@ -119,11 +122,11 @@ public function generateLinesEqual(array $changes): string $fromLine - $line + $baseLine $toLine - $line + {$changes['changed']['lines'][$lineNo]} HTML; @@ -135,7 +138,7 @@ public function generateLinesEqual(array $changes): string /** * Generates a string representation of table rows with lines that are added to the 2nd version. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string HTML code representing table rows showing with added text. */ @@ -164,7 +167,7 @@ public function generateLinesInsert(array $changes): string /** * Generates a string representation of table rows with lines that are removed from the 2nd version. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string HTML code representing table rows showing removed text. */ @@ -193,7 +196,7 @@ public function generateLinesDelete(array $changes): string /** * Generates a string representation of table rows with lines that are partially modified. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Html code representing table rows showing modified text. */ @@ -264,7 +267,7 @@ public function generateLinesReplace(array $changes): string /** * Generate a string representation of the start of a block. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Start of the diff view. */ @@ -276,7 +279,7 @@ public function generateBlockHeader(array $changes): string /** * Generate a string representation of the end of a block. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string End of the block. */ From 75358da3787cbd9ef54d26a2f21ec987fc81c35e Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 16 Nov 2020 11:02:41 +0100 Subject: [PATCH 079/206] Add new marking levels for inline differences * In addition to the existing line level, this commit adds marking at character level, word level and no inline marking. * PhpUnit tests added for line, word and character-level marking. --- composer.json | 3 +- lib/jblond/Diff/Renderer/MainRenderer.php | 122 +++++++++++++++++- .../Diff/Renderer/MainRendererAbstract.php | 41 ++++-- tests/Diff/Renderer/MainRendererTest.php | 80 ++++++++++-- 4 files changed, 218 insertions(+), 28 deletions(-) diff --git a/composer.json b/composer.json index cc5bb674..adba123e 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,8 @@ }, "autoload": { "psr-4": { - "jblond\\": "lib/jblond" + "jblond\\": "lib/jblond", + "Tests\\": "tests" } }, "config": { diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 0a00e637..b936b6d3 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -4,6 +4,8 @@ namespace jblond\Diff\Renderer; +use jblond\Diff\SequenceMatcher; + /** * Base renderer for rendering diffs for PHP DiffLib. * @@ -135,7 +137,7 @@ protected function renderSequences(): array if (($tag == 'replace') && ($blockSizeOld == $blockSizeNew)) { // Inline differences between old and new block. - $this->markInlineChange($oldText, $newText, $startOld, $endOld, $startNew); + $this->markInlineChanges($oldText, $newText, $startOld, $endOld, $startNew); } $lastBlock = $this->appendChangesArray($blocks, $tag, $startOld, $startNew); @@ -167,6 +169,118 @@ protected function renderSequences(): array return $changes; } + /** + * Surround inline changes with markers. + * + * @param array $oldText Collection of lines of old text. + * @param array $newText Collection of lines of new text. + * @param int $startOld First line of the block in old to replace. + * @param int $endOld last line of the block in old to replace. + * @param int $startNew First line of the block in new to replace. + */ + private function markInlineChanges( + array &$oldText, + array &$newText, + int $startOld, + int $endOld, + int $startNew + ): void { + if ($this->options['inlineMarking'] < self::CHANGE_LEVEL_LINE) { + $this->markInnerChange($oldText, $newText, $startOld, $endOld, $startNew); + + return; + } + + if ($this->options['inlineMarking'] == self::CHANGE_LEVEL_LINE) { + $this->markOuterChange($oldText, $newText, $startOld, $endOld, $startNew); + } + } + + /** + * Add markers around inline changes between old and new text. + * + * Each line of the old and new text is evaluated. + * When a line of old differs from the same line of new, a marker is inserted into both lines, just before the first + * different character/word. A second marker is added just before the following character/word which matches again. + * + * Setting parameter changeType to self::CHANGE_LEVEL_CHAR will mark differences at character level. + * Other values will mark differences at word level. + * + * E.g. Character level. + *
+     *         1234567890
+     * Old => "aa bbc cdd" Start marker inserted at position 4
+     * New => "aa 12c cdd" End marker inserted at position 6
+     * 
+ * E.g. Word level. + *
+     *         1234567890
+     * Old => "aa bbc cdd" Start marker inserted at position 4
+     * New => "aa 12c cdd" End marker inserted at position 7
+     * 
+ * + * @param array $oldText Collection of lines of old text. + * @param array $newText Collection of lines of new text. + * @param int $startOld First line of the block in old to replace. + * @param int $endOld last line of the block in old to replace. + * @param int $startNew First line of the block in new to replace. + */ + private function markInnerChange(array &$oldText, array &$newText, int $startOld, int $endOld, int $startNew): void + { + for ($iterator = 0; $iterator < ($endOld - $startOld); ++$iterator) { + // ChangeType 0: Character Level. + // ChangeType 1: Word Level. + $regex = $this->options['inlineMarking'] ? '/\w+|[^\w\s]|\s/u' : '/.?/u'; + + // Deconstruct the lines into arrays, including new empty element to the end in case a marker needs to be + // placed as last. + $oldLine = $this->sequenceToArray($regex, $oldText[$startOld + $iterator]); + $newLine = $this->sequenceToArray($regex, $newText[$startNew + $iterator]); + $oldLine[] = ''; + $newLine[] = ''; + + $sequenceMatcher = new SequenceMatcher($oldLine, $newLine); + $opCodes = $sequenceMatcher->getGroupedOpCodes(); + + foreach ($opCodes as $group) { + foreach ($group as [$tag, $changeStartOld, $changeEndOld, $changeStartNew, $changeEndNew]) { + if ($tag == 'equal') { + continue; + } + if ($tag == 'replace' || $tag == 'delete') { + $oldLine[$changeStartOld] = "\0" . $oldLine[$changeStartOld]; + $oldLine[$changeEndOld] = "\1" . $oldLine[$changeEndOld]; + } + if ($tag == 'replace' || $tag == 'insert') { + $newLine[$changeStartNew] = "\0" . $newLine[$changeStartNew]; + $newLine[$changeEndNew] = "\1" . $newLine[$changeEndNew]; + } + } + } + + // Reconstruct the lines and overwrite originals. + $oldText[$startOld + $iterator] = implode('', $oldLine); + $newText[$startNew + $iterator] = implode('', $newLine); + } + } + + /** + * Split a sequence of characters into an array. + * + * Each element of the returned array contains a full pattern match of the regex pattern. + * + * @param string $pattern Regex pattern to split by. + * @param string $sequence The sequence to split. + * + * @return array The split sequence. + */ + public function sequenceToArray(string $pattern, string $sequence): array + { + preg_match_all($pattern, $sequence, $matches); + + return $matches[0]; + } + /** * Add markers around inline changes between old and new text. * @@ -187,7 +301,7 @@ protected function renderSequences(): array * @param int $endOld last line of the block in old to replace. * @param int $startNew First line of the block in new to replace. */ - private function markInlineChange(array &$oldText, array &$newText, int $startOld, int $endOld, int $startNew) + private function markOuterChange(array &$oldText, array &$newText, int $startOld, int $endOld, int $startNew): void { for ($iterator = 0; $iterator < ($endOld - $startOld); ++$iterator) { // Check each line in the block for differences. @@ -195,7 +309,7 @@ private function markInlineChange(array &$oldText, array &$newText, int $startOl $newString = $newText[$startNew + $iterator]; // Determine the start and end position of the line difference. - [$start, $end] = $this->getInlineChange($oldString, $newString); + [$start, $end] = $this->getOuterChange($oldString, $newString); if ($start != 0 || $end != 0) { // Changes between the lines exist. // Add markers around the changed character sequence in the old string. @@ -233,7 +347,7 @@ private function markInlineChange(array &$oldText, array &$newText, int $startOl * * @return array Array containing the starting position (0 by default) and the ending position (-1 by default) */ - private function getInlineChange(string $oldString, string $newString): array + private function getOuterChange(string $oldString, string $newString): array { $start = 0; $limit = min(mb_strlen($oldString), mb_strlen($newString)); diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index 5a11e3e5..febcc4b9 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -11,17 +11,32 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer - * @author Mario Brandt - * @author Ferry Cools + * @package jblond\Diff\Renderer + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract { - + /** + * Mark inline character differences. + */ + public const CHANGE_LEVEL_CHAR = 0; + /** + * Mark inline word differences. + */ + public const CHANGE_LEVEL_WORD = 1; + /** + * Mark line differences. + */ + public const CHANGE_LEVEL_LINE = 2; + /** + * Mark no inline differences. + */ + public const CHANGE_LEVEL_NONE = 4; /** * @var Diff $diff Instance of the diff class that this renderer is generating the rendered diff for. */ @@ -30,6 +45,11 @@ abstract class MainRendererAbstract /** * @var array Associative array containing the default options available for this renderer and their default * value. + * - inlineMarking The level of how differences are marked. + * - self::CHANGE_LEVEL_NONE Don't Inline-Mark. + * - self::CHANGE_LEVEL_CHAR Inline-Mark each different character. + * - self::CHANGE_LEVEL_WORD Inline-Mark each different word. + * - self::CHANGE_LEVEL_LINE Inline-Mark from first to last line diff. * - tabSize The amount of spaces to replace a tab character with. * - format The format of the input texts. * - cliColor Colorized output for cli. @@ -40,6 +60,7 @@ abstract class MainRendererAbstract * - deleteColors Fore- and background color for removed text. Only when cliColor = true. */ protected $mainOptions = [ + 'inlineMarking' => self::CHANGE_LEVEL_LINE, 'tabSize' => 4, 'format' => 'plain', 'cliColor' => false, @@ -60,7 +81,7 @@ abstract class MainRendererAbstract * The constructor. Instantiates the rendering engine and if options are passed, * sets the options for the renderer. * - * @param array $options Optionally, an array of the options for the renderer. + * @param array $options Optionally, an array of the options for the renderer. */ public function __construct(array $options = []) { @@ -72,9 +93,11 @@ public function __construct(array $options = []) * * Options are merged with the default to ensure that there aren't any missing options. * When custom options are added to the default ones, they can be overwritten, but they can't be removed. + * + * @param array $options Array of options to set. + * * @see MainRendererAbstract::$mainOptions * - * @param array $options Array of options to set. */ public function setOptions(array $options) { diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 34742164..285e7f51 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -1,5 +1,7 @@ - * @author Ferry Cools + * @package Tests\Diff\Renderer + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2009 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff */ /** * Class MainRendererTest + * * @package Tests\Diff\Renderer\Html */ class MainRendererTest extends TestCase @@ -40,9 +44,9 @@ class MainRendererTest extends TestCase /** * MainRendererTest constructor. * - * @param null $name - * @param array $data - * @param string $dataName + * @param null $name + * @param array $data + * @param string $dataName */ public function __construct($name = null, array $data = [], $dataName = '') { @@ -86,14 +90,14 @@ public function testRenderSimpleDelete() /** * Call protected/private method of a class. * - * @param object &$object Instantiated object that we will run method on. - * @param string $methodName Method name to call - * @param array $parameters Array of parameters to pass into method. + * @param object $object Instantiated object that we will run method on. + * @param string $methodName Method name to call + * @param array $parameters Array of parameters to pass into method. * * @return mixed Method return. - * @throws \ReflectionException If the class doesn't exist. + * @throws ReflectionException If the class doesn't exist. */ - public function invokeMethod(&$object, $methodName, array $parameters = []) + public function invokeMethod(object $object, string $methodName, array $parameters = []) { $reflection = new ReflectionClass(get_class($object)); $method = $reflection->getMethod($methodName); @@ -137,4 +141,52 @@ public function testRenderFixesSpaces() $result ); } + + /** + * Test inline marking for changes at line level. + * + * Everything from the first difference to the last difference should be enclosed by the markers. + * + * @throws ReflectionException When invoking the method fails. + */ + public function testMarkOuterChange() + { + $renderer = new MainRenderer(); + $text1 = ['one two three four']; + $text2 = ['one tWo thrEe four']; + $this->invokeMethod($renderer, 'markOuterChange', [&$text1, &$text2, 0, 1, 0]); + $this->assertSame(["one t\0wo thre\1e four"], $text1); + $this->assertSame(["one t\0Wo thrE\1e four"], $text2); + } + + /** + * Test inline marking for changes at character and word level. + * + * At character level, everything from a different character to any subsequent different character should be + * enclosed by the markers. + * + * At word level, every word that is different should be enclosed by the markers. + * + * @throws ReflectionException When invoking the method fails. + */ + public function testMarkInnerChange() + { + $renderer = new MainRenderer(); + + // Character level. + $renderer->setOptions(['inlineMarking' => $renderer::CHANGE_LEVEL_CHAR]); + $text1 = ['one two three four']; + $text2 = ['one tWo thrEe fouR']; + $this->invokeMethod($renderer, 'markInnerChange', [&$text1, &$text2, 0, 1, 0]); + $this->assertSame(["one t\0w\1o thr\0e\1e fou\0r\1"], $text1); + $this->assertSame(["one t\0W\1o thr\0E\1e fou\0R\1"], $text2); + + // Word Level. + $renderer->setOptions(['inlineMarking' => $renderer::CHANGE_LEVEL_WORD]); + $text1 = ['one two three four']; + $text2 = ['one tWo thrEe fouR']; + $this->invokeMethod($renderer, 'markInnerChange', [&$text1, &$text2, 0, 1, 0]); + $this->assertSame(["one \0two\1 \0three\1 \0four\1"], $text1); + $this->assertSame(["one \0tWo\1 \0thrEe\1 \0fouR\1"], $text2); + } } From c27035ab52933bb0992dc1f2bbc4580ab94d36e6 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 17 Nov 2020 09:28:58 +0100 Subject: [PATCH 080/206] Add choosing marking levels to html example Sample text A is altered to see difference between word and line level more clearly. --- example/a.txt | 2 +- example/example.php | 98 ++++++++++++++++++++++++++------------------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/example/a.txt b/example/a.txt index eab1ced5..9dddb84c 100644 --- a/example/a.txt +++ b/example/a.txt @@ -8,7 +8,7 @@

This line is removed from version2.

This line is also removed from version2.

This line is the same for both versions.

-

This line has inline differences between both versions.

+

this line has inline differences between both versions.

This line is the same for both versions.

This line also has inline differences between both versions.

This line is the same for both versions.

diff --git a/example/example.php b/example/example.php index caebc983..f88e30df 100644 --- a/example/example.php +++ b/example/example.php @@ -15,7 +15,7 @@ $sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); // Options for generating the diff. -$customOptions = [ +$diffOptions = [ 'context' => 2, 'trimEqual' => false, 'ignoreWhitespace' => true, @@ -24,8 +24,14 @@ // Choose one of the initializations. $diff = new Diff($sampleA, $sampleB); // Initialize the diff class with default options. -//$diff = new Diff($sampleA, $sampleB, $customOptions); // Initialize the diff class with custom options. -?> +//$diff = new Diff($sampleA, $sampleB, $diffOptions); // Initialize the diff class with custom options. + +// Options for rendering the diff. +$rendererOptions = [ + 'inlineMarking' => $_GET['inlineMarking'] ?? Diff\Renderer\MainRenderer::CHANGE_LEVEL_LINE, +] +?> + @@ -46,50 +52,58 @@ function changeCSS(cssFile, cssLinkIndex) { -

PHP LibDiff - Examples

- -
+

PHP LibDiff - Examples

+ +
+ +
-

HTML Side by Side Diff

+

HTML Side by Side Diff

- isIdentical() ? 'No differences found.' : $diff->Render($renderer); - ?> +isIdentical() ? 'No differences found.' : $diff->Render($renderer); +?> -

HTML Inline Diff

- isIdentical() ? 'No differences found.' : $diff->Render($renderer); - ?> +

HTML Inline Diff

+isIdentical() ? 'No differences found.' : $diff->Render($renderer); +?> -

HTML Unified Diff

- isIdentical() ? 'No differences found.' : '
' . $diff->Render($renderer) . '
'; - ?> +

HTML Unified Diff

+isIdentical() ? 'No differences found.' : '
' . $diff->Render($renderer) . '
'; +?> -

Text Unified Diff

- isIdentical() ? - 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; - ?> +

Text Unified Diff

+isIdentical() ? + 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; +?> -

Text Context Diff

- isIdentical() ? - 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; - ?> +

Text Context Diff

+isIdentical() ? + 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; +?> From 6b9661c6dfdc7f389348439155edb5b1550ead6c Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 17 Nov 2020 09:31:49 +0100 Subject: [PATCH 081/206] Refactor sample text Sample text A is altered to see difference between word and line level more clearly. --- tests/resources/a.txt | 2 +- tests/resources/htmlInline.txt | 4 ++-- tests/resources/htmlSideBySide.txt | 4 ++-- tests/resources/htmlUnified.txt | 2 +- tests/resources/textContext.txt | 2 +- tests/resources/textInlineCli.txt | 2 +- tests/resources/textUnified.txt | 2 +- tests/resources/textUnifiedCli.txt | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/resources/a.txt b/tests/resources/a.txt index cdf834c1..066eedc0 100644 --- a/tests/resources/a.txt +++ b/tests/resources/a.txt @@ -7,7 +7,7 @@

This is demo content to show features of the php-diff package.

This line is removed from version2.

This line is the same for both versions.

-

This line has inline differences between both versions.

+

this line has inline differences between both versions.

This line is the same for both versions.

This line also has inline differences between both versions.

This line is the same for both versions.

diff --git a/tests/resources/htmlInline.txt b/tests/resources/htmlInline.txt index f28e973f..443cc066 100644 --- a/tests/resources/htmlInline.txt +++ b/tests/resources/htmlInline.txt @@ -56,13 +56,13 @@ 10   -         <h2>This line has inline differences between both versions.</h2> +         <h2>this line has inline differences between both versions.</h2>   9 -         <h2>This line has differences between both versions.</h2> +         <h2>This line has differences between both versions.</h2> 11 diff --git a/tests/resources/htmlSideBySide.txt b/tests/resources/htmlSideBySide.txt index fcbce226..67ce275c 100644 --- a/tests/resources/htmlSideBySide.txt +++ b/tests/resources/htmlSideBySide.txt @@ -86,11 +86,11 @@ 10 -         <h2>This line has inline differences between both versions.</h2> +         <h2>this line has inline differences between both versions.</h2> 9 -         <h2>This line has differences between both versions.</h2> +         <h2>This line has differences between both versions.</h2> 11 diff --git a/tests/resources/htmlUnified.txt b/tests/resources/htmlUnified.txt index 2da3bdd7..fc1adeeb 100644 --- a/tests/resources/htmlUnified.txt +++ b/tests/resources/htmlUnified.txt @@ -1 +1 @@ -<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file +<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>this line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file diff --git a/tests/resources/textContext.txt b/tests/resources/textContext.txt index 034c6c13..8d234956 100644 --- a/tests/resources/textContext.txt +++ b/tests/resources/textContext.txt @@ -9,7 +9,7 @@

This is demo content to show features of the php-diff package.

-

This line is removed from version2.

This line is the same for both versions.

-!

This line has inline differences between both versions.

+!

this line has inline differences between both versions.

This line is the same for both versions.

!

This line also has inline differences between both versions.

This line is the same for both versions.

diff --git a/tests/resources/textInlineCli.txt b/tests/resources/textInlineCli.txt index 3678f6f4..b3b08400 100644 --- a/tests/resources/textInlineCli.txt +++ b/tests/resources/textInlineCli.txt @@ -7,7 +7,7 @@ x| Hello -World-+You+! =|

This is demo content to show features of the php-diff package.

-|

This line is removed from version2.

 =|

This line is the same for both versions.

-x|

This line has -inline -++differences between both versions.

+x|

-this line has inline-+This line has+ differences between both versions.

=|

This line is the same for both versions.

x|

This line also has -inl-+InL+ine differences between both versions.

=|

This line is the same for both versions.

diff --git a/tests/resources/textUnified.txt b/tests/resources/textUnified.txt index 1802b813..b5976f95 100644 --- a/tests/resources/textUnified.txt +++ b/tests/resources/textUnified.txt @@ -9,7 +9,7 @@

This is demo content to show features of the php-diff package.

-

This line is removed from version2.

This line is the same for both versions.

--

This line has inline differences between both versions.

+-

this line has inline differences between both versions.

+

This line has differences between both versions.

This line is the same for both versions.

-

This line also has inline differences between both versions.

diff --git a/tests/resources/textUnifiedCli.txt b/tests/resources/textUnifiedCli.txt index c66e4752..a8842c05 100644 --- a/tests/resources/textUnifiedCli.txt +++ b/tests/resources/textUnifiedCli.txt @@ -9,7 +9,7 @@

This is demo content to show features of the php-diff package.

-

This line is removed from version2.

This line is the same for both versions.

--

This line has inline differences between both versions.

+-

this line has inline differences between both versions.

+

This line has differences between both versions.

This line is the same for both versions.

-

This line also has inline differences between both versions.

From b10fd38be306aabc3f53fade917d258bbe93ece7 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 17 Nov 2020 09:44:07 +0100 Subject: [PATCH 082/206] Fix Undefined offset notice Inline sequence changes at version 1 where assumed to exist at version 2 also. This isn't true. 1: This is a first sample. 2: this is a sample. Change "first" at 1 doesn't exist at 2. This is an effect of marking inline differences at word level. --- lib/jblond/Diff/Renderer/Text/InlineCli.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 1bcb9b6e..42684280 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -219,12 +219,14 @@ private function mergeChanges( foreach ($baselineParts as $partKey => &$part) { if ($iterator++ % 2) { - // This part of the line has been changed. Surround it with user defied markers. + // This part of the line has been changed. Surround it with user defined markers. $basePart = $this->options['deleteMarkers'][0] . $part . $this->options['deleteMarkers'][1]; - $changedPart = - $this->options['insertMarkers'][0] . - $changedLineParts[$partKey] . - $this->options['insertMarkers'][1]; + if (isset($changedLineParts[$partKey])) { + $changedPart = + $this->options['insertMarkers'][0] . + $changedLineParts[$partKey] . + $this->options['insertMarkers'][1]; + } if ($this->options['cliColor']) { // Colorize the changed part. From b5cfbd5e8667f53fe1da89ed250ad7b5f0ba8e59 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 5 Nov 2020 14:45:31 +0100 Subject: [PATCH 083/206] Fix generateBlockHeader docBlocks At the subRenderer classes and their interface, the return value of the method is described as "Start of the diff view" but should describe start of block. --- lib/jblond/Diff/Renderer/Html/Inline.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 068b1177..93e351df 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -233,7 +233,7 @@ public function generateLinesReplace(array $changes): string * * @param array $changes Contains the op-codes about the changes between two blocks of text. * - * @return string Start of the diff view. + * @return string Start of the block. */ public function generateBlockHeader(array $changes): string { diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 850663c5..b442706b 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -269,7 +269,7 @@ public function generateLinesReplace(array $changes): string * * @param array $changes Contains the op-codes about the changes between two blocks of text. * - * @return string Start of the diff view. + * @return string Start of the block. */ public function generateBlockHeader(array $changes): string { diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index e9bba020..9d6225aa 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -170,7 +170,7 @@ public function generateLinesReplace(array $change): string * * @param array $changes Contains the op-codes about the changes between two blocks of text. * - * @return string Start of the diff view. + * @return string Start of the block. */ public function generateBlockHeader(array $changes): string { diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index 89496191..dbf6465d 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -37,7 +37,7 @@ public function generateDiffHeader(): string; * * @param array $changes Contains the op-codes about the changes between two blocks of text. * - * @return string Start of the diff view. + * @return string Start of the block. */ public function generateBlockHeader(array $changes): string; From d70eaf65381aa93facea238c78d05d1160f9dbba Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 5 Nov 2020 14:48:23 +0100 Subject: [PATCH 084/206] Add Html Merged renderer. --- example/dark-theme.css | 42 +++- example/example.php | 10 +- example/styles.css | 22 +++ lib/jblond/Diff/Renderer/Html/Merged.php | 241 +++++++++++++++++++++++ 4 files changed, 306 insertions(+), 9 deletions(-) create mode 100644 lib/jblond/Diff/Renderer/Html/Merged.php diff --git a/example/dark-theme.css b/example/dark-theme.css index 1c0408bb..9a8fce04 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -52,17 +52,23 @@ a, a:visited { .Differences .Skipped { background: #F7F7F7; + color: #000000; +} + +.Differences ins, +.Differences del { + text-decoration: none; } /* * HTML Side by Side Diff */ .DifferencesSideBySide .ChangeInsert td.Left { - background: green; + background: #008000; } .DifferencesSideBySide .ChangeInsert td.Right { - background: green; + background: #008000; } .DifferencesSideBySide .ChangeDelete td.Left { @@ -85,11 +91,6 @@ a, a:visited { color: #272822; } -.Differences ins, -.Differences del { - text-decoration: none; -} - .DifferencesSideBySide .ChangeReplace ins, .DifferencesSideBySide .ChangeReplace del { background: #EEBB00; @@ -115,7 +116,7 @@ a, a:visited { } .DifferencesInline .ChangeReplace ins { - background: green; + background: #008000; } .DifferencesInline .ChangeReplace del { @@ -123,6 +124,31 @@ a, a:visited { color: #272822; } +/* + * HTML Merged Diff + */ +.DifferencesMerged .ChangeReplace .Left, +.DifferencesMerged .ChangeDelete { + background: #FFDDDD; + color: #272822; +} + +.DifferencesMerged .ChangeReplace .Right, +.DifferencesMerged .ChangeInsert { + background: #DDFFDD; + color: #272822; +} + +.DifferencesMerged .ChangeReplace ins { + background: #008000; + color: #272822; +} + +.DifferencesMerged .ChangeReplace del { + background: #EE9999; + color: #272822; +} + /* * HTML Unified Diff */ diff --git a/example/example.php b/example/example.php index f88e30df..184c230c 100644 --- a/example/example.php +++ b/example/example.php @@ -2,6 +2,7 @@ use jblond\Diff; use jblond\Diff\Renderer\Html\Inline; +use jblond\Diff\Renderer\Html\Merged; use jblond\Diff\Renderer\Html\SideBySide; use jblond\Diff\Renderer\Html\Unified as HtmlUnified; use jblond\Diff\Renderer\Text\Context; @@ -23,7 +24,7 @@ ]; // Choose one of the initializations. -$diff = new Diff($sampleA, $sampleB); // Initialize the diff class with default options. +$diff = new Diff($sampleA, $sampleB); // Initialize the diff class with default options. //$diff = new Diff($sampleA, $sampleB, $diffOptions); // Initialize the diff class with custom options. // Options for rendering the diff. @@ -83,6 +84,13 @@ function changeCSS(cssFile, cssLinkIndex) { echo $diff->isIdentical() ? 'No differences found.' : $diff->Render($renderer); ?> +

HTML Merged Diff

+isIdentical() ? 'No differences found.' : $diff->Render($renderer); +?> +

HTML Unified Diff

+ * @copyright (c) 2020 Ferry Cools + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff + */ +class Merged extends MainRenderer implements SubRendererInterface +{ + /** + * @var array Associative array containing the default options available for this renderer and their default + * value. + * - format Format of the texts. + * - insertMarkers Markers for inserted text. + * - deleteMarkers Markers for removed text. + * - title1 Title of the 1st version of text. + * - title2 Title of the 2nd version of text. + */ + protected $subOptions = [ + 'format' => 'html', + 'insertMarkers' => ['', ''], + 'deleteMarkers' => ['', ''], + 'title1' => 'Version1', + 'title2' => 'Version2', + ]; + protected $lineOffset = 0; + /** + * @var string + */ + protected $lastDeleted; + + /** + * Merged constructor. + * + * @param array $options Custom defined options for the inline diff renderer. + * + * @see Inline::$subOptions + */ + public function __construct(array $options = []) + { + parent::__construct($this->subOptions); + $this->setOptions($options); + } + + /** + * @inheritDoc + */ + public function render() + { + $changes = parent::renderSequences(); + + return parent::renderOutput($changes, $this); + } + + /** + * @inheritDoc + */ + public function generateDiffHeader(): string + { + return << + + + Merge of {$this->options['title1']} & {$this->options['title2']} + + +HTML; + } + + /** + * @inheritDoc + */ + public function generateBlockHeader(array $changes): string + { + return ''; + } + + /** + * @inheritDoc + */ + public function generateSkippedLines(): string + { + $marker = '…'; + if ($this->lastDeleted !== null) { + $marker = "*$marker"; + } + + $this->lastDeleted = null; + + return << + $marker + … + +HTML; + } + + /** + * @inheritDoc + */ + public function generateLinesEqual(array $changes): string + { + $html = ''; + + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; + if (!$lineNo && $this->lastDeleted !== null) { + $fromLine = "*$fromLine"; + } + + $html .= << + $fromLine + $line + +HTML; + $this->lastDeleted = null; + } + + return $html; + } + + /** + * @inheritDoc + */ + public function generateLinesInsert(array $changes): string + { + $html = ''; + + foreach ($changes['changed']['lines'] as $lineNo => $line) { + $this->lineOffset++; + $toLine = $changes['base']['offset'] + $this->lineOffset; + if (!$lineNo && $this->lastDeleted !== null) { + $toLine = "*$toLine"; + } + + $html .= << + $toLine + $line + +HTML; + $this->lastDeleted = null; + } + + + return $html; + } + + /** + * @inheritDoc + */ + public function generateLinesDelete(array $changes): string + { + $this->lineOffset -= count($changes['base']['lines']); + + $title = "Lines deleted at {$this->options['title2']}:\n"; + + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + + $title .= <<lastDeleted = $title; + + return ''; + } + + /** + * @inheritDoc + */ + public function generateLinesReplace(array $changes): string + { + $html = ''; + + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; + if (!$lineNo && $this->lastDeleted !== null) { + $fromLine = "*$fromLine"; + } + + // Capture added parts. + preg_match_all('/\x0.*?\x1/', $changes['changed']['lines'][$lineNo], $addedParts, PREG_PATTERN_ORDER); + array_unshift($addedParts[0], ''); + + // Concatenate removed parts with added parts. + $line = preg_replace_callback( + '/\x0.*?\x1/', + function ($removedParts) use ($addedParts) { + $addedPart = str_replace(["\0", "\1"], $this->options['insertMarkers'], next($addedParts[0])); + $removedPart = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $removedParts[0]); + + return "$removedPart$addedPart"; + }, + $line + ); + + $html .= << + $fromLine + $line + +HTML; + $this->lastDeleted = null; + } + + return $html; + } + + /** + * @inheritDoc + */ + public function generateBlockFooter(array $changes): string + { + return ''; + } + + /** + * @inheritDoc + */ + public function generateDiffFooter(): string + { + return ''; + } +} From 4512c037a89fbee65d93621e6b5e50e8a9f075ce Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 5 Nov 2020 15:30:53 +0100 Subject: [PATCH 085/206] Add PhpUnit test for html merged renderer --- .../Diff/Renderer/Html/HtmlRenderersTest.php | 21 ++++ tests/resources/htmlMerged.txt | 104 ++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 tests/resources/htmlMerged.txt diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 00f8f0e5..50e3edf8 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -6,6 +6,7 @@ use jblond\Diff; use jblond\Diff\Renderer\Html\Inline; +use jblond\Diff\Renderer\Html\Merged; use jblond\Diff\Renderer\Html\SideBySide; use jblond\Diff\Renderer\Html\Unified; use PHPUnit\Framework\TestCase; @@ -89,6 +90,26 @@ public function testInline() $this->assertStringEqualsFile('tests/resources/htmlInline.txt', $result); } + /** + * Test the output of the HTML Unified renderer. + * @covers \jblond\Diff\Renderer\Html\Merged + */ + public function testMerged() + { + $diff = new Diff( + file_get_contents('tests/resources/a.txt'), + file_get_contents('tests/resources/b.txt') + ); + + $renderer = new Merged(); + $result = $diff->render($renderer); + if ($this->genOutputFiles) { + file_put_contents('htmlMerged.txt', $result); + } + + $this->assertStringEqualsFile('tests/resources/htmlMerged.txt', $result); + } + /** * Test the output of the HTML Unified renderer. * @covers \jblond\Diff\Renderer\Html\Unified diff --git a/tests/resources/htmlMerged.txt b/tests/resources/htmlMerged.txt new file mode 100644 index 00000000..ebd6fad4 --- /dev/null +++ b/tests/resources/htmlMerged.txt @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Merge of Version1 & Version2
1<html>
2    <head>
3        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
4        <title>Hello WorldYou!</title>
5    </head>
6    <body>
7        <h1>This is demo content to show features of the php-diff package.</h1>
*8        <h2>This line is the same for both versions.</h2>
9        <h2>This line has inline differences between both versions.</h2>
10        <h2>This line is the same for both versions.</h2>
11        <h2>This line also has inlInLine differences between both versions.</h2>
12        <h2>This line is the same for both versions.</h2>
13        <h2>This line is added to version2.</h2>
14
15        <p>
16            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
17            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
18            Do you know what "金槍魚罐頭魚の缶詰" means in Chinese?
19            🍏🍎🍎🍏🙂
20        </p>
21
22        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
25        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
26        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
27        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
28                <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
29        <h2>This line is the same for both versions.</h2>
30        <h2>This line also has inline differences between both versions.!</h2>
31    </body>
32</html>
33
\ No newline at end of file From 6c95ccd6690f1eef69e06b5ae16df817c89ef3c0 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 11 Nov 2020 15:34:38 +0100 Subject: [PATCH 086/206] Document properties and constructor - Added docblock for Merged::$lineOffset. - Fixed docBlock for Merged::$lastDeleted and Merged::__construct(). --- lib/jblond/Diff/Renderer/Html/Merged.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 9e92cf63..5d2272ba 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -35,18 +35,21 @@ class Merged extends MainRenderer implements SubRendererInterface 'title1' => 'Version1', 'title2' => 'Version2', ]; + /** + * @var int Line offset to keep correct line number for merged diff. + */ protected $lineOffset = 0; /** - * @var string + * @var string last block of lines which where removed from version 2. */ protected $lastDeleted; /** * Merged constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the merged diff renderer. * - * @see Inline::$subOptions + * @see Merged::$subOptions */ public function __construct(array $options = []) { From cef85b5f7d6f72e253bd50a3f3253a9e32f72ae6 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 11 Nov 2020 15:37:18 +0100 Subject: [PATCH 087/206] Fix Merged::generateLinesReplace() - Mess Detector reported unused variable. Although always created and used, it's nicer to declare it on beforehand. --- lib/jblond/Diff/Renderer/Html/Merged.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 5d2272ba..f72f9d4c 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -199,6 +199,7 @@ public function generateLinesReplace(array $changes): string } // Capture added parts. + $addedParts = []; preg_match_all('/\x0.*?\x1/', $changes['changed']['lines'][$lineNo], $addedParts, PREG_PATTERN_ORDER); array_unshift($addedParts[0], ''); From ec0918bca72c2a383bd006aa41dc710fe4dab450 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 12 Nov 2020 13:47:01 +0100 Subject: [PATCH 088/206] Fix visibility of removed lines * Lines which are removed from version 2 where indicated by an asterisk in front of the line number. This was easy to overlook. The indicator is a class now so it can by styled by css. * Block bodies of removed lines where still rendered even though they had no content. --- example/dark-theme.css | 34 ++++++------ example/styles.css | 6 ++- lib/jblond/Diff/Renderer/Html/Merged.php | 31 ++++++----- tests/resources/htmlMerged.txt | 68 ++++++++++++------------ 4 files changed, 76 insertions(+), 63 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index 9a8fce04..c6ee4c64 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -1,6 +1,6 @@ body { background: #3A3B46; - color: #F8F8F2; + color: #F8F8F2; font-family: Arial, serif; font-size: 12px; } @@ -36,7 +36,7 @@ a, a:visited { .Differences tbody th { text-align: right; background: #AAAAAA; - color: #272822; + color: #272822; width: 4em; padding: 1px 2px; border-right: 1px solid #000000; @@ -52,7 +52,7 @@ a, a:visited { .Differences .Skipped { background: #F7F7F7; - color: #000000; + color: #000000; } .Differences ins, @@ -73,22 +73,22 @@ a, a:visited { .DifferencesSideBySide .ChangeDelete td.Left { background: #FF8888; - color: #272822; + color: #272822; } .DifferencesSideBySide .ChangeDelete td.Right { background: #FFAAAA; - color: #272822; + color: #272822; } .DifferencesSideBySide .ChangeReplace .Left { background: #FFEE99; - color: #272822; + color: #272822; } .DifferencesSideBySide .ChangeReplace .Right { background: #FFDD88; - color: #272822; + color: #272822; } .DifferencesSideBySide .ChangeReplace ins, @@ -107,7 +107,7 @@ a, a:visited { .DifferencesInline .ChangeReplace .Left, .DifferencesInline .ChangeDelete .Left { background: #FFDDDD; - color: #272822; + color: #272822; } .DifferencesInline .ChangeReplace .Right, @@ -121,7 +121,7 @@ a, a:visited { .DifferencesInline .ChangeReplace del { background: #EE9999; - color: #272822; + color: #272822; } /* @@ -130,23 +130,27 @@ a, a:visited { .DifferencesMerged .ChangeReplace .Left, .DifferencesMerged .ChangeDelete { background: #FFDDDD; - color: #272822; + color: #272822; } .DifferencesMerged .ChangeReplace .Right, .DifferencesMerged .ChangeInsert { background: #DDFFDD; - color: #272822; + color: #272822; } .DifferencesMerged .ChangeReplace ins { background: #008000; - color: #272822; + color: #272822; } .DifferencesMerged .ChangeReplace del { background: #EE9999; - color: #272822; + color: #272822; +} + +.DifferencesMerged th.ChangeDelete { + background-image: linear-gradient(-45deg, #AAAAAA 0%, #EE9999 100%); } /* @@ -160,13 +164,13 @@ a, a:visited { .DifferencesUnified .ChangeDelete .Left { background: #EE9999; - color: #272822; + color: #272822; } /* Line modified in old and new */ .DifferencesUnified .ChangeReplace { background: #FFEE99; - color: #272822; + color: #272822; display: table; } diff --git a/example/styles.css b/example/styles.css index eb85659c..fb6eaca9 100644 --- a/example/styles.css +++ b/example/styles.css @@ -1,6 +1,6 @@ body { background: #FFFFFF; - color: #000000; + color: #000000; font-family: Arial, serif; font-size: 12px; } @@ -128,6 +128,10 @@ pre { background: #EE9999; } +.DifferencesMerged th.ChangeDelete { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #EE9999 100%); +} + /* * HTML Unified Diff */ diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index f72f9d4c..22e613d1 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -87,7 +87,7 @@ public function generateDiffHeader(): string */ public function generateBlockHeader(array $changes): string { - return ''; + return $changes['tag'] != 'delete' ? '' : ''; } /** @@ -95,16 +95,18 @@ public function generateBlockHeader(array $changes): string */ public function generateSkippedLines(): string { - $marker = '…'; + $marker = '…'; + $headerClass = ''; + if ($this->lastDeleted !== null) { - $marker = "*$marker"; + $headerClass = 'ChangeDelete'; } $this->lastDeleted = null; return << - $marker + $marker … HTML; @@ -115,17 +117,18 @@ public function generateSkippedLines(): string */ public function generateLinesEqual(array $changes): string { - $html = ''; + $html = ''; + $headerClass = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; if (!$lineNo && $this->lastDeleted !== null) { - $fromLine = "*$fromLine"; + $headerClass = 'ChangeDelete'; } $html .= << - $fromLine + $fromLine $line HTML; @@ -140,18 +143,19 @@ public function generateLinesEqual(array $changes): string */ public function generateLinesInsert(array $changes): string { - $html = ''; + $html = ''; + $headerClass = ''; foreach ($changes['changed']['lines'] as $lineNo => $line) { $this->lineOffset++; $toLine = $changes['base']['offset'] + $this->lineOffset; if (!$lineNo && $this->lastDeleted !== null) { - $toLine = "*$toLine"; + $headerClass = 'ChangeDelete'; } $html .= << - $toLine + $toLine $line HTML; @@ -190,12 +194,13 @@ public function generateLinesDelete(array $changes): string */ public function generateLinesReplace(array $changes): string { - $html = ''; + $html = ''; + $headerClass = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; if (!$lineNo && $this->lastDeleted !== null) { - $fromLine = "*$fromLine"; + $headerClass = 'ChangeDelete'; } // Capture added parts. @@ -217,7 +222,7 @@ function ($removedParts) use ($addedParts) { $html .= << - $fromLine + $fromLine $line HTML; diff --git a/tests/resources/htmlMerged.txt b/tests/resources/htmlMerged.txt index ebd6fad4..1410e047 100644 --- a/tests/resources/htmlMerged.txt +++ b/tests/resources/htmlMerged.txt @@ -4,101 +4,101 @@ Merge of Version1 & Version2 - 1 + 1 <html> - 2 + 2     <head> - 3 + 3         <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> - 4 + 4         <title>Hello WorldYou!</title> - 5 + 5     </head> - 6 + 6     <body> - 7 + 7         <h1>This is demo content to show features of the php-diff package.</h1> - - + *8 +">8         <h2>This line is the same for both versions.</h2> - 9 + 9         <h2>This line has inline differences between both versions.</h2> - 10 + 10         <h2>This line is the same for both versions.</h2> - 11 + 11         <h2>This line also has inlInLine differences between both versions.</h2> - 12 + 12         <h2>This line is the same for both versions.</h2> - 13 + 13         <h2>This line is added to version2.</h2> - 14 + 14 - 15 + 15         <p> - 16 + 16             It's also compatible with multibyte characters (like Chinese and emoji) as shown below: - 17 + 17             另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革” - 18 + 18             Do you know what "金槍魚罐頭魚の缶詰" means in Chinese? - 19 + 19             🍏🍎🍎🍏🙂 - 20 + 20         </p> - 21 + 21 - 22 + 22         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - … + … … - 25 + 25         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - 26 + 26         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - 27 + 27         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - 28 + 28                 <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2> - 29 + 29         <h2>This line is the same for both versions.</h2> - 30 + 30         <h2>This line also has inline differences between both versions.!</h2> - 31 + 31     </body> - 32 + 32 </html> - 33 + 33 \ No newline at end of file From 6e2ad478c4969055c772806ab34d5756132ac2ef Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 17 Nov 2020 13:21:03 +0100 Subject: [PATCH 089/206] Fix PSR-4 Auto loading Typo --- tests/Diff/Renderer/Text/TextRenderersTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 1e80d17b..c8faa7f8 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -10,7 +10,7 @@ use PHPUnit\Framework\TestCase; /** - * Class TextRendererTest + * Class TextRenderersTest * * PHPUnit tests to verify that the output of the text renderers did not change due to code changes. * @@ -22,7 +22,7 @@ * @version 2.2.1 * @link https://github.com/JBlond/php-diff */ -class TextRendererTest extends TestCase +class TextRenderersTest extends TestCase { /** * @var bool Store the renderer's output in a file, when set to true. @@ -30,7 +30,7 @@ class TextRendererTest extends TestCase private $genOutputFiles = false; /** - * TextRendererTest constructor. + * TextRenderersTest constructor. * * @param null $name * @param array $data From 3ccaa107d2a9012f18c7ca1f1b8fd3a1fff4e7be Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 17 Nov 2020 23:52:59 +0100 Subject: [PATCH 090/206] Fix PhpUnit test The expected result didn't reflect the changes made in the sample files at commit 6b9661c6. --- tests/resources/htmlMerged.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/resources/htmlMerged.txt b/tests/resources/htmlMerged.txt index 1410e047..37364a96 100644 --- a/tests/resources/htmlMerged.txt +++ b/tests/resources/htmlMerged.txt @@ -31,7 +31,7 @@         <h2>This line is the same for both versions.</h2> 9 -         <h2>This line has inline differences between both versions.</h2> +         <h2>this line has inlineThis line has differences between both versions.</h2> 10         <h2>This line is the same for both versions.</h2> From 3e4bbe6f97d129a69a3c8c727214f07d30e177a0 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Wed, 18 Nov 2020 15:37:18 +0100 Subject: [PATCH 091/206] Add calculation for similarity ratio. Includes minor refactoring SequenceMatcher.php which will happen somewhere in the future anyway. --- example/example.php | 5 + lib/jblond/Diff.php | 48 ++- lib/jblond/Diff/SequenceMatcher.php | 624 ++++++++++++++-------------- lib/jblond/Diff/Similarity.php | 165 ++++++++ tests/Diff/SimilarityTest.php | 19 + 5 files changed, 540 insertions(+), 321 deletions(-) create mode 100644 lib/jblond/Diff/Similarity.php create mode 100644 tests/Diff/SimilarityTest.php diff --git a/example/example.php b/example/example.php index f88e30df..c823a776 100644 --- a/example/example.php +++ b/example/example.php @@ -67,6 +67,11 @@ function changeCSS(cssFile, cssLinkIndex) { None
+ +

HTML Side by Side Diff

diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 2e469b35..2b84157f 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -11,6 +11,7 @@ use jblond\Diff\Renderer\Text\Context; use jblond\Diff\Renderer\Text\Unified; use jblond\Diff\SequenceMatcher; +use jblond\Diff\Similarity; use OutOfRangeException; /** @@ -79,6 +80,10 @@ class Diff * @var bool True when compared versions are identical, False otherwise. */ private $identical; + /** + * @var float Similarity ratio of the two sequences. + */ + private $similarity; /** * The constructor. @@ -92,9 +97,9 @@ class Diff * When a keyName matches the name of a default option, that option's value will be overridden by the key's value. * Any other keyName (and it's value) can be added as an option, but will not be used if not implemented. * - * @param string|array $version1 Data to compare to. - * @param string|array $version2 Data to compare. - * @param array $options User defined option values. + * @param string|array $version1 Data to compare to. + * @param string|array $version2 Data to compare. + * @param array $options User defined option values. * * @see Diff::$defaultOptions * @@ -116,7 +121,7 @@ public function __construct($version1, $version2, array $options = []) * 0 If the type is 'array' * 1 if the type is 'string' * - * @param mixed $var Variable to get type from. + * @param mixed $var Variable to get type from. * * @return int Number indicating the type of the variable. 0 for array type and 1 for string type. * @throws InvalidArgumentException When the type isn't 'array' or 'string'. @@ -137,7 +142,7 @@ public function getArgumentType($var): int /** * Set the options to be used by the sequence matcher, called by this class. * - * @param array $options User defined option names and values. + * @param array $options User defined option names and values. * * @see Diff::$defaultOptions * @@ -174,8 +179,8 @@ public function getVersion2(): array /** * Render a diff-view using a rendering class and get its results. * - * @param object|Context|Unified|UnifiedHtml|Inline|SideBySide $renderer An instance of the rendering object, - * used for generating the diff-view. + * @param object|Context|Unified|UnifiedHtml|Inline|SideBySide $renderer An instance of the rendering object, + * used for generating the diff-view. * * @return mixed The generated diff-view. The type of the return value depends on the applied renderer. */ @@ -196,10 +201,10 @@ public function render(object $renderer) * If the arguments for both parameters are omitted, the entire array will be returned. * If the argument for the second parameter is omitted, the element defined as start will be returned. * - * @param array $array The source array. - * @param int $start The first element of the range to get. - * @param int|null $end The last element of the range to get. - * If not supplied, only the element at start will be returned. + * @param array $array The source array. + * @param int $start The first element of the range to get. + * @param int|null $end The last element of the range to get. + * If not supplied, only the element at start will be returned. * * @return array Array containing all of the elements of the specified range. * @throws OutOfRangeException When the value of start or end are invalid to define a range. @@ -265,4 +270,25 @@ public function getGroupedOpCodes(): array return $this->groupedCodes; } + + /** + * Get the similarity ratio of the two sequences. + * + * Once calculated, the results are cached in the diff class instance. + * + * @param int $method Calculation method. + * + * @return float Similarity ratio. + */ + public function getSimilarity($method = Similarity::CALC_DEFAULT): float + { + if ($this->similarity !== null) { + return $this->similarity; + } + + $similarity = new Similarity($this->version1, $this->version2, $this->options); + $this->similarity = $similarity->getSimilarity($method); + + return $this->similarity; + } } diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 70bb7a58..b887cd83 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -11,33 +11,30 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools + * @package jblond\Diff + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2020 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff */ class SequenceMatcher { - /** - * @var string|array Either a string or an array containing a callback function to determine - * if a line is "junk" or not. - */ - private $junkCallback; - /** * @var array The first sequence to compare against. */ - private $old; - + protected $old; /** * @var array The second sequence. */ - private $new; - + protected $new; + /** + * @var string|array Either a string or an array containing a callback function to determine + * if a line is "junk" or not. + */ + private $junkCallback; /** * @var array Array of characters that are considered junk from the second sequence. Characters are the array key. */ @@ -67,11 +64,11 @@ class SequenceMatcher * @var array */ private $defaultOptions = [ - 'context' => 3, - 'trimEqual' => true, + 'context' => 3, + 'trimEqual' => true, 'ignoreWhitespace' => false, - 'ignoreCase' => false, - 'ignoreNewLines' => false, + 'ignoreCase' => false, + 'ignoreNewLines' => false, ]; /** @@ -79,23 +76,23 @@ class SequenceMatcher * sequence matcher and it will perform a basic cleanup & calculate junk * elements. * - * @param string|array $old A string or array containing the lines to compare against. - * @param string|array $new A string or array containing the lines to compare. - * @param array $options - * @param string|array|null $junkCallback Either an array or string that references a callback function - * (if there is one) to determine 'junk' characters. + * @param string|array $old A string or array containing the lines to compare against. + * @param string|array $new A string or array containing the lines to compare. + * @param array $options + * @param string|array|null $junkCallback Either an array or string that references a callback function + * (if there is one) to determine 'junk' characters. */ public function __construct($old, $new, array $options = [], $junkCallback = null) { - $this->old = []; - $this->new = []; + $this->old = []; + $this->new = []; $this->junkCallback = $junkCallback; $this->setOptions($options); $this->setSequences($old, $new); } /** - * @param array $options + * @param array $options */ public function setOptions(array $options) { @@ -106,55 +103,57 @@ public function setOptions(array $options) } /** - * Set the first and second sequences to use with the sequence matcher. + * Set the first and second sequence to use with the sequence matcher. * - * @param string|array $partA A string or array containing the lines to compare against. - * @param string|array $partB A string or array containing the lines to compare. + * @param string|array $version1 A string or array containing the lines to compare against. + * @param string|array $version2 A string or array containing the lines to compare. */ - public function setSequences($partA, $partB) + public function setSequences($version1, $version2) { - $this->setSeq1($partA); - $this->setSeq2($partB); + $this->setSeq1($version1); + $this->setSeq2($version2); } /** - * Set the first sequence ($partA) and reset any internal caches to indicate that - * when calling the calculation methods, we need to recalculate them. + * Set the first sequence. + * + * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. * - * @param string|array $partA The sequence to set as the first sequence. + * @param string|array $version1 The sequence to set as the first sequence. */ - public function setSeq1($partA) + public function setSeq1($version1) { - if (!is_array($partA)) { - $partA = str_split($partA); + if (!is_array($version1)) { + $version1 = str_split($version1); } - if ($partA == $this->old) { + if ($version1 == $this->old) { return; } - $this->old = $partA; + $this->old = $version1; $this->matchingBlocks = null; - $this->opCodes = null; + $this->opCodes = null; } /** - * Set the second sequence ($partB) and reset any internal caches to indicate that - * when calling the calculation methods, we need to recalculate them. + * Set the second sequence. * - * @param string|array $partB The sequence to set as the second sequence. + * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. + * + * @param string|array $version2 The sequence to set as the second sequence. */ - public function setSeq2($partB) + public function setSeq2($version2) { - if (!is_array($partB)) { - $partB = str_split($partB); + if (!is_array($version2)) { + $version2 = str_split($version2); } - if ($partB == $this->new) { + if ($version2 == $this->new) { return; } - $this->new = $partB; + $this->new = $version2; $this->matchingBlocks = null; - $this->opCodes = null; + $this->opCodes = null; $this->chainB(); } @@ -164,8 +163,8 @@ public function setSeq2($partB) */ private function chainB() { - $length = count($this->new); - $this->b2j = []; + $length = count($this->new); + $this->b2j = []; $popularDict = []; for ($i = 0; $i < $length; ++$i) { @@ -179,7 +178,7 @@ private function chainB() } } else { $this->b2j[$char] = [ - $i + $i, ]; } } @@ -208,146 +207,164 @@ private function chainB() } /** - * Checks if a particular character is in the junk dictionary - * for the list of junk characters. - * - * @param string $bString - * @return bool True if the character is considered junk. False if not. - */ - private function isBJunk(string $bString): bool - { - return isset($this->junkDict[$bString]); - } - - /** - * Find the longest matching block in the two sequences, as defined by the - * lower and upper constraints for each sequence. (for the first sequence, - * $alo - $ahi and for the second sequence, $blo - $bhi) - * - * Essentially, of all of the maximal matching blocks, return the one that - * starts earliest in $a, and all of those maximal matching blocks that - * start earliest in $a, return the one that starts earliest in $b. + * Return a series of nested arrays containing different groups of generated + * op codes for the differences between the strings with up to $this->options['context'] lines + * of surrounding content. * - * If the junk callback is defined, do the above but with the restriction - * that the junk element appears in the block. Extend it as far as possible - * by matching only junk elements in both $a and $b. + * Essentially what happens here is any big equal blocks of strings are stripped + * out, the smaller subsets of changes are then arranged in to their groups. + * This means that the sequence matcher and diffs do not need to include the full + * content of the different files but can still provide context as to where the + * changes are. * - * @param int $aLower The lower constraint for the first sequence. - * @param int $aUpper The upper constraint for the first sequence. - * @param int $bLower The lower constraint for the second sequence. - * @param int $bUpper The upper constraint for the second sequence. - * @return array Array containing the longest match that includes the starting position in $a, - * start in $b and the length/size. + * @return array Nested array of all of the grouped op codes. */ - public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUpper): array + public function getGroupedOpCodes(): array { - $old = $this->old; - $new = $this->new; - - $bestI = $aLower; - $bestJ = $bLower; - $bestSize = 0; - - $j2Len = []; - $nothing = []; - - for ($i = $aLower; $i < $aUpper; ++$i) { - $newJ2Len = []; - $jDict = $this->b2j[$old[$i]] ?? $nothing; - foreach ($jDict as $j) { - if ($j < $bLower) { - continue; - } elseif ($j >= $bUpper) { - break; - } + $opCodes = $this->getOpCodes(); + if (empty($opCodes)) { + $opCodes = [ + [ + 'equal', + 0, + 1, + 0, + 1, + ], + ]; + } - $k = ($j2Len[$j - 1] ?? 0) + 1; - $newJ2Len[$j] = $k; - if ($k > $bestSize) { - $bestI = $i - $k + 1; - $bestJ = $j - $k + 1; - $bestSize = $k; - } + if ($this->options['trimEqual']) { + if ($opCodes['0']['0'] == 'equal') { + // Remove sequences at the start of the text, but keep the context lines. + $opCodes['0'] = [ + $opCodes['0']['0'], + max($opCodes['0']['1'], $opCodes['0']['2'] - $this->options['context']), + $opCodes['0']['2'], + max($opCodes['0']['3'], $opCodes['0']['4'] - $this->options['context']), + $opCodes['0']['4'], + ]; } - $j2Len = $newJ2Len; + $lastItem = count($opCodes) - 1; + if ($opCodes[$lastItem]['0'] == 'equal') { + [$tag, $item1, $item2, $item3, $item4] = $opCodes[$lastItem]; + // Remove sequences at the end of the text, but keep the context lines. + $opCodes[$lastItem] = [ + $tag, + $item1, + min($item2, $item1 + $this->options['context']), + $item3, + min($item4, $item3 + $this->options['context']), + ]; + } } - while ( - $bestI > $aLower && - $bestJ > $bLower && - !$this->isBJunk($new[$bestJ - 1]) && - !$this->linesAreDifferent($bestI - 1, $bestJ - 1) - ) { - --$bestI; - --$bestJ; - ++$bestSize; - } + $maxRange = $this->options['context'] * 2; + $groups = []; + $group = []; - while ( - $bestI + $bestSize < $aUpper && - ($bestJ + $bestSize) < $bUpper && - !$this->isBJunk($new[$bestJ + $bestSize]) && - !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize) - ) { - ++$bestSize; - } + foreach ($opCodes as [$tag, $item1, $item2, $item3, $item4]) { + if ($tag == 'equal' && $item2 - $item1 > $maxRange) { + $group[] = [ + $tag, + $item1, + min($item2, $item1 + $this->options['context']), + $item3, + min($item4, $item3 + $this->options['context']), + ]; + $groups[] = $group; + $group = []; + $item1 = max($item1, $item2 - $this->options['context']); + $item3 = max($item3, $item4 - $this->options['context']); + } - while ( - $bestI > $aLower && - $bestJ > $bLower && - $this->isBJunk($new[$bestJ - 1]) && - !$this->linesAreDifferent($bestI - 1, $bestJ - 1) - ) { - --$bestI; - --$bestJ; - ++$bestSize; + $group[] = [ + $tag, + $item1, + $item2, + $item3, + $item4, + ]; } - while ( - $bestI + $bestSize < $aUpper && - $bestJ + $bestSize < $bUpper && - $this->isBJunk($new[$bestJ + $bestSize]) && - !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize) - ) { - ++$bestSize; + if (!$this->options['trimEqual'] || (!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal'))) { + // Add the last sequences when !trimEqual || When there are no differences between both versions. + $groups[] = $group; } - return [ - $bestI, - $bestJ, - $bestSize - ]; + return $groups; } /** - * Check if the two lines at the given indexes are different or not. + * Return a list of all of the op codes for the differences between the + * two strings. * - * @param int $aIndex Line number to check against in a. - * @param int $bIndex Line number to check against in b. - * @return bool True if the lines are different and false if not. + * The nested array returned contains an array describing the op code + * which includes: + * 0 - The type of tag (as described below) for the op code. + * 1 - The beginning line in the first sequence. + * 2 - The end line in the first sequence. + * 3 - The beginning line in the second sequence. + * 4 - The end line in the second sequence. + * + * The different types of tags include: + * replace - The string from $i1 to $i2 in $a should be replaced by + * the string in $b from $j1 to $j2. + * delete - The string in $a from $i1 to $j2 should be deleted. + * insert - The string in $b from $j1 to $j2 should be inserted at + * $i1 in $a. + * equal - The two strings with the specified ranges are equal. + * + * @return array Array of the opcodes describing the differences between the strings. */ - public function linesAreDifferent(int $aIndex, int $bIndex): bool + public function getOpCodes(): array { - $lineA = $this->old[$aIndex]; - $lineB = $this->new[$bIndex]; - - if ($this->options['ignoreWhitespace']) { - $replace = ["\t", ' ']; - $lineA = str_replace($replace, '', $lineA); - $lineB = str_replace($replace, '', $lineB); + if (!empty($this->opCodes)) { + //Return the cached results. + return $this->opCodes; } - if ($this->options['ignoreCase']) { - $lineA = strtolower($lineA); - $lineB = strtolower($lineB); - } + $i = 0; + $j = 0; + $this->opCodes = []; - if ($lineA != $lineB) { - return true; + $blocks = $this->getMatchingBlocks(); + foreach ($blocks as [$ai, $bj, $size]) { + $tag = ''; + if ($i < $ai && $j < $bj) { + $tag = 'replace'; + } elseif ($i < $ai) { + $tag = 'delete'; + } elseif ($j < $bj) { + $tag = 'insert'; + } + + if ($tag) { + $this->opCodes[] = [ + $tag, + $i, + $ai, + $j, + $bj, + ]; + } + + $i = $ai + $size; + $j = $bj + $size; + + if ($size) { + $this->opCodes[] = [ + 'equal', + $ai, + $i, + $bj, + $j, + ]; + } } - return false; + return $this->opCodes; } /** @@ -374,8 +391,8 @@ public function getMatchingBlocks(): array 0, $aLength, 0, - $bLength - ] + $bLength, + ], ]; $matchingBlocks = []; @@ -390,7 +407,7 @@ public function getMatchingBlocks(): array $aLower, $list1, $bLower, - $list2 + $list2, ]; } @@ -399,7 +416,7 @@ public function getMatchingBlocks(): array $list1 + $list3, $aUpper, $list2 + $list3, - $bUpper + $bUpper, ]; } } @@ -412,9 +429,9 @@ function ($aArray, $bArray) { } ); - $i1 = 0; - $j1 = 0; - $k1 = 0; + $i1 = 0; + $j1 = 0; + $k1 = 0; $nonAdjacent = []; foreach ($matchingBlocks as [$list4, $list5, $list6]) { if ($i1 + $k1 == $list4 && $j1 + $k1 == $list5) { @@ -424,7 +441,7 @@ function ($aArray, $bArray) { $nonAdjacent[] = [ $i1, $j1, - $k1 + $k1, ]; } @@ -438,177 +455,164 @@ function ($aArray, $bArray) { $nonAdjacent[] = [ $i1, $j1, - $k1 + $k1, ]; } $nonAdjacent[] = [ $aLength, $bLength, - 0 + 0, ]; $this->matchingBlocks = $nonAdjacent; + return $this->matchingBlocks; } /** - * Return a list of all of the op codes for the differences between the - * two strings. + * Find the longest matching block in the two sequences, as defined by the + * lower and upper constraints for each sequence. (for the first sequence, + * $alo - $ahi and for the second sequence, $blo - $bhi) * - * The nested array returned contains an array describing the op code - * which includes: - * 0 - The type of tag (as described below) for the op code. - * 1 - The beginning line in the first sequence. - * 2 - The end line in the first sequence. - * 3 - The beginning line in the second sequence. - * 4 - The end line in the second sequence. + * Essentially, of all of the maximal matching blocks, return the one that + * starts earliest in $a, and all of those maximal matching blocks that + * start earliest in $a, return the one that starts earliest in $b. * - * The different types of tags include: - * replace - The string from $i1 to $i2 in $a should be replaced by - * the string in $b from $j1 to $j2. - * delete - The string in $a from $i1 to $j2 should be deleted. - * insert - The string in $b from $j1 to $j2 should be inserted at - * $i1 in $a. - * equal - The two strings with the specified ranges are equal. + * If the junk callback is defined, do the above but with the restriction + * that the junk element appears in the block. Extend it as far as possible + * by matching only junk elements in both $a and $b. * - * @return array Array of the opcodes describing the differences between the strings. + * @param int $aLower The lower constraint for the first sequence. + * @param int $aUpper The upper constraint for the first sequence. + * @param int $bLower The lower constraint for the second sequence. + * @param int $bUpper The upper constraint for the second sequence. + * + * @return array Array containing the longest match that includes the starting position in $a, + * start in $b and the length/size. */ - public function getOpCodes(): array + public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUpper): array { - if (!empty($this->opCodes)) { - //Return the cached results. - return $this->opCodes; - } + $old = $this->old; + $new = $this->new; - $i = 0; - $j = 0; - $this->opCodes = []; + $bestI = $aLower; + $bestJ = $bLower; + $bestSize = 0; - $blocks = $this->getMatchingBlocks(); - foreach ($blocks as [$ai, $bj, $size]) { - $tag = ''; - if ($i < $ai && $j < $bj) { - $tag = 'replace'; - } elseif ($i < $ai) { - $tag = 'delete'; - } elseif ($j < $bj) { - $tag = 'insert'; - } + $j2Len = []; + $nothing = []; - if ($tag) { - $this->opCodes[] = [ - $tag, - $i, - $ai, - $j, - $bj - ]; + for ($i = $aLower; $i < $aUpper; ++$i) { + $newJ2Len = []; + $jDict = $this->b2j[$old[$i]] ?? $nothing; + foreach ($jDict as $j) { + if ($j < $bLower) { + continue; + } elseif ($j >= $bUpper) { + break; + } + + $k = ($j2Len[$j - 1] ?? 0) + 1; + $newJ2Len[$j] = $k; + if ($k > $bestSize) { + $bestI = $i - $k + 1; + $bestJ = $j - $k + 1; + $bestSize = $k; + } } - $i = $ai + $size; - $j = $bj + $size; + $j2Len = $newJ2Len; + } - if ($size) { - $this->opCodes[] = [ - 'equal', - $ai, - $i, - $bj, - $j - ]; - } + while ( + $bestI > $aLower && + $bestJ > $bLower && + !$this->isBJunk($new[$bestJ - 1]) && + !$this->linesAreDifferent($bestI - 1, $bestJ - 1) + ) { + --$bestI; + --$bestJ; + ++$bestSize; } - return $this->opCodes; + + while ( + $bestI + $bestSize < $aUpper && + ($bestJ + $bestSize) < $bUpper && + !$this->isBJunk($new[$bestJ + $bestSize]) && + !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize) + ) { + ++$bestSize; + } + + while ( + $bestI > $aLower && + $bestJ > $bLower && + $this->isBJunk($new[$bestJ - 1]) && + !$this->linesAreDifferent($bestI - 1, $bestJ - 1) + ) { + --$bestI; + --$bestJ; + ++$bestSize; + } + + while ( + $bestI + $bestSize < $aUpper && + $bestJ + $bestSize < $bUpper && + $this->isBJunk($new[$bestJ + $bestSize]) && + !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize) + ) { + ++$bestSize; + } + + return [ + $bestI, + $bestJ, + $bestSize, + ]; } /** - * Return a series of nested arrays containing different groups of generated - * op codes for the differences between the strings with up to $this->options['context'] lines - * of surrounding content. + * Checks if a particular character is in the junk dictionary + * for the list of junk characters. * - * Essentially what happens here is any big equal blocks of strings are stripped - * out, the smaller subsets of changes are then arranged in to their groups. - * This means that the sequence matcher and diffs do not need to include the full - * content of the different files but can still provide context as to where the - * changes are. + * @param string $bString * - * @return array Nested array of all of the grouped op codes. + * @return bool True if the character is considered junk. False if not. */ - public function getGroupedOpCodes(): array + private function isBJunk(string $bString): bool { - $opCodes = $this->getOpCodes(); - if (empty($opCodes)) { - $opCodes = [ - [ - 'equal', - 0, - 1, - 0, - 1 - ] - ]; - } + return isset($this->junkDict[$bString]); + } - if ($this->options['trimEqual']) { - if ($opCodes['0']['0'] == 'equal') { - // Remove sequences at the start of the text, but keep the context lines. - $opCodes['0'] = [ - $opCodes['0']['0'], - max($opCodes['0']['1'], $opCodes['0']['2'] - $this->options['context']), - $opCodes['0']['2'], - max($opCodes['0']['3'], $opCodes['0']['4'] - $this->options['context']), - $opCodes['0']['4'] - ]; - } + /** + * Check if the two lines at the given indexes are different or not. + * + * @param int $aIndex Line number to check against in a. + * @param int $bIndex Line number to check against in b. + * + * @return bool True if the lines are different and false if not. + */ + public function linesAreDifferent(int $aIndex, int $bIndex): bool + { + $lineA = $this->old[$aIndex]; + $lineB = $this->new[$bIndex]; - $lastItem = count($opCodes) - 1; - if ($opCodes[$lastItem]['0'] == 'equal') { - [$tag, $item1, $item2, $item3, $item4] = $opCodes[$lastItem]; - // Remove sequences at the end of the text, but keep the context lines. - $opCodes[$lastItem] = [ - $tag, - $item1, - min($item2, $item1 + $this->options['context']), - $item3, - min($item4, $item3 + $this->options['context']) - ]; - } + if ($this->options['ignoreWhitespace']) { + $replace = ["\t", ' ']; + $lineA = str_replace($replace, '', $lineA); + $lineB = str_replace($replace, '', $lineB); } - $maxRange = $this->options['context'] * 2; - $groups = []; - $group = []; - - foreach ($opCodes as [$tag, $item1, $item2, $item3, $item4]) { - if ($tag == 'equal' && $item2 - $item1 > $maxRange) { - $group[] = [ - $tag, - $item1, - min($item2, $item1 + $this->options['context']), - $item3, - min($item4, $item3 + $this->options['context']) - ]; - $groups[] = $group; - $group = []; - $item1 = max($item1, $item2 - $this->options['context']); - $item3 = max($item3, $item4 - $this->options['context']); - } - - $group[] = [ - $tag, - $item1, - $item2, - $item3, - $item4 - ]; + if ($this->options['ignoreCase']) { + $lineA = strtolower($lineA); + $lineB = strtolower($lineB); } - if (!$this->options['trimEqual'] || (!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal'))) { - // Add the last sequences when !trimEqual || When there are no differences between both versions. - $groups[] = $group; + if ($lineA != $lineB) { + return true; } - return $groups; + return false; } } diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php new file mode 100644 index 00000000..6852d3bb --- /dev/null +++ b/lib/jblond/Diff/Similarity.php @@ -0,0 +1,165 @@ + + * @author Mario Brandt + * @author Ferry Cools + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff + */ +class Similarity extends SequenceMatcher +{ + /** + * Default method for calculation similarity ratio. + */ + public const CALC_DEFAULT = 0; + /** + * Fast method for calculation similarity ratio. + */ + public const CALC_FAST = 1; + /** + * Fastest method for calculation similarity ratio. + */ + public const CALC_FASTEST = 2; + /** + * @var array Count of each unique sequence at version 2. + */ + private $uniqueCount2; + + + /** + * @inheritDoc + */ + public function setSeq2($version2) + { + $this->uniqueCount2 = null; + parent::setSeq2($version2); + } + + /** + * Return a measure of similarity between the two sequences. + * + * This will be a float value between 0 and 1. + * + * Tree calculation methods are available: + * self::CALC_DEFAULT: Default method. + * self::CALC_FAST: Faster calculation. Less cpu load & less accurate than above. + * self::CALC_FASTEST: Fastest calculation. Less cpu load & less accurate than above. + * + * @param int $type Calculation method. + * + * @return float The calculated ratio. + */ + public function getSimilarity(int $type = self::CALC_DEFAULT): float + { + switch ($type) { + case self::CALC_FAST: + return $this->getRatioFast(); + case self::CALC_FASTEST: + return $this->getRatioFastest(); + default: + $matches = array_reduce($this->getMatchingBlocks(), [$this, 'ratioReduce'], 0); + + return $this->calculateRatio($matches, count($this->old) + count($this->new)); + } + } + + /** + * Quickly return an upper bound ratio for the similarity of the strings. + * + * This is quicker to compute than self::CALC_DEFAULT. + * + * @return float The calculated ratio. + */ + private function getRatioFast(): float + { + if ($this->uniqueCount2 === null) { + $this->uniqueCount2 = []; + $bLength = count($this->new); + for ($iterator = 0; $iterator < $bLength; ++$iterator) { + $char = $this->new[$iterator]; + $this->uniqueCount2[$char] = ($this->uniqueCount2[$char] ?? 0) + 1; + } + } + + $avail = []; + $matches = 0; + $aLength = count($this->old); + for ($iterator = 0; $iterator < $aLength; ++$iterator) { + $char = $this->old[$iterator]; + if (isset($avail[$char])) { + $numb = $avail[$char]; + } else { + $numb = $this->uniqueCount2[$char] ?? 0; + } + $avail[$char] = $numb - 1; + if ($numb > 0) { + ++$matches; + } + } + + return $this->calculateRatio($matches, count($this->old) + count($this->new)); + } + + /** + * Helper function for calculating the ratio to measure similarity for the strings. + * + * The ratio is defined as being 2 * (number of matches / total length) + * + * @param int $matches The number of matches in the two strings. + * @param int $length The length of the two sequences. + * + * @return float The calculated ratio. + */ + private function calculateRatio(int $matches, int $length = 0): float + { + $returnValue = 1; + if ($length) { + return 2 * ($matches / $length); + } + + return $returnValue; + } + + /** + * Return an upper bound ratio really quickly for the similarity of the strings. + * + * This is quicker to compute than self::CALC_DEFAULT and self::CALC_FAST. + * + * @return float The calculated ratio. + */ + private function getRatioFastest(): float + { + $aLength = count($this->old); + $bLength = count($this->new); + + return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength); + } + + + /** + * Helper function to calculate the number of matches for Ratio(). + * + * @param int $sum The running total for the number of matches. + * @param array $triple Array containing the matching block triple to add to the running total. + * + * @return int The new running total for the number of matches. + */ + private function ratioReduce(int $sum, array $triple): int + { + return $sum + ($triple[count($triple) - 1]); + } +} diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php new file mode 100644 index 00000000..a1be7649 --- /dev/null +++ b/tests/Diff/SimilarityTest.php @@ -0,0 +1,19 @@ +assertEquals(2 / 3, $similarity->getSimilarity(Similarity::CALC_DEFAULT)); + $this->assertEquals(2 / 3, $similarity->getSimilarity(Similarity::CALC_FAST)); + $this->assertEquals(2 / 3, $similarity->getSimilarity(Similarity::CALC_FASTEST)); + } +} From a4e505809bfb7694597958b761d9c5fb6ba7772e Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 19 Nov 2020 14:08:35 +0100 Subject: [PATCH 092/206] Update Changelog Increase version number --- changelog.md | 5 ++++- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Inline.php | 2 +- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- lib/jblond/Diff/Similarity.php | 2 +- tests/Diff/Renderer/Html/HtmlRenderersTest.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- tests/Diff/Renderer/Text/TextRenderersTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- 20 files changed, 23 insertions(+), 20 deletions(-) diff --git a/changelog.md b/changelog.md index 7210c0b8..6c91fca7 100644 --- a/changelog.md +++ b/changelog.md @@ -1,12 +1,15 @@ # changelog -## next +## 2.3.0 - Add: Change log. - Fix: Html SideBySide renders equal lines of version 1 at both sides (Option ignoreCase). - Fix: Second parameter of string repeat function minimizes to 0. - Fix: #60 - Unified Cli renderer options incompatible with Main renderer options - Fix: #64 - Calculation of maxLineMarkerWidth independent of input format. +- Add: Similarity calculation +- Add: New marking levels for inline differences +- Add: Html merged renderer ## 2.2.1 (2020-08-06) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 2b84157f..c88286a8 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -28,7 +28,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 2937456d..8372b51c 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -10,7 +10,7 @@ * @package jblond\Diff * @author Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 93e351df..82582aa2 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class Inline extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 22e613d1..87771a27 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class Merged extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index b442706b..0ad5123a 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 9d6225aa..914aaf24 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class Unified extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index b936b6d3..3c56310f 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class MainRenderer extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index febcc4b9..b8204460 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index dbf6465d..abd2b669 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -13,7 +13,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 5e616db5..6beb9e2f 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 42684280..dc4b9692 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index dec25b84..a8d89037 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index eb19a221..8e83f9b4 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -15,7 +15,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index b887cd83..c81d7bd3 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 6852d3bb..0dc1dd47 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class Similarity extends SequenceMatcher diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 50e3edf8..b3f879b0 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -21,7 +21,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class HtmlRenderersTest extends TestCase diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 285e7f51..2771417e 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -22,7 +22,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index c8faa7f8..969486e2 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2019 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class TextRenderersTest extends TestCase diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 35dcdc95..1cf1d042 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ From c64c0ccb572f725b6ab126c7ea58e4aee997b971 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 19 Nov 2020 14:09:35 +0100 Subject: [PATCH 093/206] add date --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 6c91fca7..3408adf8 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,6 @@ # changelog -## 2.3.0 +## 2.3.0 (2020-11-19) - Add: Change log. - Fix: Html SideBySide renders equal lines of version 1 at both sides (Option ignoreCase). From 11ec623eff7d2394d4771ce270914239ba8c1d1e Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 17 Nov 2020 10:57:53 +0100 Subject: [PATCH 094/206] Fix html syntax error Html Unified renderer causes following error when rendering skipped lines: Element div not allowed as child of element span in this context. --- example/dark-theme.css | 1 + example/styles.css | 1 + lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- tests/resources/htmlUnified.txt | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index c6ee4c64..8bd57baf 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -53,6 +53,7 @@ a, a:visited { .Differences .Skipped { background: #F7F7F7; color: #000000; + display: block; } .Differences ins, diff --git a/example/styles.css b/example/styles.css index fb6eaca9..305c9e02 100644 --- a/example/styles.css +++ b/example/styles.css @@ -47,6 +47,7 @@ pre { .Differences .Skipped { background: #F7F7F7; + display: block; } /* diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 914aaf24..e01932a5 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -82,7 +82,7 @@ public function generateDiffHeader(): string */ public function generateSkippedLines(): string { - return '
'; + return ''; } diff --git a/tests/resources/htmlUnified.txt b/tests/resources/htmlUnified.txt index fc1adeeb..8827106e 100644 --- a/tests/resources/htmlUnified.txt +++ b/tests/resources/htmlUnified.txt @@ -1 +1 @@ -<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>this line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file +<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>this line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file From 8e9735ffc010720eb93ec02769e5bf05cb13523c Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:42:21 +0100 Subject: [PATCH 095/206] Reformat library code --- README.md | 28 +++-- changelog.md | 103 ++++++++++-------- example/example.php | 5 +- example/styles.css | 2 +- lib/jblond/Diff/DiffUtils.php | 17 +-- lib/jblond/Diff/Renderer/Text/Context.php | 18 +-- lib/jblond/Diff/Renderer/Text/Unified.php | 23 ++-- .../Diff/Renderer/Html/HtmlRenderersTest.php | 10 +- .../Diff/Renderer/Text/TextRenderersTest.php | 22 ++-- 9 files changed, 130 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index 778ded8d..9fd6125e 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,9 @@ ## Introduction -A comprehensive library for generating differences between two hashable objects (strings or arrays). -Generated differences can be rendered in all the standard formats including: +A comprehensive library for generating differences between two hashable +objects (strings or arrays). Generated differences can be rendered in all the +standard formats including: * Unified * Context @@ -16,8 +17,9 @@ Generated differences can be rendered in all the standard formats including: * Unified HTML * Unified Commandline colored output -The logic behind the core of the diff engine (ie, the sequence matcher) is primarily based on the Python difflib -package. The reason for doing so is primarily because of its high degree of accuracy. +The logic behind the core of the diff engine (ie, the sequence matcher) is +primarily based on the Python difflib package. The reason for doing so is +primarily because of its high degree of accuracy. ## Install @@ -31,7 +33,7 @@ For cli usage you need to install the suggested `jblond/php-cli` package. ## Documentation -See the [Wiki](https://github.com/JBlond/php-diff/wiki) for +See the [Wiki](https://github.com/JBlond/php-diff/wiki) for * [Getting started](https://github.com/JBlond/php-diff/wiki/1.-Getting-Started) * [Parameters and Options](https://github.com/JBlond/php-diff/wiki/2.-Parameters-and-Options) @@ -82,8 +84,9 @@ echo $diff->isIdentical() ? 'No differences found.' : '
' . htmlspecialchars
 ```
 
 ### Example Output
-File `example.php` contains a quick demo and can be found in the `example/` directory.
-Included is a light and a dark theme.
+
+File `example.php` contains a quick demo and can be found in the `example/`
+directory. Included is a light and a dark theme.
 
 #### HTML Side By Side Example
 
@@ -115,7 +118,6 @@ Included is a light and a dark theme.
 
 
HTML Side By Side Dark Theme Example
- ![HTML Side By Side Dark Theme Example](assets/htmlSidebySideDarkTheme.png "HTML Side By Side Dark Theme Example")
@@ -128,16 +130,18 @@ Included is a light and a dark theme. ## Contribution, Issues and feature requests -If you found a bug, or have an idea for new functionality, -feel free to report it on the issue tracker - just use search beforehand. +If you found a bug, or have an idea for new functionality, feel free to report +it on the issue tracker - just use search beforehand. [Issue tracker](https://github.com/JBlond/php-diff/issues) You can also fork this repository and open a PR. ## Merge files using jQuery -Xiphe has build a jQuery plugin with that you can merge the compared files. -Have a look at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge-for-php-diff). +Xiphe has build a jQuery plugin with that you can merge the compared files. Have +a look +at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge-for-php-diff) +. ## Todo diff --git a/changelog.md b/changelog.md index 3408adf8..b2c3fcde 100644 --- a/changelog.md +++ b/changelog.md @@ -2,120 +2,133 @@ ## 2.3.0 (2020-11-19) -- Add: Change log. -- Fix: Html SideBySide renders equal lines of version 1 at both sides (Option ignoreCase). -- Fix: Second parameter of string repeat function minimizes to 0. -- Fix: #60 - Unified Cli renderer options incompatible with Main renderer options -- Fix: #64 - Calculation of maxLineMarkerWidth independent of input format. -- Add: Similarity calculation -- Add: New marking levels for inline differences -- Add: Html merged renderer +* Add: Change log. + +* Fix: Html SideBySide renders equal lines of version 1 at both sides (Option + ignoreCase). + +* Fix: Second parameter of string repeat function minimizes to 0. + +* Fix: #60 - Unified Cli renderer options incompatible with Main renderer + options + +* Fix: #64 - Calculation of maxLineMarkerWidth independent of input format. + +* Add: Similarity calculation + +* Add: New marking levels for inline differences + +* Add: Html merged renderer ## 2.2.1 (2020-08-06) -- Fix: #58 - Side by side diff shows empty diff +* Fix: #58 - Side by side diff shows empty diff ## 2.2.0 (2020-07-23) -- Add: Option for a custom override renderer. #53 -- Add: No output when there are no differences between the compared strings / files. #52 #54 +* Add: Option for a custom override renderer. #53 + +* Add: No output when there are no differences between the compared strings / + files. #52 #54 ## 2.1.1 (2020-07-17) -- Fix: #50 - Renderers produce output with equal texts, while they shouldn't. +* Fix: #50 - Renderers produce output with equal texts, while they shouldn't. ## 2.1.0 (2020-07-13) -- Add: Cli uncolored output. This allows it to be piped. +* Add: Cli uncolored output. This allows it to be piped. ## 2.0.0 (2020-07-09) -- Add: Unified Commandline colored output. -- Change: switch to semantic versioning. +* Add: Unified Commandline colored output. +* Change: switch to semantic versioning. ## 1.18 (2020-07-01) -- Add: A dark theme to the example. -- Fix: Avoid variables with short names (some). +* Add: A dark theme to the example. +* Fix: Avoid variables with short names (some). ## 1.17 (2020-06-08) -- Fix #32 - Side by side diff shows only partially all deleted lines. +* Fix #32 - Side by side diff shows only partially all deleted lines. ## 1.16 (2020-03-02) -- Features - - Add: option trimEqual. +* Features + * Add: option trimEqual. -- Fixes - - Fix PHPMD Violation. - - Code Optimization, cleanup, refactoring and commenting. +* Fixes + * Fix PHPMD Violation. + * Code Optimization, cleanup, refactoring and commenting. ## 1.15 (2020-01-24) -- Add: New Unified HTML. -- Fix: Code clean up. +* Add: New Unified HTML. +* Fix: Code clean up. ## 1.14 (2019-12-03) -- Fix: Remove some old dead code. +* Fix: Remove some old dead code. ## 1.13 (2019-10-08) -- Change: Switch to PSR12. +* Change: Switch to PSR12. ## 1.12 (2019-03-18) -- Change: Update Composer Configuration. -- Fix: PSR-2 conventions. +* Change: Update Composer Configuration. +* Fix: PSR-2 conventions. ## 1.11 (2019-02-22) -- Fix: Code clean up. -- Fix: Composer autoloader for unit tests. +* Fix: Code clean up. +* Fix: Composer autoloader for unit tests. ## 1.10 (2019-02-20) -- Fix: Code clean up. +* Fix: Code clean up. ## 1.9 (2019-02-19) -- Fix: Code clean up. +* Fix: Code clean up. ## 1.8 -- Change: Update Readme and bumping versions. -- Fix: Moved include of Autoloader from the constructor to global space for HtmlArray unit test. +* Change: Update Readme and bumping versions. + +* Fix: Moved include of Autoloader from the constructor to global space for + HtmlArray unit test. ## 1.7 -- Fix: PSR-2 code alignment. +* Fix: PSR-2 code alignment. ## 1.6 -- Change: Bump required version of PHP to v7.1. -- Add: Return type hinting. +* Change: Bump required version of PHP to v7.1. +* Add: Return type hinting. ## 1.5 (2019-01-15) -- Fix: Autoloader naming issues. +* Fix: Autoloader naming issues. ## 1.4 (2019-01-14) -- Add: PSR-4 namespace support. +* Add: PSR-4 namespace support. ## 1.3 (2019-01-11) -- Fix: PHP methods contained too much logic. That has been simplified. +* Fix: PHP methods contained too much logic. That has been simplified. ## 1.2 (2018-01-23) -- Add: Support for custom titles. +* Add: Support for custom titles. ## 1.1 (2017-05-06) -- Fix: Wrong highlight area for chinese characters. +* Fix: Wrong highlight area for chinese characters. -## 1.0 +## 1.0 -- Initial version. +* Initial version. diff --git a/example/example.php b/example/example.php index 9ac8f600..fd8861e5 100644 --- a/example/example.php +++ b/example/example.php @@ -70,7 +70,10 @@ function changeCSS(cssFile, cssLinkIndex) {

diff --git a/example/styles.css b/example/styles.css index 305c9e02..b77b6596 100644 --- a/example/styles.css +++ b/example/styles.css @@ -47,7 +47,7 @@ pre { .Differences .Skipped { background: #F7F7F7; - display: block; + display: block; } /* diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 8372b51c..aa4c99ab 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -7,19 +7,21 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff - * @author Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff + * @package jblond\Diff + * @author Mario Brandt + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff */ class DiffUtils { /** * Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks * - * @param array $aArray First array to compare. - * @param array $bArray Second array to compare. + * @param array $aArray First array to compare. + * @param array $bArray Second array to compare. + * * @return int -1, 0 or 1, as expected by the usort function. */ public static function tupleSort(array $aArray, array $bArray): int @@ -39,6 +41,7 @@ public static function tupleSort(array $aArray, array $bArray): int if (count($aArray) < count($bArray)) { return -1; } + return 1; } } diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 6beb9e2f..7b50dc33 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -11,14 +11,14 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Chris Boulton - * @author Mario Brandt - * @author Ferry Cools + * @package jblond\Diff\Renderer\Text + * @author Chris Boulton + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract { @@ -99,8 +99,8 @@ public function render() * * Given an array of groups, all groups which don't have the specified tag are returned. * - * @param array $groups A series of opCode groups. - * @param string $excludedTag Name of the opCode Tag to filter out. + * @param array $groups A series of opCode groups. + * @param string $excludedTag Name of the opCode Tag to filter out. * * @return array Filtered opCode Groups. */ diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index a8d89037..c5570cf0 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -11,13 +11,13 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Text - * @author Chris Boulton - * @author Mario Brandt + * @package jblond\Diff\Renderer\Text + * @author Chris Boulton + * @author Mario Brandt * @copyright (c) 2020 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff */ /** @@ -32,14 +32,14 @@ class Unified extends MainRendererAbstract */ public function render() { - $diff = false; + $diff = false; $opCodes = $this->diff->getGroupedOpCodes(); foreach ($opCodes as $group) { $lastItem = count($group) - 1; - $i1 = $group['0']['1']; - $i2 = $group[$lastItem]['2']; - $j1 = $group['0']['3']; - $j2 = $group[$lastItem]['4']; + $i1 = $group['0']['1']; + $i2 = $group[$lastItem]['2']; + $j1 = $group['0']['3']; + $j2 = $group[$lastItem]['4']; if ($i1 == 0 && $i2 == 0) { $i1 = -1; @@ -72,6 +72,7 @@ public function render() } } } + return $diff; } } diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index b3f879b0..5106d9ce 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -34,9 +34,9 @@ class HtmlRenderersTest extends TestCase /** * Constructor. * - * @param null $name - * @param array $data - * @param string $dataName + * @param null $name + * @param array $data + * @param string $dataName */ public function __construct($name = null, array $data = [], $dataName = '') { @@ -46,6 +46,7 @@ public function __construct($name = null, array $data = [], $dataName = '') /** * Test the output of the HTML Side by Side renderer. + * * @covers \jblond\Diff\Renderer\Html\SideBySide */ public function testSideBySide() @@ -66,6 +67,7 @@ public function testSideBySide() /** * Test the output of the HTML Inline renderer. + * * @covers \jblond\Diff\Renderer\Html\Inline */ public function testInline() @@ -92,6 +94,7 @@ public function testInline() /** * Test the output of the HTML Unified renderer. + * * @covers \jblond\Diff\Renderer\Html\Merged */ public function testMerged() @@ -112,6 +115,7 @@ public function testMerged() /** * Test the output of the HTML Unified renderer. + * * @covers \jblond\Diff\Renderer\Html\Unified */ public function testUnified() diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 969486e2..6c852ca6 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -14,13 +14,13 @@ * * PHPUnit tests to verify that the output of the text renderers did not change due to code changes. * - * @package Tests\Diff\Renderer\Text - * @author Mario Brandt - * @author Ferry Cools + * @package Tests\Diff\Renderer\Text + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2019 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff */ class TextRenderersTest extends TestCase { @@ -32,9 +32,9 @@ class TextRenderersTest extends TestCase /** * TextRenderersTest constructor. * - * @param null $name - * @param array $data - * @param string $dataName + * @param null $name + * @param array $data + * @param string $dataName */ public function __construct($name = null, array $data = [], $dataName = '') { @@ -44,6 +44,7 @@ public function __construct($name = null, array $data = [], $dataName = '') /** * Test the output of the text-context renderer. + * * @covers \jblond\Diff\Renderer\Text\Context */ public function testContext() @@ -64,6 +65,7 @@ public function testContext() /** * Test the output of the text-unified renderer. + * * @covers \jblond\Diff\Renderer\Text\Unified */ public function testUnified() @@ -84,6 +86,7 @@ public function testUnified() /** * Test the output of the CLI text-context renderer. + * * @covers \jblond\Diff\Renderer\Text\UnifiedCli */ public function testUnifiedCli() @@ -103,6 +106,7 @@ public function testUnifiedCli() /** * Test the output of the CLI text-inline renderer. + * * @covers \jblond\Diff\Renderer\Text\InlineCli */ public function testInlineCli() From 3bc08395e388ba2d720976518d769f4072db2b60 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:49:16 +0100 Subject: [PATCH 096/206] Fix property visibility and method docBlocks * Visibility of protected properties set to private where possible. * Replaced method docBlock descriptions with inheritance. --- lib/jblond/Diff/Renderer/Html/Inline.php | 37 +++++--------- lib/jblond/Diff/Renderer/Html/Merged.php | 24 +++++++-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 45 ++++++---------- lib/jblond/Diff/Renderer/Html/Unified.php | 54 ++++++++------------ lib/jblond/Diff/Renderer/Text/InlineCli.php | 40 +++++---------- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 53 ++++++++++--------- 6 files changed, 111 insertions(+), 142 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Inline.php index 82582aa2..7bb811af 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Inline.php @@ -32,7 +32,7 @@ class Inline extends MainRenderer implements SubRendererInterface * - title1 Title of the 1st version of text. * - title2 Title of the 2nd version of text. */ - protected $subOptions = [ + private $subOptions = [ 'format' => 'html', 'insertMarkers' => ['', ''], 'deleteMarkers' => ['', ''], @@ -43,7 +43,7 @@ class Inline extends MainRenderer implements SubRendererInterface /** * Inline constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the inline diff renderer. * * @see Inline::$subOptions */ @@ -54,7 +54,7 @@ public function __construct(array $options = []) } /** - * Render and return a diff-view with changes between the two sequences displayed inline (under each other). + * @inheritDoc * * @return string|false The generated diff-view or false when there's no difference. */ @@ -66,8 +66,7 @@ public function render() } /** - * Generates a string representation of the opening of a table and its header with titles from the sub renderer's - * options. + * @inheritDoc * * @return string HTML code representation of a table's header. */ @@ -86,7 +85,7 @@ public function generateDiffHeader(): string } /** - * Generates a string representation of table rows with lines that are skipped. + * @inheritDoc * * @return string HTML code representation of skipped lines. */ @@ -102,9 +101,7 @@ public function generateSkippedLines(): string } /** - * Generate a string representation of table rows with lines without differences between both versions. - * - * @param array $changes Contains the op-codes about the changes between two blocks. + * @inheritDoc * * @return string HTML code representing table rows showing text without differences. */ @@ -129,9 +126,7 @@ public function generateLinesEqual(array $changes): string } /** - * Generates a string representation of table rows with lines that are added to the 2nd version. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string HTML code representing table rows showing with added text. */ @@ -158,9 +153,7 @@ public function generateLinesInsert(array $changes): string } /** - * Generates a string representation of table rows with lines that are removed from the 2nd version. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string HTML code representing table rows showing removed text. */ @@ -187,9 +180,7 @@ public function generateLinesDelete(array $changes): string } /** - * Generates a string representation of table rows with lines that are partially modified. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Html code representing table rows showing modified text. */ @@ -229,9 +220,7 @@ public function generateLinesReplace(array $changes): string } /** - * Generate a string representation of the start of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Start of the block. */ @@ -241,9 +230,7 @@ public function generateBlockHeader(array $changes): string } /** - * Generate a string representation of the end of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string End of the block. */ @@ -253,7 +240,7 @@ public function generateBlockFooter(array $changes): string } /** - * Generate a string representation of the end of a diff view. + * @inheritDoc * * @return string End of the diff view. */ diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 87771a27..b96eb630 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -28,7 +28,7 @@ class Merged extends MainRenderer implements SubRendererInterface * - title1 Title of the 1st version of text. * - title2 Title of the 2nd version of text. */ - protected $subOptions = [ + private $subOptions = [ 'format' => 'html', 'insertMarkers' => ['', ''], 'deleteMarkers' => ['', ''], @@ -38,11 +38,11 @@ class Merged extends MainRenderer implements SubRendererInterface /** * @var int Line offset to keep correct line number for merged diff. */ - protected $lineOffset = 0; + private $lineOffset = 0; /** * @var string last block of lines which where removed from version 2. */ - protected $lastDeleted; + private $lastDeleted; /** * Merged constructor. @@ -69,6 +69,8 @@ public function render() /** * @inheritDoc + * + * @return string Start of the diff view. */ public function generateDiffHeader(): string { @@ -84,6 +86,8 @@ public function generateDiffHeader(): string /** * @inheritDoc + * + * @return string Start of the block. */ public function generateBlockHeader(array $changes): string { @@ -92,6 +96,8 @@ public function generateBlockHeader(array $changes): string /** * @inheritDoc + * + * @return string Representation of skipped lines. */ public function generateSkippedLines(): string { @@ -114,6 +120,8 @@ public function generateSkippedLines(): string /** * @inheritDoc + * + * @return string Text with no difference. */ public function generateLinesEqual(array $changes): string { @@ -140,6 +148,8 @@ public function generateLinesEqual(array $changes): string /** * @inheritDoc + * + * @return string Added text. */ public function generateLinesInsert(array $changes): string { @@ -168,6 +178,8 @@ public function generateLinesInsert(array $changes): string /** * @inheritDoc + * + * @return string Removed text. */ public function generateLinesDelete(array $changes): string { @@ -191,6 +203,8 @@ public function generateLinesDelete(array $changes): string /** * @inheritDoc + * + * @return string Modified text. */ public function generateLinesReplace(array $changes): string { @@ -234,6 +248,8 @@ function ($removedParts) use ($addedParts) { /** * @inheritDoc + * + * @return string End of the block. */ public function generateBlockFooter(array $changes): string { @@ -242,6 +258,8 @@ public function generateBlockFooter(array $changes): string /** * @inheritDoc + * + * @return string End of the diff view. */ public function generateDiffFooter(): string { diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 0ad5123a..5e4aad6e 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -32,7 +32,7 @@ class SideBySide extends MainRenderer implements SubRendererInterface * - title1 Title of the 1st version of text. * - title2 Title of the 2nd version of text. */ - protected $subOptions = [ + private $subOptions = [ 'format' => 'html', 'insertMarkers' => ['', ''], 'deleteMarkers' => ['', ''], @@ -54,7 +54,7 @@ public function __construct(array $options = []) } /** - * Render a and return diff-view with changes between the two sequences displayed side by side. + * @inheritDoc * * @return string|false The generated diff-view or false when there's no difference. */ @@ -66,7 +66,7 @@ public function render() } /** - * Generates a string representation of the opening of a predefined table and its header with titles from options. + * @inheritDoc * * @return string HTML code representation of a table's header. */ @@ -84,7 +84,7 @@ public function generateDiffHeader(): string } /** - * Generates a string representation of table rows with lines that are skipped. + * @inheritDoc * * @return string HTML code representation of a table's header. */ @@ -101,12 +101,7 @@ public function generateSkippedLines(): string } /** - * Generate a string representation of table rows with lines without differences between both versions. - * - * Note: Depending on the options, lines can be marked as being equal, while the contents actually differ. - * (E.g. ignoreWhitespace and ignoreCase) - * - * @param array $changes Contains the op-codes about the changes between two blocks. + * @inheritDoc * * @return string HTML code representing table rows showing text with no difference. */ @@ -136,9 +131,7 @@ public function generateLinesEqual(array $changes): string } /** - * Generates a string representation of table rows with lines that are added to the 2nd version. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string HTML code representing table rows showing with added text. */ @@ -165,9 +158,7 @@ public function generateLinesInsert(array $changes): string } /** - * Generates a string representation of table rows with lines that are removed from the 2nd version. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string HTML code representing table rows showing removed text. */ @@ -194,9 +185,7 @@ public function generateLinesDelete(array $changes): string } /** - * Generates a string representation of table rows with lines that are partially modified. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Html code representing table rows showing modified text. */ @@ -208,8 +197,8 @@ public function generateLinesReplace(array $changes): string if (count($changes['base']['lines']) >= count($changes['changed']['lines'])) { foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1; - $toLine = " "; - $changedLine = " "; + $toLine = ' '; + $changedLine = ' '; if (isset($changes['changed']['lines'][$lineNo])) { $toLine = $changes['changed']['offset'] + $lineNo + 1; $changedLine = $changes['changed']['lines'][$lineNo]; @@ -237,8 +226,8 @@ public function generateLinesReplace(array $changes): string foreach ($changes['changed']['lines'] as $lineNo => $changedLine) { $toLine = $changes['changed']['offset'] + $lineNo + 1; - $fromLine = " "; - $line = " "; + $fromLine = ' '; + $line = ' '; if (isset($changes['base']['lines'][$lineNo])) { $fromLine = $changes['base']['offset'] + $lineNo + 1; $line = $changes['base']['lines'][$lineNo]; @@ -265,9 +254,7 @@ public function generateLinesReplace(array $changes): string } /** - * Generate a string representation of the start of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Start of the block. */ @@ -277,9 +264,7 @@ public function generateBlockHeader(array $changes): string } /** - * Generate a string representation of the end of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string End of the block. */ @@ -289,7 +274,7 @@ public function generateBlockFooter(array $changes): string } /** - * Generate a string representation of the end of a diff view. + * @inheritDoc * * @return string End of the diff view. */ diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index e01932a5..c1feb4c7 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -32,7 +32,7 @@ class Unified extends MainRenderer implements SubRendererInterface * - title1 Title of the "old" version of text. * - title2 Title of the "new" version of text. */ - protected $subOptions = [ + private $subOptions = [ 'format' => 'html', 'insertMarkers' => ['', ''], 'deleteMarkers' => ['', ''], @@ -43,7 +43,7 @@ class Unified extends MainRenderer implements SubRendererInterface /** * Unified constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the inline diff renderer. * * @see Inline::$subOptions */ @@ -54,7 +54,7 @@ public function __construct(array $options = []) } /** - * Render a and return diff-view with changes between the two sequences (under each other). + * @inheritDoc * * @return string|false The generated diff-view or false when there's no difference. */ @@ -66,7 +66,7 @@ public function render() } /** - * Generates a string representation of the opening of a predefined table and its header with titles from options. + * @inheritDoc * * @return string HTML code representation of the diff-view header. */ @@ -76,7 +76,7 @@ public function generateDiffHeader(): string } /** - * Generates a string representation of lines that are skipped. + * @inheritDoc * * @return string HTML code representation of a table's header. */ @@ -87,17 +87,15 @@ public function generateSkippedLines(): string /** - * Generate a string representation of lines without differences between both versions. - * - * @param array $change Contains the op-codes about the changes between two blocks. + * @inheritDoc * * @return string HTML code representing the blocks of text with no difference. */ - public function generateLinesEqual(array $change): string + public function generateLinesEqual(array $changes): string { $html = ''; - foreach ($change['base']['lines'] as $line) { + foreach ($changes['base']['lines'] as $line) { $html .= '' . $line . '
'; } @@ -105,17 +103,15 @@ public function generateLinesEqual(array $change): string } /** - * Generates a string representation of lines that are added to the 2nd version. - * - * @param array $change Contains the op-codes about the changes between two blocks. + * @inheritDoc * * @return string HTML code representing a block of added text. */ - public function generateLinesInsert(array $change): string + public function generateLinesInsert(array $changes): string { $html = ''; - foreach ($change['changed']['lines'] as $line) { + foreach ($changes['changed']['lines'] as $line) { $html .= '' . $line . '
'; } @@ -123,16 +119,14 @@ public function generateLinesInsert(array $change): string } /** - * Generates a string representation of lines that are removed from the 2nd version. - * - * @param array $change Contains the op-codes about the changes between two blocks. + * @inheritDoc * * @return string HTML code representing a block of removed text. */ - public function generateLinesDelete(array $change): string + public function generateLinesDelete(array $changes): string { $html = ''; - foreach ($change['base']['lines'] as $line) { + foreach ($changes['base']['lines'] as $line) { $html .= '' . $line . '
'; } @@ -140,24 +134,22 @@ public function generateLinesDelete(array $change): string } /** - * Generates a string representation of a lines that are partially modified. - * - * @param array $change Contains the op-codes about the changes between two blocks. + * @inheritDoc * * @return string HTML code representing a block of modified text. */ - public function generateLinesReplace(array $change): string + public function generateLinesReplace(array $changes): string { $html = ''; // Lines with characters removed. - foreach ($change['base']['lines'] as $line) { + foreach ($changes['base']['lines'] as $line) { $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); $html .= '' . $line . '
'; } // Lines with characters added. - foreach ($change['changed']['lines'] as $line) { + foreach ($changes['changed']['lines'] as $line) { $line = str_replace(["\0", "\1"], $this->options['insertMarkers'], $line); $html .= '' . $line . '
'; } @@ -166,9 +158,7 @@ public function generateLinesReplace(array $change): string } /** - * Generate a string representation of the start of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Start of the block. */ @@ -178,9 +168,7 @@ public function generateBlockHeader(array $changes): string } /** - * Generate a string representation of the end of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string End of the block. */ @@ -190,7 +178,7 @@ public function generateBlockFooter(array $changes): string } /** - * Generate a string representation of the end of a diff view. + * @inheritDoc * * @return string End of the diff view. */ diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index dc4b9692..726218e4 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -26,7 +26,7 @@ class InlineCli extends MainRenderer implements SubRendererInterface * @var array Associative array containing the default options available for this renderer and their default * value. */ - protected $subOptions = []; + private $subOptions = []; /** * InlineCli constructor. @@ -42,7 +42,7 @@ public function __construct(array $options = []) } /** - * Render a and return diff-view with changes between the two sequences displayed inline. + * @inheritDoc * * @return string|false The generated diff-view or false when there's no difference. */ @@ -55,7 +55,7 @@ public function render() /** - * Generate a string representation of the start of a diff view. + * @inheritDoc * * @return string Start of the diff view. */ @@ -65,9 +65,7 @@ public function generateDiffHeader(): string } /** - * Generate a string representation of the start of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of lines. + * @inheritDoc * * @return string Start of the diff view. */ @@ -77,7 +75,7 @@ public function generateBlockHeader(array $changes): string } /** - * Generate a string representation of the lines that are skipped in the diff view. + * @inheritDoc * * @return string Representation of skipped lines. */ @@ -87,9 +85,7 @@ public function generateSkippedLines(): string } /** - * Generate a string representation lines without differences between the two versions. - * - * @param array $changes Contains the op-codes about the changes between two blocks of lines. + * @inheritDoc * * @return string Text with no difference. */ @@ -109,9 +105,7 @@ public function generateLinesEqual(array $changes): string } /** - * Generate a string representation of lines that are added to the 2nd version. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Added text. */ @@ -136,9 +130,7 @@ public function generateLinesInsert(array $changes): string } /** - * Generate a string representation of lines that are removed from the 2nd version. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Removed text. */ @@ -163,9 +155,7 @@ public function generateLinesDelete(array $changes): string } /** - * Generate a string representation of lines that are partially modified. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string Modified text. */ @@ -220,7 +210,7 @@ private function mergeChanges( foreach ($baselineParts as $partKey => &$part) { if ($iterator++ % 2) { // This part of the line has been changed. Surround it with user defined markers. - $basePart = $this->options['deleteMarkers'][0] . $part . $this->options['deleteMarkers'][1]; + $basePart = $this->options['deleteMarkers'][0] . $part . $this->options['deleteMarkers'][1]; if (isset($changedLineParts[$partKey])) { $changedPart = $this->options['insertMarkers'][0] . @@ -233,9 +223,9 @@ private function mergeChanges( [$fgColor, $bgColor] = $deleteColors; $basePart = $colorize->getColoredString($basePart, $fgColor, $bgColor); [$fgColor, $bgColor] = $insertColors; - $changedPart = $colorize->getColoredString($changedPart, $fgColor, $bgColor); + $changedPart = $colorize->getColoredString($changedPart, $fgColor, $bgColor); // FIXME } - $part = $basePart . $changedPart; + $part = $basePart . $changedPart; // FIXME } } unset($part); @@ -246,9 +236,7 @@ private function mergeChanges( } /** - * Generate a string representation of the end of a block. - * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @inheritDoc * * @return string End of the block */ @@ -258,7 +246,7 @@ public function generateBlockFooter(array $changes): string } /** - * Generate a string representation of the end of a diff view. + * @inheritDoc * * @return string End of the diff view. */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 8e83f9b4..56b68581 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -18,7 +18,6 @@ * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ - class UnifiedCli extends MainRendererAbstract { @@ -31,11 +30,12 @@ class UnifiedCli extends MainRendererAbstract * @var array Associative array containing the default options available for this renderer and their default * value. */ - protected $subOptions = []; + private $subOptions = []; /** * UnifiedCli constructor. - * @param array $options + * + * @param array $options Custom defined options for the inline diff renderer. * */ public function __construct(array $options = []) @@ -57,34 +57,21 @@ public function render(): string return $this->output(); } - - /** - * @param $string - * @param string $color - * @return string - */ - private function colorizeString($string, $color = ''): string - { - if ($this->options['cliColor']) { - return $this->colors->getColoredString($string, $color); - } - return $string; - } - /** * Render and return a unified colored diff. + * * @return string */ private function output(): string { - $diff = ''; + $diff = ''; $opCodes = $this->diff->getGroupedOpCodes(); foreach ($opCodes as $group) { $lastItem = count($group) - 1; - $i1 = $group['0']['1']; - $i2 = $group[$lastItem]['2']; - $j1 = $group['0']['3']; - $j2 = $group[$lastItem]['4']; + $i1 = $group['0']['1']; + $i2 = $group[$lastItem]['2']; + $j1 = $group['0']['3']; + $j2 = $group[$lastItem]['4']; if ($i1 == 0 && $i2 == 0) { $i1 = -1; @@ -101,7 +88,7 @@ private function output(): string "\n ", $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) ); - $diff .= $this->colorizeString(' ' . $string . "\n", 'grey'); + $diff .= $this->colorizeString(' ' . $string . "\n", 'grey'); continue; } if ($tag == 'replace' || $tag == 'delete') { @@ -109,17 +96,33 @@ private function output(): string "\n- ", $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) ); - $diff .= $this->colorizeString('-' . $string . "\n", 'light_red'); + $diff .= $this->colorizeString('-' . $string . "\n", 'light_red'); } if ($tag == 'replace' || $tag == 'insert') { $string = implode( "\n+", $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) ); - $diff .= $this->colorizeString('+' . $string . "\n", 'light_green'); + $diff .= $this->colorizeString('+' . $string . "\n", 'light_green'); } } } + return $diff; } + + /** + * @param $string + * @param string $color + * + * @return string + */ + private function colorizeString($string, $color = ''): string + { + if ($this->options['cliColor']) { + return $this->colors->getColoredString($string, $color); + } + + return $string; + } } From 73f6776bd3af176193bb16c979d37804fe6e98ac Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:51:55 +0100 Subject: [PATCH 097/206] Fix redundant and unused code. --- lib/jblond/Diff/Renderer/MainRenderer.php | 12 ++++++------ lib/jblond/Diff/Renderer/MainRendererAbstract.php | 6 +----- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 3c56310f..bff743e4 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -381,10 +381,10 @@ private function getOuterChange(string $oldString, string $newString): array * * The index of the last element of the array is always returned. * - * @param array $blocks The array which keeps the changes for the HTML renderer. - * @param string $tag Kind of difference. - * @param integer $lineInOld Start of block in "old". - * @param integer $lineInNew Start of block in "new". + * @param array $blocks The array which keeps the changes for the HTML renderer. + * @param string $tag Kind of difference. + * @param int $lineInOld Start of block in "old". + * @param int $lineInNew Start of block in "new". * * @return int The index of the last element. */ @@ -437,7 +437,7 @@ function ($line) { // Convert special characters to HTML entities $strings = array_map( function ($line) { - return htmlspecialchars($line, ENT_NOQUOTES, 'UTF-8'); + return htmlspecialchars($line, ENT_NOQUOTES); }, $strings ); @@ -447,7 +447,7 @@ function ($line) { $line = preg_replace_callback( '/(^[ \0\1]*)/', function ($matches) { - return str_replace(' ', " ", $matches[0]); + return str_replace(' ', ' ', $matches[0]); }, $line ); diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index b8204460..506bfb32 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -14,7 +14,7 @@ * @package jblond\Diff\Renderer * @author Mario Brandt * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton + * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php * @version 2.3.0 * @link https://github.com/JBlond/php-diff @@ -33,10 +33,6 @@ abstract class MainRendererAbstract * Mark line differences. */ public const CHANGE_LEVEL_LINE = 2; - /** - * Mark no inline differences. - */ - public const CHANGE_LEVEL_NONE = 4; /** * @var Diff $diff Instance of the diff class that this renderer is generating the rendered diff for. */ From 8a193c992ade7cd373582d37840e0c6fc78980a9 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:53:04 +0100 Subject: [PATCH 098/206] Document generateLinesEqual() --- .../Diff/Renderer/SubRendererInterface.php | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index abd2b669..c3a9f743 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -9,12 +9,12 @@ * * PHP version 7.2 or greater * - * @package jblond\Diff\Renderer\Html - * @author Ferry Cools + * @package jblond\Diff\Renderer\Html + * @author Ferry Cools * @copyright (c) 2020 Ferry Cools - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface { @@ -35,7 +35,7 @@ public function generateDiffHeader(): string; /** * Generate a string representation of the start of a block. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Start of the block. */ @@ -51,7 +51,10 @@ public function generateSkippedLines(): string; /** * Generate a string representation of lines without differences between both versions. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * Note: Depending on the options, lines can be marked as being equal, while the contents actually differ. + * (E.g. ignoreWhitespace and ignoreCase) + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Text with no difference. */ @@ -60,7 +63,7 @@ public function generateLinesEqual(array $changes): string; /** * Generate a string representation of lines that are added to the 2nd version. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Added text. */ @@ -69,7 +72,7 @@ public function generateLinesInsert(array $changes): string; /** * Generate a string representation of lines that are removed from the 2nd version. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Removed text. */ @@ -78,7 +81,7 @@ public function generateLinesDelete(array $changes): string; /** * Generate a string representation of lines that are partially modified. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string Modified text. */ @@ -87,7 +90,7 @@ public function generateLinesReplace(array $changes): string; /** * Generate a string representation of the end of a block. * - * @param array $changes Contains the op-codes about the changes between two blocks of text. + * @param array $changes Contains the op-codes about the changes between two blocks of text. * * @return string End of the block. */ From 5ba19f7ad84a5d008278c1e93b600304bfde853c Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:56:32 +0100 Subject: [PATCH 099/206] Refactor if/else statements --- lib/jblond/Diff/SequenceMatcher.php | 35 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index c81d7bd3..6c58d1eb 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -173,14 +173,12 @@ private function chainB() if ($length >= 200 && count($this->b2j[$char]) * 100 > $length) { $popularDict[$char] = 1; unset($this->b2j[$char]); - } else { - $this->b2j[$char][] = $i; + continue; } - } else { - $this->b2j[$char] = [ - $i, - ]; + $this->b2j[$char][] = $i; + continue; } + $this->b2j[$char] = [$i]; } // Remove leftovers @@ -436,21 +434,22 @@ function ($aArray, $bArray) { foreach ($matchingBlocks as [$list4, $list5, $list6]) { if ($i1 + $k1 == $list4 && $j1 + $k1 == $list5) { $k1 += $list6; - } else { - if ($k1) { - $nonAdjacent[] = [ - $i1, - $j1, - $k1, - ]; - } - - $i1 = $list4; - $j1 = $list5; - $k1 = $list6; + continue; + } + if ($k1) { + $nonAdjacent[] = [ + $i1, + $j1, + $k1, + ]; } + + $i1 = $list4; + $j1 = $list5; + $k1 = $list6; } + if ($k1) { $nonAdjacent[] = [ $i1, From 34a032f1f790fec65461beaa4127b8350669658b Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:58:03 +0100 Subject: [PATCH 100/206] Fix property visibility and unused code --- tests/Diff/Renderer/MainRendererTest.php | 40 ++++++------------------ 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 2771417e..7d62838e 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -37,34 +37,17 @@ class MainRendererTest extends TestCase /** * @var string[] Defines the main renderer options. */ - public $rendererOptions = [ + private $rendererOptions = [ 'format' => 'html', ]; /** - * MainRendererTest constructor. - * - * @param null $name - * @param array $data - * @param string $dataName - */ - public function __construct($name = null, array $data = [], $dataName = '') - { - //new \jblond\Autoloader(); - parent::__construct($name, $data, $dataName); - } - - /** - * + * Test if a sequence of version1 which is removed from version2 is caught by the MainRenderer. */ public function testRenderSimpleDelete() { $renderer = new MainRenderer(); - $renderer->diff = new Diff( - ['a'], - [] - ); - $result = $this->invokeMethod($renderer, 'renderSequences'); + $renderer->diff = new Diff(['a'], []); static::assertEquals( [ [ @@ -72,9 +55,7 @@ public function testRenderSimpleDelete() 'tag' => 'delete', 'base' => [ 'offset' => 0, - 'lines' => [ - 'a', - ], + 'lines' => ['a'], ], 'changed' => [ 'offset' => 0, @@ -83,7 +64,7 @@ public function testRenderSimpleDelete() ], ], ], - $result + $this->invokeMethod($renderer, 'renderSequences') ); } @@ -94,7 +75,7 @@ public function testRenderSimpleDelete() * @param string $methodName Method name to call * @param array $parameters Array of parameters to pass into method. * - * @return mixed Method return. + * @return mixed The return value of the invoked method. * @throws ReflectionException If the class doesn't exist. */ public function invokeMethod(object $object, string $methodName, array $parameters = []) @@ -107,7 +88,7 @@ public function invokeMethod(object $object, string $methodName, array $paramete } /** - * + * Test if leading spaces of a sequence are replaced with html entities. */ public function testRenderFixesSpaces() { @@ -116,7 +97,6 @@ public function testRenderFixesSpaces() [' a'], ['a'] ); - $result = $this->invokeMethod($renderer, 'renderSequences'); static::assertEquals( [ @@ -131,14 +111,12 @@ public function testRenderFixesSpaces() ], 'changed' => [ 'offset' => 0, - 'lines' => [ - "\0\1a", - ], + 'lines' => ["\0\1a"], ], ], ], ], - $result + $this->invokeMethod($renderer, 'renderSequences') ); } From 7ec484c3522c8deb894dfb2665858559c85f4bf2 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 09:58:49 +0100 Subject: [PATCH 101/206] Document PhpUnit Similarity Test --- tests/Diff/SimilarityTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index a1be7649..e6257572 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -5,9 +5,24 @@ use jblond\Diff\Similarity; use PHPUnit\Framework\TestCase; +/** + * PHPUnit Test for the Similarity class of PHP DiffLib. + * + * PHP version 7.2 or greater + * + * @package Tests\Diff + * @author Ferry Cools + * @copyright (c) 2020 Ferry Cools + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.2.1 + * @link https://github.com/JBlond/php-diff + */ class SimilarityTest extends TestCase { + /** + * Test the similarity ratio between two sequences with different methods. + */ public function testGetSimilarity() { $similarity = new Similarity(range(1, 10), range(1, 5)); From 79d989da88d6270cee771814d40e6651ee15b917 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 10:00:40 +0100 Subject: [PATCH 102/206] Refactor callbacks and if/else expressions. --- lib/jblond/Diff/Similarity.php | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 0dc1dd47..acf640d6 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -13,9 +13,8 @@ * * @package jblond\Diff * @author Chris Boulton - * @author Mario Brandt * @author Ferry Cools - * @copyright (c) 2020 Mario Brandt + * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php * @version 2.3.0 * @link https://github.com/JBlond/php-diff @@ -62,6 +61,7 @@ public function setSeq2($version2) * @param int $type Calculation method. * * @return float The calculated ratio. + * */ public function getSimilarity(int $type = self::CALC_DEFAULT): float { @@ -71,7 +71,13 @@ public function getSimilarity(int $type = self::CALC_DEFAULT): float case self::CALC_FASTEST: return $this->getRatioFastest(); default: - $matches = array_reduce($this->getMatchingBlocks(), [$this, 'ratioReduce'], 0); + $matches = array_reduce( + $this->getMatchingBlocks(), + function ($carry, $item) { + return $this->ratioReduce($carry, $item); + }, + 0 + ); return $this->calculateRatio($matches, count($this->old) + count($this->new)); } @@ -99,12 +105,8 @@ private function getRatioFast(): float $matches = 0; $aLength = count($this->old); for ($iterator = 0; $iterator < $aLength; ++$iterator) { - $char = $this->old[$iterator]; - if (isset($avail[$char])) { - $numb = $avail[$char]; - } else { - $numb = $this->uniqueCount2[$char] ?? 0; - } + $char = $this->old[$iterator]; + $numb = isset($avail[$char]) ? $avail[$char] : $this->uniqueCount2[$char] ?? 0; $avail[$char] = $numb - 1; if ($numb > 0) { ++$matches; From 77a7b5982d4cee7cb4f5c265fda70cd9117881dd Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 10:05:00 +0100 Subject: [PATCH 103/206] Fix namespace and unused code --- tests/Diff/SequenceMatcherTest.php | 43 ++++++++++-------------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 1cf1d042..80eae0c2 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -1,6 +1,6 @@ - * @author Ferry Cools + * @package Tests\Diff + * @author Mario Brandt + * @author Ferry Cools * @copyright (c) 2009 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff */ - class SequenceMatcherTest extends TestCase { - /** - * SequenceMatcherTest constructor. - * - * @param null $name - * @param array $data - * @param string $dataName + * Test the opCodes of the differences between version1 and version2 with the default options. */ - public function __construct($name = null, array $data = [], $dataName = '') - { - parent::__construct($name, $data, $dataName); - } - public function testGetGroupedOpCodesDefault() { // Test with default options. @@ -45,8 +34,10 @@ public function testGetGroupedOpCodesDefault() $this->assertEquals( [ [ - ['equal', 4, 7, 4, 7], ['replace', 7, 8, 7, 8], ['equal', 8, 11, 8, 11] - ] + ['equal', 4, 7, 4, 7], + ['replace', 7, 8, 7, 8], + ['equal', 8, 11, 8, 11], + ], ], $sequenceMatcher->getGroupedOpCodes() ); @@ -83,10 +74,7 @@ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() ['ignoreWhitespace' => true] ); - $this->assertEquals( - [], - $sequenceMatcher->getGroupedOpCodes() - ); + $this->assertEquals([], $sequenceMatcher->getGroupedOpCodes()); } public function testGetGroupedOpCodesIgnoreCaseTrue() @@ -98,9 +86,6 @@ public function testGetGroupedOpCodesIgnoreCaseTrue() ['ignoreCase' => true] ); - $this->assertEquals( - [], - $sequenceMatcher->getGroupedOpCodes() - ); + $this->assertEquals([], $sequenceMatcher->getGroupedOpCodes()); } } From 94c8bd539ac073c63c171537b34e86131fefd03f Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 10:05:26 +0100 Subject: [PATCH 104/206] Document methods --- tests/Diff/SequenceMatcherTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 80eae0c2..cbd2c932 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -43,6 +43,9 @@ public function testGetGroupedOpCodesDefault() ); } + /** + * Test the opCodes of the differences between version1 and version2 with option trimEqual disabled. + */ public function testGetGroupedOpCodesTrimEqualFalse() { // Test with trimEqual disabled. @@ -63,6 +66,9 @@ public function testGetGroupedOpCodesTrimEqualFalse() ); } + /** + * Test the opCodes of the differences between version1 and version2 with option IgnoreWhitespace enabled. + */ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() { // Test with ignoreWhitespace enabled. Both sequences are considered to be the same. @@ -77,6 +83,9 @@ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() $this->assertEquals([], $sequenceMatcher->getGroupedOpCodes()); } + /** + *T est the opCodes of the differences between version1 and version2 with option ignoreCase enabled. + */ public function testGetGroupedOpCodesIgnoreCaseTrue() { // Test with ignoreCase enabled. Both sequences are considered to be the same. From 3954a2be998431fc2996e1831d9ba18de509ce0f Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 10:40:01 +0100 Subject: [PATCH 105/206] Fix probably undefined variable --- lib/jblond/Diff/Renderer/Text/InlineCli.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 726218e4..09dafc80 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -210,7 +210,8 @@ private function mergeChanges( foreach ($baselineParts as $partKey => &$part) { if ($iterator++ % 2) { // This part of the line has been changed. Surround it with user defined markers. - $basePart = $this->options['deleteMarkers'][0] . $part . $this->options['deleteMarkers'][1]; + $basePart = $this->options['deleteMarkers'][0] . $part . $this->options['deleteMarkers'][1]; + $changedPart = ''; if (isset($changedLineParts[$partKey])) { $changedPart = $this->options['insertMarkers'][0] . @@ -219,13 +220,13 @@ private function mergeChanges( } if ($this->options['cliColor']) { - // Colorize the changed part. - [$fgColor, $bgColor] = $deleteColors; - $basePart = $colorize->getColoredString($basePart, $fgColor, $bgColor); - [$fgColor, $bgColor] = $insertColors; - $changedPart = $colorize->getColoredString($changedPart, $fgColor, $bgColor); // FIXME + // Colorize the changed part. $colorize is defined above. + $basePart = $colorize->getColoredString($basePart, ...$deleteColors); + if (!empty($changedPart)) { + $changedPart = $colorize->getColoredString($changedPart, ...$insertColors); + } } - $part = $basePart . $changedPart; // FIXME + $part = $basePart . $changedPart; } } unset($part); From 909e195331a525fbe426853628e4f573abe57e55 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 13:31:08 +0100 Subject: [PATCH 106/206] Document disabled inspection --- lib/jblond/Diff/SequenceMatcher.php | 5 +++++ tests/Diff/Renderer/MainRendererTest.php | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 6c58d1eb..e7a92b61 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -396,6 +396,11 @@ public function getMatchingBlocks(): array $matchingBlocks = []; while (!empty($queue)) { [$aLower, $aUpper, $bLower, $bUpper] = array_pop($queue); + /** + * @noinspection PhpStrictTypeCheckingInspection + * $aLower, $aUpper, $bLower, $bUpper reported as wrong type because of multiple definitions of function + * count above. + */ $longestMatch = $this->findLongestMatch($aLower, $aUpper, $bLower, $bUpper); [$list1, $list2, $list3] = $longestMatch; if ($list3) { diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 7d62838e..571f0663 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -48,6 +48,8 @@ public function testRenderSimpleDelete() { $renderer = new MainRenderer(); $renderer->diff = new Diff(['a'], []); + + /** @noinspection PhpUnhandledExceptionInspection */ static::assertEquals( [ [ @@ -98,7 +100,8 @@ public function testRenderFixesSpaces() ['a'] ); - static::assertEquals( + /** @noinspection PhpUnhandledExceptionInspection */ + $this->assertEquals( [ [ [ From 035cd33cafb22cf050aaced76b56bacf644b91c8 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 14:09:46 +0100 Subject: [PATCH 107/206] Refactor static method calls to non-static --- tests/Diff/Renderer/MainRendererTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 571f0663..a6911f10 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -50,7 +50,7 @@ public function testRenderSimpleDelete() $renderer->diff = new Diff(['a'], []); /** @noinspection PhpUnhandledExceptionInspection */ - static::assertEquals( + $this->assertEquals( [ [ [ From 013f8626a98bced1de73e410e6c45e2d03c3a5c6 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 19 Nov 2020 15:08:19 +0100 Subject: [PATCH 108/206] Bump library version --- tests/Diff/SimilarityTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index e6257572..3c51fe91 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.2.1 + * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ class SimilarityTest extends TestCase From 1ba255fa05ba4781d722428c3efc48b566437b07 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 21 Nov 2020 17:33:48 +0100 Subject: [PATCH 109/206] Cut HTML Unified Renderer --- README.md | 4 - assets/htmlUnified.png | Bin 161326 -> 0 bytes example/dark-theme.css | 62 ------ example/example.php | 8 - example/styles.css | 60 ------ lib/jblond/Diff.php | 8 +- lib/jblond/Diff/Renderer/Html/Unified.php | 189 ------------------ .../Diff/Renderer/Html/HtmlRenderersTest.php | 22 -- tests/resources/htmlUnified.txt | 1 - 9 files changed, 1 insertion(+), 353 deletions(-) delete mode 100644 assets/htmlUnified.png delete mode 100644 lib/jblond/Diff/Renderer/Html/Unified.php delete mode 100644 tests/resources/htmlUnified.txt diff --git a/README.md b/README.md index 9fd6125e..d97ce02f 100644 --- a/README.md +++ b/README.md @@ -98,10 +98,6 @@ directory. Included is a light and a dark theme. ![HTML Inline Example](assets/htmlInline.png "HTML Inline Example") -#### HTML Unified Example - -![HTML Unified Example](assets/htmlUnified.png "HTML Unified Example") - #### Text Unified Example ![Text Unified Example](assets/textUnified.png "Text Unified Example") diff --git a/assets/htmlUnified.png b/assets/htmlUnified.png deleted file mode 100644 index bc63c8cd1f3c8241816d39d4e4884d842827c538..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161326 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

yAF@KYJznjVX=Cg~iTXJRW`29xb?djXqcWrD( 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 z

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 ? 'No differences found.' : $diff->Render($renderer); ?> -

HTML Unified Diff

-isIdentical() ? 'No differences found.' : '
' . $diff->Render($renderer) . '
'; -?> -

Text Unified Diff

- * @author Mario Brandt - * @author Ferry Cools - * @copyright (c) 2009 Chris Boulton - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 - * @link https://github.com/JBlond/php-diff - */ -class Unified extends MainRenderer implements SubRendererInterface -{ - /** - * @var array Associative array containing the default options available for this renderer and their default - * value. - * - format Format of the texts. - * - insertMarkers Markers for inserted text. - * - deleteMarkers Markers for removed text. - * - title1 Title of the "old" version of text. - * - title2 Title of the "new" version of text. - */ - private $subOptions = [ - 'format' => 'html', - 'insertMarkers' => ['', ''], - 'deleteMarkers' => ['', ''], - 'title1' => 'Version1', - 'title2' => 'Version2', - ]; - - /** - * Unified constructor. - * - * @param array $options Custom defined options for the inline diff renderer. - * - * @see Inline::$subOptions - */ - public function __construct(array $options = []) - { - parent::__construct($this->subOptions); - $this->setOptions($options); - } - - /** - * @inheritDoc - * - * @return string|false The generated diff-view or false when there's no difference. - */ - public function render() - { - $changes = parent::renderSequences(); - - return parent::renderOutput($changes, $this); - } - - /** - * @inheritDoc - * - * @return string HTML code representation of the diff-view header. - */ - public function generateDiffHeader(): string - { - return ''; - } - - /** - * @inheritDoc - * - * @return string HTML code representation of a table's header. - */ - public function generateSkippedLines(): string - { - return ''; - } - - - /** - * @inheritDoc - * - * @return string HTML code representing the blocks of text with no difference. - */ - public function generateLinesEqual(array $changes): string - { - $html = ''; - - foreach ($changes['base']['lines'] as $line) { - $html .= '' . $line . '
'; - } - - return $html; - } - - /** - * @inheritDoc - * - * @return string HTML code representing a block of added text. - */ - public function generateLinesInsert(array $changes): string - { - $html = ''; - - foreach ($changes['changed']['lines'] as $line) { - $html .= '' . $line . '
'; - } - - return $html; - } - - /** - * @inheritDoc - * - * @return string HTML code representing a block of removed text. - */ - public function generateLinesDelete(array $changes): string - { - $html = ''; - foreach ($changes['base']['lines'] as $line) { - $html .= '' . $line . '
'; - } - - return $html; - } - - /** - * @inheritDoc - * - * @return string HTML code representing a block of modified text. - */ - public function generateLinesReplace(array $changes): string - { - $html = ''; - - // Lines with characters removed. - foreach ($changes['base']['lines'] as $line) { - $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); - $html .= '' . $line . '
'; - } - - // Lines with characters added. - foreach ($changes['changed']['lines'] as $line) { - $line = str_replace(["\0", "\1"], $this->options['insertMarkers'], $line); - $html .= '' . $line . '
'; - } - - return $html; - } - - /** - * @inheritDoc - * - * @return string Start of the block. - */ - public function generateBlockHeader(array $changes): string - { - return ''; - } - - /** - * @inheritDoc - * - * @return string End of the block. - */ - public function generateBlockFooter(array $changes): string - { - return ''; - } - - /** - * @inheritDoc - * - * @return string End of the diff view. - */ - public function generateDiffFooter(): string - { - return '
'; - } -} diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 5106d9ce..cb8bf303 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -8,7 +8,6 @@ use jblond\Diff\Renderer\Html\Inline; use jblond\Diff\Renderer\Html\Merged; use jblond\Diff\Renderer\Html\SideBySide; -use jblond\Diff\Renderer\Html\Unified; use PHPUnit\Framework\TestCase; /** @@ -112,25 +111,4 @@ public function testMerged() $this->assertStringEqualsFile('tests/resources/htmlMerged.txt', $result); } - - /** - * Test the output of the HTML Unified renderer. - * - * @covers \jblond\Diff\Renderer\Html\Unified - */ - public function testUnified() - { - $diff = new Diff( - file_get_contents('tests/resources/a.txt'), - file_get_contents('tests/resources/b.txt') - ); - - $renderer = new Unified(); - $result = $diff->render($renderer); - if ($this->genOutputFiles) { - file_put_contents('htmlUnified.txt', $result); - } - - $this->assertStringEqualsFile('tests/resources/htmlUnified.txt', $result); - } } diff --git a/tests/resources/htmlUnified.txt b/tests/resources/htmlUnified.txt deleted file mode 100644 index 8827106e..00000000 --- a/tests/resources/htmlUnified.txt +++ /dev/null @@ -1 +0,0 @@ -<html>
    <head>
        <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
        <title>Hello World!</title>
        <title>Hello You!</title>
    </head>
    <body>
        <h1>This is demo content to show features of the php-diff package.</h1>
        <h2>This line is removed from version2.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>this line has inline differences between both versions.</h2>
        <h2>This line has differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has InLine differences between both versions.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line is added to version2.</h2>

        <p>
            It's also compatible with multibyte characters (like Chinese and emoji) as shown below:
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "金槍魚罐頭" means in Chinese?
            🍏🍎🙂
            另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”
            Do you know what "魚の缶詰" means in Chinese?
            🍎🍏🙂
        </p>

        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2>
        <h2>This line is the same for both versions.</h2>
        <h2>This line also has inline differences between both versions.</h2>
        <h2>This line also has inline differences between both versions!</h2>
    </body>
</html>

\ No newline at end of file From cf516d13cb85a5303a7c9695335e32790279405b Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 21 Nov 2020 18:16:49 +0100 Subject: [PATCH 110/206] Refactor HTML Inline Renderer to HTML Unified --- README.md | 5 ++- assets/htmlInline.png | Bin 194457 -> 0 bytes assets/htmlUnified.png | Bin 0 -> 194190 bytes example/dark-theme.css | 16 +++++----- example/example.php | 14 ++++---- example/styles.css | 14 ++++---- .../Renderer/Html/{Inline.php => Unified.php} | 12 +++---- .../Diff/Renderer/Html/HtmlRenderersTest.php | 30 +++++++----------- .../{htmlInline.txt => htmlUnified.txt} | 2 +- 9 files changed, 43 insertions(+), 50 deletions(-) delete mode 100644 assets/htmlInline.png create mode 100644 assets/htmlUnified.png rename lib/jblond/Diff/Renderer/Html/{Inline.php => Unified.php} (95%) rename tests/resources/{htmlInline.txt => htmlUnified.txt} (99%) diff --git a/README.md b/README.md index d97ce02f..30e5a38f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ standard formats including: * Unified * Context -* Inline HTML * Side by Side HTML * Unified HTML * Unified Commandline colored output @@ -94,9 +93,9 @@ directory. Included is a light and a dark theme.
More Example Pictures
-#### HTML Inline Example +#### HTML Unified Example -![HTML Inline Example](assets/htmlInline.png "HTML Inline Example") +![HTML Unified Example](assets/htmlUnified.png "HTML Unified Example") #### Text Unified Example diff --git a/assets/htmlInline.png b/assets/htmlInline.png deleted file mode 100644 index ab141c3239a51b0ece81682afd5a82be0de25364..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194457 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
NSQy@@%Aw8`(J9@-SmI$ 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 rZ#a5^fV%PfP@A?M@)`r4i0Na5 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 diff --git a/assets/htmlUnified.png b/assets/htmlUnified.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c100f2e7e8d86bc1d3ad4bc7dbf2e4982cecee GIT binary patch literal 194190 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⁡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 RusnG@0MbfQWfGsh{2y(oibenc literal 0 HcmV?d00001 diff --git a/example/dark-theme.css b/example/dark-theme.css index 3cf32779..77669d21 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -98,29 +98,29 @@ a, a:visited { } /* - * HTML Inline Diff + * HTML Unified Diff */ -.DifferencesInline .ChangeReplace { +.DifferencesUnified .ChangeReplace { color: #272822; } -.DifferencesInline .ChangeReplace .Left, -.DifferencesInline .ChangeDelete .Left { +.DifferencesUnified .ChangeReplace .Left, +.DifferencesUnified .ChangeDelete .Left { background: #FFDDDD; color: #272822; } -.DifferencesInline .ChangeReplace .Right, -.DifferencesInline .ChangeInsert .Right { +.DifferencesUnified .ChangeReplace .Right, +.DifferencesUnified .ChangeInsert .Right { background: #DDFFDD; } -.DifferencesInline .ChangeReplace ins { +.DifferencesUnified .ChangeReplace ins { background: #008000; } -.DifferencesInline .ChangeReplace del { +.DifferencesUnified .ChangeReplace del { background: #EE9999; color: #272822; } diff --git a/example/example.php b/example/example.php index c231a32d..fe2cb0cf 100644 --- a/example/example.php +++ b/example/example.php @@ -1,11 +1,11 @@ isIdentical() ? 'No differences found.' : $diff->Render($renderer); ?> -

HTML Inline Diff

+

HTML Unified Diff

isIdentical() ? 'No differences found.' : $diff->Render($renderer); ?>

HTML Merged Diff

isIdentical() ? 'No differences found.' : $diff->Render($renderer); ?> @@ -101,7 +101,7 @@ function changeCSS(cssFile, cssLinkIndex) {

Text Unified Diff

isIdentical() ? 'No differences found.' : '
' . htmlspecialchars($diff->render($renderer)) . '
'; ?> diff --git a/example/styles.css b/example/styles.css index 7dfad2ff..bbf2ba71 100644 --- a/example/styles.css +++ b/example/styles.css @@ -88,23 +88,23 @@ pre { } /* - * HTML Inline Diff + * HTML Unified Diff */ -.DifferencesInline .ChangeReplace .Left, -.DifferencesInline .ChangeDelete .Left { +.DifferencesUnified .ChangeReplace .Left, +.DifferencesUnified .ChangeDelete .Left { background: #FFDDDD; } -.DifferencesInline .ChangeReplace .Right, -.DifferencesInline .ChangeInsert .Right { +.DifferencesUnified .ChangeReplace .Right, +.DifferencesUnified .ChangeInsert .Right { background: #DDFFDD; } -.DifferencesInline .ChangeReplace ins { +.DifferencesUnified .ChangeReplace ins { background: #99EE99; } -.DifferencesInline .ChangeReplace del { +.DifferencesUnified .ChangeReplace del { background: #EE9999; } diff --git a/lib/jblond/Diff/Renderer/Html/Inline.php b/lib/jblond/Diff/Renderer/Html/Unified.php similarity index 95% rename from lib/jblond/Diff/Renderer/Html/Inline.php rename to lib/jblond/Diff/Renderer/Html/Unified.php index 7bb811af..1569e83e 100644 --- a/lib/jblond/Diff/Renderer/Html/Inline.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -8,7 +8,7 @@ use jblond\Diff\Renderer\SubRendererInterface; /** - * Inline HTML diff generator for PHP DiffLib. + * Unified HTML diff generator for PHP DiffLib. * * PHP version 7.2 or greater * @@ -21,7 +21,7 @@ * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ -class Inline extends MainRenderer implements SubRendererInterface +class Unified extends MainRenderer implements SubRendererInterface { /** * @var array Associative array containing the default options available for this renderer and their default @@ -41,11 +41,11 @@ class Inline extends MainRenderer implements SubRendererInterface ]; /** - * Inline constructor. + * Unified constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the unified diff renderer. * - * @see Inline::$subOptions + * @see Unified::$subOptions */ public function __construct(array $options = []) { @@ -73,7 +73,7 @@ public function render() public function generateDiffHeader(): string { return << + diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index cb8bf303..10639525 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -5,9 +5,9 @@ namespace Tests\Diff\Renderer\Html; use jblond\Diff; -use jblond\Diff\Renderer\Html\Inline; use jblond\Diff\Renderer\Html\Merged; use jblond\Diff\Renderer\Html\SideBySide; +use jblond\Diff\Renderer\Html\Unified; use PHPUnit\Framework\TestCase; /** @@ -65,50 +65,44 @@ public function testSideBySide() } /** - * Test the output of the HTML Inline renderer. + * Test the output of the HTML Unified renderer. * - * @covers \jblond\Diff\Renderer\Html\Inline + * @covers \jblond\Diff\Renderer\Html\Merged */ - public function testInline() + public function testMerged() { $diff = new Diff( file_get_contents('tests/resources/a.txt'), file_get_contents('tests/resources/b.txt') ); - $renderer = new Inline( - [ - 'format' => 'html', - 'insertMarkers' => ['', ''], - 'deleteMarkers' => ['', ''], - ] - ); + $renderer = new Merged(); $result = $diff->render($renderer); if ($this->genOutputFiles) { - file_put_contents('htmlInline.txt', $result); + file_put_contents('htmlMerged.txt', $result); } - $this->assertStringEqualsFile('tests/resources/htmlInline.txt', $result); + $this->assertStringEqualsFile('tests/resources/htmlMerged.txt', $result); } /** * Test the output of the HTML Unified renderer. * - * @covers \jblond\Diff\Renderer\Html\Merged + * @covers \jblond\Diff\Renderer\Html\Unified */ - public function testMerged() + public function testUnified() { $diff = new Diff( file_get_contents('tests/resources/a.txt'), file_get_contents('tests/resources/b.txt') ); - $renderer = new Merged(); + $renderer = new Unified(); $result = $diff->render($renderer); if ($this->genOutputFiles) { - file_put_contents('htmlMerged.txt', $result); + file_put_contents('htmlUnified.txt', $result); } - $this->assertStringEqualsFile('tests/resources/htmlMerged.txt', $result); + $this->assertStringEqualsFile('tests/resources/htmlUnified.txt', $result); } } diff --git a/tests/resources/htmlInline.txt b/tests/resources/htmlUnified.txt similarity index 99% rename from tests/resources/htmlInline.txt rename to tests/resources/htmlUnified.txt index 443cc066..f8add881 100644 --- a/tests/resources/htmlInline.txt +++ b/tests/resources/htmlUnified.txt @@ -1,4 +1,4 @@ -
{$this->options['title1']}
+
From 07da484ec52ef780e0c3f45f02d30835fe5f9cfa Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 21 Nov 2020 18:18:17 +0100 Subject: [PATCH 111/206] Fix HTML Merged Renderer Stray tags present when lines removed from version 2. --- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- tests/resources/htmlMerged.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index b96eb630..b55889bc 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -253,7 +253,7 @@ function ($removedParts) use ($addedParts) { */ public function generateBlockFooter(array $changes): string { - return ''; + return $changes['tag'] != 'delete' ? '' : ''; } /** diff --git a/tests/resources/htmlMerged.txt b/tests/resources/htmlMerged.txt index 37364a96..0e261b7d 100644 --- a/tests/resources/htmlMerged.txt +++ b/tests/resources/htmlMerged.txt @@ -24,7 +24,7 @@ - + From b13ff842a5ffca21d468c40813e5e9ba31f82013 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 21 Nov 2020 18:22:07 +0100 Subject: [PATCH 112/206] Fix constructor DocBlocks DocBlocks referred to Inline class instead of class in question. --- lib/jblond/Diff/Renderer/Html/SideBySide.php | 4 ++-- lib/jblond/Diff/Renderer/Text/InlineCli.php | 4 ++-- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 5e4aad6e..cedf2d22 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -43,9 +43,9 @@ class SideBySide extends MainRenderer implements SubRendererInterface /** * SideBySide constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the SideBySide diff renderer. * - * @see Inline::$subOptions + * @see SideBySide::$subOptions */ public function __construct(array $options = []) { diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 09dafc80..a0d2f3bd 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -31,9 +31,9 @@ class InlineCli extends MainRenderer implements SubRendererInterface /** * InlineCli constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the InlineCli diff renderer. * - * @see Inline::$subOptions + * @see InlineCli::$subOptions */ public function __construct(array $options = []) { diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 56b68581..97ee212d 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -35,7 +35,7 @@ class UnifiedCli extends MainRendererAbstract /** * UnifiedCli constructor. * - * @param array $options Custom defined options for the inline diff renderer. + * @param array $options Custom defined options for the UnifiedCli diff renderer. * */ public function __construct(array $options = []) From fb50095156acd457b37f23265becc8dad894fef2 Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 30 Nov 2020 12:15:33 +0100 Subject: [PATCH 113/206] Update changelog.md --- changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index b2c3fcde..e37692c1 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,11 @@ # changelog +## next + +* Refactored HTML Inline renderer to HTML Unified. + +* The non table unified renderer is cut from the code. + ## 2.3.0 (2020-11-19) * Add: Change log. From 0bd0bd2708b99dddc7515c19a309ba51868e449c Mon Sep 17 00:00:00 2001 From: Mario Date: Mon, 30 Nov 2020 12:20:10 +0100 Subject: [PATCH 114/206] Require PHPUnit 8 or 9. --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index adba123e..0ce866aa 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "ext-pcre": "*" }, "require-dev": { - "phpunit/phpunit": "8.*", + "phpunit/phpunit": "^8 || ^9", "squizlabs/php_codesniffer": "*", "phpmd/phpmd": "2.*", "jblond/php-cli": "^1.0" From 6fcafe114f58843a0a19d7b053bd7a752f27b41d Mon Sep 17 00:00:00 2001 From: DigiLive Date: Fri, 4 Dec 2020 10:29:20 +0100 Subject: [PATCH 115/206] Fix #83 - Lines not properly marked If a line is different at the other version from the first to the last character, the line isn't marked when inlineMarking is set to CHANGE_LEVEL_LINE. --- lib/jblond/Diff/Renderer/MainRenderer.php | 38 +++++++++++------------ 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index bff743e4..f0b579ad 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -310,26 +310,24 @@ private function markOuterChange(array &$oldText, array &$newText, int $startOld // Determine the start and end position of the line difference. [$start, $end] = $this->getOuterChange($oldString, $newString); - if ($start != 0 || $end != 0) { - // Changes between the lines exist. - // Add markers around the changed character sequence in the old string. - $sequenceEnd = mb_strlen($oldString) + $end; - $oldString = - mb_substr($oldString, 0, $start) . "\0" . - mb_substr($oldString, $start, $sequenceEnd - $start) . "\1" . - mb_substr($oldString, $sequenceEnd); - - // Add markers around the changed character sequence in the new string. - $sequenceEnd = mb_strlen($newString) + $end; - $newString = - mb_substr($newString, 0, $start) . "\0" . - mb_substr($newString, $start, $sequenceEnd - $start) . "\1" . - mb_substr($newString, $sequenceEnd); - - // Overwrite the strings in the old and new text so the changed lines include the markers. - $oldText[$startOld + $iterator] = $oldString; - $newText[$startNew + $iterator] = $newString; - } + // Changes between the lines exist. + // Add markers around the changed character sequence in the old string. + $sequenceEnd = mb_strlen($oldString) + $end; + $oldString + = mb_substr($oldString, 0, $start) . "\0" . + mb_substr($oldString, $start, $sequenceEnd - $start) . "\1" . + mb_substr($oldString, $sequenceEnd); + + // Add markers around the changed character sequence in the new string. + $sequenceEnd = mb_strlen($newString) + $end; + $newString + = mb_substr($newString, 0, $start) . "\0" . + mb_substr($newString, $start, $sequenceEnd - $start) . "\1" . + mb_substr($newString, $sequenceEnd); + + // Overwrite the strings in the old and new text so the changed lines include the markers. + $oldText[$startOld + $iterator] = $oldString; + $newText[$startNew + $iterator] = $newString; } } From 8962a2b83ead8564e737902133995db40f12b114 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 7 Dec 2020 13:41:42 +0100 Subject: [PATCH 116/206] upgrade required PHP version to 7.3 --- README.md | 2 +- composer.json | 2 +- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- lib/jblond/Diff/Similarity.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- tests/Diff/SimilarityTest.php | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 30e5a38f..5cbc6f8a 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ directory. Included is a light and a dark theme. ## Requirements -* PHP 7.2 or greater +* PHP 7.3 or greater * PHP Multibyte String * [jblond/php-cli](https://github.com/jblond/php-cli) (suggested) diff --git a/composer.json b/composer.json index 0ce866aa..15fe8fbd 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ } ], "require": { - "php": ">=7.2", + "php": ">=7.3", "ext-mbstring": "*", "ext-pcre": "*" }, diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 5caf06e5..fce45e28 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -15,7 +15,7 @@ * A comprehensive library for comparing two strings and generating the differences between them in multiple formats. * (unified, side by side, inline, HTML, etc.) * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond * @author Chris Boulton diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index aa4c99ab..55bacbff 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -5,7 +5,7 @@ /** * Sequence matcher helper functions for Diff * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff * @author Mario Brandt diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index b55889bc..ab755774 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -8,7 +8,7 @@ /** * Merged diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Text * @author Ferry Cools diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index cedf2d22..545d4ed5 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -10,7 +10,7 @@ /** * Side by Side HTML diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Html * @author Chris Boulton diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 1569e83e..b69f6cff 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -10,7 +10,7 @@ /** * Unified HTML diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Html * @author Chris Boulton diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index f0b579ad..7399e0c9 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -9,7 +9,7 @@ /** * Base renderer for rendering diffs for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Html * @author Chris Boulton diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index 506bfb32..e40bfeda 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -9,7 +9,7 @@ /** * Abstract class for the main renderer in PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer * @author Mario Brandt diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index c3a9f743..a3ea1bbb 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -7,7 +7,7 @@ /** * Sub rendering class interface for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Html * @author Ferry Cools diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 7b50dc33..6fae3bbf 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -9,7 +9,7 @@ /** * Context diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Text * @author Chris Boulton diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index a0d2f3bd..fb7965cc 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -11,7 +11,7 @@ /** * Inline diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Text * @author Ferry Cools diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index c5570cf0..40b43a5b 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -9,7 +9,7 @@ /** * Unified diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Text * @author Chris Boulton diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 97ee212d..e39dc533 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -9,7 +9,7 @@ /** * Unified diff generator for PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff\Renderer\Text * @author Mario Brandt diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index e7a92b61..1e5fc92d 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -9,7 +9,7 @@ /** * Sequence matcher for Diff * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff * @author Chris Boulton diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index acf640d6..0d2ec812 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -9,7 +9,7 @@ * * @see similar_text() * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package jblond\Diff * @author Chris Boulton diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index a6911f10..9dbc3a01 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -15,7 +15,7 @@ /** * PHPUnit Test for the main renderer of PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package Tests\Diff\Renderer * @author Mario Brandt diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index cbd2c932..0d85127d 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -8,7 +8,7 @@ /** * PHPUnit Test for the main renderer of PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package Tests\Diff * @author Mario Brandt diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index 3c51fe91..b9bdbb98 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -8,7 +8,7 @@ /** * PHPUnit Test for the Similarity class of PHP DiffLib. * - * PHP version 7.2 or greater + * PHP version 7.3 or greater * * @package Tests\Diff * @author Ferry Cools From 7d973d3b18ef9b558fd784b9447251ee73c91c23 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 08:00:07 +0100 Subject: [PATCH 117/206] Document methods * Add missing documentation. * Fixes and reformatting. --- lib/jblond/Diff.php | 3 +-- lib/jblond/Diff/Renderer/MainRenderer.php | 4 ++-- lib/jblond/Diff/SequenceMatcher.php | 28 ++++++++--------------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 5caf06e5..fa3e7fc4 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -46,8 +46,7 @@ class Diff private $groupedCodes; /** - * @var array Associative array containing the default options available - * for the diff class and their default value. + * @var array Associative array containing the default options available for the diff class and their default value. * * - context The amount of lines to include around blocks that differ. * - trimEqual Strip blocks of equal lines from the start and end of the text. diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index f0b579ad..720c4609 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -124,7 +124,7 @@ protected function renderSequences(): array * 4 - The end line in the second sequence. * * The different types of tags include: - * replace - The string from $startOld to $endOld in $oldText should be replaced by + * replace - The string in $oldText from $startOld to $endOld, should be replaced by * the string in $newText from $startNew to $endNew. * delete - The string in $oldText from $startOld to $endNew should be deleted. * insert - The string in $newText from $startNew to $endNew should be inserted at $startOld in @@ -291,7 +291,7 @@ public function sequenceToArray(string $pattern, string $sequence): array * E.g. *
      *         1234567
-     * OLd => "abcdefg" Start marker inserted at position 3
+     * Old => "abcdefg" Start marker inserted at position 3
      * New => "ab123fg"   End marker inserted at position 6
      * 
* diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index e7a92b61..e3352178 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -46,17 +46,12 @@ class SequenceMatcher private $b2j = []; /** - * @var array - */ - private $options = []; - - /** - * @var null|array + * @var array A list of all of the op-codes for the differences between the compared strings. */ private $opCodes; /** - * @var null|array + * @var array A nested set of arrays for all of the matching sub-sequences the compared strings. */ private $matchingBlocks; @@ -72,9 +67,8 @@ class SequenceMatcher ]; /** - * The constructor. With the sequences being passed, they'll be set for the - * sequence matcher and it will perform a basic cleanup & calculate junk - * elements. + * The constructor. With the sequences being passed, they'll be set for the sequence matcher and it will perform a + * basic cleanup & calculate junk elements. * * @param string|array $old A string or array containing the lines to compare against. * @param string|array $new A string or array containing the lines to compare. @@ -295,11 +289,9 @@ public function getGroupedOpCodes(): array } /** - * Return a list of all of the op codes for the differences between the - * two strings. + * Return a list of all of the op codes for the differences between the two strings. * - * The nested array returned contains an array describing the op code - * which includes: + * The nested array returned contains an array describing the op code which includes: * 0 - The type of tag (as described below) for the op code. * 1 - The beginning line in the first sequence. * 2 - The end line in the first sequence. @@ -366,12 +358,10 @@ public function getOpCodes(): array } /** - * Return a nested set of arrays for all of the matching sub-sequences - * in the strings $a and $b. + * Return a nested set of arrays for all of the matching sub-sequences in compared strings $a and $b. * - * Each block contains the lower constraint of the block in $a, the lower - * constraint of the block in $b and finally the number of lines that the - * block continues for. + * Each block contains the lower constraint of the block in $a, the lower constraint of the block in $b and finally + * the number of lines that the block continues for. * * @return array Nested array of the matching blocks, as described by the function. */ From bb0eed4a8af3c68d91daae48b2289797841f7ff9 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 08:02:29 +0100 Subject: [PATCH 118/206] Optimize Sequence renderer * Reduction of cyclomatic complexity. --- lib/jblond/Diff/Renderer/MainRenderer.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 720c4609..73616eac 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -146,23 +146,23 @@ protected function renderSequences(): array $oldBlock = $this->formatLines(array_slice($oldText, $startOld, $blockSizeOld)); $newBlock = $this->formatLines(array_slice($newText, $startNew, $blockSizeNew)); - if ($tag == 'equal') { - // Old block equals New block + if ($tag != 'delete' && $tag != 'insert') { + // Old block "equals" New block or is replaced. $blocks[$lastBlock]['base']['lines'] += $oldBlock; $blocks[$lastBlock]['changed']['lines'] += $newBlock; continue; } - if ($tag == 'replace' || $tag == 'delete') { - // Inline differences or old block doesn't exist in the new text. + if ($tag == 'delete') { + // Block of version1 doesn't exist in version2. $blocks[$lastBlock]['base']['lines'] += $oldBlock; + continue; } - if ($tag == 'replace' || $tag == 'insert') { - // Inline differences or the new block doesn't exist in the old text. - $blocks[$lastBlock]['changed']['lines'] += $newBlock; - } + // Block of version2 doesn't exist in version1. + $blocks[$lastBlock]['changed']['lines'] += $newBlock; } + $changes[] = $blocks; } From 87d49c90d9a59a8385fdd1631a7061c613d5ed26 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 08:27:13 +0100 Subject: [PATCH 119/206] Start option to ignore blank lines * Add option `ignoreLines` to control the ability to ignore blank or empty lines. * Add styles of ignored lines to example css. * Add generator for ignored lines to HTML SideBySide renderer. * Add `options` property to the Sequence Mather. * Refactor option `ignoreNewLines` of the Sequence Matcher. * Add flags to define the level of ignoring blank lines. * Add tag `ignored` to the opCodes. * Add method stripLines to Similarity. * Add default option `ignoreLines` to Diff. * Add tests for testing option `ignoreLines` of the Sequence Matcher. * Reformat code. --- example/dark-theme.css | 13 ++++ example/example.php | 1 + example/styles.css | 31 ++++++--- lib/jblond/Diff.php | 26 ++++++-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 66 ++++++++++++++++++++ lib/jblond/Diff/Renderer/MainRenderer.php | 6 ++ lib/jblond/Diff/SequenceMatcher.php | 55 ++++++++++++++-- lib/jblond/Diff/Similarity.php | 31 +++++++++ tests/Diff/SequenceMatcherTest.php | 50 ++++++++++++++- 9 files changed, 259 insertions(+), 20 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index 77669d21..fec73959 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -97,6 +97,19 @@ a, a:visited { background: #EEBB00; } +.DifferencesSideBySide .ChangeIgnore .Left, +.DifferencesSideBySide .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesSideBySide .ChangeIgnore .Left.Ignore { + background: #4B4C57; +} + +.DifferencesSideBySide .ChangeIgnore .Right.Ignore { + background: #4B4C57; +} + /* * HTML Unified Diff */ diff --git a/example/example.php b/example/example.php index fe2cb0cf..e4d7ed04 100644 --- a/example/example.php +++ b/example/example.php @@ -20,6 +20,7 @@ 'trimEqual' => false, 'ignoreWhitespace' => true, 'ignoreCase' => true, + 'ignoreLines' => Diff::DIFF_IGNORE_LINE_EMPTY, ]; // Choose one of the initializations. diff --git a/example/styles.css b/example/styles.css index bbf2ba71..57af6725 100644 --- a/example/styles.css +++ b/example/styles.css @@ -6,8 +6,8 @@ body { } pre { - width: 100%; overflow: auto; + width: 100%; } /* @@ -15,34 +15,34 @@ pre { */ .Differences { - width: 100%; border-collapse: collapse; border-spacing: 0; empty-cells: show; + width: 100%; } .Differences thead th { - text-align: left; - border-bottom: 1px solid #000000; background: #AAAAAA; + border-bottom: 1px solid #000000; color: #000000; padding: 4px; + text-align: left; } .Differences tbody th { - text-align: right; background: #CCCCCC; - width: 4em; - padding: 1px 2px; border-right: 1px solid #000000; - vertical-align: top; font-size: 13px; + padding: 1px 2px; + text-align: right; + vertical-align: top; + width: 4em; } .Differences td { - padding: 1px 2px; font-family: Consolas, monospace; font-size: 13px; + padding: 1px 2px; } .Differences .Skipped { @@ -77,6 +77,19 @@ pre { background: #FFDD88; } +.DifferencesSideBySide .ChangeIgnore .Left, +.DifferencesSideBySide .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesSideBySide .ChangeIgnore .Left.Ignore { + background: #F7F7F7; +} + +.DifferencesSideBySide .ChangeIgnore .Right.Ignore { + background: #F7F7F7; +} + .Differences ins, .Differences del { text-decoration: none; diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index fa3e7fc4..02b437b6 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -28,6 +28,18 @@ */ class Diff { + /** + * Flag to disable ignore of successive empty/blank lines. + */ + public const DIFF_IGNORE_LINE_NONE = 0; + /** + * Flag to ignore successive empty lines. + */ + public const DIFF_IGNORE_LINE_EMPTY = 1; + /** + * Flag to ignore successive blank lines. (Lines which contain no or only non printable characters.) + */ + public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first version to compare. * Each element contains a line of this string. @@ -48,18 +60,20 @@ class Diff /** * @var array Associative array containing the default options available for the diff class and their default value. * - * - context The amount of lines to include around blocks that differ. - * - trimEqual Strip blocks of equal lines from the start and end of the text. - * - ignoreWhitespace When true, tabs and spaces are ignored while comparing. - * The spacing of version1 is leading. - * - ignoreCase When true, character casing is ignored while comparing. - * The casing of version1 is leading. + * - context The amount of lines to include around blocks that differ. + * - trimEqual Strip blocks of equal lines from the start and end of the text. + * - ignoreWhitespace True to ignore differences in tabs and spaces. + * - ignoreCase True to ignore differences in character casing. + * - ignoreLines 0: None. + * 1: Ignore empty lines. + * 2: Ignore blank lines. */ private $defaultOptions = [ 'context' => 3, 'trimEqual' => true, 'ignoreWhitespace' => false, 'ignoreCase' => false, + 'ignoreLines' => self::DIFF_IGNORE_LINE_NONE, ]; /** diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index cedf2d22..8abcdacf 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -282,4 +282,70 @@ public function generateDiffFooter(): string { return '
Version1
7         <h1>This is demo content to show features of the php-diff package.</h1>
8
'; } + + /** + * @inheritDoc + * + * @return string Html code representing table rows showing ignored text. + */ + public function generateLinesIgnore(array $changes): string + { + $html = ''; + + // Is below comparison result ever false? + if (count($changes['base']['lines']) >= count($changes['changed']['lines'])) { + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $toLine = ' '; + $changedLine = ' '; + if (isset($changes['changed']['lines'][$lineNo])) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $changedLine = $changes['changed']['lines'][$lineNo]; + } + + $html .= << + $fromLine + + $line + + $toLine + + $changedLine + + +HTML; + } + + return $html; + } + + foreach ($changes['changed']['lines'] as $lineNo => $changedLine) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $fromLine = ' '; + $line = ' '; + if (isset($changes['base']['lines'][$lineNo])) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $line = $changes['base']['lines'][$lineNo]; + } + + $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); + $changedLine = str_replace(["\0", "\1"], $this->options['insertMarkers'], $changedLine); + + $html .= << + $fromLine + + $line + + $toLine + + $changedLine + + +HTML; + } + + return $html; + } } diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 73616eac..cc1e2e46 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -80,6 +80,10 @@ public function renderOutput(array $changes, object $subRenderer) case 'replace': $output .= $subRenderer->generateLinesReplace($change); break; + case 'ignore': + // TODO: Keep backward compatible with renderers? + $output .= $subRenderer->generateLinesIgnore($change); + break; } $output .= $subRenderer->generateBlockFooter($change); @@ -130,6 +134,8 @@ protected function renderSequences(): array * insert - The string in $newText from $startNew to $endNew should be inserted at $startOld in * $oldText. * equal - The two strings with the specified ranges are equal. + * ignore - The string in $oldText from $startOld to $endOld and + * the string in $newText from $startNew to $endNew are different, but considered to be equal. */ $blockSizeOld = $endOld - $startOld; diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index e3352178..60c55b2f 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -22,6 +22,18 @@ */ class SequenceMatcher { + /** + * Flag to disable ignore of successive empty/blank lines. + */ + public const DIFF_IGNORE_LINE_NONE = 0; + /** + * Flag to ignore empty lines. + */ + public const DIFF_IGNORE_LINE_EMPTY = 1; + /** + * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) + */ + public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first sequence to compare against. */ @@ -30,6 +42,13 @@ class SequenceMatcher * @var array The second sequence. */ protected $new; + /** + * @var array Associative array containing the options that will be applied for generating the diff. + * The key-value pairs are set at the constructor of this class. + * + * @see SequenceMatcher::setOptions() + */ + protected $options = []; /** * @var string|array Either a string or an array containing a callback function to determine * if a line is "junk" or not. @@ -39,12 +58,10 @@ class SequenceMatcher * @var array Array of characters that are considered junk from the second sequence. Characters are the array key. */ private $junkDict = []; - /** * @var array Array of indices that do not contain junk elements. */ private $b2j = []; - /** * @var array A list of all of the op-codes for the differences between the compared strings. */ @@ -56,14 +73,22 @@ class SequenceMatcher private $matchingBlocks; /** - * @var array + * @var array Associative array containing the default options available for the diff class and their default value. + * + * - context The amount of lines to include around blocks that differ. + * - trimEqual Strip blocks of equal lines from the start and end of the text. + * - ignoreWhitespace True to ignore differences in tabs and spaces. + * - ignoreCase True to ignore differences in character casing. + * - ignoreLines 0: None. + * 1: Ignore empty lines. + * 2: Ignore blank lines. */ private $defaultOptions = [ 'context' => 3, 'trimEqual' => true, 'ignoreWhitespace' => false, 'ignoreCase' => false, - 'ignoreNewLines' => false, + 'ignoreLines' => self::DIFF_IGNORE_LINE_NONE, ]; /** @@ -330,6 +355,28 @@ public function getOpCodes(): array $tag = 'insert'; } + if ($this->options['ignoreLines']) { + $part1 = array_slice($this->old, $i, $ai - $i); + $part2 = array_slice($this->new, $j, $bj - $j); + + if ($this->options['ignoreLines'] == 2) { + array_walk($part1, function (&$line) { + $line = trim($line); + }); + array_walk($part2, function (&$line) { + $line = trim($line); + }); + unset($line); + } + + if ( + ($tag == 'delete' && implode('', $part1) == '') || + ($tag == 'insert' && implode('', $part2) == '') + ) { + $tag = 'ignore'; + } + } + if ($tag) { $this->opCodes[] = [ $tag, diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index acf640d6..12285fe1 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -71,6 +71,9 @@ public function getSimilarity(int $type = self::CALC_DEFAULT): float case self::CALC_FASTEST: return $this->getRatioFastest(); default: + if ($this->options['ignoreLines']) { + $this->stripLines(); + } $matches = array_reduce( $this->getMatchingBlocks(), function ($carry, $item) { @@ -80,6 +83,7 @@ function ($carry, $item) { ); return $this->calculateRatio($matches, count($this->old) + count($this->new)); + // TODO: Restore original (un-stripped) versions? } } @@ -151,6 +155,33 @@ private function getRatioFastest(): float return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength); } + /** + * Strip empty or blank lines from the sequences to compare. + * + */ + private function stripLines(): void + { + foreach (['old', 'new'] as $version) { + if ($this->options['ignoreLines'] == self::DIFF_IGNORE_LINE_BLANK) { + array_walk( + $this->$version, + function (&$line) { + $line = trim($line); + } + ); + unset($line); + } + + $this->$version = array_filter( + $this->$version, + function ($line) { + return $line != ''; + } + ); + } + + $this->setSequences(array_values($this->old), array_values($this->new)); + } /** * Helper function to calculate the number of matches for Ratio(). diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index cbd2c932..aab22514 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -84,7 +84,7 @@ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() } /** - *T est the opCodes of the differences between version1 and version2 with option ignoreCase enabled. + * Test the opCodes of the differences between version1 and version2 with option ignoreCase enabled. */ public function testGetGroupedOpCodesIgnoreCaseTrue() { @@ -97,4 +97,52 @@ public function testGetGroupedOpCodesIgnoreCaseTrue() $this->assertEquals([], $sequenceMatcher->getGroupedOpCodes()); } + + /** + * Test the opCodes of the differences between version1 and version2 with option ignoreLines set to empty. + */ + public function testGetGroupedOpCodesIgnoreLinesEmpty() + { + // Test with ignoreCase enabled. Both sequences are considered to be the same. + $sequenceMatcher = new SequenceMatcher( + [0, 1, 2, 3], + [0, 1, '', 2, 3], + ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_EMPTY] + ); + + $this->assertEquals( + [ + [ + ['equal', 0, 2, 0, 2], + ['ignore', 2, 2, 2, 3], + ['equal', 2, 4, 3, 5], + ], + ], + $sequenceMatcher->getGroupedOpCodes() + ); + } + + /** + * Test the opCodes of the differences between version1 and version2 with option ignoreLines set to blank. + */ + public function testGetGroupedOpCodesIgnoreLinesBlank() + { + // Test with ignoreCase enabled. Both sequences are considered to be the same. + $sequenceMatcher = new SequenceMatcher( + [0, 1, 2, 3], + [0, 1, "\t", 2, 3], + ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_BLANK] + ); + + $this->assertEquals( + [ + [ + ['equal', 0, 2, 0, 2], + ['ignore', 2, 2, 2, 3], + ['equal', 2, 4, 3, 5], + ], + ], + $sequenceMatcher->getGroupedOpCodes() + ); + } } From 5bd040c7e7f1a53f33c3c55eb20ddab0bf3252c2 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 15 Dec 2020 15:08:37 +0100 Subject: [PATCH 120/206] Update Key words --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0ce866aa..43742be5 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,10 @@ "php", "diff", "side-by-sidediff", - "unified" + "unified", + "udiff", + "unidiff", + "unified diff" ], "authors": [ { From 08c9244feb11817759a7d2f861f7f98b9352bf74 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 15 Dec 2020 15:18:48 +0100 Subject: [PATCH 121/206] exclude not needed files for zip / composer export --- .gitattributes | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7460cf4e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +assets/ export-ignore +tests/ export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +phpcs.xml export-ignore From 8edb202e4bf46b67ce917080e39cc2f55973fef8 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 16 Dec 2020 10:02:05 +0100 Subject: [PATCH 122/206] keep assets for readme file --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 7460cf4e..fdade2f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ -assets/ export-ignore -tests/ export-ignore +tests export-ignore .editorconfig export-ignore .gitattributes export-ignore phpcs.xml export-ignore From 7382ee880650c3072348a78abf1c0fb6f4ae03d6 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 17 Dec 2020 10:28:45 +0100 Subject: [PATCH 123/206] add phpunit config file --- composer.json | 2 +- phpunit.xml | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 phpunit.xml diff --git a/composer.json b/composer.json index 43742be5..3ce0482e 100644 --- a/composer.json +++ b/composer.json @@ -50,7 +50,7 @@ "classmap-authoritative": true }, "scripts": { - "phpunit": "phpunit ./tests/", + "phpunit": "phpunit", "php_src": "phpcs --standard=phpcs.xml -s -p --colors ./lib/", "php_test": "phpcs --standard=phpcs.xml -s -p --colors ./tests/", "phpmd": "phpmd ./ ansi cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor" diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..8152c643 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,7 @@ + + + + tests + + + From 2925723bc82951a677975476740e644a4d14c203 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 15 Dec 2020 15:08:37 +0100 Subject: [PATCH 124/206] Update Key words --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 0ce866aa..43742be5 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,10 @@ "php", "diff", "side-by-sidediff", - "unified" + "unified", + "udiff", + "unidiff", + "unified diff" ], "authors": [ { From caef106269c42948c23f2eadfe80ac06dd7d3ec2 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 15 Dec 2020 15:18:48 +0100 Subject: [PATCH 125/206] exclude not needed files for zip / composer export --- .gitattributes | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..7460cf4e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +assets/ export-ignore +tests/ export-ignore +.editorconfig export-ignore +.gitattributes export-ignore +phpcs.xml export-ignore From dabb4676a6b7553f7e9b7b36b79e0e01a6c2658a Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 16 Dec 2020 10:02:05 +0100 Subject: [PATCH 126/206] keep assets for readme file --- .gitattributes | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 7460cf4e..fdade2f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,4 @@ -assets/ export-ignore -tests/ export-ignore +tests export-ignore .editorconfig export-ignore .gitattributes export-ignore phpcs.xml export-ignore From 3591515d1362080fa7b8de5614929de67eb4b747 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 12:01:22 +0100 Subject: [PATCH 127/206] Optimize constant usage Instead of defining constants with the same name and values at different namespaces, they're now defined at an interface which can be shared among classes by implementing this interface. --- lib/jblond/Diff.php | 15 ++---------- lib/jblond/Diff/ConstantsInterface.php | 33 ++++++++++++++++++++++++++ lib/jblond/Diff/SequenceMatcher.php | 32 ++++++++++--------------- 3 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 lib/jblond/Diff/ConstantsInterface.php diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 02b437b6..048e1dbb 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -5,6 +5,7 @@ namespace jblond; use InvalidArgumentException; +use jblond\Diff\ConstantsInterface; use jblond\Diff\SequenceMatcher; use jblond\Diff\Similarity; use OutOfRangeException; @@ -26,20 +27,8 @@ * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ -class Diff +class Diff implements ConstantsInterface { - /** - * Flag to disable ignore of successive empty/blank lines. - */ - public const DIFF_IGNORE_LINE_NONE = 0; - /** - * Flag to ignore successive empty lines. - */ - public const DIFF_IGNORE_LINE_EMPTY = 1; - /** - * Flag to ignore successive blank lines. (Lines which contain no or only non printable characters.) - */ - public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first version to compare. * Each element contains a line of this string. diff --git a/lib/jblond/Diff/ConstantsInterface.php b/lib/jblond/Diff/ConstantsInterface.php new file mode 100644 index 00000000..121e7cb6 --- /dev/null +++ b/lib/jblond/Diff/ConstantsInterface.php @@ -0,0 +1,33 @@ + + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff + */ +interface ConstantsInterface +{ + /** + * Flag to disable ignore of successive empty/blank lines. + */ + public const DIFF_IGNORE_LINE_NONE = 0; + /** + * Flag to ignore empty lines. + */ + public const DIFF_IGNORE_LINE_EMPTY = 1; + /** + * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) + */ + public const DIFF_IGNORE_LINE_BLANK = 2; + +} diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 60c55b2f..ef97f172 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -20,20 +20,8 @@ * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ -class SequenceMatcher +class SequenceMatcher implements ConstantsInterface { - /** - * Flag to disable ignore of successive empty/blank lines. - */ - public const DIFF_IGNORE_LINE_NONE = 0; - /** - * Flag to ignore empty lines. - */ - public const DIFF_IGNORE_LINE_EMPTY = 1; - /** - * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) - */ - public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first sequence to compare against. */ @@ -360,12 +348,18 @@ public function getOpCodes(): array $part2 = array_slice($this->new, $j, $bj - $j); if ($this->options['ignoreLines'] == 2) { - array_walk($part1, function (&$line) { - $line = trim($line); - }); - array_walk($part2, function (&$line) { - $line = trim($line); - }); + array_walk( + $part1, + function (&$line) { + $line = trim($line); + } + ); + array_walk( + $part2, + function (&$line) { + $line = trim($line); + } + ); unset($line); } From 19634bbaf9882ec014c8e6aa1c469356df7b0749 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 12:08:25 +0100 Subject: [PATCH 128/206] Document option `ignoreLines` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30e5a38f..5920ae96 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,8 @@ $options = [ 'ignoreWhitespace' => true, 'ignoreCase' => true, 'context' => 2, - 'cliColor' => true // for cli output + 'cliColor' => true, // for cli output + 'ignoreLines' => Diff::DIFF_IGNORE_LINE_BLANK, ]; // Initialize the diff class. @@ -140,7 +141,6 @@ at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge-for-php-dif ## Todo -* Ability to ignore blank line changes * 3 way diff support ## Contributors From 9403eba4aacad481f762bcd029b298a8fcdb3d7a Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:28:05 +0100 Subject: [PATCH 129/206] Add deprecation notice for missing method If a used sub renderer, which extends the main renderer, a deprecation notice will be thrown when the sub renderer is missing method `generateLinesIgnore`. --- lib/jblond/Diff/Renderer/MainRenderer.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index cc1e2e46..3a26186d 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -65,7 +65,23 @@ public function renderOutput(array $changes, object $subRenderer) strlen($this->options['equalityMarkers'][1]) ); + $deprecationTriggered = false; foreach ($blocks as $change) { + if ( + $subRenderer instanceof MainRenderer && + !method_exists($subRenderer, 'generateLinesIgnore') && + $change['tag'] == 'ignore' + ) { + if (!$deprecationTriggered) { + trigger_error( + 'The use of a subRenderer without method generateLinesIgnore() is deprecated!', + E_USER_DEPRECATED + ); + $deprecationTriggered = true; + } + $change['tag'] = + (count($change['base']['lines']) > count($change['changed']['lines'])) ? 'delete' : 'insert'; + } $output .= $subRenderer->generateBlockHeader($change); switch ($change['tag']) { case 'equal': From 75f5ce0e14039b8f2d9c477c99f28c203ff1394a Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:38:24 +0100 Subject: [PATCH 130/206] Add method `generateLinesIgnore` Currently the line is commented out, because the method is not required until the deprecation period for missing this method is over. --- .../Diff/Renderer/SubRendererInterface.php | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index c3a9f743..d4d95f09 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -41,13 +41,6 @@ public function generateDiffHeader(): string; */ public function generateBlockHeader(array $changes): string; - /** - * Generate a string representation of lines that are skipped in the diff view. - * - * @return string Representation of skipped lines. - */ - public function generateSkippedLines(): string; - /** * Generate a string representation of lines without differences between both versions. * @@ -69,6 +62,23 @@ public function generateLinesEqual(array $changes): string; */ public function generateLinesInsert(array $changes): string; + /** + * Generate a string representation of lines that are skipped in the diff view. + * + * @return string Representation of skipped lines. + */ + public function generateSkippedLines(): string; + + /** + * Generate a string representation of lines with ignored differences between both versions. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Text with no difference. + * @todo: Uncomment once deprecation period is over. + */ + // public function generateLinesIgnore(array $changes): string; + /** * Generate a string representation of lines that are removed from the 2nd version. * From a239f179492ddda3d8531333ee915d85341e3072 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:46:45 +0100 Subject: [PATCH 131/206] Optimize stripping empty/blank lines For calculating the similarity ratio when empty/blank lines are ignored, these lines have to be stripped from the sequences beforehand. The stripped lines are restored after calculation so the class can also be used as sequenceMatcher. --- lib/jblond/Diff/Similarity.php | 100 +++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 12285fe1..b4e2e23d 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -37,6 +37,11 @@ class Similarity extends SequenceMatcher * @var array Count of each unique sequence at version 2. */ private $uniqueCount2; + /** + * @var array Contains the indexes of lines which are stripped from the sequences by Similarity::stripLines(). + * @see Similarity::stripLines() + */ + private $stripped = ['old' => [], 'new' => []]; /** @@ -65,15 +70,22 @@ public function setSeq2($version2) */ public function getSimilarity(int $type = self::CALC_DEFAULT): float { + if ($this->options['ignoreLines']) { + // Backup original sequences and filter non blank lines. + $this->stripLines(); + } + switch ($type) { case self::CALC_FAST: - return $this->getRatioFast(); + $ratio = $this->getRatioFast(); + $this->restoreLines(); + break; case self::CALC_FASTEST: - return $this->getRatioFastest(); + $ratio = $this->getRatioFastest(); + $this->restoreLines(); + break; default: - if ($this->options['ignoreLines']) { - $this->stripLines(); - } + $this->setSequences($this->old, $this->new); $matches = array_reduce( $this->getMatchingBlocks(), function ($carry, $item) { @@ -82,8 +94,44 @@ function ($carry, $item) { 0 ); - return $this->calculateRatio($matches, count($this->old) + count($this->new)); - // TODO: Restore original (un-stripped) versions? + $ratio = $this->calculateRatio($matches, count($this->old) + count($this->new)); + $this->restoreLines(); + $this->setSequences($this->old, $this->new); + } + + return $ratio; + } + + /** + * Strip empty or blank lines from the sequences to compare. + * + */ + private function stripLines(): void + { + foreach (['old', 'new'] as $version) { + // Remove empty lines. + $this->$version = array_filter( + $this->$version, + function ($line, $index) use ($version) { + $sanitizedLine = $line; + if ($this->options['ignoreLines'] == self::DIFF_IGNORE_LINE_BLANK) { + $sanitizedLine = trim($line); + } + + if ($sanitizedLine == '') { + // Store line to be able to restore later. + $this->stripped[$version][$index] = $line; + + return false; + } + + return true; + }, + ARRAY_FILTER_USE_BOTH + ); + + // Re-index sequence. + $this->$version = array_values($this->$version); } } @@ -97,6 +145,7 @@ function ($carry, $item) { private function getRatioFast(): float { if ($this->uniqueCount2 === null) { + // Build unless cached. $this->uniqueCount2 = []; $bLength = count($this->new); for ($iterator = 0; $iterator < $bLength; ++$iterator) { @@ -140,6 +189,15 @@ private function calculateRatio(int $matches, int $length = 0): float return $returnValue; } + private function restoreLines() + { + foreach (['old', 'new'] as $version) { + foreach ($this->stripped[$version] as $index => $line) { + array_splice($this->$version, $index, 0, $line); + } + } + } + /** * Return an upper bound ratio really quickly for the similarity of the strings. * @@ -155,34 +213,6 @@ private function getRatioFastest(): float return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength); } - /** - * Strip empty or blank lines from the sequences to compare. - * - */ - private function stripLines(): void - { - foreach (['old', 'new'] as $version) { - if ($this->options['ignoreLines'] == self::DIFF_IGNORE_LINE_BLANK) { - array_walk( - $this->$version, - function (&$line) { - $line = trim($line); - } - ); - unset($line); - } - - $this->$version = array_filter( - $this->$version, - function ($line) { - return $line != ''; - } - ); - } - - $this->setSequences(array_values($this->old), array_values($this->new)); - } - /** * Helper function to calculate the number of matches for Ratio(). * From 251ccf062a8822d7cc774e2e4b09c3b7dd6dfc53 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:47:19 +0100 Subject: [PATCH 132/206] Refactor variables --- lib/jblond/Diff/SequenceMatcher.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index ef97f172..df042acb 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -344,18 +344,18 @@ public function getOpCodes(): array } if ($this->options['ignoreLines']) { - $part1 = array_slice($this->old, $i, $ai - $i); - $part2 = array_slice($this->new, $j, $bj - $j); + $slice1 = array_slice($this->old, $i, $ai - $i); + $slice2 = array_slice($this->new, $j, $bj - $j); if ($this->options['ignoreLines'] == 2) { array_walk( - $part1, + $slice1, function (&$line) { $line = trim($line); } ); array_walk( - $part2, + $slice2, function (&$line) { $line = trim($line); } @@ -364,8 +364,8 @@ function (&$line) { } if ( - ($tag == 'delete' && implode('', $part1) == '') || - ($tag == 'insert' && implode('', $part2) == '') + ($tag == 'delete' && implode('', $slice1) == '') || + ($tag == 'insert' && implode('', $slice2) == '') ) { $tag = 'ignore'; } From 4dec4adcec6d810b6ef919500e770af740bd5bc8 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Fri, 18 Dec 2020 15:06:45 +0100 Subject: [PATCH 133/206] Add generator for ignored lines --- example/dark-theme.css | 17 +++++ example/styles.css | 17 +++++ lib/jblond/Diff/Renderer/Html/Merged.php | 82 ++++++++++++++--------- lib/jblond/Diff/Renderer/Html/Unified.php | 38 +++++++++++ lib/jblond/Diff/Renderer/Text/Context.php | 2 + 5 files changed, 125 insertions(+), 31 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index fec73959..cd151ac0 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -138,6 +138,19 @@ a, a:visited { color: #272822; } +.DifferencesUnified .ChangeIgnore .Left, +.DifferencesUnified .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesUnified .ChangeIgnore .Left.Ignore { + background: #4B4C57; +} + +.DifferencesUnified .ChangeIgnore .Right.Ignore { + background: #4B4C57; +} + /* * HTML Merged Diff */ @@ -166,3 +179,7 @@ a, a:visited { .DifferencesMerged th.ChangeDelete { background-image: linear-gradient(-45deg, #AAAAAA 0%, #EE9999 100%); } + +.DifferencesMerged th.ChangeIgnore { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #4B4C57 100%); +} diff --git a/example/styles.css b/example/styles.css index 57af6725..a67d04ab 100644 --- a/example/styles.css +++ b/example/styles.css @@ -121,6 +121,19 @@ pre { background: #EE9999; } +.DifferencesUnified .ChangeIgnore .Left, +.DifferencesUnified .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesUnified .ChangeIgnore .Left.Ignore { + background: #F7F7F7; +} + +.DifferencesUnified .ChangeIgnore .Right.Ignore { + background: #F7F7F7; +} + /* * HTML Merged Diff */ @@ -145,3 +158,7 @@ pre { .DifferencesMerged th.ChangeDelete { background-image: linear-gradient(-45deg, #CCCCCC 0%, #EE9999 100%); } + +.DifferencesMerged th.ChangeIgnore { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #F7F7F7 100%); +} diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index b55889bc..dfd89bff 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -43,6 +43,10 @@ class Merged extends MainRenderer implements SubRendererInterface * @var string last block of lines which where removed from version 2. */ private $lastDeleted; + /** + * @var string + */ + private $headerClass = ''; /** * Merged constructor. @@ -101,21 +105,17 @@ public function generateBlockHeader(array $changes): string */ public function generateSkippedLines(): string { - $marker = '…'; - $headerClass = ''; - - if ($this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } - - $this->lastDeleted = null; - - return << - $marker + … … HTML; + + $this->headerClass = ''; + $this->lastDeleted = null; + + return $html; } /** @@ -125,22 +125,20 @@ public function generateSkippedLines(): string */ public function generateLinesEqual(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } - $html .= << - $fromLine + $fromLine $line HTML; + $this->lastDeleted = null; + $this->headerClass = ''; } return $html; @@ -153,22 +151,20 @@ public function generateLinesEqual(array $changes): string */ public function generateLinesInsert(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; - foreach ($changes['changed']['lines'] as $lineNo => $line) { + foreach ($changes['changed']['lines'] as $line) { $this->lineOffset++; $toLine = $changes['base']['offset'] + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } $html .= << - $toLine + $toLine $line HTML; + + $this->headerClass = ''; $this->lastDeleted = null; } @@ -197,6 +193,7 @@ public function generateLinesDelete(array $changes): string } $this->lastDeleted = $title; + $this->headerClass = 'ChangeDelete'; return ''; } @@ -208,14 +205,10 @@ public function generateLinesDelete(array $changes): string */ public function generateLinesReplace(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } // Capture added parts. $addedParts = []; @@ -236,10 +229,11 @@ function ($removedParts) use ($addedParts) { $html .= << - $fromLine + $fromLine $line HTML; + $this->headerClass = ''; $this->lastDeleted = null; } @@ -265,4 +259,30 @@ public function generateDiffFooter(): string { return ''; } + + /** + * @inheritDoc + * + * @return string Modified text. + */ + public function generateLinesIgnore(array $changes): string + { + $baseLineCount = count($changes['base']['lines']); + $changedLineCount = count($changes['changed']['lines']); + + $this->lineOffset -= $baseLineCount; + + $title = "Lines ignored at {$this->options['title2']}: "; + $title .= $changes['changed']['offset'] + 1 . '-' . ($changes['changed']['offset'] + $changedLineCount); + + if ($baseLineCount > $changedLineCount) { + $title = "Lines ignored at {$this->options['title1']}: "; + $title .= $changes['base']['offset'] + 1 . '-' . ($changes['base']['offset'] + $baseLineCount); + } + + $this->lastDeleted = $title; + $this->headerClass = 'ChangeIgnore'; + + return ''; + } } diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 1569e83e..537681d6 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -219,6 +219,44 @@ public function generateLinesReplace(array $changes): string return $html; } + /** + * @inheritDoc + * + * @return string Html code representing table rows showing modified text. + */ + public function generateLinesIgnore(array $changes): string + { + $html = ''; + + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $html .= << + $fromLine + + + $line + + +HTML; + } + + foreach ($changes['changed']['lines'] as $lineNo => $line) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $html .= << + + $toLine + + $line + + +HTML; + } + + return $html; + } + /** * @inheritDoc * diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 7b50dc33..e8b8228e 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -65,6 +65,7 @@ public function render() // Line differences between versions or lines of version 1 are removed from version 2. // Add all operations to diff-view of version 1, except for insert. $filteredGroups = $this->filterGroups($group, 'insert'); + $filteredGroups = $this->filterGroups($filteredGroups, 'ignore'); foreach ($filteredGroups as [$tag, $start1, $end1, $start2, $end2]) { $diff .= $this->tagMap[$tag] . ' ' . implode( @@ -81,6 +82,7 @@ public function render() // Line differences between versions or lines are inserted into version 2. // Add all operations to diff-view of version 2, except for delete. $filteredGroups = $this->filterGroups($group, 'delete'); + $filteredGroups = $this->filterGroups($filteredGroups, 'ignore'); foreach ($filteredGroups as [$tag, $start1, $end1, $start2, $end2]) { $diff .= $this->tagMap[$tag] . ' ' . implode( From 9699b5bf6d05638e73d3a57d9bef78fc45f0cdae Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 08:00:07 +0100 Subject: [PATCH 134/206] Document methods * Add missing documentation. * Fixes and reformatting. --- lib/jblond/Diff.php | 3 +-- lib/jblond/Diff/Renderer/MainRenderer.php | 4 ++-- lib/jblond/Diff/SequenceMatcher.php | 28 ++++++++--------------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index fce45e28..69125dde 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -46,8 +46,7 @@ class Diff private $groupedCodes; /** - * @var array Associative array containing the default options available - * for the diff class and their default value. + * @var array Associative array containing the default options available for the diff class and their default value. * * - context The amount of lines to include around blocks that differ. * - trimEqual Strip blocks of equal lines from the start and end of the text. diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 7399e0c9..64f1aca9 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -124,7 +124,7 @@ protected function renderSequences(): array * 4 - The end line in the second sequence. * * The different types of tags include: - * replace - The string from $startOld to $endOld in $oldText should be replaced by + * replace - The string in $oldText from $startOld to $endOld, should be replaced by * the string in $newText from $startNew to $endNew. * delete - The string in $oldText from $startOld to $endNew should be deleted. * insert - The string in $newText from $startNew to $endNew should be inserted at $startOld in @@ -291,7 +291,7 @@ public function sequenceToArray(string $pattern, string $sequence): array * E.g. *
      *         1234567
-     * OLd => "abcdefg" Start marker inserted at position 3
+     * Old => "abcdefg" Start marker inserted at position 3
      * New => "ab123fg"   End marker inserted at position 6
      * 
* diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 1e5fc92d..a9e40f65 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -46,17 +46,12 @@ class SequenceMatcher private $b2j = []; /** - * @var array - */ - private $options = []; - - /** - * @var null|array + * @var array A list of all of the op-codes for the differences between the compared strings. */ private $opCodes; /** - * @var null|array + * @var array A nested set of arrays for all of the matching sub-sequences the compared strings. */ private $matchingBlocks; @@ -72,9 +67,8 @@ class SequenceMatcher ]; /** - * The constructor. With the sequences being passed, they'll be set for the - * sequence matcher and it will perform a basic cleanup & calculate junk - * elements. + * The constructor. With the sequences being passed, they'll be set for the sequence matcher and it will perform a + * basic cleanup & calculate junk elements. * * @param string|array $old A string or array containing the lines to compare against. * @param string|array $new A string or array containing the lines to compare. @@ -295,11 +289,9 @@ public function getGroupedOpCodes(): array } /** - * Return a list of all of the op codes for the differences between the - * two strings. + * Return a list of all of the op codes for the differences between the two strings. * - * The nested array returned contains an array describing the op code - * which includes: + * The nested array returned contains an array describing the op code which includes: * 0 - The type of tag (as described below) for the op code. * 1 - The beginning line in the first sequence. * 2 - The end line in the first sequence. @@ -366,12 +358,10 @@ public function getOpCodes(): array } /** - * Return a nested set of arrays for all of the matching sub-sequences - * in the strings $a and $b. + * Return a nested set of arrays for all of the matching sub-sequences in compared strings $a and $b. * - * Each block contains the lower constraint of the block in $a, the lower - * constraint of the block in $b and finally the number of lines that the - * block continues for. + * Each block contains the lower constraint of the block in $a, the lower constraint of the block in $b and finally + * the number of lines that the block continues for. * * @return array Nested array of the matching blocks, as described by the function. */ From 576830c45c0fd86365bffa45231feaa83bac0fd5 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 08:02:29 +0100 Subject: [PATCH 135/206] Optimize Sequence renderer * Reduction of cyclomatic complexity. --- lib/jblond/Diff/Renderer/MainRenderer.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 64f1aca9..f4291544 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -146,23 +146,23 @@ protected function renderSequences(): array $oldBlock = $this->formatLines(array_slice($oldText, $startOld, $blockSizeOld)); $newBlock = $this->formatLines(array_slice($newText, $startNew, $blockSizeNew)); - if ($tag == 'equal') { - // Old block equals New block + if ($tag != 'delete' && $tag != 'insert') { + // Old block "equals" New block or is replaced. $blocks[$lastBlock]['base']['lines'] += $oldBlock; $blocks[$lastBlock]['changed']['lines'] += $newBlock; continue; } - if ($tag == 'replace' || $tag == 'delete') { - // Inline differences or old block doesn't exist in the new text. + if ($tag == 'delete') { + // Block of version1 doesn't exist in version2. $blocks[$lastBlock]['base']['lines'] += $oldBlock; + continue; } - if ($tag == 'replace' || $tag == 'insert') { - // Inline differences or the new block doesn't exist in the old text. - $blocks[$lastBlock]['changed']['lines'] += $newBlock; - } + // Block of version2 doesn't exist in version1. + $blocks[$lastBlock]['changed']['lines'] += $newBlock; } + $changes[] = $blocks; } From 7b2ab7977148fc6a372751112acbf0c3e2291b7b Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 08:27:13 +0100 Subject: [PATCH 136/206] Start option to ignore blank lines * Add option `ignoreLines` to control the ability to ignore blank or empty lines. * Add styles of ignored lines to example css. * Add generator for ignored lines to HTML SideBySide renderer. * Add `options` property to the Sequence Mather. * Refactor option `ignoreNewLines` of the Sequence Matcher. * Add flags to define the level of ignoring blank lines. * Add tag `ignored` to the opCodes. * Add method stripLines to Similarity. * Add default option `ignoreLines` to Diff. * Add tests for testing option `ignoreLines` of the Sequence Matcher. * Reformat code. --- example/dark-theme.css | 13 ++++ example/example.php | 1 + example/styles.css | 31 ++++++--- lib/jblond/Diff.php | 26 ++++++-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 66 ++++++++++++++++++++ lib/jblond/Diff/Renderer/MainRenderer.php | 6 ++ lib/jblond/Diff/SequenceMatcher.php | 55 ++++++++++++++-- lib/jblond/Diff/Similarity.php | 31 +++++++++ tests/Diff/SequenceMatcherTest.php | 50 ++++++++++++++- 9 files changed, 259 insertions(+), 20 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index 77669d21..fec73959 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -97,6 +97,19 @@ a, a:visited { background: #EEBB00; } +.DifferencesSideBySide .ChangeIgnore .Left, +.DifferencesSideBySide .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesSideBySide .ChangeIgnore .Left.Ignore { + background: #4B4C57; +} + +.DifferencesSideBySide .ChangeIgnore .Right.Ignore { + background: #4B4C57; +} + /* * HTML Unified Diff */ diff --git a/example/example.php b/example/example.php index fe2cb0cf..e4d7ed04 100644 --- a/example/example.php +++ b/example/example.php @@ -20,6 +20,7 @@ 'trimEqual' => false, 'ignoreWhitespace' => true, 'ignoreCase' => true, + 'ignoreLines' => Diff::DIFF_IGNORE_LINE_EMPTY, ]; // Choose one of the initializations. diff --git a/example/styles.css b/example/styles.css index bbf2ba71..57af6725 100644 --- a/example/styles.css +++ b/example/styles.css @@ -6,8 +6,8 @@ body { } pre { - width: 100%; overflow: auto; + width: 100%; } /* @@ -15,34 +15,34 @@ pre { */ .Differences { - width: 100%; border-collapse: collapse; border-spacing: 0; empty-cells: show; + width: 100%; } .Differences thead th { - text-align: left; - border-bottom: 1px solid #000000; background: #AAAAAA; + border-bottom: 1px solid #000000; color: #000000; padding: 4px; + text-align: left; } .Differences tbody th { - text-align: right; background: #CCCCCC; - width: 4em; - padding: 1px 2px; border-right: 1px solid #000000; - vertical-align: top; font-size: 13px; + padding: 1px 2px; + text-align: right; + vertical-align: top; + width: 4em; } .Differences td { - padding: 1px 2px; font-family: Consolas, monospace; font-size: 13px; + padding: 1px 2px; } .Differences .Skipped { @@ -77,6 +77,19 @@ pre { background: #FFDD88; } +.DifferencesSideBySide .ChangeIgnore .Left, +.DifferencesSideBySide .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesSideBySide .ChangeIgnore .Left.Ignore { + background: #F7F7F7; +} + +.DifferencesSideBySide .ChangeIgnore .Right.Ignore { + background: #F7F7F7; +} + .Differences ins, .Differences del { text-decoration: none; diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 69125dde..c7b0368c 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -28,6 +28,18 @@ */ class Diff { + /** + * Flag to disable ignore of successive empty/blank lines. + */ + public const DIFF_IGNORE_LINE_NONE = 0; + /** + * Flag to ignore successive empty lines. + */ + public const DIFF_IGNORE_LINE_EMPTY = 1; + /** + * Flag to ignore successive blank lines. (Lines which contain no or only non printable characters.) + */ + public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first version to compare. * Each element contains a line of this string. @@ -48,18 +60,20 @@ class Diff /** * @var array Associative array containing the default options available for the diff class and their default value. * - * - context The amount of lines to include around blocks that differ. - * - trimEqual Strip blocks of equal lines from the start and end of the text. - * - ignoreWhitespace When true, tabs and spaces are ignored while comparing. - * The spacing of version1 is leading. - * - ignoreCase When true, character casing is ignored while comparing. - * The casing of version1 is leading. + * - context The amount of lines to include around blocks that differ. + * - trimEqual Strip blocks of equal lines from the start and end of the text. + * - ignoreWhitespace True to ignore differences in tabs and spaces. + * - ignoreCase True to ignore differences in character casing. + * - ignoreLines 0: None. + * 1: Ignore empty lines. + * 2: Ignore blank lines. */ private $defaultOptions = [ 'context' => 3, 'trimEqual' => true, 'ignoreWhitespace' => false, 'ignoreCase' => false, + 'ignoreLines' => self::DIFF_IGNORE_LINE_NONE, ]; /** diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 545d4ed5..e8213f17 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -282,4 +282,70 @@ public function generateDiffFooter(): string { return ''; } + + /** + * @inheritDoc + * + * @return string Html code representing table rows showing ignored text. + */ + public function generateLinesIgnore(array $changes): string + { + $html = ''; + + // Is below comparison result ever false? + if (count($changes['base']['lines']) >= count($changes['changed']['lines'])) { + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $toLine = ' '; + $changedLine = ' '; + if (isset($changes['changed']['lines'][$lineNo])) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $changedLine = $changes['changed']['lines'][$lineNo]; + } + + $html .= << + $fromLine + + $line + + $toLine + + $changedLine + + +HTML; + } + + return $html; + } + + foreach ($changes['changed']['lines'] as $lineNo => $changedLine) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $fromLine = ' '; + $line = ' '; + if (isset($changes['base']['lines'][$lineNo])) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $line = $changes['base']['lines'][$lineNo]; + } + + $line = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $line); + $changedLine = str_replace(["\0", "\1"], $this->options['insertMarkers'], $changedLine); + + $html .= << + $fromLine + + $line + + $toLine + + $changedLine + + +HTML; + } + + return $html; + } } diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index f4291544..b24459f5 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -80,6 +80,10 @@ public function renderOutput(array $changes, object $subRenderer) case 'replace': $output .= $subRenderer->generateLinesReplace($change); break; + case 'ignore': + // TODO: Keep backward compatible with renderers? + $output .= $subRenderer->generateLinesIgnore($change); + break; } $output .= $subRenderer->generateBlockFooter($change); @@ -130,6 +134,8 @@ protected function renderSequences(): array * insert - The string in $newText from $startNew to $endNew should be inserted at $startOld in * $oldText. * equal - The two strings with the specified ranges are equal. + * ignore - The string in $oldText from $startOld to $endOld and + * the string in $newText from $startNew to $endNew are different, but considered to be equal. */ $blockSizeOld = $endOld - $startOld; diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index a9e40f65..595f1b42 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -22,6 +22,18 @@ */ class SequenceMatcher { + /** + * Flag to disable ignore of successive empty/blank lines. + */ + public const DIFF_IGNORE_LINE_NONE = 0; + /** + * Flag to ignore empty lines. + */ + public const DIFF_IGNORE_LINE_EMPTY = 1; + /** + * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) + */ + public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first sequence to compare against. */ @@ -30,6 +42,13 @@ class SequenceMatcher * @var array The second sequence. */ protected $new; + /** + * @var array Associative array containing the options that will be applied for generating the diff. + * The key-value pairs are set at the constructor of this class. + * + * @see SequenceMatcher::setOptions() + */ + protected $options = []; /** * @var string|array Either a string or an array containing a callback function to determine * if a line is "junk" or not. @@ -39,12 +58,10 @@ class SequenceMatcher * @var array Array of characters that are considered junk from the second sequence. Characters are the array key. */ private $junkDict = []; - /** * @var array Array of indices that do not contain junk elements. */ private $b2j = []; - /** * @var array A list of all of the op-codes for the differences between the compared strings. */ @@ -56,14 +73,22 @@ class SequenceMatcher private $matchingBlocks; /** - * @var array + * @var array Associative array containing the default options available for the diff class and their default value. + * + * - context The amount of lines to include around blocks that differ. + * - trimEqual Strip blocks of equal lines from the start and end of the text. + * - ignoreWhitespace True to ignore differences in tabs and spaces. + * - ignoreCase True to ignore differences in character casing. + * - ignoreLines 0: None. + * 1: Ignore empty lines. + * 2: Ignore blank lines. */ private $defaultOptions = [ 'context' => 3, 'trimEqual' => true, 'ignoreWhitespace' => false, 'ignoreCase' => false, - 'ignoreNewLines' => false, + 'ignoreLines' => self::DIFF_IGNORE_LINE_NONE, ]; /** @@ -330,6 +355,28 @@ public function getOpCodes(): array $tag = 'insert'; } + if ($this->options['ignoreLines']) { + $part1 = array_slice($this->old, $i, $ai - $i); + $part2 = array_slice($this->new, $j, $bj - $j); + + if ($this->options['ignoreLines'] == 2) { + array_walk($part1, function (&$line) { + $line = trim($line); + }); + array_walk($part2, function (&$line) { + $line = trim($line); + }); + unset($line); + } + + if ( + ($tag == 'delete' && implode('', $part1) == '') || + ($tag == 'insert' && implode('', $part2) == '') + ) { + $tag = 'ignore'; + } + } + if ($tag) { $this->opCodes[] = [ $tag, diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 0d2ec812..a13c240a 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -71,6 +71,9 @@ public function getSimilarity(int $type = self::CALC_DEFAULT): float case self::CALC_FASTEST: return $this->getRatioFastest(); default: + if ($this->options['ignoreLines']) { + $this->stripLines(); + } $matches = array_reduce( $this->getMatchingBlocks(), function ($carry, $item) { @@ -80,6 +83,7 @@ function ($carry, $item) { ); return $this->calculateRatio($matches, count($this->old) + count($this->new)); + // TODO: Restore original (un-stripped) versions? } } @@ -151,6 +155,33 @@ private function getRatioFastest(): float return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength); } + /** + * Strip empty or blank lines from the sequences to compare. + * + */ + private function stripLines(): void + { + foreach (['old', 'new'] as $version) { + if ($this->options['ignoreLines'] == self::DIFF_IGNORE_LINE_BLANK) { + array_walk( + $this->$version, + function (&$line) { + $line = trim($line); + } + ); + unset($line); + } + + $this->$version = array_filter( + $this->$version, + function ($line) { + return $line != ''; + } + ); + } + + $this->setSequences(array_values($this->old), array_values($this->new)); + } /** * Helper function to calculate the number of matches for Ratio(). diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 0d85127d..939de5d5 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -84,7 +84,7 @@ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() } /** - *T est the opCodes of the differences between version1 and version2 with option ignoreCase enabled. + * Test the opCodes of the differences between version1 and version2 with option ignoreCase enabled. */ public function testGetGroupedOpCodesIgnoreCaseTrue() { @@ -97,4 +97,52 @@ public function testGetGroupedOpCodesIgnoreCaseTrue() $this->assertEquals([], $sequenceMatcher->getGroupedOpCodes()); } + + /** + * Test the opCodes of the differences between version1 and version2 with option ignoreLines set to empty. + */ + public function testGetGroupedOpCodesIgnoreLinesEmpty() + { + // Test with ignoreCase enabled. Both sequences are considered to be the same. + $sequenceMatcher = new SequenceMatcher( + [0, 1, 2, 3], + [0, 1, '', 2, 3], + ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_EMPTY] + ); + + $this->assertEquals( + [ + [ + ['equal', 0, 2, 0, 2], + ['ignore', 2, 2, 2, 3], + ['equal', 2, 4, 3, 5], + ], + ], + $sequenceMatcher->getGroupedOpCodes() + ); + } + + /** + * Test the opCodes of the differences between version1 and version2 with option ignoreLines set to blank. + */ + public function testGetGroupedOpCodesIgnoreLinesBlank() + { + // Test with ignoreCase enabled. Both sequences are considered to be the same. + $sequenceMatcher = new SequenceMatcher( + [0, 1, 2, 3], + [0, 1, "\t", 2, 3], + ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_BLANK] + ); + + $this->assertEquals( + [ + [ + ['equal', 0, 2, 0, 2], + ['ignore', 2, 2, 2, 3], + ['equal', 2, 4, 3, 5], + ], + ], + $sequenceMatcher->getGroupedOpCodes() + ); + } } From d0cede314d53674b162c8224fd5f3e5b2d491c34 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 12:01:22 +0100 Subject: [PATCH 137/206] Optimize constant usage Instead of defining constants with the same name and values at different namespaces, they're now defined at an interface which can be shared among classes by implementing this interface. --- lib/jblond/Diff.php | 15 ++---------- lib/jblond/Diff/ConstantsInterface.php | 33 ++++++++++++++++++++++++++ lib/jblond/Diff/SequenceMatcher.php | 32 ++++++++++--------------- 3 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 lib/jblond/Diff/ConstantsInterface.php diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index c7b0368c..f166ace7 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -5,6 +5,7 @@ namespace jblond; use InvalidArgumentException; +use jblond\Diff\ConstantsInterface; use jblond\Diff\SequenceMatcher; use jblond\Diff\Similarity; use OutOfRangeException; @@ -26,20 +27,8 @@ * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ -class Diff +class Diff implements ConstantsInterface { - /** - * Flag to disable ignore of successive empty/blank lines. - */ - public const DIFF_IGNORE_LINE_NONE = 0; - /** - * Flag to ignore successive empty lines. - */ - public const DIFF_IGNORE_LINE_EMPTY = 1; - /** - * Flag to ignore successive blank lines. (Lines which contain no or only non printable characters.) - */ - public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first version to compare. * Each element contains a line of this string. diff --git a/lib/jblond/Diff/ConstantsInterface.php b/lib/jblond/Diff/ConstantsInterface.php new file mode 100644 index 00000000..121e7cb6 --- /dev/null +++ b/lib/jblond/Diff/ConstantsInterface.php @@ -0,0 +1,33 @@ + + * @copyright (c) 2020 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.3.0 + * @link https://github.com/JBlond/php-diff + */ +interface ConstantsInterface +{ + /** + * Flag to disable ignore of successive empty/blank lines. + */ + public const DIFF_IGNORE_LINE_NONE = 0; + /** + * Flag to ignore empty lines. + */ + public const DIFF_IGNORE_LINE_EMPTY = 1; + /** + * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) + */ + public const DIFF_IGNORE_LINE_BLANK = 2; + +} diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 595f1b42..19ea8fa9 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -20,20 +20,8 @@ * @version 2.3.0 * @link https://github.com/JBlond/php-diff */ -class SequenceMatcher +class SequenceMatcher implements ConstantsInterface { - /** - * Flag to disable ignore of successive empty/blank lines. - */ - public const DIFF_IGNORE_LINE_NONE = 0; - /** - * Flag to ignore empty lines. - */ - public const DIFF_IGNORE_LINE_EMPTY = 1; - /** - * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) - */ - public const DIFF_IGNORE_LINE_BLANK = 2; /** * @var array The first sequence to compare against. */ @@ -360,12 +348,18 @@ public function getOpCodes(): array $part2 = array_slice($this->new, $j, $bj - $j); if ($this->options['ignoreLines'] == 2) { - array_walk($part1, function (&$line) { - $line = trim($line); - }); - array_walk($part2, function (&$line) { - $line = trim($line); - }); + array_walk( + $part1, + function (&$line) { + $line = trim($line); + } + ); + array_walk( + $part2, + function (&$line) { + $line = trim($line); + } + ); unset($line); } From 0849a1e4c9ebebf017d49f078e796bdfd0d67a29 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 10 Dec 2020 12:08:25 +0100 Subject: [PATCH 138/206] Document option `ignoreLines` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5cbc6f8a..3ad115ef 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,8 @@ $options = [ 'ignoreWhitespace' => true, 'ignoreCase' => true, 'context' => 2, - 'cliColor' => true // for cli output + 'cliColor' => true, // for cli output + 'ignoreLines' => Diff::DIFF_IGNORE_LINE_BLANK, ]; // Initialize the diff class. @@ -140,7 +141,6 @@ at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge-for-php-dif ## Todo -* Ability to ignore blank line changes * 3 way diff support ## Contributors From f494b3abd15c55a5050498d95c1222c522191407 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:28:05 +0100 Subject: [PATCH 139/206] Add deprecation notice for missing method If a used sub renderer, which extends the main renderer, a deprecation notice will be thrown when the sub renderer is missing method `generateLinesIgnore`. --- lib/jblond/Diff/Renderer/MainRenderer.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index b24459f5..05e71cf2 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -65,7 +65,23 @@ public function renderOutput(array $changes, object $subRenderer) strlen($this->options['equalityMarkers'][1]) ); + $deprecationTriggered = false; foreach ($blocks as $change) { + if ( + $subRenderer instanceof MainRenderer && + !method_exists($subRenderer, 'generateLinesIgnore') && + $change['tag'] == 'ignore' + ) { + if (!$deprecationTriggered) { + trigger_error( + 'The use of a subRenderer without method generateLinesIgnore() is deprecated!', + E_USER_DEPRECATED + ); + $deprecationTriggered = true; + } + $change['tag'] = + (count($change['base']['lines']) > count($change['changed']['lines'])) ? 'delete' : 'insert'; + } $output .= $subRenderer->generateBlockHeader($change); switch ($change['tag']) { case 'equal': From 6ef61bc7518d9728a9bf405e9928eb105cbe913d Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:38:24 +0100 Subject: [PATCH 140/206] Add method `generateLinesIgnore` Currently the line is commented out, because the method is not required until the deprecation period for missing this method is over. --- .../Diff/Renderer/SubRendererInterface.php | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index a3ea1bbb..e468843d 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -41,13 +41,6 @@ public function generateDiffHeader(): string; */ public function generateBlockHeader(array $changes): string; - /** - * Generate a string representation of lines that are skipped in the diff view. - * - * @return string Representation of skipped lines. - */ - public function generateSkippedLines(): string; - /** * Generate a string representation of lines without differences between both versions. * @@ -69,6 +62,23 @@ public function generateLinesEqual(array $changes): string; */ public function generateLinesInsert(array $changes): string; + /** + * Generate a string representation of lines that are skipped in the diff view. + * + * @return string Representation of skipped lines. + */ + public function generateSkippedLines(): string; + + /** + * Generate a string representation of lines with ignored differences between both versions. + * + * @param array $changes Contains the op-codes about the changes between two blocks of text. + * + * @return string Text with no difference. + * @todo: Uncomment once deprecation period is over. + */ + // public function generateLinesIgnore(array $changes): string; + /** * Generate a string representation of lines that are removed from the 2nd version. * From ea6a2e4554ab0ab24271ad3770b53e1b2e0080b7 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:46:45 +0100 Subject: [PATCH 141/206] Optimize stripping empty/blank lines For calculating the similarity ratio when empty/blank lines are ignored, these lines have to be stripped from the sequences beforehand. The stripped lines are restored after calculation so the class can also be used as sequenceMatcher. --- lib/jblond/Diff/Similarity.php | 100 +++++++++++++++++++++------------ 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index a13c240a..eef9b447 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -37,6 +37,11 @@ class Similarity extends SequenceMatcher * @var array Count of each unique sequence at version 2. */ private $uniqueCount2; + /** + * @var array Contains the indexes of lines which are stripped from the sequences by Similarity::stripLines(). + * @see Similarity::stripLines() + */ + private $stripped = ['old' => [], 'new' => []]; /** @@ -65,15 +70,22 @@ public function setSeq2($version2) */ public function getSimilarity(int $type = self::CALC_DEFAULT): float { + if ($this->options['ignoreLines']) { + // Backup original sequences and filter non blank lines. + $this->stripLines(); + } + switch ($type) { case self::CALC_FAST: - return $this->getRatioFast(); + $ratio = $this->getRatioFast(); + $this->restoreLines(); + break; case self::CALC_FASTEST: - return $this->getRatioFastest(); + $ratio = $this->getRatioFastest(); + $this->restoreLines(); + break; default: - if ($this->options['ignoreLines']) { - $this->stripLines(); - } + $this->setSequences($this->old, $this->new); $matches = array_reduce( $this->getMatchingBlocks(), function ($carry, $item) { @@ -82,8 +94,44 @@ function ($carry, $item) { 0 ); - return $this->calculateRatio($matches, count($this->old) + count($this->new)); - // TODO: Restore original (un-stripped) versions? + $ratio = $this->calculateRatio($matches, count($this->old) + count($this->new)); + $this->restoreLines(); + $this->setSequences($this->old, $this->new); + } + + return $ratio; + } + + /** + * Strip empty or blank lines from the sequences to compare. + * + */ + private function stripLines(): void + { + foreach (['old', 'new'] as $version) { + // Remove empty lines. + $this->$version = array_filter( + $this->$version, + function ($line, $index) use ($version) { + $sanitizedLine = $line; + if ($this->options['ignoreLines'] == self::DIFF_IGNORE_LINE_BLANK) { + $sanitizedLine = trim($line); + } + + if ($sanitizedLine == '') { + // Store line to be able to restore later. + $this->stripped[$version][$index] = $line; + + return false; + } + + return true; + }, + ARRAY_FILTER_USE_BOTH + ); + + // Re-index sequence. + $this->$version = array_values($this->$version); } } @@ -97,6 +145,7 @@ function ($carry, $item) { private function getRatioFast(): float { if ($this->uniqueCount2 === null) { + // Build unless cached. $this->uniqueCount2 = []; $bLength = count($this->new); for ($iterator = 0; $iterator < $bLength; ++$iterator) { @@ -140,6 +189,15 @@ private function calculateRatio(int $matches, int $length = 0): float return $returnValue; } + private function restoreLines() + { + foreach (['old', 'new'] as $version) { + foreach ($this->stripped[$version] as $index => $line) { + array_splice($this->$version, $index, 0, $line); + } + } + } + /** * Return an upper bound ratio really quickly for the similarity of the strings. * @@ -155,34 +213,6 @@ private function getRatioFastest(): float return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength); } - /** - * Strip empty or blank lines from the sequences to compare. - * - */ - private function stripLines(): void - { - foreach (['old', 'new'] as $version) { - if ($this->options['ignoreLines'] == self::DIFF_IGNORE_LINE_BLANK) { - array_walk( - $this->$version, - function (&$line) { - $line = trim($line); - } - ); - unset($line); - } - - $this->$version = array_filter( - $this->$version, - function ($line) { - return $line != ''; - } - ); - } - - $this->setSequences(array_values($this->old), array_values($this->new)); - } - /** * Helper function to calculate the number of matches for Ratio(). * From 9d46847558b44d2239e53772b36d7d0795713659 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Thu, 17 Dec 2020 07:47:19 +0100 Subject: [PATCH 142/206] Refactor variables --- lib/jblond/Diff/SequenceMatcher.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 19ea8fa9..545fed9c 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -344,18 +344,18 @@ public function getOpCodes(): array } if ($this->options['ignoreLines']) { - $part1 = array_slice($this->old, $i, $ai - $i); - $part2 = array_slice($this->new, $j, $bj - $j); + $slice1 = array_slice($this->old, $i, $ai - $i); + $slice2 = array_slice($this->new, $j, $bj - $j); if ($this->options['ignoreLines'] == 2) { array_walk( - $part1, + $slice1, function (&$line) { $line = trim($line); } ); array_walk( - $part2, + $slice2, function (&$line) { $line = trim($line); } @@ -364,8 +364,8 @@ function (&$line) { } if ( - ($tag == 'delete' && implode('', $part1) == '') || - ($tag == 'insert' && implode('', $part2) == '') + ($tag == 'delete' && implode('', $slice1) == '') || + ($tag == 'insert' && implode('', $slice2) == '') ) { $tag = 'ignore'; } From 6b8662e35f0967b4fffe7fa721d9166e2cd85cb1 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Fri, 18 Dec 2020 15:06:45 +0100 Subject: [PATCH 143/206] Add generator for ignored lines --- example/dark-theme.css | 17 +++++ example/styles.css | 17 +++++ lib/jblond/Diff/Renderer/Html/Merged.php | 82 ++++++++++++++--------- lib/jblond/Diff/Renderer/Html/Unified.php | 38 +++++++++++ lib/jblond/Diff/Renderer/Text/Context.php | 2 + 5 files changed, 125 insertions(+), 31 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index fec73959..cd151ac0 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -138,6 +138,19 @@ a, a:visited { color: #272822; } +.DifferencesUnified .ChangeIgnore .Left, +.DifferencesUnified .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesUnified .ChangeIgnore .Left.Ignore { + background: #4B4C57; +} + +.DifferencesUnified .ChangeIgnore .Right.Ignore { + background: #4B4C57; +} + /* * HTML Merged Diff */ @@ -166,3 +179,7 @@ a, a:visited { .DifferencesMerged th.ChangeDelete { background-image: linear-gradient(-45deg, #AAAAAA 0%, #EE9999 100%); } + +.DifferencesMerged th.ChangeIgnore { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #4B4C57 100%); +} diff --git a/example/styles.css b/example/styles.css index 57af6725..a67d04ab 100644 --- a/example/styles.css +++ b/example/styles.css @@ -121,6 +121,19 @@ pre { background: #EE9999; } +.DifferencesUnified .ChangeIgnore .Left, +.DifferencesUnified .ChangeIgnore .Right { + background: #FBF2BF; +} + +.DifferencesUnified .ChangeIgnore .Left.Ignore { + background: #F7F7F7; +} + +.DifferencesUnified .ChangeIgnore .Right.Ignore { + background: #F7F7F7; +} + /* * HTML Merged Diff */ @@ -145,3 +158,7 @@ pre { .DifferencesMerged th.ChangeDelete { background-image: linear-gradient(-45deg, #CCCCCC 0%, #EE9999 100%); } + +.DifferencesMerged th.ChangeIgnore { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #F7F7F7 100%); +} diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index ab755774..7492d9f9 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -43,6 +43,10 @@ class Merged extends MainRenderer implements SubRendererInterface * @var string last block of lines which where removed from version 2. */ private $lastDeleted; + /** + * @var string + */ + private $headerClass = ''; /** * Merged constructor. @@ -101,21 +105,17 @@ public function generateBlockHeader(array $changes): string */ public function generateSkippedLines(): string { - $marker = '…'; - $headerClass = ''; - - if ($this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } - - $this->lastDeleted = null; - - return << - $marker + … … HTML; + + $this->headerClass = ''; + $this->lastDeleted = null; + + return $html; } /** @@ -125,22 +125,20 @@ public function generateSkippedLines(): string */ public function generateLinesEqual(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } - $html .= << - $fromLine + $fromLine $line HTML; + $this->lastDeleted = null; + $this->headerClass = ''; } return $html; @@ -153,22 +151,20 @@ public function generateLinesEqual(array $changes): string */ public function generateLinesInsert(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; - foreach ($changes['changed']['lines'] as $lineNo => $line) { + foreach ($changes['changed']['lines'] as $line) { $this->lineOffset++; $toLine = $changes['base']['offset'] + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } $html .= << - $toLine + $toLine $line HTML; + + $this->headerClass = ''; $this->lastDeleted = null; } @@ -197,6 +193,7 @@ public function generateLinesDelete(array $changes): string } $this->lastDeleted = $title; + $this->headerClass = 'ChangeDelete'; return ''; } @@ -208,14 +205,10 @@ public function generateLinesDelete(array $changes): string */ public function generateLinesReplace(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; - } // Capture added parts. $addedParts = []; @@ -236,10 +229,11 @@ function ($removedParts) use ($addedParts) { $html .= << - $fromLine + $fromLine $line HTML; + $this->headerClass = ''; $this->lastDeleted = null; } @@ -265,4 +259,30 @@ public function generateDiffFooter(): string { return ''; } + + /** + * @inheritDoc + * + * @return string Modified text. + */ + public function generateLinesIgnore(array $changes): string + { + $baseLineCount = count($changes['base']['lines']); + $changedLineCount = count($changes['changed']['lines']); + + $this->lineOffset -= $baseLineCount; + + $title = "Lines ignored at {$this->options['title2']}: "; + $title .= $changes['changed']['offset'] + 1 . '-' . ($changes['changed']['offset'] + $changedLineCount); + + if ($baseLineCount > $changedLineCount) { + $title = "Lines ignored at {$this->options['title1']}: "; + $title .= $changes['base']['offset'] + 1 . '-' . ($changes['base']['offset'] + $baseLineCount); + } + + $this->lastDeleted = $title; + $this->headerClass = 'ChangeIgnore'; + + return ''; + } } diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index b69f6cff..63dff3c8 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -219,6 +219,44 @@ public function generateLinesReplace(array $changes): string return $html; } + /** + * @inheritDoc + * + * @return string Html code representing table rows showing modified text. + */ + public function generateLinesIgnore(array $changes): string + { + $html = ''; + + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1; + $html .= << + $fromLine + + + $line + + +HTML; + } + + foreach ($changes['changed']['lines'] as $lineNo => $line) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; + $html .= << + + $toLine + + $line + + +HTML; + } + + return $html; + } + /** * @inheritDoc * diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 6fae3bbf..ab4e3113 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -65,6 +65,7 @@ public function render() // Line differences between versions or lines of version 1 are removed from version 2. // Add all operations to diff-view of version 1, except for insert. $filteredGroups = $this->filterGroups($group, 'insert'); + $filteredGroups = $this->filterGroups($filteredGroups, 'ignore'); foreach ($filteredGroups as [$tag, $start1, $end1, $start2, $end2]) { $diff .= $this->tagMap[$tag] . ' ' . implode( @@ -81,6 +82,7 @@ public function render() // Line differences between versions or lines are inserted into version 2. // Add all operations to diff-view of version 2, except for delete. $filteredGroups = $this->filterGroups($group, 'delete'); + $filteredGroups = $this->filterGroups($filteredGroups, 'ignore'); foreach ($filteredGroups as [$tag, $start1, $end1, $start2, $end2]) { $diff .= $this->tagMap[$tag] . ' ' . implode( From 0a6a84f8289463875289131b2ec61e35e9b6c539 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 26 Jan 2021 11:41:19 +0100 Subject: [PATCH 144/206] Add DigiLive/gitChangelog for change log generation --- composer.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 3005a1b3..7925aa52 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,8 @@ "phpunit/phpunit": "^8 || ^9", "squizlabs/php_codesniffer": "*", "phpmd/phpmd": "2.*", - "jblond/php-cli": "^1.0" + "jblond/php-cli": "^1.0", + "digilive/git-changelog": "^1" }, "suggest": { "jblond/php-cli": "^1.0" @@ -53,12 +54,14 @@ "phpunit": "phpunit", "php_src": "phpcs --standard=phpcs.xml -s -p --colors ./lib/", "php_test": "phpcs --standard=phpcs.xml -s -p --colors ./tests/", - "phpmd": "phpmd ./ ansi cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor" + "phpmd": "phpmd ./ ansi cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor", + "changelog": "php generateChangelog.php" }, "scripts-descriptions": { "phpunit": "Run PHPUnit tests", "php_src": "Run code sniffer on lib directory", "php_test": "Run code sniffer on tests directory", - "phpmd": "Run php mess detector" + "phpmd": "Run php mess detector", + "changelog": "generate changelog from commits" } } From c9881d30785b431b55aada6a7e76ce9ed0984b94 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 26 Jan 2021 11:42:43 +0100 Subject: [PATCH 145/206] Document Update Changelog --- changelog.md | 552 +++++++++++++++++++++++++++++++----------- generateChangelog.php | 13 + 2 files changed, 425 insertions(+), 140 deletions(-) create mode 100644 generateChangelog.php diff --git a/changelog.md b/changelog.md index e37692c1..836fe924 100644 --- a/changelog.md +++ b/changelog.md @@ -1,140 +1,412 @@ -# changelog - -## next - -* Refactored HTML Inline renderer to HTML Unified. - -* The non table unified renderer is cut from the code. - -## 2.3.0 (2020-11-19) - -* Add: Change log. - -* Fix: Html SideBySide renders equal lines of version 1 at both sides (Option - ignoreCase). - -* Fix: Second parameter of string repeat function minimizes to 0. - -* Fix: #60 - Unified Cli renderer options incompatible with Main renderer - options - -* Fix: #64 - Calculation of maxLineMarkerWidth independent of input format. - -* Add: Similarity calculation - -* Add: New marking levels for inline differences - -* Add: Html merged renderer - -## 2.2.1 (2020-08-06) - -* Fix: #58 - Side by side diff shows empty diff - -## 2.2.0 (2020-07-23) - -* Add: Option for a custom override renderer. #53 - -* Add: No output when there are no differences between the compared strings / - files. #52 #54 - -## 2.1.1 (2020-07-17) - -* Fix: #50 - Renderers produce output with equal texts, while they shouldn't. - -## 2.1.0 (2020-07-13) - -* Add: Cli uncolored output. This allows it to be piped. - -## 2.0.0 (2020-07-09) - -* Add: Unified Commandline colored output. -* Change: switch to semantic versioning. - -## 1.18 (2020-07-01) - -* Add: A dark theme to the example. -* Fix: Avoid variables with short names (some). - -## 1.17 (2020-06-08) - -* Fix #32 - Side by side diff shows only partially all deleted lines. - -## 1.16 (2020-03-02) - -* Features - * Add: option trimEqual. - -* Fixes - * Fix PHPMD Violation. - * Code Optimization, cleanup, refactoring and commenting. - -## 1.15 (2020-01-24) - -* Add: New Unified HTML. -* Fix: Code clean up. - -## 1.14 (2019-12-03) - -* Fix: Remove some old dead code. - -## 1.13 (2019-10-08) - -* Change: Switch to PSR12. - -## 1.12 (2019-03-18) - -* Change: Update Composer Configuration. -* Fix: PSR-2 conventions. - -## 1.11 (2019-02-22) - -* Fix: Code clean up. -* Fix: Composer autoloader for unit tests. - -## 1.10 (2019-02-20) - -* Fix: Code clean up. - -## 1.9 (2019-02-19) - -* Fix: Code clean up. - -## 1.8 - -* Change: Update Readme and bumping versions. - -* Fix: Moved include of Autoloader from the constructor to global space for - HtmlArray unit test. - -## 1.7 - -* Fix: PSR-2 code alignment. - -## 1.6 - -* Change: Bump required version of PHP to v7.1. -* Add: Return type hinting. - -## 1.5 (2019-01-15) - -* Fix: Autoloader naming issues. - -## 1.4 (2019-01-14) - -* Add: PSR-4 namespace support. - -## 1.3 (2019-01-11) - -* Fix: PHP methods contained too much logic. That has been simplified. - -## 1.2 (2018-01-23) - -* Add: Support for custom titles. - -## 1.1 (2017-05-06) - -* Fix: Wrong highlight area for chinese characters. - -## 1.0 - -* Initial version. +# Changelog + +## Upcoming changes (Undetermined) + +* Add DigiLive/gitChangelog for change log generation (0a6a84f) +* Bump library version (013f862) +* Cut HTML Unified Renderer (1ba255f) +* Document PhpUnit Similarity Test (7ec484c) +* Document Update Changelog (1646605) +* Document disabled inspection (909e195) +* Document generateLinesEqual() (8a193c9) +* Document methods (94c8bd5) +* Fix #83 - Lines not properly marked (6fcafe1) +* Fix HTML Merged Renderer (07da484) +* Fix constructor DocBlocks (b13ff84) +* Fix html syntax error (11ec623) +* Fix namespace and unused code (77a7b59) +* Fix probably undefined variable (3954a2b) +* Fix property visibility and method docBlocks (3bc0839) +* Fix property visibility and unused code (34a032f) +* Fix redundant and unused code. (73f6776) +* Refactor HTML Inline Renderer to HTML Unified (cf516d1) +* Refactor callbacks and if/else expressions. (79d989d) +* Refactor if/else statements (5ba19f7) +* Refactor static method calls to non-static (035cd33) +* Reformat library code (8e9735f) +* Require PHPUnit 8 or 9. (0bd0bd2) +* Update Key words (5bd040c) +* Update changelog.md (fb50095) +* add phpunit config file (7382ee8) +* exclude not needed files for zip / composer export (08c9244) +* keep assets for readme file (8edb202) +* upgrade required PHP version to 7.3 (8962a2b) + +## v2.3.0 (2020-11-19) + +* Add Html Merged renderer. (d70eaf6) +* Add PhpUnit test for html merged renderer (4512c03) +* Add calculation for similarity ratio. (3e4bbe6) +* Add choosing marking levels to html example (c27035a) +* Add new marking levels for inline differences (75358da) +* Document properties and constructor (6c95ccd) +* Fix: Html SideBySide renders equal lines of version 1 at both sides. (ccfc465) +* Fix Merged::generateLinesReplace() (cef85b5) +* Fix PSR-4 Auto loading Typo (6e2ad47) +* Fix PhpUnit test (3ccaa10) +* Fix Undefined offset notice (b10fd38) +* Fixes #64 - maxLineMarkerWidth only calculated for input format plain. (c5f6d72) +* Fix generateBlockHeader docBlocks (b5cfbd5) +* Fix visibility of removed lines (ec0918b) +* Refactor sample text (6b9661c) +* Simplify code (276d84d) +* Simplify options merge (24c8bb9) +* Update Changelog Increase version number (a4e5058) +* Update changelog.md (491d539) +* add changelog (4b7a56f) +* add changelog to Readme file (09aea70) +* add date (c64c0cc) +* add declaration (cff7db1) +* add wiki links to README.md (ccd5a6d) +* change cli colors option from simple to true (38864db) +* check only if option is set (98781fd) +* check type of option (fbccaf4) +* correct typos (df270f5) +* github markdown urls should not contain ")" (1a71822) +* if option is true, not only if it is set (8098c71) +* merge options instead of set them directly (0e3fd21) +* update README file (0a16fd1, eb382fa) +* update changelog (98ac4c5) + +## v2.2.1 (2020-08-06) + +* Fix #58 - Side by side diff shows empty diff (0946d59, 369b146, 02695d5) +* add to dev for unit tests (acd12cb) +* make jblond/php-cli optional (0346948) +* pcre is needed (147b89e) +* return direct from isset (0822804) +* update readme file (2bb7a09) +* update version number (e6812d0) + +## v2.2.0 (2020-07-23) + +* Change rendering flow. (c323f77) +* Fix code quality. (0ef6def) +* Resolve #52 and fixes. (2be0c51, fda4852) +* add line for readabiltity (e28511b) +* increase version number for the next release (6acb81e) + +## v2.1.1 (2020-07-17) + +* Fix #50. (47d6288) +* add unit test for cli output (0c75757) +* correct typo (4f2b31a) +* increase version number for #50 bug fix release (eda111b) +* move images to assets directory (fbea75e) +* remove empty line (65f2aa4) +* remove second empty last line (af5b2c5) +* update doc (8555fdd, 66e8de5) +* update doc in unit test (7ec0dbb) + +## v2.1.0 (2020-07-13) + +* Following up #42. (f3a8f0d) +* add plain output for cli (d7bbe12) +* follow up https://github.com/JBlond/php-diff/pull/42 (8586225) +* refactor variable names (b48cbe6) +* remove not used variable (1ecdac5) +* remove output example (89602af) +* remove some complexity (a1e61fb) + +## v2.0.0 (2020-07-09) + +* Add Cli color support (4192d8b) +* Add dark theme example (6f41894) +* Add example picture (ee37a28) +* Correct typo in wording (99150a4) +* Hide images by default, to have a shorter readme (5cd9113) +* Update README.md (bae640e, 9c4e77c) +* Update README.md Requirements (fe63c57) +* Update background color (3d82cd2) +* add composer scripts descriptions. Update key words (6bfd4f9) +* add missing tag from merge (639f3cc) +* adjust color (ae6cfe4) +* a new line for each change (12950b2, d3b5ec9) +* change composer require for package (ede59fb) +* correct some markdown warnings in README.md (d3de726) +* increase version number (f44ee81) +* reduce Cyclomatic Complexity (8fcc5fb) +* remove Autoloader.php and have only the one from composer (7a49d76) +* remove from merge conflict (d00d224) +* resize image (e1126f5) +* revert that change (e93d249, f1d90c2) +* show one picture as a preview (ab6eb28, 606ff22) +* update Readme (7e6e125) +* update example with full class path (37088ab) + +## v1.18 (2020-07-01) + +* Avoid variables with short names (70e327b) +* add author (e132cdb) +* add dark theme example (b9d0ef6) +* ignore phpstorm settings (19bdb97) +* increase version number (69b7e07) +* remove exclude (cac11d6) + +## v1.17 (2020-06-08) + +* Code Fixes. (dd07685) +* Fix issue #32. (7ef67e6) +* Property initializer is redundant (bbd3f38) +* Update LICENSE (8c2c88a) +* change to new array format (1da5da2, 2090f98) +* chris did not add this file at all (dc68ae0) +* fix typo in phpdoc (db259fc) +* increase version number for release (5912a3f) +* remove used property (6de7325) +* update readme example (217c513) +* use SPL (0466227) + +## v1.16 (2020-03-02) + +* Add composer package PHP Mess Detector v2.* (3e527d1) +* Add contributor to author lists. (4c2cbb7, c11b4ba) +* Add trimEqual option. (98d993e) +* Add types of elements for renderer (4d1b4a0, 83b4104) +* Change example texts. (cd653c2) +* Code Optimization, cleanup, refactoring and commenting. (c29a8aa, 0e230e3) +* Code fixes, optimization, cleanup, refactoring and commenting. (54892e1) +* Fix PHPMD Violation. (5d03eae) +* Fix expected value for HtmlRendererTest::testUnified() (fbda2bd) +* Line exceeds 120 characters; contains 121 (0b3dea0) +* Remove formatting of "collapsed block" indicator. (3d33000) +* Update README.md (b2dd9e9, 43ba9e0) +* import (66af1f7) +* phpmd warning: The method render uses an else expression (df413d4) +* remove TODO warning (55a4eba) +* remove some warnings from https://insight.symfony.com/projects/aa609edb-cdb1-45cf-ad51-afbdab48f6a1/analyses/56 (2fe16f9) +* update Version number (f8d5fe2) + +## v1.15 (2020-01-24) + +* Code Fixes, Optimization, cleanup, refactoring and commenting. (78a1658) +* Code Fixes. (d1c724c) +* Code Optimization, cleanup, refactoring and commenting. (7748252, c017af5, c984365, 6bc3f7c, 0d8c872) +* Code Style Fixes. (5e7ddf3) +* Code cleanup, bumped required PHP version to >= 7.2 and updated readme. (71b63a1) +* Code commenting. (e6cd9e0) +* Code reformatting and minor optimization, Typo fixes (7f87ce3, 3a1c258) +* Correct paths for composer run-script phpunit (6bfc5e7) +* HTML Unified Renderer added, Code optimization, cleanup and commenting. (0c5e1a4) +* PHPUnit test added for diff-view renderers. (122a72c) +* PHPUnit test for HTML Unified Renderer added. (611dc21) +* PSR12 fixes (e227356, 2a01869) +* PSR12.Files.DeclareStatement (7c75b07) +* Preperation for local developement. (4352698) +* Update PHPUnit tests (3b2c367) +* fix notation (795fe20) +* ignore composer lock file (ec0e0a6) +* raise version number (9700db7) +* remove blank line (35cd1eb) +* remove list, but use an array (aed258f, 84941b3) +* valid html can have no white space before the first tag (42b1ace) + +## v1.14 (2019-12-03) + +* prepare 1.14 (fab2a43) +* remove unused function (49e2c3a) +* some code clean up (1cc43c3) + +## v1.13 (2019-10-08) + +* Use PSR 12 (039fab0) +* prepare 1.13 (1cdd3dc) +* update phpunit (d883a00) + +## v1.12 (2019-03-18) + +* PHP Mess Detector Avoid unused private methods such as '__autoload'. even if not correct (e0f6842) +* add more files to .gitignore (27b21eb) +* add phpunit test to composer (e8a3f71) +* add tests (6d165a6) +* increase version number (f755fce) +* remove BOM (1dd40d8) +* remove files from .gitignore (2f11a9d) +* tabs vs space (745b331) +* update Readme with example code (3396d35) + +## v1.11 (2019-02-22) + +* avoid short variable names (5d07754) +* increase version number (aa4cf3b) +* license is in an external file. (7468872) +* remove dead code (5ad1cb3) +* remove idea (0f27cc1) +* update (93663b5) +* update composer file (autoload) (288f33c) +* update doc (8c56a2d) +* update example (718ec11) +* update phpdoc (33f71f1) + +## v1.10 (2019-02-20) + +* PSR2 indention (ef0f9ae) +* avoid short variable names (f75c870, 8a699ef, e940dd9, 7482c2b, 0a7fff5) +* avoid short variable names fix codacy warnings (4428ffe) +* fix codacy warnings of unused functions (8037d99) +* fix example (9207f73) +* ignore ide files (cd49cec) +* increase version (8e72ea7) +* remove else (3af88d2) +* remove unsued function (96f028c) +* update example (c6977f3) +* update package names (f21937d) +* update readme (247ddb1) + +## v1.9 (2019-02-19) + +* add comment like in the other file (8b68a5d) +* add stronger type hinting (3a6ef42) +* deduplicate render code (5967e91) +* increase version number (8f19707) +* lib\jblond\Diff\SequenceMatcher.php:622 PhanTypeMismatchDimFetch When fetching an array index from a value of type array|array{}, found an array index of type '0', but expected the index to be of type int (1c537ff) +* longer variable names (68e517a) +* stronger type hinting (9cc5cfb) + +## v1.8 (2019-02-13) + +* PSR1.Files.SideEffects.FoundWithSymbols (7699e4f) +* Revert "PSR1.Files.SideEffects.FoundWithSymbols" make unit test work again (5231883) +* change PHP version (d36ca2b) +* fix test (b4cfce1) +* increase version number (7d22093) +* refer to License file (6311fd4) +* relative path to pictures (3df01cc) +* short variable name (7c62963, c8ec74b) +* update version string (5d22b81) + +## v1.7 (2019-01-19) + +* add code sniffer PSR2 file (6fa3c76) +* adding curly brackets (148e787) +* done. support for PSR4 is given (aea2437) +* fix PSR1.Files.SideEffects.FoundWithSymbols (fe21917) +* fix tabs (354bf5c) +* remove useless use import (4113efe) +* return type match (53502f2) +* tabs vs space (f326877) + +## v1.6 (2019-01-19) + +* EOF (bb7b472, 77323c6) +* Fix warning with PHP 7.2 when trying to count NULL (fe69c4f) +* PSR2 (4579c63) +* add ci file (add8165) +* add dock block (2aafad1) +* add unit tests (0db511d) +* brace on a new line (a850718) +* code formating (39d6dbd) +* correct type hint warnings (e0cc8c3) +* fix tests (44a6ab0) +* follow PSR2 rules (a8adfcb) +* follow PSR2 rules except tabs vs space (e7830fd) +* increase required PHP version (0c3fd1a) +* increase version number (ea70fdf, 3b2b9e7) +* remove floor function. Thanks jfcherng for the hint (5327190) +* update (9509231, 2416e52, 277c3b4) +* update to PHPUnit 7 (2ee25e3) +* updatew (501d061) +* use XML (be786d3) +* use elseif, not else if (6f057bf) +* use strict types (c53c230) + +## v1.5 (2019-01-15) + +* remove require_once, use only autoloader (4623f1b) + +## v1.4 (2019-01-14) + +* Add PSR4 autoloader (bda1da9) +* Update README.md (ea93fb9) +* add badge (0fac082) +* add keywords (e64716d) +* add name spacing (1d15164) +* increase version (6500c97) +* remove debug line (62b01c5) +* rename files (b4769cf) +* shorten code (87edbec) + +## v1.3 (2019-01-11) + +* Fixed lengths of functions (3591789) +* Fix some typos (5ca2257) +* Update README.md (fdfc17a) +* added missing doc block (c6f3745) +* add lang to html (1623626) +* add second image (176b647) +* change readme (94defe0) +* increase version number (89f7feb) +* optional parameters should be the last parameter (18e0b93) +* packagist.org warning (ca954c3) + +## v1.2 (2018-01-23) + +* Handle side by side title customization (d620b8c) +* Update README.md (8515967) +* added example code from https://github.com/JBlond/php-diff/issues/1 (258b976) +* add image to README.md (0432f78) +* update copyright (14b612c) +* update example (980c7da) + +## v1.1 (2017-05-05) + +*   is not HTML5 valid (4804307) +* Add ability not to expand tabs (f5da126) +* Added note about https://github.com/Xiphe/jQuery-Merge-for-php-diff (2ebc51f) +* Add in working ignoreWhitespace and ignoreCase options (self-describing), fix up an issue where a diff of two files exactly the same would show the last $context lines, general cleanup (690419d) +* Add mbstring extension as package dependency (a929467) +* Add missing docblock. Rename isLineDifferent to linesAreDifferent (516c4be) +* Fix ' (c81931f) +* Fix an issue with insertions being skipped. (b13d23d) +* Fix links (2c38d0e) +* Fix tab expansion and deprecated preg_replace use on fixSpaces. (f0aba03) +* Fix the ignoring of option context (60de296) +* HTML5 (ded9951) +* Make `Diff_Renderer_Html_Array::formatLines` method protected (a44f99d) +* Make `Diff_Renderer_Html_Array::formatLines` method protected https://github.com/chrisboulton/php-diff/pull/26 (0bc8fa4) +* Rename README to README.md (d9242f7) +* Replace the substring with multi byte (19a92b3) +* Support for PHP 5.5 and above https://github.com/chrisboulton/php-diff/pull/25 (22822bb) +* This function has never been used (b3b089c) +* UTF-8 (1139134) +* Update LICENSE file new line at the end (d42578a) +* Update README.md (8ca3a1e) +* User specific files should not appear in .gitignore (af6fe2e) +* add composer file (be8dc58) +* added ' (09d0c4c) +* added License (3b5b338) +* added widget (d1a5e18) +* adding composer manifest to distribute as a library (9083bd6) +* add missing doc blocks (d3b9a63) +* bug fix https://github.com/chrisboulton/php-diff/pull/21 (a9b8ef7) +* clean ' (bf2398c) +* clean up (f1d7fdc) +* correct line number https://github.com/chrisboulton/php-diff/pull/23 (25905e7) +* created License (7cb8e63) +* end with a new line (b433ddb) +* end witha new line (b660567) +* example files Chinese (f63f3d6) +* fullBCount wasn't declared (f99d93b) +* get rid of PHP warning when custom options are not set (bf3353c) +* issue catch from https://github.com/one2/php-diff/commit/784ff858c3b1d46d98c42a43673c07674fc2cd5e (47cae23) +* matchingBlocks wasn't declared (e0ff768) +* no composer (de3e02e) +* not a valid email (358d10c) +* only the chinese line (cb6e774) +* opCodes wasn't declared (c19f1d6) +* some fixing (0ef9663) +* superfluous closing tags (dfca0df) +* syntax error (7650451) +* try to fix "Wrong highlight area in Chinese" (4c1bb37) +* unused function (c8efb81, 4ffd751) +* update (09b54e4) +* updated to my repo (c9c4c99) +* update json file (b587d23) +* update phpdoc block (edc62b4) +* use index instead of an assumption of a constant (5d8ade8) +* visibility (d3eb3ab) + +## v1.0 (2010-03-11) + +* Initial import (ac22200) +* Redo directory structure to match current coding style, rename classes to match directory style, fix up naming conventions (5c5c179) diff --git a/generateChangelog.php b/generateChangelog.php new file mode 100644 index 00000000..e73f3f9b --- /dev/null +++ b/generateChangelog.php @@ -0,0 +1,13 @@ +build(); +} catch (Exception $exception) { + echo $exception->getMessage(); +} +$changeLog->save('changelog.md'); From 28e1dc010ebca69cce647b32b9fcf3434114e7b6 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 3 Feb 2021 13:05:46 +0100 Subject: [PATCH 146/206] Document Update Changelog --- changelog.md | 446 +++++++++++------------------------------- generateChangelog.php | 16 ++ 2 files changed, 127 insertions(+), 335 deletions(-) diff --git a/changelog.md b/changelog.md index 836fe924..503428c4 100644 --- a/changelog.md +++ b/changelog.md @@ -1,412 +1,188 @@ # Changelog -## Upcoming changes (Undetermined) - -* Add DigiLive/gitChangelog for change log generation (0a6a84f) -* Bump library version (013f862) -* Cut HTML Unified Renderer (1ba255f) -* Document PhpUnit Similarity Test (7ec484c) -* Document Update Changelog (1646605) -* Document disabled inspection (909e195) -* Document generateLinesEqual() (8a193c9) -* Document methods (94c8bd5) -* Fix #83 - Lines not properly marked (6fcafe1) -* Fix HTML Merged Renderer (07da484) -* Fix constructor DocBlocks (b13ff84) -* Fix html syntax error (11ec623) -* Fix namespace and unused code (77a7b59) -* Fix probably undefined variable (3954a2b) -* Fix property visibility and method docBlocks (3bc0839) -* Fix property visibility and unused code (34a032f) -* Fix redundant and unused code. (73f6776) -* Refactor HTML Inline Renderer to HTML Unified (cf516d1) -* Refactor callbacks and if/else expressions. (79d989d) -* Refactor if/else statements (5ba19f7) -* Refactor static method calls to non-static (035cd33) -* Reformat library code (8e9735f) -* Require PHPUnit 8 or 9. (0bd0bd2) -* Update Key words (5bd040c) -* Update changelog.md (fb50095) -* add phpunit config file (7382ee8) -* exclude not needed files for zip / composer export (08c9244) -* keep assets for readme file (8edb202) -* upgrade required PHP version to 7.3 (8962a2b) +## 2.3.1 (2021-02-03) + +* Add DigiLive/gitChangelog for change log generation ([0a6a84f](https://github.com/JBlond/php-diff/commit/0a6a84f)) +* Bump library version ([013f862](https://github.com/JBlond/php-diff/commit/013f862)) +* Cut HTML Unified Renderer ([1ba255f](https://github.com/JBlond/php-diff/commit/1ba255f)) +* Document PhpUnit Similarity Test ([7ec484c](https://github.com/JBlond/php-diff/commit/7ec484c)) +* Document Update Changelog ([7d6c8bb](https://github.com/JBlond/php-diff/commit/7d6c8bb), [c9881d3](https://github.com/JBlond/php-diff/commit/c9881d3)) +* Document disabled inspection ([909e195](https://github.com/JBlond/php-diff/commit/909e195)) +* Document generateLinesEqual() ([8a193c9](https://github.com/JBlond/php-diff/commit/8a193c9)) +* Document methods ([94c8bd5](https://github.com/JBlond/php-diff/commit/94c8bd5)) +* Fix [#83](https://github.com/JBlond/php-diff/issues/83) - Lines not properly marked ([6fcafe1](https://github.com/JBlond/php-diff/commit/6fcafe1)) +* Fix HTML Merged Renderer ([07da484](https://github.com/JBlond/php-diff/commit/07da484)) +* Fix constructor DocBlocks ([b13ff84](https://github.com/JBlond/php-diff/commit/b13ff84)) +* Fix html syntax error ([11ec623](https://github.com/JBlond/php-diff/commit/11ec623)) +* Fix namespace and unused code ([77a7b59](https://github.com/JBlond/php-diff/commit/77a7b59)) +* Fix probably undefined variable ([3954a2b](https://github.com/JBlond/php-diff/commit/3954a2b)) +* Fix property visibility and method docBlocks ([3bc0839](https://github.com/JBlond/php-diff/commit/3bc0839)) +* Fix property visibility and unused code ([34a032f](https://github.com/JBlond/php-diff/commit/34a032f)) +* Fix redundant and unused code. ([73f6776](https://github.com/JBlond/php-diff/commit/73f6776)) +* add phpunit config file ([7382ee8](https://github.com/JBlond/php-diff/commit/7382ee8)) ## v2.3.0 (2020-11-19) -* Add Html Merged renderer. (d70eaf6) -* Add PhpUnit test for html merged renderer (4512c03) -* Add calculation for similarity ratio. (3e4bbe6) -* Add choosing marking levels to html example (c27035a) -* Add new marking levels for inline differences (75358da) -* Document properties and constructor (6c95ccd) -* Fix: Html SideBySide renders equal lines of version 1 at both sides. (ccfc465) -* Fix Merged::generateLinesReplace() (cef85b5) -* Fix PSR-4 Auto loading Typo (6e2ad47) -* Fix PhpUnit test (3ccaa10) -* Fix Undefined offset notice (b10fd38) -* Fixes #64 - maxLineMarkerWidth only calculated for input format plain. (c5f6d72) -* Fix generateBlockHeader docBlocks (b5cfbd5) -* Fix visibility of removed lines (ec0918b) -* Refactor sample text (6b9661c) -* Simplify code (276d84d) -* Simplify options merge (24c8bb9) -* Update Changelog Increase version number (a4e5058) -* Update changelog.md (491d539) -* add changelog (4b7a56f) -* add changelog to Readme file (09aea70) -* add date (c64c0cc) -* add declaration (cff7db1) -* add wiki links to README.md (ccd5a6d) -* change cli colors option from simple to true (38864db) -* check only if option is set (98781fd) -* check type of option (fbccaf4) -* correct typos (df270f5) -* github markdown urls should not contain ")" (1a71822) -* if option is true, not only if it is set (8098c71) -* merge options instead of set them directly (0e3fd21) -* update README file (0a16fd1, eb382fa) -* update changelog (98ac4c5) +* Add Html Merged renderer. ([d70eaf6](https://github.com/JBlond/php-diff/commit/d70eaf6)) +* Add PhpUnit test for html merged renderer ([4512c03](https://github.com/JBlond/php-diff/commit/4512c03)) +* Add calculation for similarity ratio. ([3e4bbe6](https://github.com/JBlond/php-diff/commit/3e4bbe6)) +* Add choosing marking levels to html example ([c27035a](https://github.com/JBlond/php-diff/commit/c27035a)) +* Add new marking levels for inline differences ([75358da](https://github.com/JBlond/php-diff/commit/75358da)) +* Document properties and constructor ([6c95ccd](https://github.com/JBlond/php-diff/commit/6c95ccd)) +* Fix: Html SideBySide renders equal lines of version 1 at both sides. ([ccfc465](https://github.com/JBlond/php-diff/commit/ccfc465)) +* Fix Merged::generateLinesReplace() ([cef85b5](https://github.com/JBlond/php-diff/commit/cef85b5)) +* Fix PSR-4 Auto loading Typo ([6e2ad47](https://github.com/JBlond/php-diff/commit/6e2ad47)) +* Fix PhpUnit test ([3ccaa10](https://github.com/JBlond/php-diff/commit/3ccaa10)) +* Fix Undefined offset notice ([b10fd38](https://github.com/JBlond/php-diff/commit/b10fd38)) +* Fixes [#64](https://github.com/JBlond/php-diff/issues/64) - maxLineMarkerWidth only calculated for input format plain. ([c5f6d72](https://github.com/JBlond/php-diff/commit/c5f6d72)) +* Fix generateBlockHeader docBlocks ([b5cfbd5](https://github.com/JBlond/php-diff/commit/b5cfbd5)) +* Fix visibility of removed lines ([ec0918b](https://github.com/JBlond/php-diff/commit/ec0918b)) +* add changelog ([4b7a56f](https://github.com/JBlond/php-diff/commit/4b7a56f)) +* add changelog to Readme file ([09aea70](https://github.com/JBlond/php-diff/commit/09aea70)) +* add date ([c64c0cc](https://github.com/JBlond/php-diff/commit/c64c0cc)) +* add declaration ([cff7db1](https://github.com/JBlond/php-diff/commit/cff7db1)) +* add wiki links to README.md ([ccd5a6d](https://github.com/JBlond/php-diff/commit/ccd5a6d)) ## v2.2.1 (2020-08-06) -* Fix #58 - Side by side diff shows empty diff (0946d59, 369b146, 02695d5) -* add to dev for unit tests (acd12cb) -* make jblond/php-cli optional (0346948) -* pcre is needed (147b89e) -* return direct from isset (0822804) -* update readme file (2bb7a09) -* update version number (e6812d0) +* Fix [#58](https://github.com/JBlond/php-diff/issues/58) - Side by side diff shows empty diff ([0946d59](https://github.com/JBlond/php-diff/commit/0946d59), [369b146](https://github.com/JBlond/php-diff/commit/369b146), [02695d5](https://github.com/JBlond/php-diff/commit/02695d5)) +* add to dev for unit tests ([acd12cb](https://github.com/JBlond/php-diff/commit/acd12cb)) ## v2.2.0 (2020-07-23) -* Change rendering flow. (c323f77) -* Fix code quality. (0ef6def) -* Resolve #52 and fixes. (2be0c51, fda4852) -* add line for readabiltity (e28511b) -* increase version number for the next release (6acb81e) +* Fix code quality. ([0ef6def](https://github.com/JBlond/php-diff/commit/0ef6def)) +* add line for readabiltity ([e28511b](https://github.com/JBlond/php-diff/commit/e28511b)) ## v2.1.1 (2020-07-17) -* Fix #50. (47d6288) -* add unit test for cli output (0c75757) -* correct typo (4f2b31a) -* increase version number for #50 bug fix release (eda111b) -* move images to assets directory (fbea75e) -* remove empty line (65f2aa4) -* remove second empty last line (af5b2c5) -* update doc (8555fdd, 66e8de5) -* update doc in unit test (7ec0dbb) +* Fix [#50](https://github.com/JBlond/php-diff/issues/50). ([47d6288](https://github.com/JBlond/php-diff/commit/47d6288)) +* add unit test for cli output ([0c75757](https://github.com/JBlond/php-diff/commit/0c75757)) ## v2.1.0 (2020-07-13) -* Following up #42. (f3a8f0d) -* add plain output for cli (d7bbe12) -* follow up https://github.com/JBlond/php-diff/pull/42 (8586225) -* refactor variable names (b48cbe6) -* remove not used variable (1ecdac5) -* remove output example (89602af) -* remove some complexity (a1e61fb) +* add plain output for cli ([d7bbe12](https://github.com/JBlond/php-diff/commit/d7bbe12)) ## v2.0.0 (2020-07-09) -* Add Cli color support (4192d8b) -* Add dark theme example (6f41894) -* Add example picture (ee37a28) -* Correct typo in wording (99150a4) -* Hide images by default, to have a shorter readme (5cd9113) -* Update README.md (bae640e, 9c4e77c) -* Update README.md Requirements (fe63c57) -* Update background color (3d82cd2) -* add composer scripts descriptions. Update key words (6bfd4f9) -* add missing tag from merge (639f3cc) -* adjust color (ae6cfe4) -* a new line for each change (12950b2, d3b5ec9) -* change composer require for package (ede59fb) -* correct some markdown warnings in README.md (d3de726) -* increase version number (f44ee81) -* reduce Cyclomatic Complexity (8fcc5fb) -* remove Autoloader.php and have only the one from composer (7a49d76) -* remove from merge conflict (d00d224) -* resize image (e1126f5) -* revert that change (e93d249, f1d90c2) -* show one picture as a preview (ab6eb28, 606ff22) -* update Readme (7e6e125) -* update example with full class path (37088ab) +* Add Cli color support ([4192d8b](https://github.com/JBlond/php-diff/commit/4192d8b)) +* Add dark theme example ([6f41894](https://github.com/JBlond/php-diff/commit/6f41894)) +* Add example picture ([ee37a28](https://github.com/JBlond/php-diff/commit/ee37a28)) +* add composer scripts descriptions. Update key words ([6bfd4f9](https://github.com/JBlond/php-diff/commit/6bfd4f9)) +* add missing tag from merge ([639f3cc](https://github.com/JBlond/php-diff/commit/639f3cc)) ## v1.18 (2020-07-01) -* Avoid variables with short names (70e327b) -* add author (e132cdb) -* add dark theme example (b9d0ef6) -* ignore phpstorm settings (19bdb97) -* increase version number (69b7e07) -* remove exclude (cac11d6) +* add author ([e132cdb](https://github.com/JBlond/php-diff/commit/e132cdb)) +* add dark theme example ([b9d0ef6](https://github.com/JBlond/php-diff/commit/b9d0ef6)) ## v1.17 (2020-06-08) -* Code Fixes. (dd07685) -* Fix issue #32. (7ef67e6) -* Property initializer is redundant (bbd3f38) -* Update LICENSE (8c2c88a) -* change to new array format (1da5da2, 2090f98) -* chris did not add this file at all (dc68ae0) -* fix typo in phpdoc (db259fc) -* increase version number for release (5912a3f) -* remove used property (6de7325) -* update readme example (217c513) -* use SPL (0466227) +* Fix issue [#32](https://github.com/JBlond/php-diff/issues/32). ([7ef67e6](https://github.com/JBlond/php-diff/commit/7ef67e6)) +* fix typo in phpdoc ([db259fc](https://github.com/JBlond/php-diff/commit/db259fc)) ## v1.16 (2020-03-02) -* Add composer package PHP Mess Detector v2.* (3e527d1) -* Add contributor to author lists. (4c2cbb7, c11b4ba) -* Add trimEqual option. (98d993e) -* Add types of elements for renderer (4d1b4a0, 83b4104) -* Change example texts. (cd653c2) -* Code Optimization, cleanup, refactoring and commenting. (c29a8aa, 0e230e3) -* Code fixes, optimization, cleanup, refactoring and commenting. (54892e1) -* Fix PHPMD Violation. (5d03eae) -* Fix expected value for HtmlRendererTest::testUnified() (fbda2bd) -* Line exceeds 120 characters; contains 121 (0b3dea0) -* Remove formatting of "collapsed block" indicator. (3d33000) -* Update README.md (b2dd9e9, 43ba9e0) -* import (66af1f7) -* phpmd warning: The method render uses an else expression (df413d4) -* remove TODO warning (55a4eba) -* remove some warnings from https://insight.symfony.com/projects/aa609edb-cdb1-45cf-ad51-afbdab48f6a1/analyses/56 (2fe16f9) -* update Version number (f8d5fe2) +* Add composer package PHP Mess Detector v2.* ([3e527d1](https://github.com/JBlond/php-diff/commit/3e527d1)) +* Add contributor to author lists. ([4c2cbb7](https://github.com/JBlond/php-diff/commit/4c2cbb7), [c11b4ba](https://github.com/JBlond/php-diff/commit/c11b4ba)) +* Add trimEqual option. ([98d993e](https://github.com/JBlond/php-diff/commit/98d993e)) +* Add types of elements for renderer ([4d1b4a0](https://github.com/JBlond/php-diff/commit/4d1b4a0), [83b4104](https://github.com/JBlond/php-diff/commit/83b4104)) +* Fix PHPMD Violation. ([5d03eae](https://github.com/JBlond/php-diff/commit/5d03eae)) +* Fix expected value for HtmlRendererTest::testUnified() ([fbda2bd](https://github.com/JBlond/php-diff/commit/fbda2bd)) ## v1.15 (2020-01-24) -* Code Fixes, Optimization, cleanup, refactoring and commenting. (78a1658) -* Code Fixes. (d1c724c) -* Code Optimization, cleanup, refactoring and commenting. (7748252, c017af5, c984365, 6bc3f7c, 0d8c872) -* Code Style Fixes. (5e7ddf3) -* Code cleanup, bumped required PHP version to >= 7.2 and updated readme. (71b63a1) -* Code commenting. (e6cd9e0) -* Code reformatting and minor optimization, Typo fixes (7f87ce3, 3a1c258) -* Correct paths for composer run-script phpunit (6bfc5e7) -* HTML Unified Renderer added, Code optimization, cleanup and commenting. (0c5e1a4) -* PHPUnit test added for diff-view renderers. (122a72c) -* PHPUnit test for HTML Unified Renderer added. (611dc21) -* PSR12 fixes (e227356, 2a01869) -* PSR12.Files.DeclareStatement (7c75b07) -* Preperation for local developement. (4352698) -* Update PHPUnit tests (3b2c367) -* fix notation (795fe20) -* ignore composer lock file (ec0e0a6) -* raise version number (9700db7) -* remove blank line (35cd1eb) -* remove list, but use an array (aed258f, 84941b3) -* valid html can have no white space before the first tag (42b1ace) +* fix notation ([795fe20](https://github.com/JBlond/php-diff/commit/795fe20)) ## v1.14 (2019-12-03) -* prepare 1.14 (fab2a43) -* remove unused function (49e2c3a) -* some code clean up (1cc43c3) +* No changes. ## v1.13 (2019-10-08) -* Use PSR 12 (039fab0) -* prepare 1.13 (1cdd3dc) -* update phpunit (d883a00) +* No changes. ## v1.12 (2019-03-18) -* PHP Mess Detector Avoid unused private methods such as '__autoload'. even if not correct (e0f6842) -* add more files to .gitignore (27b21eb) -* add phpunit test to composer (e8a3f71) -* add tests (6d165a6) -* increase version number (f755fce) -* remove BOM (1dd40d8) -* remove files from .gitignore (2f11a9d) -* tabs vs space (745b331) -* update Readme with example code (3396d35) +* add more files to .gitignore ([27b21eb](https://github.com/JBlond/php-diff/commit/27b21eb)) +* add phpunit test to composer ([e8a3f71](https://github.com/JBlond/php-diff/commit/e8a3f71)) +* add tests ([6d165a6](https://github.com/JBlond/php-diff/commit/6d165a6)) ## v1.11 (2019-02-22) -* avoid short variable names (5d07754) -* increase version number (aa4cf3b) -* license is in an external file. (7468872) -* remove dead code (5ad1cb3) -* remove idea (0f27cc1) -* update (93663b5) -* update composer file (autoload) (288f33c) -* update doc (8c56a2d) -* update example (718ec11) -* update phpdoc (33f71f1) +* No changes. ## v1.10 (2019-02-20) -* PSR2 indention (ef0f9ae) -* avoid short variable names (f75c870, 8a699ef, e940dd9, 7482c2b, 0a7fff5) -* avoid short variable names fix codacy warnings (4428ffe) -* fix codacy warnings of unused functions (8037d99) -* fix example (9207f73) -* ignore ide files (cd49cec) -* increase version (8e72ea7) -* remove else (3af88d2) -* remove unsued function (96f028c) -* update example (c6977f3) -* update package names (f21937d) -* update readme (247ddb1) +* fix codacy warnings of unused functions ([8037d99](https://github.com/JBlond/php-diff/commit/8037d99)) +* fix example ([9207f73](https://github.com/JBlond/php-diff/commit/9207f73)) ## v1.9 (2019-02-19) -* add comment like in the other file (8b68a5d) -* add stronger type hinting (3a6ef42) -* deduplicate render code (5967e91) -* increase version number (8f19707) -* lib\jblond\Diff\SequenceMatcher.php:622 PhanTypeMismatchDimFetch When fetching an array index from a value of type array|array{}, found an array index of type '0', but expected the index to be of type int (1c537ff) -* longer variable names (68e517a) -* stronger type hinting (9cc5cfb) +* add comment like in the other file ([8b68a5d](https://github.com/JBlond/php-diff/commit/8b68a5d)) +* add stronger type hinting ([3a6ef42](https://github.com/JBlond/php-diff/commit/3a6ef42)) ## v1.8 (2019-02-13) -* PSR1.Files.SideEffects.FoundWithSymbols (7699e4f) -* Revert "PSR1.Files.SideEffects.FoundWithSymbols" make unit test work again (5231883) -* change PHP version (d36ca2b) -* fix test (b4cfce1) -* increase version number (7d22093) -* refer to License file (6311fd4) -* relative path to pictures (3df01cc) -* short variable name (7c62963, c8ec74b) -* update version string (5d22b81) +* fix test ([b4cfce1](https://github.com/JBlond/php-diff/commit/b4cfce1)) ## v1.7 (2019-01-19) -* add code sniffer PSR2 file (6fa3c76) -* adding curly brackets (148e787) -* done. support for PSR4 is given (aea2437) -* fix PSR1.Files.SideEffects.FoundWithSymbols (fe21917) -* fix tabs (354bf5c) -* remove useless use import (4113efe) -* return type match (53502f2) -* tabs vs space (f326877) +* add code sniffer PSR2 file ([6fa3c76](https://github.com/JBlond/php-diff/commit/6fa3c76)) +* adding curly brackets ([148e787](https://github.com/JBlond/php-diff/commit/148e787)) +* fix PSR1.Files.SideEffects.FoundWithSymbols ([fe21917](https://github.com/JBlond/php-diff/commit/fe21917)) +* fix tabs ([354bf5c](https://github.com/JBlond/php-diff/commit/354bf5c)) ## v1.6 (2019-01-19) -* EOF (bb7b472, 77323c6) -* Fix warning with PHP 7.2 when trying to count NULL (fe69c4f) -* PSR2 (4579c63) -* add ci file (add8165) -* add dock block (2aafad1) -* add unit tests (0db511d) -* brace on a new line (a850718) -* code formating (39d6dbd) -* correct type hint warnings (e0cc8c3) -* fix tests (44a6ab0) -* follow PSR2 rules (a8adfcb) -* follow PSR2 rules except tabs vs space (e7830fd) -* increase required PHP version (0c3fd1a) -* increase version number (ea70fdf, 3b2b9e7) -* remove floor function. Thanks jfcherng for the hint (5327190) -* update (9509231, 2416e52, 277c3b4) -* update to PHPUnit 7 (2ee25e3) -* updatew (501d061) -* use XML (be786d3) -* use elseif, not else if (6f057bf) -* use strict types (c53c230) +* Fix warning with PHP 7.2 when trying to count NULL ([fe69c4f](https://github.com/JBlond/php-diff/commit/fe69c4f)) +* add ci file ([add8165](https://github.com/JBlond/php-diff/commit/add8165)) +* add dock block ([2aafad1](https://github.com/JBlond/php-diff/commit/2aafad1)) +* add unit tests ([0db511d](https://github.com/JBlond/php-diff/commit/0db511d)) +* fix tests ([44a6ab0](https://github.com/JBlond/php-diff/commit/44a6ab0)) ## v1.5 (2019-01-15) -* remove require_once, use only autoloader (4623f1b) +* No changes. ## v1.4 (2019-01-14) -* Add PSR4 autoloader (bda1da9) -* Update README.md (ea93fb9) -* add badge (0fac082) -* add keywords (e64716d) -* add name spacing (1d15164) -* increase version (6500c97) -* remove debug line (62b01c5) -* rename files (b4769cf) -* shorten code (87edbec) +* Add PSR4 autoloader ([bda1da9](https://github.com/JBlond/php-diff/commit/bda1da9)) +* add badge ([0fac082](https://github.com/JBlond/php-diff/commit/0fac082)) +* add keywords ([e64716d](https://github.com/JBlond/php-diff/commit/e64716d)) +* add name spacing ([1d15164](https://github.com/JBlond/php-diff/commit/1d15164)) ## v1.3 (2019-01-11) -* Fixed lengths of functions (3591789) -* Fix some typos (5ca2257) -* Update README.md (fdfc17a) -* added missing doc block (c6f3745) -* add lang to html (1623626) -* add second image (176b647) -* change readme (94defe0) -* increase version number (89f7feb) -* optional parameters should be the last parameter (18e0b93) -* packagist.org warning (ca954c3) +* Fixed lengths of functions ([3591789](https://github.com/JBlond/php-diff/commit/3591789)) +* Fix some typos ([5ca2257](https://github.com/JBlond/php-diff/commit/5ca2257)) +* added missing doc block ([c6f3745](https://github.com/JBlond/php-diff/commit/c6f3745)) +* add lang to html ([1623626](https://github.com/JBlond/php-diff/commit/1623626)) +* add second image ([176b647](https://github.com/JBlond/php-diff/commit/176b647)) ## v1.2 (2018-01-23) -* Handle side by side title customization (d620b8c) -* Update README.md (8515967) -* added example code from https://github.com/JBlond/php-diff/issues/1 (258b976) -* add image to README.md (0432f78) -* update copyright (14b612c) -* update example (980c7da) +* added example code from https://github.com/JBlond/php-diff/issues/1 ([258b976](https://github.com/JBlond/php-diff/commit/258b976)) +* add image to README.md ([0432f78](https://github.com/JBlond/php-diff/commit/0432f78)) ## v1.1 (2017-05-05) -*   is not HTML5 valid (4804307) -* Add ability not to expand tabs (f5da126) -* Added note about https://github.com/Xiphe/jQuery-Merge-for-php-diff (2ebc51f) -* Add in working ignoreWhitespace and ignoreCase options (self-describing), fix up an issue where a diff of two files exactly the same would show the last $context lines, general cleanup (690419d) -* Add mbstring extension as package dependency (a929467) -* Add missing docblock. Rename isLineDifferent to linesAreDifferent (516c4be) -* Fix ' (c81931f) -* Fix an issue with insertions being skipped. (b13d23d) -* Fix links (2c38d0e) -* Fix tab expansion and deprecated preg_replace use on fixSpaces. (f0aba03) -* Fix the ignoring of option context (60de296) -* HTML5 (ded9951) -* Make `Diff_Renderer_Html_Array::formatLines` method protected (a44f99d) -* Make `Diff_Renderer_Html_Array::formatLines` method protected https://github.com/chrisboulton/php-diff/pull/26 (0bc8fa4) -* Rename README to README.md (d9242f7) -* Replace the substring with multi byte (19a92b3) -* Support for PHP 5.5 and above https://github.com/chrisboulton/php-diff/pull/25 (22822bb) -* This function has never been used (b3b089c) -* UTF-8 (1139134) -* Update LICENSE file new line at the end (d42578a) -* Update README.md (8ca3a1e) -* User specific files should not appear in .gitignore (af6fe2e) -* add composer file (be8dc58) -* added ' (09d0c4c) -* added License (3b5b338) -* added widget (d1a5e18) -* adding composer manifest to distribute as a library (9083bd6) -* add missing doc blocks (d3b9a63) -* bug fix https://github.com/chrisboulton/php-diff/pull/21 (a9b8ef7) -* clean ' (bf2398c) -* clean up (f1d7fdc) -* correct line number https://github.com/chrisboulton/php-diff/pull/23 (25905e7) -* created License (7cb8e63) -* end with a new line (b433ddb) -* end witha new line (b660567) -* example files Chinese (f63f3d6) -* fullBCount wasn't declared (f99d93b) -* get rid of PHP warning when custom options are not set (bf3353c) -* issue catch from https://github.com/one2/php-diff/commit/784ff858c3b1d46d98c42a43673c07674fc2cd5e (47cae23) -* matchingBlocks wasn't declared (e0ff768) -* no composer (de3e02e) -* not a valid email (358d10c) -* only the chinese line (cb6e774) -* opCodes wasn't declared (c19f1d6) -* some fixing (0ef9663) -* superfluous closing tags (dfca0df) -* syntax error (7650451) -* try to fix "Wrong highlight area in Chinese" (4c1bb37) -* unused function (c8efb81, 4ffd751) -* update (09b54e4) -* updated to my repo (c9c4c99) -* update json file (b587d23) -* update phpdoc block (edc62b4) -* use index instead of an assumption of a constant (5d8ade8) -* visibility (d3eb3ab) +* Add ability not to expand tabs ([f5da126](https://github.com/JBlond/php-diff/commit/f5da126)) +* Added note about https://github.com/Xiphe/jQuery-Merge-for-php-diff ([2ebc51f](https://github.com/JBlond/php-diff/commit/2ebc51f)) +* Add in working ignoreWhitespace and ignoreCase options (self-describing), fix up an issue where a diff of two files exactly the same would show the last $context lines, general cleanup ([690419d](https://github.com/JBlond/php-diff/commit/690419d)) +* Add mbstring extension as package dependency ([a929467](https://github.com/JBlond/php-diff/commit/a929467)) +* Add missing docblock. Rename isLineDifferent to linesAreDifferent ([516c4be](https://github.com/JBlond/php-diff/commit/516c4be)) +* Fix ' ([c81931f](https://github.com/JBlond/php-diff/commit/c81931f)) +* Fix an issue with insertions being skipped. ([b13d23d](https://github.com/JBlond/php-diff/commit/b13d23d)) +* Fix links ([2c38d0e](https://github.com/JBlond/php-diff/commit/2c38d0e)) +* Fix tab expansion and deprecated preg_replace use on fixSpaces. ([f0aba03](https://github.com/JBlond/php-diff/commit/f0aba03)) +* Fix the ignoring of option context ([60de296](https://github.com/JBlond/php-diff/commit/60de296)) +* add composer file ([be8dc58](https://github.com/JBlond/php-diff/commit/be8dc58)) +* added ' ([09d0c4c](https://github.com/JBlond/php-diff/commit/09d0c4c)) +* added License ([3b5b338](https://github.com/JBlond/php-diff/commit/3b5b338)) +* added widget ([d1a5e18](https://github.com/JBlond/php-diff/commit/d1a5e18)) +* adding composer manifest to distribute as a library ([9083bd6](https://github.com/JBlond/php-diff/commit/9083bd6)) +* add missing doc blocks ([d3b9a63](https://github.com/JBlond/php-diff/commit/d3b9a63)) ## v1.0 (2010-03-11) -* Initial import (ac22200) -* Redo directory structure to match current coding style, rename classes to match directory style, fix up naming conventions (5c5c179) +* No changes. diff --git a/generateChangelog.php b/generateChangelog.php index e73f3f9b..c32f2ce8 100644 --- a/generateChangelog.php +++ b/generateChangelog.php @@ -4,7 +4,23 @@ require 'vendor/autoload.php'; +$changelogOptions = [ + 'headTagName' => '2.3.1', + 'headTagDate' => '2021-02-03', + 'titleOrder' => 'ASC', +]; +$changelogLabels = ['Add', 'Cut', 'Fix', 'Bump', 'Document','Optimize']; + + $changeLog = new MarkDown(); +$changeLog->commitUrl = 'https://github.com/JBlond/php-diff/commit/{hash}'; +$changeLog->issueUrl = 'https://github.com/JBlond/php-diff/issues/{issue}'; +try { + $changeLog->setOptions($changelogOptions); +} catch (Exception $exception) { + echo $exception->getMessage(); +} +$changeLog->setLabels(...$changelogLabels); try { $changeLog->build(); } catch (Exception $exception) { From 7eba3404df76ba62a0a89bc880db97ea3d259656 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Tue, 16 Feb 2021 14:24:32 +0100 Subject: [PATCH 147/206] Fix colors * Some background colors made did not match between the two versions. * Some foreground colors blended into the background color. * Color styles added for HTML Merged Renderer. --- example/dark-theme.css | 35 ++++++++++++++++++++++------------- example/styles.css | 33 ++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index 77669d21..bbbc31b3 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -6,8 +6,8 @@ body { } pre { - width: 100%; overflow: auto; + width: 100%; } a, a:visited { @@ -19,35 +19,35 @@ a, a:visited { */ .Differences { - width: 100%; border-collapse: collapse; border-spacing: 0; empty-cells: show; + width: 100%; } .Differences thead th { - text-align: left; - border-bottom: 1px solid #000000; background: #AAAAAA; + border-bottom: 1px solid #000000; color: #000000; padding: 4px; + text-align: left; } .Differences tbody th { - text-align: right; background: #AAAAAA; + border-right: 1px solid #000000; color: #272822; - width: 4em; + font-size: 13px; padding: 1px 2px; - border-right: 1px solid #000000; + text-align: right; vertical-align: top; - font-size: 13px; + width: 4em; } .Differences td { - padding: 1px 2px; font-family: Consolas, monospace; font-size: 13px; + padding: 1px 2px; } .Differences .Skipped { @@ -65,7 +65,7 @@ a, a:visited { * HTML Side by Side Diff */ .DifferencesSideBySide .ChangeInsert td.Left { - background: #008000; + background: #DDFFDD; } .DifferencesSideBySide .ChangeInsert td.Right { @@ -83,7 +83,7 @@ a, a:visited { } .DifferencesSideBySide .ChangeReplace .Left { - background: #FFEE99; + background: #FFDD88; color: #272822; } @@ -114,10 +114,12 @@ a, a:visited { .DifferencesUnified .ChangeReplace .Right, .DifferencesUnified .ChangeInsert .Right { background: #DDFFDD; + color: #272822; } .DifferencesUnified .ChangeReplace ins { background: #008000; + color: #272822; } .DifferencesUnified .ChangeReplace del { @@ -128,13 +130,16 @@ a, a:visited { /* * HTML Merged Diff */ -.DifferencesMerged .ChangeReplace .Left, +.DifferencesMerged td.ChangeInsert { + background: #FFDD88; + color: #272822; +} + .DifferencesMerged .ChangeDelete { background: #FFDDDD; color: #272822; } -.DifferencesMerged .ChangeReplace .Right, .DifferencesMerged .ChangeInsert { background: #DDFFDD; color: #272822; @@ -153,3 +158,7 @@ a, a:visited { .DifferencesMerged th.ChangeDelete { background-image: linear-gradient(-45deg, #AAAAAA 0%, #EE9999 100%); } + +.DifferencesMerged th.ChangeReplace { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #FFDD88 100%); +} diff --git a/example/styles.css b/example/styles.css index bbf2ba71..bd617467 100644 --- a/example/styles.css +++ b/example/styles.css @@ -6,8 +6,8 @@ body { } pre { - width: 100%; overflow: auto; + width: 100%; } /* @@ -15,34 +15,35 @@ pre { */ .Differences { - width: 100%; border-collapse: collapse; border-spacing: 0; empty-cells: show; + width: 100%; } .Differences thead th { - text-align: left; - border-bottom: 1px solid #000000; background: #AAAAAA; + border-bottom: 1px solid #000000; color: #000000; padding: 4px; + text-align: left; } .Differences tbody th { - text-align: right; background: #CCCCCC; - width: 4em; - padding: 1px 2px; border-right: 1px solid #000000; - vertical-align: top; font-size: 13px; + padding: 1px 2px; + text-align: right; + vertical-align: top; + width: 4em; } .Differences td { - padding: 1px 2px; - font-family: Consolas, monospace; - font-size: 13px; + font-family: Consolas, monospace; + font-size: 13px; + padding: 1px 2px; + vertical-align: top; } .Differences .Skipped { @@ -111,12 +112,14 @@ pre { /* * HTML Merged Diff */ -.DifferencesMerged .ChangeReplace .Left, +.DifferencesMerged td.ChangeInsert { + background: #FFDD88; +} + .DifferencesMerged .ChangeDelete { background: #FFDDDD; } -.DifferencesMerged .ChangeReplace .Right, .DifferencesMerged .ChangeInsert { background: #DDFFDD; } @@ -132,3 +135,7 @@ pre { .DifferencesMerged th.ChangeDelete { background-image: linear-gradient(-45deg, #CCCCCC 0%, #EE9999 100%); } + +.DifferencesMerged th.ChangeReplace { + background-image: linear-gradient(-45deg, #CCCCCC 0%, #FFDD88 100%); +} From acbfd7d6a03395479a5dfb2be092bd12daa02e11 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 27 Mar 2021 11:36:42 +0100 Subject: [PATCH 148/206] Fix #90 - Merged Diff shows result only partially * Renderer doesn't show lines which where added to version 2 of a replaced block. Code assumed the same amount of lines in replacement blocks at both versions. Now it handles replacement block differently when the amount of lines are equal or differs. * Code cleanup. * ClassName for lines of replacement blocks are incorrect. Insertion is insinuated, but should be replacement. --- example/dark-theme.css | 2 +- example/styles.css | 2 +- lib/jblond/Diff/Renderer/Html/Merged.php | 83 ++++++++++++++++-------- 3 files changed, 57 insertions(+), 30 deletions(-) diff --git a/example/dark-theme.css b/example/dark-theme.css index bbbc31b3..175b075e 100644 --- a/example/dark-theme.css +++ b/example/dark-theme.css @@ -130,7 +130,7 @@ a, a:visited { /* * HTML Merged Diff */ -.DifferencesMerged td.ChangeInsert { +.DifferencesMerged td.ChangeReplace { background: #FFDD88; color: #272822; } diff --git a/example/styles.css b/example/styles.css index bd617467..5dd6abeb 100644 --- a/example/styles.css +++ b/example/styles.css @@ -112,7 +112,7 @@ pre { /* * HTML Merged Diff */ -.DifferencesMerged td.ChangeInsert { +.DifferencesMerged td.ChangeReplace { background: #FFDD88; } diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index ab755774..679b6a70 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -112,7 +112,7 @@ public function generateSkippedLines(): string return << - $marker + $marker … HTML; @@ -136,7 +136,7 @@ public function generateLinesEqual(array $changes): string $html .= << - $fromLine + $fromLine $line HTML; @@ -165,7 +165,7 @@ public function generateLinesInsert(array $changes): string $html .= << - $toLine + $toLine $line HTML; @@ -208,41 +208,68 @@ public function generateLinesDelete(array $changes): string */ public function generateLinesReplace(array $changes): string { - $html = ''; - $headerClass = ''; - - foreach ($changes['base']['lines'] as $lineNo => $line) { - $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; - if (!$lineNo && $this->lastDeleted !== null) { - $headerClass = 'ChangeDelete'; + $html = ''; + $baseLineCount = count($changes['base']['lines']); + $changedLineCount = count($changes['changed']['lines']); + + if (count($changes['base']['lines']) == $changedLineCount) { + // Lines of Version 1 are modified at version 2. + foreach ($changes['base']['lines'] as $lineNo => $line) { + $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; + + // Capture line-parts which are added to the same line at version 2. + $addedParts = []; + preg_match_all('/\x0.*?\x1/', $changes['changed']['lines'][$lineNo], $addedParts, PREG_PATTERN_ORDER); + array_unshift($addedParts[0], ''); + + // Inline Replacement: + // Concatenate line-parts which are removed at version2 with line-parts which are added at version 2. + $line = preg_replace_callback( + '/\x0.*?\x1/', + function ($removedParts) use ($addedParts) { + $addedPart = str_replace(["\0", "\1"], $this->options['insertMarkers'], next($addedParts[0])); + $removedPart = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $removedParts[0]); + + return "$removedPart$addedPart"; + }, + $line + ); + + $html .= << + $fromLine + $line + +HTML; } - // Capture added parts. - $addedParts = []; - preg_match_all('/\x0.*?\x1/', $changes['changed']['lines'][$lineNo], $addedParts, PREG_PATTERN_ORDER); - array_unshift($addedParts[0], ''); + return $html; + } - // Concatenate removed parts with added parts. - $line = preg_replace_callback( - '/\x0.*?\x1/', - function ($removedParts) use ($addedParts) { - $addedPart = str_replace(["\0", "\1"], $this->options['insertMarkers'], next($addedParts[0])); - $removedPart = str_replace(["\0", "\1"], $this->options['deleteMarkers'], $removedParts[0]); + // More or less lines at version 2. Block of version 1 is replaced by block of version 2. + $title = ''; - return "$removedPart$addedPart"; - }, - $line - ); + foreach ($changes['changed']['lines'] as $lineNo => $line) { + $toLine = $changes['changed']['offset'] + $lineNo + 1; - $html .= << $baseLine) { + $title .= $changes['base']['offset'] + $baseLineNo + 1 . ": $baseLine\n"; + } + } + + $title = htmlentities($title); + $html .= << - $fromLine - $line + $toLine + $line HTML; - $this->lastDeleted = null; } + $this->lineOffset = $this->lineOffset + $changedLineCount - $baseLineCount; + return $html; } From fb32453362b81d811062dce548540e5ea672282c Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 27 Mar 2021 11:42:51 +0100 Subject: [PATCH 149/206] Fix repeating class assignment of line header Line headers of each equal or inserted line were given a class where it was supposed to be only the first line. --- lib/jblond/Diff/Renderer/Html/Merged.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 679b6a70..25912357 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -125,11 +125,12 @@ public function generateSkippedLines(): string */ public function generateLinesEqual(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; foreach ($changes['base']['lines'] as $lineNo => $line) { - $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; + $fromLine = $changes['base']['offset'] + $lineNo + 1 + $this->lineOffset; + $headerClass = ''; + if (!$lineNo && $this->lastDeleted !== null) { $headerClass = 'ChangeDelete'; } @@ -153,12 +154,12 @@ public function generateLinesEqual(array $changes): string */ public function generateLinesInsert(array $changes): string { - $html = ''; - $headerClass = ''; + $html = ''; foreach ($changes['changed']['lines'] as $lineNo => $line) { $this->lineOffset++; - $toLine = $changes['base']['offset'] + $this->lineOffset; + $toLine = $changes['base']['offset'] + $this->lineOffset; + $headerClass = ''; if (!$lineNo && $this->lastDeleted !== null) { $headerClass = 'ChangeDelete'; } From 533a6bfac0f3b45c94661bff8da76a44eed4912f Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 27 Mar 2021 11:46:30 +0100 Subject: [PATCH 150/206] Fix title attribute values * Some values of title attributes had hardcoded references to one of the compared versions of text. They now refer to these versions using the titles as set in the renderers options. * Values can contain character sequences that break the HTML output of the renderer. The characters are now converted to HTML entities. --- lib/jblond/Diff/Renderer/Html/Merged.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 25912357..3ccfd045 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -186,7 +186,7 @@ public function generateLinesDelete(array $changes): string { $this->lineOffset -= count($changes['base']['lines']); - $title = "Lines deleted at {$this->options['title2']}:\n"; + $title = "Lines of {$this->options['title1']} deleted at {$this->options['title2']}:\n"; foreach ($changes['base']['lines'] as $lineNo => $line) { $fromLine = $changes['base']['offset'] + $lineNo + 1; @@ -197,7 +197,7 @@ public function generateLinesDelete(array $changes): string TEXT; } - $this->lastDeleted = $title; + $this->lastDeleted = htmlentities($title); return ''; } From 7a67d32e366587c2ac865f28b356def1b43fa2ea Mon Sep 17 00:00:00 2001 From: DigiLive Date: Sat, 27 Mar 2021 12:13:35 +0100 Subject: [PATCH 151/206] Refactor expected output for HTML merged renderer Code changes of the HTML merged renderer causes different output. The expected output for the phpunit test of this renderer is refactored to reflect those changes. --- tests/resources/htmlMerged.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/resources/htmlMerged.txt b/tests/resources/htmlMerged.txt index 0e261b7d..666263db 100644 --- a/tests/resources/htmlMerged.txt +++ b/tests/resources/htmlMerged.txt @@ -13,7 +13,7 @@ 3         <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> - 4 + 4         <title>Hello WorldYou!</title> 5 @@ -25,18 +25,18 @@ 7         <h1>This is demo content to show features of the php-diff package.</h1> - 8         <h2>This line is the same for both versions.</h2> - 9 + 9         <h2>this line has inlineThis line has differences between both versions.</h2> 10         <h2>This line is the same for both versions.</h2> - 11 + 11         <h2>This line also has inlInLine differences between both versions.</h2> 12 @@ -54,13 +54,13 @@ 16             It's also compatible with multibyte characters (like Chinese and emoji) as shown below: - 17 + 17             另外我覺得那個評的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革” - 18 + 18             Do you know what "金槍魚罐頭魚の缶詰" means in Chinese? - 19 + 19             🍏🍎🍎🍏🙂 20 @@ -84,13 +84,13 @@ 27         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - 28 + 28                 <h2>This line also has inline differences between both versions. It's the whitespace in front.</h2> 29         <h2>This line is the same for both versions.</h2> - 30 + 30         <h2>This line also has inline differences between both versions.!</h2> 31 From 8a83b39d2c8b97e4c3d338f693879e2119eeecbe Mon Sep 17 00:00:00 2001 From: JBlond Date: Sat, 27 Mar 2021 14:39:21 +0100 Subject: [PATCH 152/206] Bump library version und update Changelog --- changelog.md | 12 ++++++++++-- generateChangelog.php | 4 ++-- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- lib/jblond/Diff/Similarity.php | 2 +- tests/Diff/Renderer/Html/HtmlRenderersTest.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- tests/Diff/Renderer/Text/TextRenderersTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- tests/Diff/SimilarityTest.php | 2 +- 21 files changed, 31 insertions(+), 23 deletions(-) diff --git a/changelog.md b/changelog.md index 503428c4..f26dae25 100644 --- a/changelog.md +++ b/changelog.md @@ -1,12 +1,20 @@ # Changelog -## 2.3.1 (2021-02-03) +## 2.3.2 (2021-03-27) + +* Bump library version ([6e42d96](https://github.com/JBlond/php-diff/commit/6e42d96)) +* Fix [#90](https://github.com/JBlond/php-diff/issues/90) - Merged Diff shows result only partially ([acbfd7d](https://github.com/JBlond/php-diff/commit/acbfd7d)) +* Fix colors ([7eba340](https://github.com/JBlond/php-diff/commit/7eba340)) +* Fix repeating class assignment of line header ([fb32453](https://github.com/JBlond/php-diff/commit/fb32453)) +* Fix title attribute values ([533a6bf](https://github.com/JBlond/php-diff/commit/533a6bf)) + +## v2.3.1 (2021-02-03) * Add DigiLive/gitChangelog for change log generation ([0a6a84f](https://github.com/JBlond/php-diff/commit/0a6a84f)) * Bump library version ([013f862](https://github.com/JBlond/php-diff/commit/013f862)) * Cut HTML Unified Renderer ([1ba255f](https://github.com/JBlond/php-diff/commit/1ba255f)) * Document PhpUnit Similarity Test ([7ec484c](https://github.com/JBlond/php-diff/commit/7ec484c)) -* Document Update Changelog ([7d6c8bb](https://github.com/JBlond/php-diff/commit/7d6c8bb), [c9881d3](https://github.com/JBlond/php-diff/commit/c9881d3)) +* Document Update Changelog ([28e1dc0](https://github.com/JBlond/php-diff/commit/28e1dc0), [c9881d3](https://github.com/JBlond/php-diff/commit/c9881d3)) * Document disabled inspection ([909e195](https://github.com/JBlond/php-diff/commit/909e195)) * Document generateLinesEqual() ([8a193c9](https://github.com/JBlond/php-diff/commit/8a193c9)) * Document methods ([94c8bd5](https://github.com/JBlond/php-diff/commit/94c8bd5)) diff --git a/generateChangelog.php b/generateChangelog.php index c32f2ce8..53af40c1 100644 --- a/generateChangelog.php +++ b/generateChangelog.php @@ -5,8 +5,8 @@ require 'vendor/autoload.php'; $changelogOptions = [ - 'headTagName' => '2.3.1', - 'headTagDate' => '2021-02-03', + 'headTagName' => '2.3.2', + 'headTagDate' => '2021-03-27', 'titleOrder' => 'ASC', ]; $changelogLabels = ['Add', 'Cut', 'Fix', 'Bump', 'Document','Optimize']; diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index fce45e28..8d06e9ae 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -23,7 +23,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 55bacbff..f3e75fbb 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -11,7 +11,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 3ccfd045..0e5a86c3 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class Merged extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 545d4ed5..6f84b150 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index b69f6cff..9674bcc7 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class Unified extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 7399e0c9..4e0af497 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class MainRenderer extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index e40bfeda..da0623f1 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index a3ea1bbb..1cb7fdc2 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -13,7 +13,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 6fae3bbf..5e2da541 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index fb7965cc..51f5dd9b 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 40b43a5b..3465edd5 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index e39dc533..750fef97 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -15,7 +15,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class UnifiedCli extends MainRendererAbstract diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 1e5fc92d..e325f4c9 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 0d2ec812..acebbb98 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class Similarity extends SequenceMatcher diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 10639525..69830568 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -20,7 +20,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class HtmlRenderersTest extends TestCase diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 9dbc3a01..4780419c 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -22,7 +22,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 6c852ca6..b506bb80 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2019 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class TextRenderersTest extends TestCase diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 0d85127d..0517609a 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class SequenceMatcherTest extends TestCase diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index b9bdbb98..3171ae61 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.0 + * @version 2.3.2 * @link https://github.com/JBlond/php-diff */ class SimilarityTest extends TestCase From 3c05022e651c3f430e16f8098292b3246f481e89 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 8 Jun 2021 08:58:10 +0200 Subject: [PATCH 153/206] Use coalesce for $avail[$char] --- .gitignore | 4 +++- lib/jblond/Diff/Similarity.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 9e1ec532..67b315d0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ ### Composer ### composer.phar /vendor/ +/composer.lock +/.phpunit.result.cache + # Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file @@ -72,4 +75,3 @@ local.properties # End of https://www.gitignore.io/api/windows,eclipse,composer -/composer.lock diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index acebbb98..5f10d649 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -106,7 +106,7 @@ private function getRatioFast(): float $aLength = count($this->old); for ($iterator = 0; $iterator < $aLength; ++$iterator) { $char = $this->old[$iterator]; - $numb = isset($avail[$char]) ? $avail[$char] : $this->uniqueCount2[$char] ?? 0; + $numb = $avail[$char] ?? ($this->uniqueCount2[$char] ?? 0); $avail[$char] = $numb - 1; if ($numb > 0) { ++$matches; From 31b4222936f6ac0dd1eef767ca492efd74675045 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 23 Aug 2021 15:34:32 +0200 Subject: [PATCH 154/206] Fix Autoload test classes only in development --- composer.json | 6 +++++- generateChangelog.php | 4 ++-- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- lib/jblond/Diff/Similarity.php | 2 +- tests/Diff/Renderer/Html/HtmlRenderersTest.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- tests/Diff/Renderer/Text/TextRenderersTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- tests/Diff/SimilarityTest.php | 2 +- 21 files changed, 26 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 7925aa52..e8ea5228 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,11 @@ }, "autoload": { "psr-4": { - "jblond\\": "lib/jblond", + "jblond\\": "lib/jblond" + } + }, + "autoload-dev": { + "psr-4": { "Tests\\": "tests" } }, diff --git a/generateChangelog.php b/generateChangelog.php index 53af40c1..c023e160 100644 --- a/generateChangelog.php +++ b/generateChangelog.php @@ -5,8 +5,8 @@ require 'vendor/autoload.php'; $changelogOptions = [ - 'headTagName' => '2.3.2', - 'headTagDate' => '2021-03-27', + 'headTagName' => '2.3.3', + 'headTagDate' => '2021-08-23', 'titleOrder' => 'ASC', ]; $changelogLabels = ['Add', 'Cut', 'Fix', 'Bump', 'Document','Optimize']; diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 8d06e9ae..9c01f746 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -23,7 +23,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class Diff diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index f3e75fbb..29553e0a 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -11,7 +11,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 0e5a86c3..4a16e968 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class Merged extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 6f84b150..2878589a 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 9674bcc7..31d17e86 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class Unified extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 4e0af497..eee5cce6 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class MainRenderer extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index da0623f1..59759633 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index 1cb7fdc2..4f3ad3d6 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -13,7 +13,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 5e2da541..d6f04ccb 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 51f5dd9b..2e4ef15d 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 3465edd5..86291f04 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 750fef97..3c6a36b5 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -15,7 +15,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class UnifiedCli extends MainRendererAbstract diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index e325f4c9..701a598e 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 5f10d649..ea7b46e7 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class Similarity extends SequenceMatcher diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 69830568..a32dcd96 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -20,7 +20,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class HtmlRenderersTest extends TestCase diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 4780419c..500aa686 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -22,7 +22,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index b506bb80..8eeeaf32 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2019 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class TextRenderersTest extends TestCase diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 0517609a..b968609e 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class SequenceMatcherTest extends TestCase diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index 3171ae61..fc51ae5d 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.2 + * @version 2.3.3 * @link https://github.com/JBlond/php-diff */ class SimilarityTest extends TestCase From f5ce6bc138a7b03024b9d06476c917155a2e0c96 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 23 Aug 2021 15:45:34 +0200 Subject: [PATCH 155/206] Bump library version und update Changelog --- changelog.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index f26dae25..f1efde8a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,8 +1,12 @@ # Changelog -## 2.3.2 (2021-03-27) +## 2.3.3 (2021-08-23) -* Bump library version ([6e42d96](https://github.com/JBlond/php-diff/commit/6e42d96)) +* Fix Autoload test classes only in development ([31b4222](https://github.com/JBlond/php-diff/commit/31b4222)) + +## v2.3.2 (2021-03-27) + +* Bump library version und update Changelog ([8a83b39](https://github.com/JBlond/php-diff/commit/8a83b39)) * Fix [#90](https://github.com/JBlond/php-diff/issues/90) - Merged Diff shows result only partially ([acbfd7d](https://github.com/JBlond/php-diff/commit/acbfd7d)) * Fix colors ([7eba340](https://github.com/JBlond/php-diff/commit/7eba340)) * Fix repeating class assignment of line header ([fb32453](https://github.com/JBlond/php-diff/commit/fb32453)) From 02cf114a972b87fb191018c1b48f302473abf113 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 24 Aug 2021 12:32:19 +0200 Subject: [PATCH 156/206] Optimize colorize is only used here --- lib/jblond/Diff/Renderer/Text/InlineCli.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 2e4ef15d..25cf07fb 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -198,10 +198,6 @@ private function mergeChanges( max($this->maxLineMarkerWidth - strlen($this->options['equalityMarkers'][1]), 0) ); - if ($this->options['cliColor']) { - $colorize = new CliColors(); - } - foreach ($baseLines as $lineKey => $line) { $iterator = 0; $baselineParts = preg_split('/\x00(.*?)\x01/', $line, -1, PREG_SPLIT_DELIM_CAPTURE); @@ -220,7 +216,7 @@ private function mergeChanges( } if ($this->options['cliColor']) { - // Colorize the changed part. $colorize is defined above. + $colorize = new CliColors(); $basePart = $colorize->getColoredString($basePart, ...$deleteColors); if (!empty($changedPart)) { $changedPart = $colorize->getColoredString($changedPart, ...$insertColors); From 3f44195750ecd7c26ed307a321805ee9659fc4a6 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 24 Aug 2021 12:42:34 +0200 Subject: [PATCH 157/206] Document update grammar in the comments --- lib/jblond/Diff.php | 10 +++++----- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 6 +++--- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 6 +++--- lib/jblond/Diff/SequenceMatcher.php | 10 +++++----- tests/Diff/SequenceMatcherTest.php | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 9c01f746..3bb3ce0b 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -87,7 +87,7 @@ class Diff * The values can be of type string or array. * If the type is string, it's split into array elements by line-end characters. * - * Options for comparison can be set by using the third parameter. The format of this value is expected to be a + * Options for comparison can be set by using the third parameter. The format of this value is expected to be an * associative array where each key-value pair represents an option and its value (E.g. ['context' => 3], ...). * When a keyName matches the name of a default option, that option's value will be overridden by the key's value. * Any other keyName (and it's value) can be added as an option, but will not be used if not implemented. @@ -110,7 +110,7 @@ public function __construct($version1, $version2, array $options = []) } /** - * Get the type of a variable. + * Get the kind of variable. * * The return value depend on the type of variable: * 0 If the type is 'array' @@ -200,11 +200,11 @@ public function render(object $renderer) * @param int|null $end The last element of the range to get. * If not supplied, only the element at start will be returned. * - * @return array Array containing all of the elements of the specified range. + * @return array Array containing all the elements of the specified range. * @throws OutOfRangeException When the value of start or end are invalid to define a range. * */ - public function getArrayRange(array $array, int $start = 0, $end = null): array + public function getArrayRange(array $array, int $start = 0, ?int $end = null): array { if ($start < 0 || $end < 0 || $end < $start) { throw new OutOfRangeException('Start parameter must be lower than End parameter while both are positive!'); @@ -274,7 +274,7 @@ public function getGroupedOpCodes(): array * * @return float Similarity ratio. */ - public function getSimilarity($method = Similarity::CALC_DEFAULT): float + public function getSimilarity(int $method = Similarity::CALC_DEFAULT): float { if ($this->similarity !== null) { return $this->similarity; diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 4a16e968..68833785 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -22,7 +22,7 @@ class Merged extends MainRenderer implements SubRendererInterface /** * @var array Associative array containing the default options available for this renderer and their default * value. - * - format Format of the texts. + * - format The Format of the texts. * - insertMarkers Markers for inserted text. * - deleteMarkers Markers for removed text. * - title1 Title of the 1st version of text. diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 2878589a..72a23e21 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -26,7 +26,7 @@ class SideBySide extends MainRenderer implements SubRendererInterface /** * @var array Associative array containing the default options available for this renderer and their default * value. - * - format Format of the texts. + * - format The Format of the texts. * - insertMarkers Markers for inserted text. * - deleteMarkers Markers for removed text. * - title1 Title of the 1st version of text. diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 31d17e86..cd8cd009 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -26,7 +26,7 @@ class Unified extends MainRenderer implements SubRendererInterface /** * @var array Associative array containing the default options available for this renderer and their default * value. - * - format Format of the texts. + * - format The Format of the texts. * - insertMarkers Markers for inserted text. * - deleteMarkers Markers for removed text. * - title1 Title of the 1st version of text. diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index eee5cce6..91a63306 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -116,7 +116,7 @@ protected function renderSequences(): array foreach ($group as $code) { [$tag, $startOld, $endOld, $startNew, $endNew] = $code; /** - * $code is an array describing a op-code which includes: + * $code is an array describing an op-code which includes: * 0 - The type of tag (as described below) for the op code. * 1 - The beginning line in the first sequence. * 2 - The end line in the first sequence. @@ -351,7 +351,7 @@ private function getOuterChange(string $oldString, string $newString): array $limit = min(mb_strlen($oldString), mb_strlen($newString)); // Find the position of the first character which is different between old and new. - // Starts at the begin of the strings. + // Starts at the beginning of the strings. // Stops at the end of the shortest string. while ($start < $limit && mb_substr($oldString, $start, 1) == mb_substr($newString, $start, 1)) { ++$start; @@ -375,7 +375,7 @@ private function getOuterChange(string $oldString, string $newString): array /** * Helper function that will fill the changes-array for the renderer with default values. - * Every time a operation changes (specified by $tag) , a new element will be appended to this array. + * Every time an operation changes (specified by $tag) , a new element will be appended to this array. * * The index of the last element of the array is always returned. * diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 3c6a36b5..50b11d32 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -112,12 +112,12 @@ private function output(): string } /** - * @param $string - * @param string $color + * @param string $string + * @param string $color * * @return string */ - private function colorizeString($string, $color = ''): string + private function colorizeString(string $string, string $color = ''): string { if ($this->options['cliColor']) { return $this->colors->getColoredString($string, $color); diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 701a598e..32af5d4f 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -73,7 +73,7 @@ class SequenceMatcher /** * The constructor. With the sequences being passed, they'll be set for the - * sequence matcher and it will perform a basic cleanup & calculate junk + * sequence matcher, and it will perform a basic cleanup & calculate junk * elements. * * @param string|array $old A string or array containing the lines to compare against. @@ -215,7 +215,7 @@ private function chainB() * content of the different files but can still provide context as to where the * changes are. * - * @return array Nested array of all of the grouped op codes. + * @return array Nested array of all the grouped op codes. */ public function getGroupedOpCodes(): array { @@ -295,7 +295,7 @@ public function getGroupedOpCodes(): array } /** - * Return a list of all of the op codes for the differences between the + * Return a list of all the op codes for the differences between the * two strings. * * The nested array returned contains an array describing the op code @@ -366,7 +366,7 @@ public function getOpCodes(): array } /** - * Return a nested set of arrays for all of the matching sub-sequences + * Return a nested set of arrays for all the matching sub-sequences * in the strings $a and $b. * * Each block contains the lower constraint of the block in $a, the lower @@ -479,7 +479,7 @@ function ($aArray, $bArray) { * lower and upper constraints for each sequence. (for the first sequence, * $alo - $ahi and for the second sequence, $blo - $bhi) * - * Essentially, of all of the maximal matching blocks, return the one that + * Essentially, of all the maximal matching blocks, return the one that * starts earliest in $a, and all of those maximal matching blocks that * start earliest in $a, return the one that starts earliest in $b. * diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index b968609e..16f8d3d4 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -73,7 +73,7 @@ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() { // Test with ignoreWhitespace enabled. Both sequences are considered to be the same. // Note: The sequenceMatcher evaluates the string character by character. Option ignoreWhitespace will ignore - // if the difference if the character is a tab in one sequence and a space in the other. + // if the difference is the character or is a tab in one sequence and a space in the other. $sequenceMatcher = new SequenceMatcher( "\t54321ABXDE12345 ", " 54321ABXDE12345\t", From 0bf1a08ceb06cbf099c4dd07c52c4bf6265fb31f Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 26 Oct 2021 19:56:23 +0200 Subject: [PATCH 158/206] Fix PSR-12 code style --- lib/jblond/Diff/ConstantsInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jblond/Diff/ConstantsInterface.php b/lib/jblond/Diff/ConstantsInterface.php index 121e7cb6..4166a608 100644 --- a/lib/jblond/Diff/ConstantsInterface.php +++ b/lib/jblond/Diff/ConstantsInterface.php @@ -1,6 +1,7 @@ Date: Tue, 26 Oct 2021 20:08:46 +0200 Subject: [PATCH 159/206] Bump library version und update Changelog --- changelog.md | 20 +++++++++++++++++-- generateChangelog.php | 2 +- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 2 +- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- .../Diff/Renderer/MainRendererAbstract.php | 2 +- .../Diff/Renderer/SubRendererInterface.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 2 +- lib/jblond/Diff/Renderer/Text/Unified.php | 2 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 2 +- lib/jblond/Diff/Similarity.php | 2 +- .../Diff/Renderer/Html/HtmlRenderersTest.php | 2 +- tests/Diff/Renderer/MainRendererTest.php | 2 +- .../Diff/Renderer/Text/TextRenderersTest.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- tests/Diff/SimilarityTest.php | 2 +- 21 files changed, 38 insertions(+), 22 deletions(-) diff --git a/changelog.md b/changelog.md index f1efde8a..7a16af50 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,23 @@ # Changelog -## 2.3.3 (2021-08-23) - +## 2.4.0 (2021-08-23) + +* Add deprecation notice for missing method ([f494b3a](https://github.com/JBlond/php-diff/commit/f494b3a), [9403eba](https://github.com/JBlond/php-diff/commit/9403eba)) +* Add generator for ignored lines ([6b8662e](https://github.com/JBlond/php-diff/commit/6b8662e), [4dec4ad](https://github.com/JBlond/php-diff/commit/4dec4ad)) +* Add method `generateLinesIgnore` ([6ef61bc](https://github.com/JBlond/php-diff/commit/6ef61bc), [75f5ce0](https://github.com/JBlond/php-diff/commit/75f5ce0)) +* Bump library version und update Changelog ([a5c49d1](https://github.com/JBlond/php-diff/commit/a5c49d1)) +* Document methods ([9699b5b](https://github.com/JBlond/php-diff/commit/9699b5b), [7d973d3](https://github.com/JBlond/php-diff/commit/7d973d3)) +* Document option `ignoreLines` ([0849a1e](https://github.com/JBlond/php-diff/commit/0849a1e), [19634bb](https://github.com/JBlond/php-diff/commit/19634bb)) +* Document update grammar in the comments ([3f44195](https://github.com/JBlond/php-diff/commit/3f44195)) +* Fix PSR-12 code style ([0bf1a08](https://github.com/JBlond/php-diff/commit/0bf1a08)) +* Optimize Sequence renderer ([576830c](https://github.com/JBlond/php-diff/commit/576830c), [bb0eed4](https://github.com/JBlond/php-diff/commit/bb0eed4)) +* Optimize colorize is only used here ([02cf114](https://github.com/JBlond/php-diff/commit/02cf114)) +* Optimize constant usage ([d0cede3](https://github.com/JBlond/php-diff/commit/d0cede3), [3591515](https://github.com/JBlond/php-diff/commit/3591515)) +* Optimize stripping empty/blank lines ([ea6a2e4](https://github.com/JBlond/php-diff/commit/ea6a2e4), [a239f17](https://github.com/JBlond/php-diff/commit/a239f17)) + +## v2.3.3 (2021-08-23) + +* Bump library version und update Changelog ([f5ce6bc](https://github.com/JBlond/php-diff/commit/f5ce6bc)) * Fix Autoload test classes only in development ([31b4222](https://github.com/JBlond/php-diff/commit/31b4222)) ## v2.3.2 (2021-03-27) diff --git a/generateChangelog.php b/generateChangelog.php index c023e160..ceab516e 100644 --- a/generateChangelog.php +++ b/generateChangelog.php @@ -5,7 +5,7 @@ require 'vendor/autoload.php'; $changelogOptions = [ - 'headTagName' => '2.3.3', + 'headTagName' => '2.4.0', 'headTagDate' => '2021-08-23', 'titleOrder' => 'ASC', ]; diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 40380560..86c4350e 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -24,7 +24,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class Diff implements ConstantsInterface diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 29553e0a..0dee1f0c 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -11,7 +11,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class DiffUtils diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 68833785..5b20e811 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class Merged extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index db7ccf70..9fddd544 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class SideBySide extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 1f9faf3b..df1b3cff 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -18,7 +18,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class Unified extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 21e9a97f..4ee80d44 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class MainRenderer extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index 59759633..4cedfcb9 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ abstract class MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index 8feffbef..cc12eadc 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -13,7 +13,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ interface SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 30b11c4e..c9523593 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2009 Chris Boulton * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class Context extends MainRendererAbstract diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 25cf07fb..d5167379 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class InlineCli extends MainRenderer implements SubRendererInterface diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 86291f04..da8fc182 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -16,7 +16,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 50b11d32..96c67953 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -15,7 +15,7 @@ * @author Mario Brandt * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class UnifiedCli extends MainRendererAbstract diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 5c7859e8..73ce32c6 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -17,7 +17,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class SequenceMatcher implements ConstantsInterface diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index fc9c9617..1b8a3070 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -16,7 +16,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class Similarity extends SequenceMatcher diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index a32dcd96..3054e6de 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -20,7 +20,7 @@ * @author Ferry Cools * @copyright (c) 2020 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class HtmlRenderersTest extends TestCase diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 500aa686..67719d97 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -22,7 +22,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 8eeeaf32..016c6076 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -19,7 +19,7 @@ * @author Ferry Cools * @copyright (c) 2019 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class TextRenderersTest extends TestCase diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index af8f200e..3900a145 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -15,7 +15,7 @@ * @author Ferry Cools * @copyright (c) 2009 Mario Brandt * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class SequenceMatcherTest extends TestCase diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index fc51ae5d..410a6fe9 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -14,7 +14,7 @@ * @author Ferry Cools * @copyright (c) 2020 Ferry Cools * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.3.3 + * @version 2.4.0 * @link https://github.com/JBlond/php-diff */ class SimilarityTest extends TestCase From 054d249c58417ed72117ff570a6b18da69ed4ddc Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 26 Oct 2021 20:11:06 +0200 Subject: [PATCH 160/206] Bump changelog --- changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index 7a16af50..a9ef3e4d 100644 --- a/changelog.md +++ b/changelog.md @@ -5,7 +5,7 @@ * Add deprecation notice for missing method ([f494b3a](https://github.com/JBlond/php-diff/commit/f494b3a), [9403eba](https://github.com/JBlond/php-diff/commit/9403eba)) * Add generator for ignored lines ([6b8662e](https://github.com/JBlond/php-diff/commit/6b8662e), [4dec4ad](https://github.com/JBlond/php-diff/commit/4dec4ad)) * Add method `generateLinesIgnore` ([6ef61bc](https://github.com/JBlond/php-diff/commit/6ef61bc), [75f5ce0](https://github.com/JBlond/php-diff/commit/75f5ce0)) -* Bump library version und update Changelog ([a5c49d1](https://github.com/JBlond/php-diff/commit/a5c49d1)) +* Bump library version und update Changelog ([e88dffb](https://github.com/JBlond/php-diff/commit/e88dffb)) * Document methods ([9699b5b](https://github.com/JBlond/php-diff/commit/9699b5b), [7d973d3](https://github.com/JBlond/php-diff/commit/7d973d3)) * Document option `ignoreLines` ([0849a1e](https://github.com/JBlond/php-diff/commit/0849a1e), [19634bb](https://github.com/JBlond/php-diff/commit/19634bb)) * Document update grammar in the comments ([3f44195](https://github.com/JBlond/php-diff/commit/3f44195)) From 550312ab6bd14c65c65bea4acfcd2692763c8295 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 26 Oct 2021 20:38:24 +0200 Subject: [PATCH 161/206] Optimize code base #103 --- example/cli.php | 6 ++-- example/example.php | 8 ++--- lib/jblond/Diff.php | 2 +- lib/jblond/Diff/DiffUtils.php | 4 ++- lib/jblond/Diff/Renderer/Html/Merged.php | 4 +-- lib/jblond/Diff/Renderer/Html/SideBySide.php | 6 ++-- lib/jblond/Diff/Renderer/Html/Unified.php | 6 ++-- lib/jblond/Diff/Renderer/MainRenderer.php | 24 +++++++-------- .../Diff/Renderer/MainRendererAbstract.php | 2 +- lib/jblond/Diff/Renderer/Text/Context.php | 2 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 4 +-- lib/jblond/Diff/SequenceMatcher.php | 30 +++++++++---------- lib/jblond/Diff/Similarity.php | 14 ++++----- .../Diff/Renderer/Html/HtmlRenderersTest.php | 6 ++-- tests/Diff/Renderer/MainRendererTest.php | 8 ++--- .../Diff/Renderer/Text/TextRenderersTest.php | 8 ++--- tests/Diff/SequenceMatcherTest.php | 17 ++++++----- tests/Diff/SimilarityTest.php | 2 +- 18 files changed, 76 insertions(+), 77 deletions(-) diff --git a/example/cli.php b/example/cli.php index 8b3ea7de..6c456acd 100644 --- a/example/cli.php +++ b/example/cli.php @@ -6,7 +6,7 @@ use jblond\Diff\Renderer\Text\UnifiedCli; // Validate the interpreter. -if (php_sapi_name() !== 'cli') { +if (PHP_SAPI !== 'cli') { echo 'This script demonstrates console support for the php-diff package.
'; echo 'Please execute it from a cli interpreter.'; throw new RuntimeException('Script for CLI use only!'); @@ -17,8 +17,8 @@ require '../vendor/autoload.php'; // Include two sample files for comparison. -$sampleA = file_get_contents(dirname(__FILE__) . '/a.txt'); -$sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); +$sampleA = file_get_contents(__DIR__ . '/a.txt'); +$sampleB = file_get_contents(__DIR__ . '/b.txt'); $customOptions = [ 'context' => 2, diff --git a/example/example.php b/example/example.php index e4d7ed04..04c0deb9 100644 --- a/example/example.php +++ b/example/example.php @@ -11,8 +11,8 @@ require '../vendor/autoload.php'; // Include two sample files for comparison. -$sampleA = file_get_contents(dirname(__FILE__) . '/a.txt'); -$sampleB = file_get_contents(dirname(__FILE__) . '/b.txt'); +$sampleA = file_get_contents(__DIR__ . '/a.txt'); +$sampleB = file_get_contents(__DIR__ . '/b.txt'); // Options for generating the diff. $diffOptions = [ @@ -20,7 +20,7 @@ 'trimEqual' => false, 'ignoreWhitespace' => true, 'ignoreCase' => true, - 'ignoreLines' => Diff::DIFF_IGNORE_LINE_EMPTY, + 'ignoreLines' => Diff\ConstantsInterface::DIFF_IGNORE_LINE_EMPTY, ]; // Choose one of the initializations. @@ -29,7 +29,7 @@ // Options for rendering the diff. $rendererOptions = [ - 'inlineMarking' => $_GET['inlineMarking'] ?? Diff\Renderer\MainRenderer::CHANGE_LEVEL_LINE, + 'inlineMarking' => $_GET['inlineMarking'] ?? Diff\Renderer\MainRendererAbstract::CHANGE_LEVEL_LINE, ] ?> diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 86c4350e..9e1cf536 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -148,7 +148,7 @@ public function getArgumentType($var): int * When a keyName matches the name of a default option, that option's value will be overridden by the key's value. * Any other keyName (and it's value) will be added as an option, but will not be used if not implemented. */ - public function setOptions(array $options) + public function setOptions(array $options): void { $this->options = array_merge($this->defaultOptions, $options); } diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 0dee1f0c..76fe272e 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -30,7 +30,9 @@ public static function tupleSort(array $aArray, array $bArray): int for ($counter = 0; $counter < $max; ++$counter) { if ($aArray[$counter] < $bArray[$counter]) { return -1; - } elseif ($aArray[$counter] > $bArray[$counter]) { + } + + if ($aArray[$counter] > $bArray[$counter]) { return 1; } } diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 5b20e811..e7e87428 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -62,9 +62,9 @@ public function __construct(array $options = []) */ public function render() { - $changes = parent::renderSequences(); + $changes = $this->renderSequences(); - return parent::renderOutput($changes, $this); + return $this->renderOutput($changes, $this); } /** diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 9fddd544..dc3026e8 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -60,9 +60,9 @@ public function __construct(array $options = []) */ public function render() { - $changes = parent::renderSequences(); + $changes = $this->renderSequences(); - return parent::renderOutput($changes, $this); + return $this->renderOutput($changes, $this); } /** @@ -284,7 +284,7 @@ public function generateDiffFooter(): string } /** - * @inheritDoc + * * * @return string Html code representing table rows showing ignored text. */ diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index df1b3cff..59c5f98d 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -60,9 +60,9 @@ public function __construct(array $options = []) */ public function render() { - $changes = parent::renderSequences(); + $changes = $this->renderSequences(); - return parent::renderOutput($changes, $this); + return $this->renderOutput($changes, $this); } /** @@ -220,7 +220,7 @@ public function generateLinesReplace(array $changes): string } /** - * @inheritDoc + * * * @return string Html code representing table rows showing modified text. */ diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 4ee80d44..d5a23eb7 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -68,9 +68,9 @@ public function renderOutput(array $changes, object $subRenderer) $deprecationTriggered = false; foreach ($blocks as $change) { if ( - $subRenderer instanceof MainRenderer && + $subRenderer instanceof self && !method_exists($subRenderer, 'generateLinesIgnore') && - $change['tag'] == 'ignore' + $change['tag'] === 'ignore' ) { if (!$deprecationTriggered) { trigger_error( @@ -157,7 +157,7 @@ protected function renderSequences(): array $blockSizeOld = $endOld - $startOld; $blockSizeNew = $endNew - $startNew; - if (($tag == 'replace') && ($blockSizeOld == $blockSizeNew)) { + if (($tag === 'replace') && ($blockSizeOld == $blockSizeNew)) { // Inline differences between old and new block. $this->markInlineChanges($oldText, $newText, $startOld, $endOld, $startNew); } @@ -168,14 +168,14 @@ protected function renderSequences(): array $oldBlock = $this->formatLines(array_slice($oldText, $startOld, $blockSizeOld)); $newBlock = $this->formatLines(array_slice($newText, $startNew, $blockSizeNew)); - if ($tag != 'delete' && $tag != 'insert') { + if ($tag !== 'delete' && $tag !== 'insert') { // Old block "equals" New block or is replaced. $blocks[$lastBlock]['base']['lines'] += $oldBlock; $blocks[$lastBlock]['changed']['lines'] += $newBlock; continue; } - if ($tag == 'delete') { + if ($tag === 'delete') { // Block of version1 doesn't exist in version2. $blocks[$lastBlock]['base']['lines'] += $oldBlock; continue; @@ -266,14 +266,14 @@ private function markInnerChange(array &$oldText, array &$newText, int $startOld foreach ($opCodes as $group) { foreach ($group as [$tag, $changeStartOld, $changeEndOld, $changeStartNew, $changeEndNew]) { - if ($tag == 'equal') { + if ($tag === 'equal') { continue; } - if ($tag == 'replace' || $tag == 'delete') { + if ($tag === 'replace' || $tag === 'delete') { $oldLine[$changeStartOld] = "\0" . $oldLine[$changeStartOld]; $oldLine[$changeEndOld] = "\1" . $oldLine[$changeEndOld]; } - if ($tag == 'replace' || $tag == 'insert') { + if ($tag === 'replace' || $tag === 'insert') { $newLine[$changeStartNew] = "\0" . $newLine[$changeStartNew]; $newLine[$changeEndNew] = "\1" . $newLine[$changeEndNew]; } @@ -380,7 +380,7 @@ private function getOuterChange(string $oldString, string $newString): array } $end = -1; - $limit = $limit - $start; + $limit -= $start; // Find the position of the last character which is different between old and new. // Starts at the end of the shortest string. @@ -453,10 +453,10 @@ function ($line) { ); } - if (strtolower($this->options['format']) == 'html') { + if (strtolower($this->options['format']) === 'html') { // Convert special characters to HTML entities $strings = array_map( - function ($line) { + static function ($line) { return htmlspecialchars($line, ENT_NOQUOTES); }, $strings @@ -466,7 +466,7 @@ function ($line) { foreach ($strings as &$line) { $line = preg_replace_callback( '/(^[ \0\1]*)/', - function ($matches) { + static function ($matches) { return str_replace(' ', ' ', $matches[0]); }, $line diff --git a/lib/jblond/Diff/Renderer/MainRendererAbstract.php b/lib/jblond/Diff/Renderer/MainRendererAbstract.php index 4cedfcb9..b45f089a 100644 --- a/lib/jblond/Diff/Renderer/MainRendererAbstract.php +++ b/lib/jblond/Diff/Renderer/MainRendererAbstract.php @@ -95,7 +95,7 @@ public function __construct(array $options = []) * @see MainRendererAbstract::$mainOptions * */ - public function setOptions(array $options) + public function setOptions(array $options): void { $this->options = array_merge($this->mainOptions, $this->options, $options); } diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index c9523593..812cce8e 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -110,7 +110,7 @@ private function filterGroups(array $groups, string $excludedTag): array { return array_filter( $groups, - function ($operation) use ($excludedTag) { + static function ($operation) use ($excludedTag) { return $operation[0] != $excludedTag; } ); diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index d5167379..6580eba2 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -48,9 +48,9 @@ public function __construct(array $options = []) */ public function render() { - $changes = parent::renderSequences(); + $changes = $this->renderSequences(); - return parent::renderOutput($changes, $this); + return $this->renderOutput($changes, $this); } diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 73ce32c6..27ce2ca7 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -102,7 +102,7 @@ public function __construct($old, $new, array $options = [], $junkCallback = nul /** * @param array $options */ - public function setOptions(array $options) + public function setOptions(array $options): void { if (isset($options['context']) && $options['context'] < 0) { throw new InvalidArgumentException('The context option cannot be a negative value!'); @@ -115,8 +115,9 @@ public function setOptions(array $options) * * @param string|array $version1 A string or array containing the lines to compare against. * @param string|array $version2 A string or array containing the lines to compare. + * @return void */ - public function setSequences($version1, $version2) + public function setSequences($version1, $version2): void { $this->setSeq1($version1); $this->setSeq2($version2); @@ -127,9 +128,10 @@ public function setSequences($version1, $version2) * * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. * - * @param string|array $version1 The sequence to set as the first sequence. + * @param string|array|void $version1 The sequence to set as the first sequence. + * @return void */ - public function setSeq1($version1) + public function setSeq1($version1): void { if (!is_array($version1)) { $version1 = str_split($version1); @@ -148,7 +150,7 @@ public function setSeq1($version1) * * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. * - * @param string|array $version2 The sequence to set as the second sequence. + * @param string|array|void $version2 The sequence to set as the second sequence. */ public function setSeq2($version2) { @@ -169,14 +171,14 @@ public function setSeq2($version2) * Generate the internal arrays containing the list of junk and non-junk * characters for the second ($b) sequence. */ - private function chainB() + private function chainB(): void { $length = count($this->new); $this->b2j = []; $popularDict = []; - for ($i = 0; $i < $length; ++$i) { - $char = $this->new[$i]; + foreach ($this->new as $i => $iValue) { + $char = $iValue; if (isset($this->b2j[$char])) { if ($length >= 200 && count($this->b2j[$char]) * 100 > $length) { $popularDict[$char] = 1; @@ -352,13 +354,13 @@ public function getOpCodes(): array if ($this->options['ignoreLines'] == 2) { array_walk( $slice1, - function (&$line) { + static function (&$line) { $line = trim($line); } ); array_walk( $slice2, - function (&$line) { + static function (&$line) { $line = trim($line); } ); @@ -461,7 +463,7 @@ public function getMatchingBlocks(): array usort( $matchingBlocks, - function ($aArray, $bArray) { + static function ($aArray, $bArray) { return DiffUtils::tupleSort($aArray, $bArray); } ); @@ -647,10 +649,6 @@ public function linesAreDifferent(int $aIndex, int $bIndex): bool $lineB = strtolower($lineB); } - if ($lineA != $lineB) { - return true; - } - - return false; + return $lineA != $lineB; } } diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 1b8a3070..77a205d8 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -47,7 +47,7 @@ class Similarity extends SequenceMatcher /** * @inheritDoc */ - public function setSeq2($version2) + public function setSeq2($version2): void { $this->uniqueCount2 = null; parent::setSeq2($version2); @@ -147,18 +147,16 @@ private function getRatioFast(): float if ($this->uniqueCount2 === null) { // Build unless cached. $this->uniqueCount2 = []; - $bLength = count($this->new); - for ($iterator = 0; $iterator < $bLength; ++$iterator) { - $char = $this->new[$iterator]; + foreach ($this->new as $iteratorValue) { + $char = $iteratorValue; $this->uniqueCount2[$char] = ($this->uniqueCount2[$char] ?? 0) + 1; } } $avail = []; $matches = 0; - $aLength = count($this->old); - for ($iterator = 0; $iterator < $aLength; ++$iterator) { - $char = $this->old[$iterator]; + foreach ($this->old as $iteratorValue) { + $char = $iteratorValue; $numb = $avail[$char] ?? ($this->uniqueCount2[$char] ?? 0); $avail[$char] = $numb - 1; if ($numb > 0) { @@ -189,7 +187,7 @@ private function calculateRatio(int $matches, int $length = 0): float return $returnValue; } - private function restoreLines() + private function restoreLines(): void { foreach (['old', 'new'] as $version) { foreach ($this->stripped[$version] as $index => $line) { diff --git a/tests/Diff/Renderer/Html/HtmlRenderersTest.php b/tests/Diff/Renderer/Html/HtmlRenderersTest.php index 3054e6de..4df97271 100644 --- a/tests/Diff/Renderer/Html/HtmlRenderersTest.php +++ b/tests/Diff/Renderer/Html/HtmlRenderersTest.php @@ -48,7 +48,7 @@ public function __construct($name = null, array $data = [], $dataName = '') * * @covers \jblond\Diff\Renderer\Html\SideBySide */ - public function testSideBySide() + public function testSideBySide(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), @@ -69,7 +69,7 @@ public function testSideBySide() * * @covers \jblond\Diff\Renderer\Html\Merged */ - public function testMerged() + public function testMerged(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), @@ -90,7 +90,7 @@ public function testMerged() * * @covers \jblond\Diff\Renderer\Html\Unified */ - public function testUnified() + public function testUnified(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 67719d97..2ffc33e4 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -44,7 +44,7 @@ class MainRendererTest extends TestCase /** * Test if a sequence of version1 which is removed from version2 is caught by the MainRenderer. */ - public function testRenderSimpleDelete() + public function testRenderSimpleDelete(): void { $renderer = new MainRenderer(); $renderer->diff = new Diff(['a'], []); @@ -92,7 +92,7 @@ public function invokeMethod(object $object, string $methodName, array $paramete /** * Test if leading spaces of a sequence are replaced with html entities. */ - public function testRenderFixesSpaces() + public function testRenderFixesSpaces(): void { $renderer = new MainRenderer($this->rendererOptions); $renderer->diff = new Diff( @@ -130,7 +130,7 @@ public function testRenderFixesSpaces() * * @throws ReflectionException When invoking the method fails. */ - public function testMarkOuterChange() + public function testMarkOuterChange(): void { $renderer = new MainRenderer(); $text1 = ['one two three four']; @@ -150,7 +150,7 @@ public function testMarkOuterChange() * * @throws ReflectionException When invoking the method fails. */ - public function testMarkInnerChange() + public function testMarkInnerChange(): void { $renderer = new MainRenderer(); diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 016c6076..337eab36 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -47,7 +47,7 @@ public function __construct($name = null, array $data = [], $dataName = '') * * @covers \jblond\Diff\Renderer\Text\Context */ - public function testContext() + public function testContext(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), @@ -68,7 +68,7 @@ public function testContext() * * @covers \jblond\Diff\Renderer\Text\Unified */ - public function testUnified() + public function testUnified(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), @@ -89,7 +89,7 @@ public function testUnified() * * @covers \jblond\Diff\Renderer\Text\UnifiedCli */ - public function testUnifiedCli() + public function testUnifiedCli(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), @@ -109,7 +109,7 @@ public function testUnifiedCli() * * @covers \jblond\Diff\Renderer\Text\InlineCli */ - public function testInlineCli() + public function testInlineCli(): void { $diff = new Diff( file_get_contents('tests/resources/a.txt'), diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 3900a145..47a40134 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -2,6 +2,7 @@ namespace Tests\Diff; +use jblond\Diff\ConstantsInterface; use jblond\Diff\SequenceMatcher; use PHPUnit\Framework\TestCase; @@ -23,7 +24,7 @@ class SequenceMatcherTest extends TestCase /** * Test the opCodes of the differences between version1 and version2 with the default options. */ - public function testGetGroupedOpCodesDefault() + public function testGetGroupedOpCodesDefault(): void { // Test with default options. $sequenceMatcher = new SequenceMatcher( @@ -46,7 +47,7 @@ public function testGetGroupedOpCodesDefault() /** * Test the opCodes of the differences between version1 and version2 with option trimEqual disabled. */ - public function testGetGroupedOpCodesTrimEqualFalse() + public function testGetGroupedOpCodesTrimEqualFalse(): void { // Test with trimEqual disabled. // First and last context lines of the sequences are included. @@ -69,7 +70,7 @@ public function testGetGroupedOpCodesTrimEqualFalse() /** * Test the opCodes of the differences between version1 and version2 with option IgnoreWhitespace enabled. */ - public function testGetGroupedOpCodesIgnoreWhitespaceTrue() + public function testGetGroupedOpCodesIgnoreWhitespaceTrue(): void { // Test with ignoreWhitespace enabled. Both sequences are considered to be the same. // Note: The sequenceMatcher evaluates the string character by character. Option ignoreWhitespace will ignore @@ -86,7 +87,7 @@ public function testGetGroupedOpCodesIgnoreWhitespaceTrue() /** * Test the opCodes of the differences between version1 and version2 with option ignoreCase enabled. */ - public function testGetGroupedOpCodesIgnoreCaseTrue() + public function testGetGroupedOpCodesIgnoreCaseTrue(): void { // Test with ignoreCase enabled. Both sequences are considered to be the same. $sequenceMatcher = new SequenceMatcher( @@ -101,13 +102,13 @@ public function testGetGroupedOpCodesIgnoreCaseTrue() /** * Test the opCodes of the differences between version1 and version2 with option ignoreLines set to empty. */ - public function testGetGroupedOpCodesIgnoreLinesEmpty() + public function testGetGroupedOpCodesIgnoreLinesEmpty(): void { // Test with ignoreCase enabled. Both sequences are considered to be the same. $sequenceMatcher = new SequenceMatcher( [0, 1, 2, 3], [0, 1, '', 2, 3], - ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_EMPTY] + ['ignoreLines' => ConstantsInterface::DIFF_IGNORE_LINE_EMPTY] ); $this->assertEquals( @@ -125,13 +126,13 @@ public function testGetGroupedOpCodesIgnoreLinesEmpty() /** * Test the opCodes of the differences between version1 and version2 with option ignoreLines set to blank. */ - public function testGetGroupedOpCodesIgnoreLinesBlank() + public function testGetGroupedOpCodesIgnoreLinesBlank(): void { // Test with ignoreCase enabled. Both sequences are considered to be the same. $sequenceMatcher = new SequenceMatcher( [0, 1, 2, 3], [0, 1, "\t", 2, 3], - ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_BLANK] + ['ignoreLines' => ConstantsInterface::DIFF_IGNORE_LINE_BLANK] ); $this->assertEquals( diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index 410a6fe9..ea4701e0 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -23,7 +23,7 @@ class SimilarityTest extends TestCase /** * Test the similarity ratio between two sequences with different methods. */ - public function testGetSimilarity() + public function testGetSimilarity(): void { $similarity = new Similarity(range(1, 10), range(1, 5)); From 962623ddacbae5c88c0dec1574fec94dc2660a8f Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 10:25:13 +0200 Subject: [PATCH 162/206] Fix phpdoc and return type --- lib/jblond/Diff/SequenceMatcher.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 27ce2ca7..01a9da51 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -150,9 +150,10 @@ public function setSeq1($version1): void * * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. * - * @param string|array|void $version2 The sequence to set as the second sequence. + * @param string|array $version2 The sequence to set as the second sequence. + * @return void */ - public function setSeq2($version2) + public function setSeq2($version2): void { if (!is_array($version2)) { $version2 = str_split($version2); From 013918b0eb90b8b49bef58cfda9aa7ae31f979d7 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 10:46:57 +0200 Subject: [PATCH 163/206] Revert changes suggested by DigiLive --- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index e7e87428..cc976ecb 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -62,7 +62,7 @@ public function __construct(array $options = []) */ public function render() { - $changes = $this->renderSequences(); + $changes = parent::renderSequences(); return $this->renderOutput($changes, $this); } diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index dc3026e8..0e7c0d3c 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -60,7 +60,7 @@ public function __construct(array $options = []) */ public function render() { - $changes = $this->renderSequences(); + $changes = parent::renderSequences(); return $this->renderOutput($changes, $this); } diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 59c5f98d..75c72942 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -60,7 +60,7 @@ public function __construct(array $options = []) */ public function render() { - $changes = $this->renderSequences(); + $changes = parent::renderSequences(); return $this->renderOutput($changes, $this); } From 3486ace2438829649c79df221368d1b929e4303a Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 10:48:47 +0200 Subject: [PATCH 164/206] Revert changes suggested by DigiLive --- example/example.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/example.php b/example/example.php index 04c0deb9..c619eb60 100644 --- a/example/example.php +++ b/example/example.php @@ -20,7 +20,7 @@ 'trimEqual' => false, 'ignoreWhitespace' => true, 'ignoreCase' => true, - 'ignoreLines' => Diff\ConstantsInterface::DIFF_IGNORE_LINE_EMPTY, + 'ignoreLines' => Diff::DIFF_IGNORE_LINE_EMPTY, ]; // Choose one of the initializations. From 2ebc3efdb37e6751ecf81223840c4099c546027d Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 10:51:19 +0200 Subject: [PATCH 165/206] Remove no longer working sensio labs --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3ad115ef..631f2d3b 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # PHP Diff Class -[![SensioLabsInsight](https://insight.sensiolabs.com/projects/aa609edb-cdb1-45cf-ad51-afbdab48f6a1/mini.png)](https://insight.sensiolabs.com/projects/aa609edb-cdb1-45cf-ad51-afbdab48f6a1) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/db5f8d57b1234502aeb852afc87e0dfe)](https://www.codacy.com/app/leet31337/php-diff) - -[![Latest Version](https://img.shields.io/github/release/JBlond/php-diff.svg?style=flat-square&label=Release)](https://github.com/JBlond/php-diff/releases) [![Packagist Installs](https://badgen.net/packagist/dt/JBlond/php-diff)](https://packagist.org/packages/jblond/php-diff) +[[![Codacy Badge](https://api.codacy.com/project/badge/Grade/db5f8d57b1234502aeb852afc87e0dfe)](https://www.codacy.com/app/leet31337/php-diff) +[![Latest Version](https://img.shields.io/github/release/JBlond/php-diff.svg?style=flat-square&label=Release)](https://github.com/JBlond/php-diff/releases) +[![Packagist Installs](https://badgen.net/packagist/dt/JBlond/php-diff)](https://packagist.org/packages/jblond/php-diff) ## Introduction From 07a75ba1b62dfd0134a73f89278158c2b603c54b Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 10:55:24 +0200 Subject: [PATCH 166/206] Revert PHPDoc changes --- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 0e7c0d3c..30e23116 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -284,7 +284,7 @@ public function generateDiffFooter(): string } /** - * + * @inheritDoc * * @return string Html code representing table rows showing ignored text. */ diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index 75c72942..aa8aafa9 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -220,7 +220,7 @@ public function generateLinesReplace(array $changes): string } /** - * + * @inheritDoc * * @return string Html code representing table rows showing modified text. */ diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 47a40134..92192f1e 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -108,7 +108,7 @@ public function testGetGroupedOpCodesIgnoreLinesEmpty(): void $sequenceMatcher = new SequenceMatcher( [0, 1, 2, 3], [0, 1, '', 2, 3], - ['ignoreLines' => ConstantsInterface::DIFF_IGNORE_LINE_EMPTY] + ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_EMPTY] ); $this->assertEquals( From 63b7366111dfb3fc8aab71216fe4404b080d1e70 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 11:00:16 +0200 Subject: [PATCH 167/206] Revert strict comparison --- example/example.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/example.php b/example/example.php index c619eb60..ba2cf80d 100644 --- a/example/example.php +++ b/example/example.php @@ -29,7 +29,7 @@ // Options for rendering the diff. $rendererOptions = [ - 'inlineMarking' => $_GET['inlineMarking'] ?? Diff\Renderer\MainRendererAbstract::CHANGE_LEVEL_LINE, + 'inlineMarking' => $_GET['inlineMarking'] ?? Diff\Renderer\MainRenderer::CHANGE_LEVEL_LINE, ] ?> diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index d5a23eb7..2100cdcf 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -70,7 +70,7 @@ public function renderOutput(array $changes, object $subRenderer) if ( $subRenderer instanceof self && !method_exists($subRenderer, 'generateLinesIgnore') && - $change['tag'] === 'ignore' + $change['tag'] == 'ignore' ) { if (!$deprecationTriggered) { trigger_error( @@ -157,7 +157,7 @@ protected function renderSequences(): array $blockSizeOld = $endOld - $startOld; $blockSizeNew = $endNew - $startNew; - if (($tag === 'replace') && ($blockSizeOld == $blockSizeNew)) { + if (($tag == 'replace') && ($blockSizeOld == $blockSizeNew)) { // Inline differences between old and new block. $this->markInlineChanges($oldText, $newText, $startOld, $endOld, $startNew); } @@ -168,14 +168,14 @@ protected function renderSequences(): array $oldBlock = $this->formatLines(array_slice($oldText, $startOld, $blockSizeOld)); $newBlock = $this->formatLines(array_slice($newText, $startNew, $blockSizeNew)); - if ($tag !== 'delete' && $tag !== 'insert') { + if ($tag != 'delete' && $tag != 'insert') { // Old block "equals" New block or is replaced. $blocks[$lastBlock]['base']['lines'] += $oldBlock; $blocks[$lastBlock]['changed']['lines'] += $newBlock; continue; } - if ($tag === 'delete') { + if ($tag == 'delete') { // Block of version1 doesn't exist in version2. $blocks[$lastBlock]['base']['lines'] += $oldBlock; continue; @@ -266,14 +266,14 @@ private function markInnerChange(array &$oldText, array &$newText, int $startOld foreach ($opCodes as $group) { foreach ($group as [$tag, $changeStartOld, $changeEndOld, $changeStartNew, $changeEndNew]) { - if ($tag === 'equal') { + if ($tag == 'equal') { continue; } - if ($tag === 'replace' || $tag === 'delete') { + if ($tag == 'replace' || $tag == 'delete') { $oldLine[$changeStartOld] = "\0" . $oldLine[$changeStartOld]; $oldLine[$changeEndOld] = "\1" . $oldLine[$changeEndOld]; } - if ($tag === 'replace' || $tag === 'insert') { + if ($tag == 'replace' || $tag == 'insert') { $newLine[$changeStartNew] = "\0" . $newLine[$changeStartNew]; $newLine[$changeEndNew] = "\1" . $newLine[$changeEndNew]; } @@ -453,7 +453,7 @@ function ($line) { ); } - if (strtolower($this->options['format']) === 'html') { + if (strtolower($this->options['format']) == 'html') { // Convert special characters to HTML entities $strings = array_map( static function ($line) { From 5bcf6051bf81721ad35f62becd62f76b9e047152 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 11:05:52 +0200 Subject: [PATCH 168/206] Revert Parent class changes --- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- tests/Diff/SequenceMatcherTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 2100cdcf..76a5dcfa 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -68,7 +68,7 @@ public function renderOutput(array $changes, object $subRenderer) $deprecationTriggered = false; foreach ($blocks as $change) { if ( - $subRenderer instanceof self && + $subRenderer instanceof MainRenderer && !method_exists($subRenderer, 'generateLinesIgnore') && $change['tag'] == 'ignore' ) { diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 92192f1e..787f8a30 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -132,7 +132,7 @@ public function testGetGroupedOpCodesIgnoreLinesBlank(): void $sequenceMatcher = new SequenceMatcher( [0, 1, 2, 3], [0, 1, "\t", 2, 3], - ['ignoreLines' => ConstantsInterface::DIFF_IGNORE_LINE_BLANK] + ['ignoreLines' => SequenceMatcher::DIFF_IGNORE_LINE_BLANK] ); $this->assertEquals( From bf8ec7db375d1cc65a64ce87eb77b8ed300a420e Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 14:14:13 +0200 Subject: [PATCH 169/206] Revert to parent call --- lib/jblond/Diff/Renderer/Html/Merged.php | 2 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 2 +- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index cc976ecb..5b20e811 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -64,7 +64,7 @@ public function render() { $changes = parent::renderSequences(); - return $this->renderOutput($changes, $this); + return parent::renderOutput($changes, $this); } /** diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 30e23116..9fddd544 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -62,7 +62,7 @@ public function render() { $changes = parent::renderSequences(); - return $this->renderOutput($changes, $this); + return parent::renderOutput($changes, $this); } /** diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index aa8aafa9..df1b3cff 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -62,7 +62,7 @@ public function render() { $changes = parent::renderSequences(); - return $this->renderOutput($changes, $this); + return parent::renderOutput($changes, $this); } /** From bc30dd0a1b0c09abdeedf86803c44c42a6414ab0 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 14:15:30 +0200 Subject: [PATCH 170/206] Revert to parent call --- lib/jblond/Diff/Renderer/Text/InlineCli.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index 6580eba2..d5167379 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -48,9 +48,9 @@ public function __construct(array $options = []) */ public function render() { - $changes = $this->renderSequences(); + $changes = parent::renderSequences(); - return $this->renderOutput($changes, $this); + return parent::renderOutput($changes, $this); } From ff0bb2990cbf9349566fb1cd950627a656c21cbb Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 27 Oct 2021 14:19:13 +0200 Subject: [PATCH 171/206] Fix Readme Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 631f2d3b..87bd71cc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PHP Diff Class -[[![Codacy Badge](https://api.codacy.com/project/badge/Grade/db5f8d57b1234502aeb852afc87e0dfe)](https://www.codacy.com/app/leet31337/php-diff) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/db5f8d57b1234502aeb852afc87e0dfe)](https://www.codacy.com/app/leet31337/php-diff) [![Latest Version](https://img.shields.io/github/release/JBlond/php-diff.svg?style=flat-square&label=Release)](https://github.com/JBlond/php-diff/releases) [![Packagist Installs](https://badgen.net/packagist/dt/JBlond/php-diff)](https://packagist.org/packages/jblond/php-diff) From ed1f204403c63bf2504e5003a17d46324d7ff5fd Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 1 Nov 2021 11:05:18 +0100 Subject: [PATCH 172/206] Add statistics function for #97 --- example/example.php | 7 +++++- lib/jblond/Diff.php | 11 ++++++++++ lib/jblond/Diff/Similarity.php | 35 ++++++++++++++++++++++++++++++ tests/Diff/SequenceMatcherTest.php | 1 - tests/Diff/SimilarityTest.php | 17 +++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/example/example.php b/example/example.php index ba2cf80d..d2f03fc3 100644 --- a/example/example.php +++ b/example/example.php @@ -72,8 +72,13 @@ function changeCSS(cssFile, cssLinkIndex) {

Informational

Between the two versions, there's a getStatistics(); echo round($diff->getSimilarity(), 2) * 100; - ?>% match. + ?>% match.
+ Inserted lines:
+ Deleted lines:
+ Not modified lines:
+ Lines with replacement:

diff --git a/lib/jblond/Diff.php b/lib/jblond/Diff.php index 9e1cf536..adeccfd4 100644 --- a/lib/jblond/Diff.php +++ b/lib/jblond/Diff.php @@ -287,4 +287,15 @@ public function getSimilarity(int $method = Similarity::CALC_DEFAULT): float return $this->similarity; } + + /** + * Get diff statistics + * + * @return array + */ + public function getStatistics(): array + { + $similarity = new Similarity($this->version1, $this->version2, $this->options); + return $similarity->getDifference(); + } } diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 77a205d8..2ac87b78 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -223,4 +223,39 @@ private function ratioReduce(int $sum, array $triple): int { return $sum + ($triple[count($triple) - 1]); } + + /** + * Get diff statistics + * + * @return array + */ + public function getDifference(): array + { + $return = [ + 'inserted' => 0, + 'deleted' => 0, + 'notModified' => 0, + 'replaced' => 0, + ]; + + foreach ($this->getGroupedOpCodes() as $chunk) { + foreach ($chunk as [$string, $one, $two, $three, $four]) { + switch ($string) { + case 'delete': + $return['deleted'] += $two - $one; + break; + case 'insert': + $return['inserted'] += $four - $three; + break; + case 'replace': + $return['replaced'] += $two - $one; + break; + } + } + } + + $return['notModified'] = count($this->old) - $return['replaced'] - $return['deleted']; + + return $return; + } } diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 787f8a30..18073d14 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -2,7 +2,6 @@ namespace Tests\Diff; -use jblond\Diff\ConstantsInterface; use jblond\Diff\SequenceMatcher; use PHPUnit\Framework\TestCase; diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index ea4701e0..1d5ee8e7 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -31,4 +31,21 @@ public function testGetSimilarity(): void $this->assertEquals(2 / 3, $similarity->getSimilarity(Similarity::CALC_FAST)); $this->assertEquals(2 / 3, $similarity->getSimilarity(Similarity::CALC_FASTEST)); } + + /** + * Test the statistics function + */ + public function testGetDifference(): void + { + $similarity = new Similarity(range(0, 10), range(1, 23)); + $this->assertEquals( + [ + 'inserted' => 13, + 'deleted' => 1, + 'notModified' => 10, + 'replaced' => 0, + ], + $similarity->getDifference() + ); + } } From 188f25853df7c60d118e3b0a0d833bb14c9a26c8 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 1 Nov 2021 15:39:14 +0100 Subject: [PATCH 173/206] Add statistics function for #97 "equal" in the switch rather than "notModified" --- example/example.php | 2 +- lib/jblond/Diff/Similarity.php | 10 +++++----- tests/Diff/SimilarityTest.php | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/example.php b/example/example.php index d2f03fc3..8b8b6cd8 100644 --- a/example/example.php +++ b/example/example.php @@ -77,7 +77,7 @@ function changeCSS(cssFile, cssLinkIndex) { ?>% match.
Inserted lines:
Deleted lines:
- Not modified lines:
+ Not modified lines:
Lines with replacement:

diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 2ac87b78..34b1664b 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -232,10 +232,10 @@ private function ratioReduce(int $sum, array $triple): int public function getDifference(): array { $return = [ - 'inserted' => 0, - 'deleted' => 0, - 'notModified' => 0, - 'replaced' => 0, + 'inserted' => 0, + 'deleted' => 0, + 'equal' => 0, + 'replaced' => 0, ]; foreach ($this->getGroupedOpCodes() as $chunk) { @@ -254,7 +254,7 @@ public function getDifference(): array } } - $return['notModified'] = count($this->old) - $return['replaced'] - $return['deleted']; + $return['equal'] = count($this->old) - $return['replaced'] - $return['deleted']; return $return; } diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index 1d5ee8e7..4d262495 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -42,7 +42,7 @@ public function testGetDifference(): void [ 'inserted' => 13, 'deleted' => 1, - 'notModified' => 10, + 'equal' => 10, 'replaced' => 0, ], $similarity->getDifference() From 54c0e03f08c9aa9f40368654661d03e2c75b6418 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 1 Nov 2021 16:39:05 +0100 Subject: [PATCH 174/206] Remove array element since it will be written a few lines later --- lib/jblond/Diff/Similarity.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 34b1664b..5beb60d6 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -234,7 +234,6 @@ public function getDifference(): array $return = [ 'inserted' => 0, 'deleted' => 0, - 'equal' => 0, 'replaced' => 0, ]; From c07c8ac6fbfe20a5a1dfa55300c12a6e47b3d1ee Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 16 Nov 2021 10:20:38 +0100 Subject: [PATCH 175/206] Add composer test command --- composer.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e8ea5228..b2602d0e 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,12 @@ "php_src": "phpcs --standard=phpcs.xml -s -p --colors ./lib/", "php_test": "phpcs --standard=phpcs.xml -s -p --colors ./tests/", "phpmd": "phpmd ./ ansi cleancode,codesize,controversial,design,naming,unusedcode --exclude vendor", - "changelog": "php generateChangelog.php" + "changelog": "php generateChangelog.php", + "test": [ + "@php_src", + "@php_test", + "phpunit --colors=always --testdox" + ] }, "scripts-descriptions": { "phpunit": "Run PHPUnit tests", From a0323ed13a0203789065de0362e4e2ea57fca126 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 16 Nov 2021 10:43:06 +0100 Subject: [PATCH 176/206] Add TupleSort test --- tests/Diff/DiffUtilsTest.php | 155 +++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tests/Diff/DiffUtilsTest.php diff --git a/tests/Diff/DiffUtilsTest.php b/tests/Diff/DiffUtilsTest.php new file mode 100644 index 00000000..d69c60d5 --- /dev/null +++ b/tests/Diff/DiffUtilsTest.php @@ -0,0 +1,155 @@ + + * @author Ferry Cools + * @copyright (c) 2021 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.4.0 + * @link https://github.com/JBlond/php-diff + */ +class DiffUtilsTest extends TestCase +{ + /** + * Test the sorting of an array by the nested arrays it contains + */ + public function testTupleSort(): void + { + $this->assertEquals( + 1, + DiffUtils::tupleSort( + [ + + 0 => [ + 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', + 'title' => 'Flower', + 'order' => 3, + ], + 1 => [ + 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', + 'title' => 'Free', + 'order' => 2, + ], + + 2 => [ + 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', + 'title' => 'Ready', + 'order' => 1 + ] + ], + [ + + 0 => [ + 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', + 'title' => 'Flower', + 'order' => 3, + ], + 1 => [ + 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', + 'title' => 'Free', + 'order' => 2, + ], + + 2 => [ + ] + ], + ) + ); + + $this->assertEquals( + 0, + DiffUtils::tupleSort( + [ + + 0 => [ + 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', + 'title' => 'Flower', + 'order' => 3, + ], + 1 => [ + 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', + 'title' => 'Free', + 'order' => 2, + ], + + 2 => [ + 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', + 'title' => 'Ready', + 'order' => 1 + ] + ], + [ + + 0 => [ + 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', + 'title' => 'Flower', + 'order' => 3, + ], + 1 => [ + 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', + 'title' => 'Free', + 'order' => 2, + ], + + 2 => [ + 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', + 'title' => 'Ready', + 'order' => 1 + ] + ], + ) + ); + + $this->assertEquals( + -1, + DiffUtils::tupleSort( + [ + + 0 => [ + 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', + 'title' => 'Flower', + 'order' => 3, + ], + 1 => [ + 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', + 'title' => 'Free', + 'order' => 2, + ], + + 2 => [ + + ] + ], + [ + + 0 => [ + 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', + 'title' => 'Flower', + 'order' => 3, + ], + 1 => [ + 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', + 'title' => 'Free', + 'order' => 2, + ], + + 2 => [ + 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', + 'title' => 'Ready', + 'order' => 1 + ] + ], + ) + ); + } +} From 7b9bce94484976269832318742664dcc541c9cf6 Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 17 Nov 2021 21:33:16 +0100 Subject: [PATCH 177/206] Fix test function length --- tests/Diff/DiffUtilsTest.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/Diff/DiffUtilsTest.php b/tests/Diff/DiffUtilsTest.php index d69c60d5..b46d5597 100644 --- a/tests/Diff/DiffUtilsTest.php +++ b/tests/Diff/DiffUtilsTest.php @@ -23,7 +23,7 @@ class DiffUtilsTest extends TestCase /** * Test the sorting of an array by the nested arrays it contains */ - public function testTupleSort(): void + public function testTupleSortOne(): void { $this->assertEquals( 1, @@ -65,7 +65,13 @@ public function testTupleSort(): void ], ) ); + } + /** + * Test the sorting of an array by the nested arrays it contains + */ + public function testTupleSortZero(): void + { $this->assertEquals( 0, DiffUtils::tupleSort( @@ -109,7 +115,13 @@ public function testTupleSort(): void ], ) ); + } + /** + * Test the sorting of an array by the nested arrays it contains + */ + public function testTupleSortMinusOne(): void + { $this->assertEquals( -1, DiffUtils::tupleSort( From d0391861f476b18760ed8a3944b8c9cc05ceae94 Mon Sep 17 00:00:00 2001 From: JBlond Date: Thu, 18 Nov 2021 10:10:38 +0100 Subject: [PATCH 178/206] Add coverage test --- .gitignore | 1 + composer.json | 7 +++++-- phpunit.xml | 22 ++++++++++++++++------ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 67b315d0..ddbe8d8f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ ### Composer ### composer.phar +/codeCoverage /vendor/ /composer.lock /.phpunit.result.cache diff --git a/composer.json b/composer.json index b2602d0e..dd9b68bb 100644 --- a/composer.json +++ b/composer.json @@ -64,13 +64,16 @@ "@php_src", "@php_test", "phpunit --colors=always --testdox" - ] + ], + "coverage": "phpunit --colors=always --coverage-html codeCoverage" }, "scripts-descriptions": { "phpunit": "Run PHPUnit tests", "php_src": "Run code sniffer on lib directory", "php_test": "Run code sniffer on tests directory", "phpmd": "Run php mess detector", - "changelog": "generate changelog from commits" + "changelog": "generate changelog from commits", + "test": "Run code formatting test and phpunit", + "coverage": "Run phpunit code overage" } } diff --git a/phpunit.xml b/phpunit.xml index 8152c643..b0543e73 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,7 +1,17 @@ - - - - tests - - + + + + + ./lib + + + + + tests + + From 56ed81df3d8006f68f098c347109725205457d02 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 19 Nov 2021 09:44:58 +0100 Subject: [PATCH 179/206] Optimize SequenceMatcher.php sort. The native PHP sort function is sufficient. There is no need for a callback function tupleSort. --- lib/jblond/Diff/DiffUtils.php | 1 + lib/jblond/Diff/SequenceMatcher.php | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php index 76fe272e..74380786 100644 --- a/lib/jblond/Diff/DiffUtils.php +++ b/lib/jblond/Diff/DiffUtils.php @@ -23,6 +23,7 @@ class DiffUtils * @param array $bArray Second array to compare. * * @return int -1, 0 or 1, as expected by the usort function. + * @deprecated */ public static function tupleSort(array $aArray, array $bArray): int { diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 01a9da51..bf120b3d 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -462,12 +462,7 @@ public function getMatchingBlocks(): array } } - usort( - $matchingBlocks, - static function ($aArray, $bArray) { - return DiffUtils::tupleSort($aArray, $bArray); - } - ); + sort($matchingBlocks); $i1 = 0; $j1 = 0; From 0ecdd1657a694d11c6311865ec21896684d73f90 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 22 Nov 2021 14:52:44 +0100 Subject: [PATCH 180/206] Keep "Out Of Context" lines in opCodes Instead of removing the lines which are out of context from the opCodes, They're now kept in the opCodes, but tagged as "outOfContext". This replaces the `generateLinesSkipped()` methods of the renderers. Other changes present like code reformatting and comments. --- lib/jblond/Diff/Renderer/Html/Merged.php | 4 +- lib/jblond/Diff/Renderer/Html/SideBySide.php | 4 +- lib/jblond/Diff/Renderer/Html/Unified.php | 4 +- lib/jblond/Diff/Renderer/MainRenderer.php | 28 +++--- .../Diff/Renderer/SubRendererInterface.php | 6 +- lib/jblond/Diff/Renderer/Text/Context.php | 8 +- lib/jblond/Diff/Renderer/Text/InlineCli.php | 4 +- lib/jblond/Diff/Renderer/Text/Unified.php | 8 +- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 13 ++- lib/jblond/Diff/SequenceMatcher.php | 92 ++++++++++--------- tests/Diff/SequenceMatcherTest.php | 2 + 11 files changed, 94 insertions(+), 79 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Html/Merged.php b/lib/jblond/Diff/Renderer/Html/Merged.php index 5b20e811..1ac26263 100644 --- a/lib/jblond/Diff/Renderer/Html/Merged.php +++ b/lib/jblond/Diff/Renderer/Html/Merged.php @@ -97,9 +97,9 @@ public function generateBlockHeader(array $changes): string /** * @inheritDoc * - * @return string Representation of skipped lines. + * @return string HTML code representing table rows showing text which is 'Out Of Context' */ - public function generateSkippedLines(): string + public function generateLinesOutOfContext($change): string { $marker = '…'; $headerClass = ''; diff --git a/lib/jblond/Diff/Renderer/Html/SideBySide.php b/lib/jblond/Diff/Renderer/Html/SideBySide.php index 9fddd544..67b6e2ef 100644 --- a/lib/jblond/Diff/Renderer/Html/SideBySide.php +++ b/lib/jblond/Diff/Renderer/Html/SideBySide.php @@ -86,9 +86,9 @@ public function generateDiffHeader(): string /** * @inheritDoc * - * @return string HTML code representation of a table's header. + * @return string HTML code representing table rows showing text which is "Out Of Context" */ - public function generateSkippedLines(): string + public function generateLinesOutOfContext($change): string { return << diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index df1b3cff..a3128106 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -87,9 +87,9 @@ public function generateDiffHeader(): string /** * @inheritDoc * - * @return string HTML code representation of skipped lines. + * @return string HTML code representing table rows showing text which is 'Out Of Context' */ - public function generateSkippedLines(): string + public function generateLinesOutOfContext($change): string { return << diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 76a5dcfa..6aa38b44 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -51,13 +51,7 @@ public function renderOutput(array $changes, object $subRenderer) $output = $subRenderer->generateDiffHeader(); - foreach ($changes as $iterator => $blocks) { - if ($iterator > 0) { - // If this is a separate block, we're condensing code to indicate a significant portion of the code - // has been collapsed as it did not change. - $output .= $subRenderer->generateSkippedLines(); - } - + foreach ($changes as $blocks) { $this->maxLineMarkerWidth = max( strlen($this->options['insertMarkers'][0]), strlen($this->options['deleteMarkers'][0]), @@ -100,6 +94,10 @@ public function renderOutput(array $changes, object $subRenderer) // TODO: Keep backward compatible with renderers? $output .= $subRenderer->generateLinesIgnore($change); break; + case 'outOfContext': + // TODO: Keep backward compatible with renderers? + $output .= $subRenderer->generateLinesOutOfContext($change); + break; } $output .= $subRenderer->generateBlockFooter($change); @@ -335,17 +333,15 @@ private function markOuterChange(array &$oldText, array &$newText, int $startOld // Changes between the lines exist. // Add markers around the changed character sequence in the old string. $sequenceEnd = mb_strlen($oldString) + $end; - $oldString - = mb_substr($oldString, 0, $start) . "\0" . - mb_substr($oldString, $start, $sequenceEnd - $start) . "\1" . - mb_substr($oldString, $sequenceEnd); + $oldString = mb_substr($oldString, 0, $start) . "\0" . + mb_substr($oldString, $start, $sequenceEnd - $start) . "\1" . + mb_substr($oldString, $sequenceEnd); // Add markers around the changed character sequence in the new string. $sequenceEnd = mb_strlen($newString) + $end; - $newString - = mb_substr($newString, 0, $start) . "\0" . - mb_substr($newString, $start, $sequenceEnd - $start) . "\1" . - mb_substr($newString, $sequenceEnd); + $newString = mb_substr($newString, 0, $start) . "\0" . + mb_substr($newString, $start, $sequenceEnd - $start) . "\1" . + mb_substr($newString, $sequenceEnd); // Overwrite the strings in the old and new text so the changed lines include the markers. $oldText[$startOld + $iterator] = $oldString; @@ -397,7 +393,7 @@ private function getOuterChange(string $oldString, string $newString): array /** * Helper function that will fill the changes-array for the renderer with default values. - * Every time an operation changes (specified by $tag) , a new element will be appended to this array. + * Every time an operation changes (specified by $tag), a new element will be appended to this array. * * The index of the last element of the array is always returned. * diff --git a/lib/jblond/Diff/Renderer/SubRendererInterface.php b/lib/jblond/Diff/Renderer/SubRendererInterface.php index cc12eadc..48d8069e 100644 --- a/lib/jblond/Diff/Renderer/SubRendererInterface.php +++ b/lib/jblond/Diff/Renderer/SubRendererInterface.php @@ -63,11 +63,11 @@ public function generateLinesEqual(array $changes): string; public function generateLinesInsert(array $changes): string; /** - * Generate a string representation of lines that are skipped in the diff view. + * Generate a string representation of lines that are "Out Of Context" for the diff view. * - * @return string Representation of skipped lines. + * @return string Representation of 'Out Of Context' lines. */ - public function generateSkippedLines(): string; + public function generateLinesOutOfContext($change): string; /** * Generate a string representation of lines with ignored differences between both versions. diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 812cce8e..5e037882 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -44,9 +44,13 @@ public function render() $diff = false; $opCodes = $this->diff->getGroupedOpCodes(); - foreach ($opCodes as $group) { + foreach ($opCodes as $key => $group) { + if ($key % 2) { + // Skip lines which are Out Of Context. + continue; + } $diff .= "***************\n"; - $lastItem = count($group) - 1; + $lastItem = array_key_last($group); $start1 = $group['0']['1']; $end1 = $group[$lastItem]['2']; $start2 = $group['0']['3']; diff --git a/lib/jblond/Diff/Renderer/Text/InlineCli.php b/lib/jblond/Diff/Renderer/Text/InlineCli.php index d5167379..74e0951d 100644 --- a/lib/jblond/Diff/Renderer/Text/InlineCli.php +++ b/lib/jblond/Diff/Renderer/Text/InlineCli.php @@ -77,9 +77,9 @@ public function generateBlockHeader(array $changes): string /** * @inheritDoc * - * @return string Representation of skipped lines. + * @return string HTML code representing table rows showing text which is 'Out Of Context' */ - public function generateSkippedLines(): string + public function generateLinesOutOfContext($change): string { return "...\n"; } diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index da8fc182..0c497e4c 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -34,8 +34,12 @@ public function render() { $diff = false; $opCodes = $this->diff->getGroupedOpCodes(); - foreach ($opCodes as $group) { - $lastItem = count($group) - 1; + foreach ($opCodes as $key => $group) { + if ($key % 2) { + // Skip lines which are Out Of Context. + continue; + } + $lastItem = array_key_last($group); $i1 = $group['0']['1']; $i2 = $group[$lastItem]['2']; $j1 = $group['0']['3']; diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 96c67953..0af4c4af 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -66,8 +66,12 @@ private function output(): string { $diff = ''; $opCodes = $this->diff->getGroupedOpCodes(); - foreach ($opCodes as $group) { - $lastItem = count($group) - 1; + foreach ($opCodes as $key => $group) { + if ($key % 2) { + // Skip lines which are Out Of Context. + continue; + } + $lastItem = array_key_last($group); $i1 = $group['0']['1']; $i2 = $group[$lastItem]['2']; $j1 = $group['0']['3']; @@ -82,6 +86,7 @@ private function output(): string '@@ -' . ($i1 + 1) . ',' . ($i2 - $i1) . ' +' . ($j1 + 1) . ',' . ($j2 - $j1) . " @@\n", 'purple' ); + foreach ($group as [$tag, $i1, $i2, $j1, $j2]) { if ($tag == 'equal') { $string = implode( @@ -112,8 +117,8 @@ private function output(): string } /** - * @param string $string - * @param string $color + * @param string $string + * @param string $color * * @return string */ diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index bf120b3d..1942436c 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -115,6 +115,7 @@ public function setOptions(array $options): void * * @param string|array $version1 A string or array containing the lines to compare against. * @param string|array $version2 A string or array containing the lines to compare. + * * @return void */ public function setSequences($version1, $version2): void @@ -129,6 +130,7 @@ public function setSequences($version1, $version2): void * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. * * @param string|array|void $version1 The sequence to set as the first sequence. + * * @return void */ public function setSeq1($version1): void @@ -150,7 +152,8 @@ public function setSeq1($version1): void * * Also resets internal caches to indicate that, when calling the calculation methods, we need to recalculate them. * - * @param string|array $version2 The sequence to set as the second sequence. + * @param string|array $version2 The sequence to set as the second sequence. + * * @return void */ public function setSeq2($version2): void @@ -186,9 +189,11 @@ private function chainB(): void unset($this->b2j[$char]); continue; } + $this->b2j[$char][] = $i; continue; } + $this->b2j[$char] = [$i]; } @@ -216,49 +221,34 @@ private function chainB(): void } /** - * Return a series of nested arrays containing different groups of generated - * op codes for the differences between the strings with up to $this->options['context'] lines - * of surrounding content. + * Return a series of nested arrays containing different groups of generated op codes for the differences between + * the strings with up to $this->options['context'] lines of surrounding content. * - * Essentially what happens here is any big equal blocks of strings are stripped - * out, the smaller subsets of changes are then arranged in to their groups. - * This means that the sequence matcher and diffs do not need to include the full - * content of the different files but can still provide context as to where the - * changes are. + * Any large equal block of strings is separated into smaller subsets which are "Within- or Out Of Context". * * @return array Nested array of all the grouped op codes. */ public function getGroupedOpCodes(): array { $opCodes = $this->getOpCodes(); - if (empty($opCodes)) { - $opCodes = [ - [ - 'equal', - 0, - 1, - 0, - 1, - ], - ]; - } + $opCodes = $opCodes ?: [['equal', 0, 1, 0, 1,],]; if ($this->options['trimEqual']) { - if ($opCodes['0']['0'] == 'equal') { - // Remove sequences at the start of the text, but keep the context lines. - $opCodes['0'] = [ - $opCodes['0']['0'], - max($opCodes['0']['1'], $opCodes['0']['2'] - $this->options['context']), - $opCodes['0']['2'], - max($opCodes['0']['3'], $opCodes['0']['4'] - $this->options['context']), - $opCodes['0']['4'], + if ($opCodes[0][0] == 'equal') { + // Remove equal sequences at the start of the text, but keep the context lines. + $opCodes[0] = [ + $opCodes[0][0], + max($opCodes[0][1], $opCodes[0][2] - $this->options['context']), + $opCodes[0][2], + max($opCodes[0][3], $opCodes[0][4] - $this->options['context']), + $opCodes[0][4], ]; } - $lastItem = count($opCodes) - 1; - if ($opCodes[$lastItem]['0'] == 'equal') { + $lastItem = array_key_last($opCodes); + if ($opCodes[$lastItem][0] == 'equal') { + // Remove equal sequences at the end of the text, but keep the context lines. [$tag, $item1, $item2, $item3, $item4] = $opCodes[$lastItem]; - // Remove sequences at the end of the text, but keep the context lines. $opCodes[$lastItem] = [ $tag, $item1, @@ -271,35 +261,49 @@ public function getGroupedOpCodes(): array $maxRange = $this->options['context'] * 2; $groups = []; - $group = []; + $newGroup = []; foreach ($opCodes as [$tag, $item1, $item2, $item3, $item4]) { if ($tag == 'equal' && $item2 - $item1 > $maxRange) { - $group[] = [ + // Count of equal lines is greater than defined maximum context. + // Define lines before "Out of Context". + $newGroup[] = [ $tag, $item1, min($item2, $item1 + $this->options['context']), $item3, min($item4, $item3 + $this->options['context']), ]; - $groups[] = $group; - $group = []; + + $groups[] = $newGroup; + + // Define lines which are "Out Of Context". + $newGroup = []; + $newGroup[] = [ + 'outOfContext', + min($item2, $item1 + $this->options['context']), + max($item1, $item2 - $this->options['context']), + min($item4, $item3 + $this->options['context']), + max($item3, $item4 - $this->options['context']), + ]; + $groups[] = $newGroup; + + // Define start of lines after "Out Of Context". + $newGroup = []; $item1 = max($item1, $item2 - $this->options['context']); $item3 = max($item3, $item4 - $this->options['context']); } - $group[] = [ - $tag, - $item1, - $item2, - $item3, - $item4, - ]; + // Define lines "Within Context". + $newGroup[] = [$tag, $item1, $item2, $item3, $item4,]; } - if (!$this->options['trimEqual'] || (!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal'))) { + if ( + !$this->options['trimEqual'] || + (!empty($newGroup) && !(count($newGroup) == 1 && $newGroup[0][0] == 'equal')) + ) { // Add the last sequences when !trimEqual || When there are no differences between both versions. - $groups[] = $group; + $groups[] = $newGroup; } return $groups; diff --git a/tests/Diff/SequenceMatcherTest.php b/tests/Diff/SequenceMatcherTest.php index 18073d14..3a767489 100644 --- a/tests/Diff/SequenceMatcherTest.php +++ b/tests/Diff/SequenceMatcherTest.php @@ -59,7 +59,9 @@ public function testGetGroupedOpCodesTrimEqualFalse(): void $this->assertEquals( [ [['equal', 0, 3, 0, 3]], + [['outOfContext', 3, 4, 3, 4]], [['equal', 4, 7, 4, 7], ['replace', 7, 8, 7, 8], ['equal', 8, 11, 8, 11]], + [['outOfContext', 11, 12, 11, 12]], [['equal', 12, 15, 12, 15]], ], $sequenceMatcher->getGroupedOpCodes() From e74c993713b617e0966bc1c18d752980740b28d8 Mon Sep 17 00:00:00 2001 From: Mario Date: Thu, 27 Jan 2022 13:39:26 +0100 Subject: [PATCH 181/206] Upate Link from Xiphe to DigiLive jQuery-Merge-for-php-diff --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 87bd71cc..251ed218 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ You can also fork this repository and open a PR. Xiphe has build a jQuery plugin with that you can merge the compared files. Have a look -at [jQuery-Merge-for-php-diff](https://github.com/Xiphe/jQuery-Merge-for-php-diff) +at [jQuery-Merge-for-php-diff](https://github.com/DigiLive/jQuery-Merge-for-php-diff) . ## Todo From c8e40897e15009f2224b9a4e93dbfd11b1c3306b Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 18:56:49 +0100 Subject: [PATCH 182/206] Refactor array indexes --- lib/jblond/Diff/Renderer/Text/Context.php | 8 ++++---- lib/jblond/Diff/Renderer/Text/Unified.php | 8 ++++---- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/Context.php b/lib/jblond/Diff/Renderer/Text/Context.php index 5e037882..75d9b46a 100644 --- a/lib/jblond/Diff/Renderer/Text/Context.php +++ b/lib/jblond/Diff/Renderer/Text/Context.php @@ -51,10 +51,10 @@ public function render() } $diff .= "***************\n"; $lastItem = array_key_last($group); - $start1 = $group['0']['1']; - $end1 = $group[$lastItem]['2']; - $start2 = $group['0']['3']; - $end2 = $group[$lastItem]['4']; + $start1 = $group[0][1]; + $end1 = $group[$lastItem][2]; + $start2 = $group[0][3]; + $end2 = $group[$lastItem][4]; // Line to line header for version 1. $diffStart = $end1 - $start1 >= 2 ? $start1 + 1 . ',' : ''; diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 0c497e4c..0fdb5f52 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -40,10 +40,10 @@ public function render() continue; } $lastItem = array_key_last($group); - $i1 = $group['0']['1']; - $i2 = $group[$lastItem]['2']; - $j1 = $group['0']['3']; - $j2 = $group[$lastItem]['4']; + $i1 = $group[0][1]; + $i2 = $group[$lastItem][2]; + $j1 = $group[0][3]; + $j2 = $group[$lastItem][4]; if ($i1 == 0 && $i2 == 0) { $i1 = -1; diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 0af4c4af..ae0e2092 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -72,10 +72,10 @@ private function output(): string continue; } $lastItem = array_key_last($group); - $i1 = $group['0']['1']; - $i2 = $group[$lastItem]['2']; - $j1 = $group['0']['3']; - $j2 = $group[$lastItem]['4']; + $i1 = $group[0][1]; + $i2 = $group[$lastItem][2]; + $j1 = $group[0][3]; + $j2 = $group[$lastItem][4]; if ($i1 == 0 && $i2 == 0) { $i1 = -1; From 11bc0fc4c78f9b4d4dc4b41a13577cfe7bb745ef Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 18:57:59 +0100 Subject: [PATCH 183/206] Refactor test resources --- tests/resources/htmlMerged.txt | 4 ++-- tests/resources/htmlSideBySide.txt | 4 ++-- tests/resources/htmlUnified.txt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/resources/htmlMerged.txt b/tests/resources/htmlMerged.txt index 666263db..ead95a7c 100644 --- a/tests/resources/htmlMerged.txt +++ b/tests/resources/htmlMerged.txt @@ -71,10 +71,10 @@ 22         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - + … … - + 25         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> diff --git a/tests/resources/htmlSideBySide.txt b/tests/resources/htmlSideBySide.txt index 67ce275c..9d114465 100644 --- a/tests/resources/htmlSideBySide.txt +++ b/tests/resources/htmlSideBySide.txt @@ -207,12 +207,12 @@         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - + … … … … - + 25         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> diff --git a/tests/resources/htmlUnified.txt b/tests/resources/htmlUnified.txt index f8add881..5eb2dc15 100644 --- a/tests/resources/htmlUnified.txt +++ b/tests/resources/htmlUnified.txt @@ -151,11 +151,11 @@ 22 22         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> - + … … … - + 25 25         <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.</p> From 073a478a5ffe4f2c78b80367f2d56078f5b22ef5 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 19:31:35 +0100 Subject: [PATCH 184/206] Cut redundant suppression --- lib/jblond/Diff/SequenceMatcher.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 1942436c..47117aa4 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -437,11 +437,6 @@ public function getMatchingBlocks(): array $matchingBlocks = []; while (!empty($queue)) { [$aLower, $aUpper, $bLower, $bUpper] = array_pop($queue); - /** - * @noinspection PhpStrictTypeCheckingInspection - * $aLower, $aUpper, $bLower, $bUpper reported as wrong type because of multiple definitions of function - * count above. - */ $longestMatch = $this->findLongestMatch($aLower, $aUpper, $bLower, $bUpper); [$list1, $list2, $list3] = $longestMatch; if ($list3) { From a9635beb2098986d894b7a0774e2b0cfad62d784 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 19:55:35 +0100 Subject: [PATCH 185/206] Fix docblock --- lib/jblond/Diff/Renderer/Html/Unified.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/jblond/Diff/Renderer/Html/Unified.php b/lib/jblond/Diff/Renderer/Html/Unified.php index a3128106..af61751d 100644 --- a/lib/jblond/Diff/Renderer/Html/Unified.php +++ b/lib/jblond/Diff/Renderer/Html/Unified.php @@ -222,7 +222,7 @@ public function generateLinesReplace(array $changes): string /** * @inheritDoc * - * @return string Html code representing table rows showing modified text. + * @return string Html code representing table rows showing ignored text. */ public function generateLinesIgnore(array $changes): string { From cfa3033487de8a6c73c70c590023acb42c87ffe6 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 19:57:45 +0100 Subject: [PATCH 186/206] Bump PHPUnit xml schema to version 9.5 --- phpunit.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml b/phpunit.xml index b0543e73..7b889f61 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" bootstrap="vendor/autoload.php" - xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"> + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"> ./lib From 160a3ae6472fc357aff71e03f4bf26a0453df0d2 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 20:08:48 +0100 Subject: [PATCH 187/206] Fix potentially polymorphic call --- lib/jblond/Diff/Renderer/MainRenderer.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index 6aa38b44..eea64cb1 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -37,12 +37,13 @@ class MainRenderer extends MainRendererAbstract * * This method is called by the renderers which extends this class. * - * @param array $changes Contains the op-codes about the differences between version1 and version2. - * @param object $subRenderer Renderer which is subClass of this class. + * @param array $changes Contains the op-codes about the differences between version1 and + * version2. + * @param SubRendererInterface $subRenderer Renderer which is child class of this class. * * @return string|false String representation of the differences or false when versions are identical. */ - public function renderOutput(array $changes, object $subRenderer) + public function renderOutput(array $changes, SubRendererInterface $subRenderer) { if (!$changes) { //No changes between version1 and version2 From 40f418f5ad741ff925db484e027477dadd5ee1d7 Mon Sep 17 00:00:00 2001 From: DigiLive Date: Mon, 21 Feb 2022 20:27:09 +0100 Subject: [PATCH 188/206] Fix grammar --- lib/jblond/Diff/ConstantsInterface.php | 2 +- lib/jblond/Diff/Renderer/MainRenderer.php | 2 +- lib/jblond/Diff/SequenceMatcher.php | 8 ++++---- lib/jblond/Diff/Similarity.php | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/jblond/Diff/ConstantsInterface.php b/lib/jblond/Diff/ConstantsInterface.php index 4166a608..c41e6055 100644 --- a/lib/jblond/Diff/ConstantsInterface.php +++ b/lib/jblond/Diff/ConstantsInterface.php @@ -27,7 +27,7 @@ interface ConstantsInterface */ public const DIFF_IGNORE_LINE_EMPTY = 1; /** - * Flag to ignore blank lines. (Lines which contain no or only non printable characters.) + * Flag to ignore blank lines. (Lines which contain no or only non-printable characters.) */ public const DIFF_IGNORE_LINE_BLANK = 2; } diff --git a/lib/jblond/Diff/Renderer/MainRenderer.php b/lib/jblond/Diff/Renderer/MainRenderer.php index eea64cb1..db0d4cd1 100644 --- a/lib/jblond/Diff/Renderer/MainRenderer.php +++ b/lib/jblond/Diff/Renderer/MainRenderer.php @@ -429,7 +429,7 @@ private function appendChangesArray(array &$blocks, string $tag, int $lineInOld, } /** - * Format a series of strings which are suitable for output in a HTML rendered diff. + * Format a series of strings which are suitable for output in an HTML rendered diff. * * This involves replacing tab characters with spaces, making the HTML safe for output by ensuring that double * spaces are replaced with   etc. diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 47117aa4..31313e59 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -51,12 +51,12 @@ class SequenceMatcher implements ConstantsInterface */ private $b2j = []; /** - * @var array A list of all of the op-codes for the differences between the compared strings. + * @var array A list of all the op-codes for the differences between the compared strings. */ private $opCodes; /** - * @var array A nested set of arrays for all of the matching sub-sequences the compared strings. + * @var array A nested set of arrays for all the matching sub-sequences the compared strings. */ private $matchingBlocks; @@ -623,8 +623,8 @@ private function isBJunk(string $bString): bool /** * Check if the two lines at the given indexes are different or not. * - * @param int $aIndex Line number to check against in a. - * @param int $bIndex Line number to check against in b. + * @param int $aIndex Number of line to check against in A. + * @param int $bIndex Number of line to check against in B. * * @return bool True if the lines are different and false if not. */ diff --git a/lib/jblond/Diff/Similarity.php b/lib/jblond/Diff/Similarity.php index 5beb60d6..59ace0c8 100644 --- a/lib/jblond/Diff/Similarity.php +++ b/lib/jblond/Diff/Similarity.php @@ -71,7 +71,7 @@ public function setSeq2($version2): void public function getSimilarity(int $type = self::CALC_DEFAULT): float { if ($this->options['ignoreLines']) { - // Backup original sequences and filter non blank lines. + // Backup original sequences and filter non-blank lines. $this->stripLines(); } From 0d45b031654d5bc97476c07bf3aa5df751d3e8ef Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 16 May 2022 11:08:31 +0200 Subject: [PATCH 189/206] Fix: #112 Call to function unset() contains undefined variable $line. --- composer.json | 3 ++- lib/jblond/Diff/SequenceMatcher.php | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index dd9b68bb..bdbc4bad 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "squizlabs/php_codesniffer": "*", "phpmd/phpmd": "2.*", "jblond/php-cli": "^1.0", - "digilive/git-changelog": "^1" + "digilive/git-changelog": "^1", + "vimeo/psalm": "^4.23" }, "suggest": { "jblond/php-cli": "^1.0" diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 31313e59..0ee8ab22 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -369,7 +369,6 @@ static function (&$line) { $line = trim($line); } ); - unset($line); } if ( From e1a9ec5bbd9a2eedb4736987667e262238f78786 Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 16 May 2022 11:11:41 +0200 Subject: [PATCH 190/206] Remove package --- composer.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index bdbc4bad..dd9b68bb 100644 --- a/composer.json +++ b/composer.json @@ -36,8 +36,7 @@ "squizlabs/php_codesniffer": "*", "phpmd/phpmd": "2.*", "jblond/php-cli": "^1.0", - "digilive/git-changelog": "^1", - "vimeo/psalm": "^4.23" + "digilive/git-changelog": "^1" }, "suggest": { "jblond/php-cli": "^1.0" From 42ea73b7b455abf3385ea1c02be73b45ee17c5b8 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 12 Jul 2022 11:13:39 +0200 Subject: [PATCH 191/206] Optimize Remove unused tupleSort function --- lib/jblond/Diff/DiffUtils.php | 50 ---------- tests/Diff/DiffUtilsTest.php | 167 ---------------------------------- 2 files changed, 217 deletions(-) delete mode 100644 lib/jblond/Diff/DiffUtils.php delete mode 100644 tests/Diff/DiffUtilsTest.php diff --git a/lib/jblond/Diff/DiffUtils.php b/lib/jblond/Diff/DiffUtils.php deleted file mode 100644 index 74380786..00000000 --- a/lib/jblond/Diff/DiffUtils.php +++ /dev/null @@ -1,50 +0,0 @@ - - * @copyright (c) 2020 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.4.0 - * @link https://github.com/JBlond/php-diff - */ -class DiffUtils -{ - /** - * Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks - * - * @param array $aArray First array to compare. - * @param array $bArray Second array to compare. - * - * @return int -1, 0 or 1, as expected by the usort function. - * @deprecated - */ - public static function tupleSort(array $aArray, array $bArray): int - { - $max = max(count($aArray), count($bArray)); - for ($counter = 0; $counter < $max; ++$counter) { - if ($aArray[$counter] < $bArray[$counter]) { - return -1; - } - - if ($aArray[$counter] > $bArray[$counter]) { - return 1; - } - } - - if (count($aArray) == count($bArray)) { - return 0; - } - if (count($aArray) < count($bArray)) { - return -1; - } - - return 1; - } -} diff --git a/tests/Diff/DiffUtilsTest.php b/tests/Diff/DiffUtilsTest.php deleted file mode 100644 index b46d5597..00000000 --- a/tests/Diff/DiffUtilsTest.php +++ /dev/null @@ -1,167 +0,0 @@ - - * @author Ferry Cools - * @copyright (c) 2021 Mario Brandt - * @license New BSD License http://www.opensource.org/licenses/bsd-license.php - * @version 2.4.0 - * @link https://github.com/JBlond/php-diff - */ -class DiffUtilsTest extends TestCase -{ - /** - * Test the sorting of an array by the nested arrays it contains - */ - public function testTupleSortOne(): void - { - $this->assertEquals( - 1, - DiffUtils::tupleSort( - [ - - 0 => [ - 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', - 'title' => 'Flower', - 'order' => 3, - ], - 1 => [ - 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', - 'title' => 'Free', - 'order' => 2, - ], - - 2 => [ - 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', - 'title' => 'Ready', - 'order' => 1 - ] - ], - [ - - 0 => [ - 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', - 'title' => 'Flower', - 'order' => 3, - ], - 1 => [ - 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', - 'title' => 'Free', - 'order' => 2, - ], - - 2 => [ - ] - ], - ) - ); - } - - /** - * Test the sorting of an array by the nested arrays it contains - */ - public function testTupleSortZero(): void - { - $this->assertEquals( - 0, - DiffUtils::tupleSort( - [ - - 0 => [ - 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', - 'title' => 'Flower', - 'order' => 3, - ], - 1 => [ - 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', - 'title' => 'Free', - 'order' => 2, - ], - - 2 => [ - 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', - 'title' => 'Ready', - 'order' => 1 - ] - ], - [ - - 0 => [ - 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', - 'title' => 'Flower', - 'order' => 3, - ], - 1 => [ - 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', - 'title' => 'Free', - 'order' => 2, - ], - - 2 => [ - 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', - 'title' => 'Ready', - 'order' => 1 - ] - ], - ) - ); - } - - /** - * Test the sorting of an array by the nested arrays it contains - */ - public function testTupleSortMinusOne(): void - { - $this->assertEquals( - -1, - DiffUtils::tupleSort( - [ - - 0 => [ - 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', - 'title' => 'Flower', - 'order' => 3, - ], - 1 => [ - 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', - 'title' => 'Free', - 'order' => 2, - ], - - 2 => [ - - ] - ], - [ - - 0 => [ - 'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4', - 'title' => 'Flower', - 'order' => 3, - ], - 1 => [ - 'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594', - 'title' => 'Free', - 'order' => 2, - ], - - 2 => [ - 'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b', - 'title' => 'Ready', - 'order' => 1 - ] - ], - ) - ); - } -} From 54124a65d4eb28caa21f0b4c67e0b6c2403a29a0 Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 12 Jul 2022 11:21:34 +0200 Subject: [PATCH 192/206] Fix "Opening brace must not be followed by a blank" --- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 1 - tests/Diff/Renderer/MainRendererTest.php | 1 - tests/Diff/SimilarityTest.php | 1 - 3 files changed, 3 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index ae0e2092..c4338a33 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -20,7 +20,6 @@ */ class UnifiedCli extends MainRendererAbstract { - /** * @var CliColors */ diff --git a/tests/Diff/Renderer/MainRendererTest.php b/tests/Diff/Renderer/MainRendererTest.php index 2ffc33e4..e6f0ba15 100644 --- a/tests/Diff/Renderer/MainRendererTest.php +++ b/tests/Diff/Renderer/MainRendererTest.php @@ -33,7 +33,6 @@ */ class MainRendererTest extends TestCase { - /** * @var string[] Defines the main renderer options. */ diff --git a/tests/Diff/SimilarityTest.php b/tests/Diff/SimilarityTest.php index 4d262495..abab54c7 100644 --- a/tests/Diff/SimilarityTest.php +++ b/tests/Diff/SimilarityTest.php @@ -19,7 +19,6 @@ */ class SimilarityTest extends TestCase { - /** * Test the similarity ratio between two sequences with different methods. */ From d62afcf55fb1e335f5d4c0ff31789cf50be659fe Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 12 Jul 2022 11:35:58 +0200 Subject: [PATCH 193/206] Fix PHPMD warnings --- lib/jblond/Diff/SequenceMatcher.php | 80 +++++++++---------- .../Diff/Renderer/Text/TextRenderersTest.php | 2 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 0ee8ab22..48497634 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -337,24 +337,24 @@ public function getOpCodes(): array return $this->opCodes; } - $i = 0; - $j = 0; + $iFrom = 0; + $jFrom = 0; $this->opCodes = []; $blocks = $this->getMatchingBlocks(); - foreach ($blocks as [$ai, $bj, $size]) { + foreach ($blocks as [$blockA, $blockB, $size]) { $tag = ''; - if ($i < $ai && $j < $bj) { + if ($iFrom < $blockA && $jFrom < $blockB) { $tag = 'replace'; - } elseif ($i < $ai) { + } elseif ($iFrom < $blockA) { $tag = 'delete'; - } elseif ($j < $bj) { + } elseif ($jFrom < $blockB) { $tag = 'insert'; } if ($this->options['ignoreLines']) { - $slice1 = array_slice($this->old, $i, $ai - $i); - $slice2 = array_slice($this->new, $j, $bj - $j); + $slice1 = array_slice($this->old, $iFrom, $blockA - $iFrom); + $slice2 = array_slice($this->new, $jFrom, $blockB - $jFrom); if ($this->options['ignoreLines'] == 2) { array_walk( @@ -382,23 +382,23 @@ static function (&$line) { if ($tag) { $this->opCodes[] = [ $tag, - $i, - $ai, - $j, - $bj, + $iFrom, + $blockA, + $jFrom, + $blockB, ]; } - $i = $ai + $size; - $j = $bj + $size; + $iFrom = $blockA + $size; + $jFrom = $blockB + $size; if ($size) { $this->opCodes[] = [ 'equal', - $ai, - $i, - $bj, - $j, + $blockA, + $iFrom, + $blockB, + $jFrom, ]; } } @@ -462,34 +462,34 @@ public function getMatchingBlocks(): array sort($matchingBlocks); - $i1 = 0; - $j1 = 0; - $k1 = 0; + $iMatchingBlock = 0; + $jMatchingBlock = 0; + $kMatchingBlock = 0; $nonAdjacent = []; foreach ($matchingBlocks as [$list4, $list5, $list6]) { - if ($i1 + $k1 == $list4 && $j1 + $k1 == $list5) { - $k1 += $list6; + if ($iMatchingBlock + $kMatchingBlock == $list4 && $jMatchingBlock + $kMatchingBlock == $list5) { + $kMatchingBlock += $list6; continue; } - if ($k1) { + if ($kMatchingBlock) { $nonAdjacent[] = [ - $i1, - $j1, - $k1, + $iMatchingBlock, + $jMatchingBlock, + $kMatchingBlock, ]; } - $i1 = $list4; - $j1 = $list5; - $k1 = $list6; + $iMatchingBlock = $list4; + $jMatchingBlock = $list5; + $kMatchingBlock = $list6; } - if ($k1) { + if ($kMatchingBlock) { $nonAdjacent[] = [ - $i1, - $j1, - $k1, + $iMatchingBlock, + $jMatchingBlock, + $kMatchingBlock, ]; } @@ -547,12 +547,12 @@ public function findLongestMatch(int $aLower, int $aUpper, int $bLower, int $bUp break; } - $k = ($j2Len[$j - 1] ?? 0) + 1; - $newJ2Len[$j] = $k; - if ($k > $bestSize) { - $bestI = $i - $k + 1; - $bestJ = $j - $k + 1; - $bestSize = $k; + $kRatio = ($j2Len[$j - 1] ?? 0) + 1; + $newJ2Len[$j] = $kRatio; + if ($kRatio > $bestSize) { + $bestI = $i - $kRatio + 1; + $bestJ = $j - $kRatio + 1; + $bestSize = $kRatio; } } diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index 337eab36..f76484f0 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -27,7 +27,7 @@ class TextRenderersTest extends TestCase /** * @var bool Store the renderer's output in a file, when set to true. */ - private $genOutputFiles = false; + protected $genOutputFiles = false; /** * TextRenderersTest constructor. From 839b0f068f7f609ef3e6aaea7a70d726c1447d0d Mon Sep 17 00:00:00 2001 From: JBlond Date: Tue, 12 Jul 2022 11:42:00 +0200 Subject: [PATCH 194/206] Fix PHPMD warnings --- lib/jblond/Diff/Renderer/Text/Unified.php | 24 ++++++++++---------- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 24 ++++++++++---------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 0fdb5f52..897c30d5 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -40,23 +40,23 @@ public function render() continue; } $lastItem = array_key_last($group); - $i1 = $group[0][1]; - $i2 = $group[$lastItem][2]; - $j1 = $group[0][3]; - $j2 = $group[$lastItem][4]; + $iGroup1 = $group[0][1]; + $iGroup2 = $group[$lastItem][2]; + $jGroup1 = $group[0][3]; + $jGroup2 = $group[$lastItem][4]; - if ($i1 == 0 && $i2 == 0) { - $i1 = -1; - $i2 = -1; + if ($iGroup1 == 0 && $iGroup2 == 0) { + $iGroup1 = -1; + $iGroup2 = -1; } - $diff .= '@@ -' . ($i1 + 1) . ',' . ($i2 - $i1) . ' +' . ($j1 + 1) . ',' . ($j2 - $j1) . " @@\n"; - foreach ($group as [$tag, $i1, $i2, $j1, $j2]) { + $diff .= '@@ -' . ($iGroup1 + 1) . ',' . ($iGroup2 - $iGroup1) . ' +' . ($jGroup1 + 1) . ',' . ($jGroup2 - $jGroup1) . " @@\n"; + foreach ($group as [$tag, $iGroup1, $iGroup2, $jGroup1, $jGroup2]) { if ($tag == 'equal') { $diff .= ' ' . implode( "\n ", - $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + $this->diff->getArrayRange($this->diff->getVersion1(), $iGroup1, $iGroup2) ) . "\n"; continue; } @@ -64,14 +64,14 @@ public function render() $diff .= '-' . implode( "\n-", - $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + $this->diff->getArrayRange($this->diff->getVersion1(), $iGroup1, $iGroup2) ) . "\n"; } if ($tag == 'replace' || $tag == 'insert') { $diff .= '+' . implode( "\n+", - $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) + $this->diff->getArrayRange($this->diff->getVersion2(), $jGroup1, $jGroup2) ) . "\n"; } } diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index c4338a33..6d5a74b2 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -71,26 +71,26 @@ private function output(): string continue; } $lastItem = array_key_last($group); - $i1 = $group[0][1]; - $i2 = $group[$lastItem][2]; - $j1 = $group[0][3]; - $j2 = $group[$lastItem][4]; + $iGroup1 = $group[0][1]; + $iGroup2 = $group[$lastItem][2]; + $jGroup1 = $group[0][3]; + $jGroup2 = $group[$lastItem][4]; - if ($i1 == 0 && $i2 == 0) { - $i1 = -1; - $i2 = -1; + if ($iGroup1 == 0 && $iGroup2 == 0) { + $iGroup1 = -1; + $iGroup2 = -1; } $diff .= $this->colorizeString( - '@@ -' . ($i1 + 1) . ',' . ($i2 - $i1) . ' +' . ($j1 + 1) . ',' . ($j2 - $j1) . " @@\n", + '@@ -' . ($iGroup1 + 1) . ',' . ($iGroup2 - $iGroup1) . ' +' . ($jGroup1 + 1) . ',' . ($jGroup2 - $jGroup1) . " @@\n", 'purple' ); - foreach ($group as [$tag, $i1, $i2, $j1, $j2]) { + foreach ($group as [$tag, $iGroup1, $iGroup2, $jGroup1, $jGroup2]) { if ($tag == 'equal') { $string = implode( "\n ", - $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + $this->diff->getArrayRange($this->diff->getVersion1(), $iGroup1, $iGroup2) ); $diff .= $this->colorizeString(' ' . $string . "\n", 'grey'); continue; @@ -98,14 +98,14 @@ private function output(): string if ($tag == 'replace' || $tag == 'delete') { $string = implode( "\n- ", - $this->diff->getArrayRange($this->diff->getVersion1(), $i1, $i2) + $this->diff->getArrayRange($this->diff->getVersion1(), $iGroup1, $iGroup2) ); $diff .= $this->colorizeString('-' . $string . "\n", 'light_red'); } if ($tag == 'replace' || $tag == 'insert') { $string = implode( "\n+", - $this->diff->getArrayRange($this->diff->getVersion2(), $j1, $j2) + $this->diff->getArrayRange($this->diff->getVersion2(), $jGroup1, $jGroup2) ); $diff .= $this->colorizeString('+' . $string . "\n", 'light_green'); } From 7cbae823c99077b3a69aaf885a409c68b81f50bc Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 12 Dec 2022 14:56:41 +0100 Subject: [PATCH 195/206] Update: digilive/git-changelog --- composer.json | 2 +- generateChangelog.php | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index dd9b68bb..3f3b1233 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "squizlabs/php_codesniffer": "*", "phpmd/phpmd": "2.*", "jblond/php-cli": "^1.0", - "digilive/git-changelog": "^1" + "digilive/git-changelog": "^2" }, "suggest": { "jblond/php-cli": "^1.0" diff --git a/generateChangelog.php b/generateChangelog.php index ceab516e..6c99c338 100644 --- a/generateChangelog.php +++ b/generateChangelog.php @@ -13,8 +13,9 @@ $changeLog = new MarkDown(); -$changeLog->commitUrl = 'https://github.com/JBlond/php-diff/commit/{hash}'; -$changeLog->issueUrl = 'https://github.com/JBlond/php-diff/issues/{issue}'; +$changeLog->setUrl('commit', 'https://github.com/JBlond/php-diff/commit/{hash}'); +$changeLog->setUrl('issue', 'https://github.com/JBlond/php-diff/issues/{issue}'); + try { $changeLog->setOptions($changelogOptions); } catch (Exception $exception) { @@ -26,4 +27,4 @@ } catch (Exception $exception) { echo $exception->getMessage(); } -$changeLog->save('changelog.md'); +file_put_contents('changelog.md', $changeLog->get()); From 2ec33c940ac690c40af9d07f3343c302cd1927ac Mon Sep 17 00:00:00 2001 From: JBlond Date: Mon, 12 Dec 2022 15:55:24 +0100 Subject: [PATCH 196/206] Fix: Commit URL in changelog --- generateChangelog.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generateChangelog.php b/generateChangelog.php index 6c99c338..f834c5b7 100644 --- a/generateChangelog.php +++ b/generateChangelog.php @@ -13,7 +13,7 @@ $changeLog = new MarkDown(); -$changeLog->setUrl('commit', 'https://github.com/JBlond/php-diff/commit/{hash}'); +$changeLog->setUrl('commit', 'https://github.com/JBlond/php-diff/commit/{commit}'); $changeLog->setUrl('issue', 'https://github.com/JBlond/php-diff/issues/{issue}'); try { From 21e12d1fbc8edff044d8f932186f870a244d87e9 Mon Sep 17 00:00:00 2001 From: Mario Date: Tue, 13 Dec 2022 08:38:45 +0100 Subject: [PATCH 197/206] Update codacy link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 251ed218..0ccb5eab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # PHP Diff Class -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/db5f8d57b1234502aeb852afc87e0dfe)](https://www.codacy.com/app/leet31337/php-diff) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/db5f8d57b1234502aeb852afc87e0dfe)](https://app.codacy.com/gh/JBlond/php-diff/dashboard) [![Latest Version](https://img.shields.io/github/release/JBlond/php-diff.svg?style=flat-square&label=Release)](https://github.com/JBlond/php-diff/releases) [![Packagist Installs](https://badgen.net/packagist/dt/JBlond/php-diff)](https://packagist.org/packages/jblond/php-diff) From 46528f26b40d2e981312836bb12bb348a4f1918a Mon Sep 17 00:00:00 2001 From: JBlond Date: Wed, 1 Feb 2023 12:11:38 +0100 Subject: [PATCH 198/206] Add: Json renderer --- composer.json | 1 + lib/jblond/Diff/Renderer/Text/Json.php | 61 ++++ .../Diff/Renderer/Text/TextRenderersTest.php | 19 ++ tests/resources/textResult.json | 319 ++++++++++++++++++ 4 files changed, 400 insertions(+) create mode 100644 lib/jblond/Diff/Renderer/Text/Json.php create mode 100644 tests/resources/textResult.json diff --git a/composer.json b/composer.json index 3f3b1233..bda77fcb 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "digilive/git-changelog": "^2" }, "suggest": { + "ext-json": "*", "jblond/php-cli": "^1.0" }, "autoload": { diff --git a/lib/jblond/Diff/Renderer/Text/Json.php b/lib/jblond/Diff/Renderer/Text/Json.php new file mode 100644 index 00000000..ed86e1f5 --- /dev/null +++ b/lib/jblond/Diff/Renderer/Text/Json.php @@ -0,0 +1,61 @@ + + * @copyright (c) 2023 Mario Brandt + * @license New BSD License http://www.opensource.org/licenses/bsd-license.php + * @version 2.4.0 + * @link https://github.com/JBlond/php-diff + */ + +/** + * Class Diff_Renderer_Text_Json + */ +class Json extends MainRendererAbstract +{ + /** + * @return false|string + */ + public function render() + { + $return = []; + $opCodes = $this->diff->getGroupedOpCodes(); + + foreach ($opCodes as $key => $group) { + $return[] = $this->toArray($group); + } + return json_encode($return, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + } + + /** + * @param $group + * @return array + */ + protected function toArray($group): array + { + $return = []; + foreach ($group as [$tag, $iGroup1, $iGroup2, $jGroup1, $jGroup2]) { + $return[] = [ + 'tag' => $tag, + 'old' => [ + 'offset' => $iGroup1, + 'lines' => $this->diff->getArrayRange($this->diff->getVersion1(), $iGroup1, $iGroup2) + ], + 'new' => [ + 'offset' => $jGroup1, + 'lines' => $this->diff->getArrayRange($this->diff->getVersion2(), $jGroup1, $jGroup2) + ], + ]; + } + return $return; + } +} diff --git a/tests/Diff/Renderer/Text/TextRenderersTest.php b/tests/Diff/Renderer/Text/TextRenderersTest.php index f76484f0..1452e74f 100644 --- a/tests/Diff/Renderer/Text/TextRenderersTest.php +++ b/tests/Diff/Renderer/Text/TextRenderersTest.php @@ -130,4 +130,23 @@ public function testInlineCli(): void } $this->assertStringEqualsFile('tests/resources/textInlineCli.txt', $result); } + + /** + * Test the output of the JSON text renderer + * + * @covers \jblond\Diff\Renderer\Text\Json + */ + public function testJson(): void + { + $diff = new Diff( + file_get_contents('tests/resources/a.txt'), + file_get_contents('tests/resources/b.txt') + ); + $renderer = new Diff\Renderer\Text\Json(); + $result = $diff->render($renderer); + if ($this->genOutputFiles) { + file_put_contents('results.json', $result); + } + $this->assertStringEqualsFile('tests/resources/textResult.json', $result); + } } diff --git a/tests/resources/textResult.json b/tests/resources/textResult.json new file mode 100644 index 00000000..0f1c1b16 --- /dev/null +++ b/tests/resources/textResult.json @@ -0,0 +1,319 @@ +[ + [ + { + "tag": "equal", + "old": { + "offset": 0, + "lines": [ + "", + " ", + " " + ] + }, + "new": { + "offset": 0, + "lines": [ + "", + " ", + " " + ] + } + }, + { + "tag": "replace", + "old": { + "offset": 3, + "lines": [ + " Hello World!<\/title>" + ] + }, + "new": { + "offset": 3, + "lines": [ + " <title>Hello You!<\/title>" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 4, + "lines": [ + " <\/head>", + " <body>", + " <h1>This is demo content to show features of the php-diff package.<\/h1>" + ] + }, + "new": { + "offset": 4, + "lines": [ + " <\/head>", + " <body>", + " <h1>This is demo content to show features of the php-diff package.<\/h1>" + ] + } + }, + { + "tag": "delete", + "old": { + "offset": 7, + "lines": [ + " <h2>This line is removed from version2.<\/h2>" + ] + }, + "new": { + "offset": 7, + "lines": [] + } + }, + { + "tag": "equal", + "old": { + "offset": 8, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + }, + "new": { + "offset": 7, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + } + }, + { + "tag": "replace", + "old": { + "offset": 9, + "lines": [ + " <h2>this line has inline differences between both versions.<\/h2>" + ] + }, + "new": { + "offset": 8, + "lines": [ + " <h2>This line has differences between both versions.<\/h2>" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 10, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + }, + "new": { + "offset": 9, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + } + }, + { + "tag": "replace", + "old": { + "offset": 11, + "lines": [ + " <h2>This line also has inline differences between both versions.<\/h2>" + ] + }, + "new": { + "offset": 10, + "lines": [ + " <h2>This line also has InLine differences between both versions.<\/h2>" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 12, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + }, + "new": { + "offset": 11, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + } + }, + { + "tag": "insert", + "old": { + "offset": 13, + "lines": [] + }, + "new": { + "offset": 12, + "lines": [ + " <h2>This line is added to version2.<\/h2>" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 13, + "lines": [ + "", + " <p>", + " It's also compatible with multibyte characters (like Chinese and emoji) as shown below:" + ] + }, + "new": { + "offset": 13, + "lines": [ + "", + " <p>", + " It's also compatible with multibyte characters (like Chinese and emoji) as shown below:" + ] + } + }, + { + "tag": "replace", + "old": { + "offset": 16, + "lines": [ + " 另外我覺得那個評價的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”", + " Do you know what \"金槍魚罐頭\" means in Chinese?", + " 🍏🍎🙂" + ] + }, + "new": { + "offset": 16, + "lines": [ + " 另外我覺得那個評鑑的白色櫃子有點沒有必要欸。外觀我就不說了 ,怎麼連空間都那麼狹隘。不過倒是從這個地方看出所謂的“改革”", + " Do you know what \"魚の缶詰\" means in Chinese?", + " 🍎🍏🙂" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 19, + "lines": [ + " <\/p>", + "", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>" + ] + }, + "new": { + "offset": 19, + "lines": [ + " <\/p>", + "", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>" + ] + } + } + ], + [ + { + "tag": "outOfContext", + "old": { + "offset": 22, + "lines": [ + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>" + ] + }, + "new": { + "offset": 22, + "lines": [ + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>" + ] + } + } + ], + [ + { + "tag": "equal", + "old": { + "offset": 24, + "lines": [ + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>" + ] + }, + "new": { + "offset": 24, + "lines": [ + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>", + " <p>Just some lines to demonstrate the collapsing of a block of lines which are the same in both versions.<\/p>" + ] + } + }, + { + "tag": "replace", + "old": { + "offset": 27, + "lines": [ + "\t\t<h2>This line also has inline differences between both versions. It's the whitespace in front.<\/h2>" + ] + }, + "new": { + "offset": 27, + "lines": [ + " <h2>This line also has inline differences between both versions. It's the whitespace in front.<\/h2>" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 28, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + }, + "new": { + "offset": 28, + "lines": [ + " <h2>This line is the same for both versions.<\/h2>" + ] + } + }, + { + "tag": "replace", + "old": { + "offset": 29, + "lines": [ + " <h2>This line also has inline differences between both versions.<\/h2>" + ] + }, + "new": { + "offset": 29, + "lines": [ + " <h2>This line also has inline differences between both versions!<\/h2>" + ] + } + }, + { + "tag": "equal", + "old": { + "offset": 30, + "lines": [ + " <\/body>", + "<\/html>", + "" + ] + }, + "new": { + "offset": 30, + "lines": [ + " <\/body>", + "<\/html>", + "" + ] + } + } + ] +] \ No newline at end of file From 8bee18d285745b0a93d26ef8bf0e44eae8b0453f Mon Sep 17 00:00:00 2001 From: JBlond <leet31337@web.de> Date: Wed, 1 Feb 2023 12:29:15 +0100 Subject: [PATCH 199/206] Add: Json renderer Options --- README.md | 7 ++++--- lib/jblond/Diff/Renderer/Text/Json.php | 24 +++++++++++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0ccb5eab..349971fd 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ standard formats including: * Side by Side HTML * Unified HTML * Unified Commandline colored output +* JSON The logic behind the core of the diff engine (ie, the sequence matcher) is primarily based on the Python difflib package. The reason for doing so is @@ -147,9 +148,9 @@ at [jQuery-Merge-for-php-diff](https://github.com/DigiLive/jQuery-Merge-for-php- Contributors since I forked the repo. -* maxxer -* Creris -* jfcherng +* [maxxer](https://github.com/maxxer) +* [Creris](https://github.com/Creris) +* [jfcherng](https://github.com/jfcherng) * [DigiLive](https://github.com/DigiLive) ### License (BSD License) diff --git a/lib/jblond/Diff/Renderer/Text/Json.php b/lib/jblond/Diff/Renderer/Text/Json.php index ed86e1f5..07946227 100644 --- a/lib/jblond/Diff/Renderer/Text/Json.php +++ b/lib/jblond/Diff/Renderer/Text/Json.php @@ -22,6 +22,28 @@ */ class Json extends MainRendererAbstract { + + /** + * @var array Associative array containing the default options available for this renderer and their default + * value. + */ + private $subOptions = [ + 'json' => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE + ]; + + /** + * InlineCli constructor. + * + * @param array $options Custom defined options for the InlineCli diff renderer. + * + * @see Json::$subOptions + */ + public function __construct(array $options = []) + { + parent::__construct($this->subOptions); + $this->setOptions($options); + } + /** * @return false|string */ @@ -33,7 +55,7 @@ public function render() foreach ($opCodes as $key => $group) { $return[] = $this->toArray($group); } - return json_encode($return, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + return json_encode($return, $this->options['json']); } /** From 94460efa113d10b1190e4e62dfe7cf6601a99b8d Mon Sep 17 00:00:00 2001 From: JBlond <leet31337@web.de> Date: Wed, 1 Feb 2023 13:55:06 +0100 Subject: [PATCH 200/206] Add: Json renderer Options --- lib/jblond/Diff/Renderer/Text/Json.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/jblond/Diff/Renderer/Text/Json.php b/lib/jblond/Diff/Renderer/Text/Json.php index 07946227..1c2ddd6a 100644 --- a/lib/jblond/Diff/Renderer/Text/Json.php +++ b/lib/jblond/Diff/Renderer/Text/Json.php @@ -22,7 +22,6 @@ */ class Json extends MainRendererAbstract { - /** * @var array Associative array containing the default options available for this renderer and their default * value. From 104e77fd84f87eb627a9492627585d8ddaba9f27 Mon Sep 17 00:00:00 2001 From: JBlond <leet31337@web.de> Date: Tue, 14 Feb 2023 09:53:31 +0100 Subject: [PATCH 201/206] Fix: Title, check if ext-json is loaded --- lib/jblond/Diff/Renderer/Text/Json.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/Json.php b/lib/jblond/Diff/Renderer/Text/Json.php index 1c2ddd6a..bffce672 100644 --- a/lib/jblond/Diff/Renderer/Text/Json.php +++ b/lib/jblond/Diff/Renderer/Text/Json.php @@ -2,10 +2,11 @@ namespace jblond\Diff\Renderer\Text; +use RuntimeException; use jblond\Diff\Renderer\MainRendererAbstract; /** - * Unified diff generator for PHP DiffLib. + * json diff generator for PHP DiffLib. * * PHP version 7.3 or greater * @@ -27,23 +28,28 @@ class Json extends MainRendererAbstract * value. */ private $subOptions = [ - 'json' => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE + 'json' => JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR ]; /** - * InlineCli constructor. + * json constructor. * - * @param array $options Custom defined options for the InlineCli diff renderer. + * @param array $options Custom defined options for the json diff renderer. * * @see Json::$subOptions */ public function __construct(array $options = []) { + if (!extension_loaded('json')) { + throw new RuntimeException('json extension is not available'); + } parent::__construct($this->subOptions); $this->setOptions($options); } /** + * @inheritDoc + * * @return false|string */ public function render() @@ -51,13 +57,14 @@ public function render() $return = []; $opCodes = $this->diff->getGroupedOpCodes(); - foreach ($opCodes as $key => $group) { + foreach ($opCodes as $group) { $return[] = $this->toArray($group); } return json_encode($return, $this->options['json']); } /** + * Convert the * @param $group * @return array */ From bd5d3d322ffb826767f92f62df972bd92208848b Mon Sep 17 00:00:00 2001 From: JBlond <leet31337@web.de> Date: Tue, 14 Feb 2023 10:00:27 +0100 Subject: [PATCH 202/206] Fix: Line length and CLI test --- lib/jblond/Diff/Renderer/Text/Unified.php | 3 ++- lib/jblond/Diff/Renderer/Text/UnifiedCli.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/jblond/Diff/Renderer/Text/Unified.php b/lib/jblond/Diff/Renderer/Text/Unified.php index 897c30d5..261760f4 100644 --- a/lib/jblond/Diff/Renderer/Text/Unified.php +++ b/lib/jblond/Diff/Renderer/Text/Unified.php @@ -50,7 +50,8 @@ public function render() $iGroup2 = -1; } - $diff .= '@@ -' . ($iGroup1 + 1) . ',' . ($iGroup2 - $iGroup1) . ' +' . ($jGroup1 + 1) . ',' . ($jGroup2 - $jGroup1) . " @@\n"; + $diff .= '@@ -' . ($iGroup1 + 1) . ',' . ($iGroup2 - $iGroup1) . ' +' . ($jGroup1 + 1) + . ',' . ($jGroup2 - $jGroup1) . " @@\n"; foreach ($group as [$tag, $iGroup1, $iGroup2, $jGroup1, $jGroup2]) { if ($tag == 'equal') { $diff .= ' ' . diff --git a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php index 6d5a74b2..dd0285d1 100644 --- a/lib/jblond/Diff/Renderer/Text/UnifiedCli.php +++ b/lib/jblond/Diff/Renderer/Text/UnifiedCli.php @@ -82,7 +82,8 @@ private function output(): string } $diff .= $this->colorizeString( - '@@ -' . ($iGroup1 + 1) . ',' . ($iGroup2 - $iGroup1) . ' +' . ($jGroup1 + 1) . ',' . ($jGroup2 - $jGroup1) . " @@\n", + '@@ -' . ($iGroup1 + 1) . ',' . ($iGroup2 - $iGroup1) . ' +' . ($jGroup1 + 1) + . ',' . ($jGroup2 - $jGroup1) . " @@\n", 'purple' ); From 7f64374a3c6553a80029bb981cb3697caa39cb9a Mon Sep 17 00:00:00 2001 From: DigiLive <info@digiLive.nl> Date: Sun, 19 Feb 2023 10:33:42 +0100 Subject: [PATCH 203/206] Fix #125 - Make str_split multibyte save str_split() will split into bytes, rather than characters when dealing with a multi-byte encoded string. Use mb_str_split() to split the string into code points. --- composer.json | 3 ++- lib/jblond/Diff/SequenceMatcher.php | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 3f3b1233..490cce8a 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,8 @@ "require": { "php": ">=7.3", "ext-mbstring": "*", - "ext-pcre": "*" + "ext-pcre": "*", + "symfony/polyfill-mbstring": "^1" }, "require-dev": { "phpunit/phpunit": "^8 || ^9", diff --git a/lib/jblond/Diff/SequenceMatcher.php b/lib/jblond/Diff/SequenceMatcher.php index 48497634..ded67ee1 100644 --- a/lib/jblond/Diff/SequenceMatcher.php +++ b/lib/jblond/Diff/SequenceMatcher.php @@ -136,7 +136,7 @@ public function setSequences($version1, $version2): void public function setSeq1($version1): void { if (!is_array($version1)) { - $version1 = str_split($version1); + $version1 = mb_str_split($version1); } if ($version1 == $this->old) { return; @@ -159,7 +159,7 @@ public function setSeq1($version1): void public function setSeq2($version2): void { if (!is_array($version2)) { - $version2 = str_split($version2); + $version2 = mb_str_split($version2); } if ($version2 == $this->new) { return; From 06d1b8f4dd5b34b961501e21c8be00845cc6f616 Mon Sep 17 00:00:00 2001 From: JBlond <leet31337@web.de> Date: Tue, 1 Aug 2023 15:34:07 +0200 Subject: [PATCH 204/206] Add: Docker compose dev environment. --- docker-compose.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..7bfd6bb6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +version: '3.9' +# For all options see +# https://dockerfile.readthedocs.io/en/latest/content/DockerImages/dockerfiles/php-nginx-dev.html +services: + php: + image: webdevops/php-nginx-dev:8.2 + container_name: diff + working_dir: /app + environment: + - WEB_DOCUMENT_ROOT=/app/example + - WEB_DOCUMENT_INDEX=example.php + - PHP_DISPLAY_ERRORS=1 + - PHP_MEMORY_LIMIT=2048M + - PHP_MAX_EXECUTION_TIME=-1 + - PHP_DATE_TIMEZONE = Europe/Berlin + - XDEBUG_IDE_KEY=PHPSTORM + ports: + - "88:80" + - "9000:9000" + volumes: + - ./:/app:rw,cached From 0428dff7ac7fa2b96f5c32dd00b851e9edfff98f Mon Sep 17 00:00:00 2001 From: Mario <JBlond@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:46:28 +0200 Subject: [PATCH 205/206] Version number is depricated --- docker-compose.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 7bfd6bb6..18e3520f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.9' # For all options see # https://dockerfile.readthedocs.io/en/latest/content/DockerImages/dockerfiles/php-nginx-dev.html services: From 994211443fd4d8f7873afb800845513cd17db375 Mon Sep 17 00:00:00 2001 From: Mario <JBlond@users.noreply.github.com> Date: Sat, 10 May 2025 12:25:23 +0200 Subject: [PATCH 206/206] Update docker-compose.yml Fix ENV entry --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 18e3520f..c4a37646 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ services: - PHP_DISPLAY_ERRORS=1 - PHP_MEMORY_LIMIT=2048M - PHP_MAX_EXECUTION_TIME=-1 - - PHP_DATE_TIMEZONE = Europe/Berlin + - PHP_DATE_TIMEZONE=Europe/Berlin - XDEBUG_IDE_KEY=PHPSTORM ports: - "88:80"

~=B1Q{sbm!s_0upa1| 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 V(^%tj^l9ibN{={S{~rVz+9Ut~ literal 0 HcmV?d00001 From e1126f5cdf01f1d1c8c787e6b6f595f33404c048 Mon Sep 17 00:00:00 2001 From: JBlond Date: Fri, 3 Jul 2020 10:16:14 +0200 Subject: [PATCH 020/206] resize image --- htmlSidebySideDarkTheme.png | Bin 89507 -> 141375 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/htmlSidebySideDarkTheme.png b/htmlSidebySideDarkTheme.png index a1144e92733047908d3b5442cc7662bee39d125f..2e5ede8ae9692c20b9b3424ddf111c47418650b8 100644 GIT binary patch literal 141375 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�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 literal 89507 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 z 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⁣}$8Hgx6JltEavjkr$7<_Y{iBs==k_f;@ z)~g-i(02m{Gpby_Vd%5GkgH*Iz4tkCtD2Erq2KElM+ofFl{$XNNY8%z#+##~U?pt_ z8Cs>0Jel~u!$%+5AZnsJn~F4%yXX$keYl~uZ^1uc=HMe8I}}Kacx!uTpbJS`|EV$ zRkbazj$Y(87>(ZYk^gd7ZGY;IS#M5KIVHdGJQd1aHOf{(IIdw_JY*nk! zyzicu(XL%av}AVFFJgERkEbw&D2tyUg+F2AIi@t^=|X2OlQ&kih-o`rfZqdLp`|R zUpyRwsW|FkG<@u}m5sAEFyt}t7roJ5C~{vCAbP1iPgdJcWlMn_>~C{`lk%(tFmJbP zseS(COE>@h67?a@NbL*6wrh3-(fIQ_wrrs~-N+2sd>!ye@Rx}KspOVdQovUm0nF0C zkDFt^1pn}}EVg)ngRG;+)LO(?LSG@V9nQaBDSyAlr}|73@|AbNnTeAU`D+T+S@D<5 zshvjL$dOg!Z04p`AGz=Y##D%@$bLmcqXOGyHc>vw;ZC{I!ez-adU+YXT_r}eLpDNM zJ50ffbK=$fF<(_)YsW4HkF;zfjQ>ltITLl$VPRhVuz$9W@ctP@EN`)i!+g}iSI4nW;KQ|gXXd8pqXI`)WwG7ttQeah7R9uMI1Zh0B`A#OQXBiNJ)KXkBxHxpX8TokUM zE5w<$s|D83I4035rz{`!V9tq)R}P3fSI_gmZYA}0Nx&ViyEeAk3@|qk+AOiRxYoTW z!u?x1c%bW3atTjKU1P2h*L#XHOx5w3Lb?#ir;)^U{2iv~dYK_hc}NUHEvbviq;(Sx zYH@&}r`W(SozQD)47#t-fRT)n;|ye*u#p}e<`ggdA&?{KGQ;S@R2=0+nD!C$Pgx1e zrn8xPHgiP+qDEvaXIIy|t_^z8oUd#i)B$Ukc=BsbKz6&i%DSX#HI~GMc7D=ILUDXh z4jo0^=R_YnbC(8|9TFF}+OWEK1CT|OG@0}UxuiikEjC<