aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--autoload.php4
-rw-r--r--includes/diff/DairikiDiff.php233
-rw-r--r--includes/diff/WordAccumulator.php107
-rw-r--r--includes/diff/WordLevelDiff.php141
4 files changed, 252 insertions, 233 deletions
diff --git a/autoload.php b/autoload.php
index cf0e4171d063..2f7a9bac7d00 100644
--- a/autoload.php
+++ b/autoload.php
@@ -779,7 +779,6 @@ $wgAutoloadLocalClasses = [
'MalformedTitleException' => __DIR__ . '/includes/title/MalformedTitleException.php',
'ManualLogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
'MapCacheLRU' => __DIR__ . '/includes/libs/MapCacheLRU.php',
- 'MappedDiff' => __DIR__ . '/includes/diff/DairikiDiff.php',
'MappedIterator' => __DIR__ . '/includes/libs/MappedIterator.php',
'MarkpatrolledAction' => __DIR__ . '/includes/actions/MarkpatrolledAction.php',
'McTest' => __DIR__ . '/maintenance/mctest.php',
@@ -829,6 +828,7 @@ $wgAutoloadLocalClasses = [
'MediaWiki\\Auth\\Throttler' => __DIR__ . '/includes/auth/Throttler.php',
'MediaWiki\\Auth\\UserDataAuthenticationRequest' => __DIR__ . '/includes/auth/UserDataAuthenticationRequest.php',
'MediaWiki\\Auth\\UsernameAuthenticationRequest' => __DIR__ . '/includes/auth/UsernameAuthenticationRequest.php',
+ 'MediaWiki\\Diff\\WordAccumulator' => __DIR__ . '/includes/diff/WordAccumulator.php',
'MediaWiki\\Languages\\Data\\Names' => __DIR__ . '/languages/data/Names.php',
'MediaWiki\\Languages\\Data\\ZhConversion' => __DIR__ . '/languages/data/ZhConversion.php',
'MediaWiki\\Linker\\LinkTarget' => __DIR__ . '/includes/linker/LinkTarget.php',
@@ -1518,7 +1518,7 @@ $wgAutoloadLocalClasses = [
'WikitextContentHandler' => __DIR__ . '/includes/content/WikitextContentHandler.php',
'WinCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/WinCacheBagOStuff.php',
'WithoutInterwikiPage' => __DIR__ . '/includes/specials/SpecialWithoutinterwiki.php',
- 'WordLevelDiff' => __DIR__ . '/includes/diff/DairikiDiff.php',
+ 'WordLevelDiff' => __DIR__ . '/includes/diff/WordLevelDiff.php',
'WrapOldPasswords' => __DIR__ . '/maintenance/wrapOldPasswords.php',
'XCFHandler' => __DIR__ . '/includes/media/XCF.php',
'XCacheBagOStuff' => __DIR__ . '/includes/libs/objectcache/XCacheBagOStuff.php',
diff --git a/includes/diff/DairikiDiff.php b/includes/diff/DairikiDiff.php
index e5e082feda51..72db5e132d54 100644
--- a/includes/diff/DairikiDiff.php
+++ b/includes/diff/DairikiDiff.php
@@ -559,236 +559,7 @@ class Diff {
}
/**
- * @todo document, bad name.
- * @private
- * @ingroup DifferenceEngine
- */
-class MappedDiff extends Diff {
- /**
- * Constructor.
- *
- * Computes diff between sequences of strings.
- *
- * This can be used to compute things like
- * case-insensitve diffs, or diffs which ignore
- * changes in white-space.
- *
- * @param string[] $from_lines An array of strings.
- * Typically these are lines from a file.
- * @param string[] $to_lines An array of strings.
- * @param string[] $mapped_from_lines This array should
- * have the same size number of elements as $from_lines.
- * The elements in $mapped_from_lines and
- * $mapped_to_lines are what is actually compared
- * when computing the diff.
- * @param string[] $mapped_to_lines This array should
- * have the same number of elements as $to_lines.
- */
- public function __construct( $from_lines, $to_lines,
- $mapped_from_lines, $mapped_to_lines ) {
-
- assert( count( $from_lines ) == count( $mapped_from_lines ) );
- assert( count( $to_lines ) == count( $mapped_to_lines ) );
-
- parent::__construct( $mapped_from_lines, $mapped_to_lines );
-
- $xi = $yi = 0;
- $editCount = count( $this->edits );
- for ( $i = 0; $i < $editCount; $i++ ) {
- $orig = &$this->edits[$i]->orig;
- if ( is_array( $orig ) ) {
- $orig = array_slice( $from_lines, $xi, count( $orig ) );
- $xi += count( $orig );
- }
-
- $closing = &$this->edits[$i]->closing;
- if ( is_array( $closing ) ) {
- $closing = array_slice( $to_lines, $yi, count( $closing ) );
- $yi += count( $closing );
- }
- }
- }
-}
-
-/**
- * Additions by Axel Boldt follow, partly taken from diff.php, phpwiki-1.3.3
- */
-
-/**
- * @todo document
- * @private
- * @ingroup DifferenceEngine
+ * @deprecated Alias for WordAccumulator, to be soon removed
*/
-class HWLDFWordAccumulator {
- public $insClass = ' class="diffchange diffchange-inline"';
- public $delClass = ' class="diffchange diffchange-inline"';
-
- private $lines = [];
- private $line = '';
- private $group = '';
- private $tag = '';
-
- /**
- * @param string $new_tag
- */
- private function flushGroup( $new_tag ) {
- if ( $this->group !== '' ) {
- if ( $this->tag == 'ins' ) {
- $this->line .= "<ins{$this->insClass}>" .
- htmlspecialchars( $this->group ) . '</ins>';
- } elseif ( $this->tag == 'del' ) {
- $this->line .= "<del{$this->delClass}>" .
- htmlspecialchars( $this->group ) . '</del>';
- } else {
- $this->line .= htmlspecialchars( $this->group );
- }
- }
- $this->group = '';
- $this->tag = $new_tag;
- }
-
- /**
- * @param string $new_tag
- */
- private function flushLine( $new_tag ) {
- $this->flushGroup( $new_tag );
- if ( $this->line != '' ) {
- array_push( $this->lines, $this->line );
- } else {
- # make empty lines visible by inserting an NBSP
- array_push( $this->lines, '&#160;' );
- }
- $this->line = '';
- }
-
- /**
- * @param string[] $words
- * @param string $tag
- */
- public function addWords( $words, $tag = '' ) {
- if ( $tag != $this->tag ) {
- $this->flushGroup( $tag );
- }
-
- foreach ( $words as $word ) {
- // new-line should only come as first char of word.
- if ( $word == '' ) {
- continue;
- }
- if ( $word[0] == "\n" ) {
- $this->flushLine( $tag );
- $word = substr( $word, 1 );
- }
- assert( !strstr( $word, "\n" ) );
- $this->group .= $word;
- }
- }
-
- /**
- * @return string[]
- */
- public function getLines() {
- $this->flushLine( '~done' );
-
- return $this->lines;
- }
-}
-
-/**
- * @todo document
- * @private
- * @ingroup DifferenceEngine
- */
-class WordLevelDiff extends MappedDiff {
- const MAX_LINE_LENGTH = 10000;
-
- /**
- * @param string[] $orig_lines
- * @param string[] $closing_lines
- */
- public function __construct( $orig_lines, $closing_lines ) {
-
- list( $orig_words, $orig_stripped ) = $this->split( $orig_lines );
- list( $closing_words, $closing_stripped ) = $this->split( $closing_lines );
-
- parent::__construct( $orig_words, $closing_words,
- $orig_stripped, $closing_stripped );
- }
-
- /**
- * @param string[] $lines
- *
- * @return array[]
- */
- private function split( $lines ) {
-
- $words = [];
- $stripped = [];
- $first = true;
- foreach ( $lines as $line ) {
- # If the line is too long, just pretend the entire line is one big word
- # This prevents resource exhaustion problems
- if ( $first ) {
- $first = false;
- } else {
- $words[] = "\n";
- $stripped[] = "\n";
- }
- if ( strlen( $line ) > self::MAX_LINE_LENGTH ) {
- $words[] = $line;
- $stripped[] = $line;
- } else {
- $m = [];
- if ( preg_match_all( '/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
- $line, $m )
- ) {
- foreach ( $m[0] as $word ) {
- $words[] = $word;
- }
- foreach ( $m[1] as $stripped_word ) {
- $stripped[] = $stripped_word;
- }
- }
- }
- }
-
- return [ $words, $stripped ];
- }
-
- /**
- * @return string[]
- */
- public function orig() {
- $orig = new HWLDFWordAccumulator;
-
- foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' ) {
- $orig->addWords( $edit->orig );
- } elseif ( $edit->orig ) {
- $orig->addWords( $edit->orig, 'del' );
- }
- }
- $lines = $orig->getLines();
-
- return $lines;
- }
-
- /**
- * @return string[]
- */
- public function closing() {
- $closing = new HWLDFWordAccumulator;
-
- foreach ( $this->edits as $edit ) {
- if ( $edit->type == 'copy' ) {
- $closing->addWords( $edit->closing );
- } elseif ( $edit->closing ) {
- $closing->addWords( $edit->closing, 'ins' );
- }
- }
- $lines = $closing->getLines();
-
- return $lines;
- }
-
+class HWLDFWordAccumulator extends MediaWiki\Diff\WordAccumulator {
}
diff --git a/includes/diff/WordAccumulator.php b/includes/diff/WordAccumulator.php
new file mode 100644
index 000000000000..a26775ffa80c
--- /dev/null
+++ b/includes/diff/WordAccumulator.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup DifferenceEngine
+ * @defgroup DifferenceEngine DifferenceEngine
+ */
+
+namespace MediaWiki\Diff;
+
+/**
+ * Stores, escapes and formats the results of word-level diff
+ *
+ * @private
+ * @ingroup DifferenceEngine
+ */
+class WordAccumulator {
+ public $insClass = ' class="diffchange diffchange-inline"';
+ public $delClass = ' class="diffchange diffchange-inline"';
+
+ private $lines = [];
+ private $line = '';
+ private $group = '';
+ private $tag = '';
+
+ /**
+ * @param string $new_tag
+ */
+ private function flushGroup( $new_tag ) {
+ if ( $this->group !== '' ) {
+ if ( $this->tag == 'ins' ) {
+ $this->line .= "<ins{$this->insClass}>" .
+ htmlspecialchars( $this->group ) . '</ins>';
+ } elseif ( $this->tag == 'del' ) {
+ $this->line .= "<del{$this->delClass}>" .
+ htmlspecialchars( $this->group ) . '</del>';
+ } else {
+ $this->line .= htmlspecialchars( $this->group );
+ }
+ }
+ $this->group = '';
+ $this->tag = $new_tag;
+ }
+
+ /**
+ * @param string $new_tag
+ */
+ private function flushLine( $new_tag ) {
+ $this->flushGroup( $new_tag );
+ if ( $this->line != '' ) {
+ array_push( $this->lines, $this->line );
+ } else {
+ # make empty lines visible by inserting an NBSP
+ array_push( $this->lines, '&#160;' );
+ }
+ $this->line = '';
+ }
+
+ /**
+ * @param string[] $words
+ * @param string $tag
+ */
+ public function addWords( $words, $tag = '' ) {
+ if ( $tag != $this->tag ) {
+ $this->flushGroup( $tag );
+ }
+
+ foreach ( $words as $word ) {
+ // new-line should only come as first char of word.
+ if ( $word == '' ) {
+ continue;
+ }
+ if ( $word[0] == "\n" ) {
+ $this->flushLine( $tag );
+ $word = substr( $word, 1 );
+ }
+ assert( !strstr( $word, "\n" ) );
+ $this->group .= $word;
+ }
+ }
+
+ /**
+ * @return string[]
+ */
+ public function getLines() {
+ $this->flushLine( '~done' );
+
+ return $this->lines;
+ }
+}
diff --git a/includes/diff/WordLevelDiff.php b/includes/diff/WordLevelDiff.php
new file mode 100644
index 000000000000..12cf37671d78
--- /dev/null
+++ b/includes/diff/WordLevelDiff.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * Copyright © 2000, 2001 Geoffrey T. Dairiki <dairiki@dairiki.org>
+ * You may copy this code freely under the conditions of the GPL.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup DifferenceEngine
+ * @defgroup DifferenceEngine DifferenceEngine
+ */
+
+use MediaWiki\Diff\WordAccumulator;
+
+/**
+ * Performs a word-level diff on several lines
+ *
+ * @ingroup DifferenceEngine
+ */
+class WordLevelDiff extends \Diff {
+ const MAX_LINE_LENGTH = 10000;
+
+ /**
+ * @param string[] $linesBefore
+ * @param string[] $linesAfter
+ */
+ public function __construct( $linesBefore, $linesAfter ) {
+
+ list( $wordsBefore, $wordsBeforeStripped ) = $this->split( $linesBefore );
+ list( $wordsAfter, $wordsAfterStripped ) = $this->split( $linesAfter );
+
+ parent::__construct( $wordsBeforeStripped, $wordsAfterStripped );
+
+ $xi = $yi = 0;
+ $editCount = count( $this->edits );
+ for ( $i = 0; $i < $editCount; $i++ ) {
+ $orig = &$this->edits[$i]->orig;
+ if ( is_array( $orig ) ) {
+ $orig = array_slice( $wordsBefore, $xi, count( $orig ) );
+ $xi += count( $orig );
+ }
+
+ $closing = &$this->edits[$i]->closing;
+ if ( is_array( $closing ) ) {
+ $closing = array_slice( $wordsAfter, $yi, count( $closing ) );
+ $yi += count( $closing );
+ }
+ }
+
+ }
+
+ /**
+ * @param string[] $lines
+ *
+ * @return array[]
+ */
+ private function split( $lines ) {
+
+ $words = [];
+ $stripped = [];
+ $first = true;
+ foreach ( $lines as $line ) {
+ # If the line is too long, just pretend the entire line is one big word
+ # This prevents resource exhaustion problems
+ if ( $first ) {
+ $first = false;
+ } else {
+ $words[] = "\n";
+ $stripped[] = "\n";
+ }
+ if ( strlen( $line ) > self::MAX_LINE_LENGTH ) {
+ $words[] = $line;
+ $stripped[] = $line;
+ } else {
+ $m = [];
+ if ( preg_match_all( '/ ( [^\S\n]+ | [0-9_A-Za-z\x80-\xff]+ | . ) (?: (?!< \n) [^\S\n])? /xs',
+ $line, $m )
+ ) {
+ foreach ( $m[0] as $word ) {
+ $words[] = $word;
+ }
+ foreach ( $m[1] as $stripped_word ) {
+ $stripped[] = $stripped_word;
+ }
+ }
+ }
+ }
+
+ return [ $words, $stripped ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public function orig() {
+ $orig = new WordAccumulator;
+
+ foreach ( $this->edits as $edit ) {
+ if ( $edit->type == 'copy' ) {
+ $orig->addWords( $edit->orig );
+ } elseif ( $edit->orig ) {
+ $orig->addWords( $edit->orig, 'del' );
+ }
+ }
+ $lines = $orig->getLines();
+
+ return $lines;
+ }
+
+ /**
+ * @return string[]
+ */
+ public function closing() {
+ $closing = new WordAccumulator;
+
+ foreach ( $this->edits as $edit ) {
+ if ( $edit->type == 'copy' ) {
+ $closing->addWords( $edit->closing );
+ } elseif ( $edit->closing ) {
+ $closing->addWords( $edit->closing, 'ins' );
+ }
+ }
+ $lines = $closing->getLines();
+
+ return $lines;
+ }
+
+}