[Pkg-mediawiki-commits] [wikidiff2] 01/11: Imported Upstream version 1.2

Jonathan Wiltshire jmw at moszumanska.debian.org
Sat Jun 21 22:29:50 UTC 2014


This is an automated email from the git hooks/post-receive script.

jmw pushed a commit to branch master
in repository wikidiff2.

commit ca427f77552c6135b30a1323528ef114acf19025
Author: Jonathan Wiltshire <jmw at debian.org>
Date:   Sat Jun 21 14:30:45 2014 +0100

    Imported Upstream version 1.2
---
 .gitignore                     |  25 +++++++
 .gitreview                     |   5 ++
 DiffEngine.h                   |  58 +++++++--------
 DiffTest/Api.php               |  13 ++++
 DiffTest/Change.php            |  43 +++++++++++
 DiffTest/Differ.php            |  34 +++++++++
 DiffTest/test.php              | 114 +++++++++++++++++++++++++++++
 InlineDiff.cpp                 |  91 +++++++++++++++++++++++
 InlineDiff.h                   |  18 +++++
 README                         |  14 +++-
 TableDiff.cpp                  | 123 +++++++++++++++++++++++++++++++
 TableDiff.h                    |  19 +++++
 wikidiff2.cpp => Wikidiff2.cpp | 161 ++++++-----------------------------------
 wikidiff2.h => Wikidiff2.h     |  31 ++++----
 Word.h                         |  12 +--
 config.cmake                   |   3 +
 config.m4                      |   2 +-
 debian/changelog               |  12 +++
 debian/conffiles               |   1 -
 debian/control                 |   2 +-
 debian/copyright               |  27 ++-----
 debian/rules                   |   6 +-
 ext_wikidiff2.php              |   6 ++
 hhvm_wikidiff2.cpp             |  76 +++++++++++++++++++
 php_wikidiff2.cpp              |  55 ++++++++++++--
 php_wikidiff2.h                |   1 +
 tests/001.phpt                 |   4 +-
 tests/003.phpt                 |   2 +-
 tests/004.phpt                 |  38 ++++++++++
 wikidiff2.ini                  |   2 +-
 30 files changed, 771 insertions(+), 227 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..17f8943
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,25 @@
+.svn
+*~
+*.kate-swp
+.*.swp
+*.in
+*.lo
+*.la
+*.m4
+Makefile*
+config.*
+
+.deps
+configure
+install-sh
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+run-tests.php
+
+.libs
+autom4te.cache
+build
+modules
+
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..3311ca4
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/php/wikidiff2.git
+defaultbranch=master
diff --git a/DiffEngine.h b/DiffEngine.h
index aeef88d..646bb08 100644
--- a/DiffEngine.h
+++ b/DiffEngine.h
@@ -18,19 +18,19 @@
 #include "JudyHS.h"
 #endif
 
-#include "wikidiff2.h"
+#include "Wikidiff2.h"
 
 /**
  * Diff operation
- * 
+ *
  * from and to are vectors containing pointers to the objects passed in from_lines and to_lines
  *
  * op is one of the following
- *    copy:    A sequence of lines (in from and to) which are the same in both files. 
+ *    copy:    A sequence of lines (in from and to) which are the same in both files.
  *    del:     A sequence of lines (in from) which were in the first file but not the second.
  *    add:     A sequence of lines (in to) which were in the second file but not the first.
- *    change:  A sequence of lines which are different between the two files. Lines from the 
- *             first file are in from, lines from the second are in to. The two vectors need 
+ *    change:  A sequence of lines which are different between the two files. Lines from the
+ *             first file are in from, lines from the second are in to. The two vectors need
  *             not be the same length.
  */
 template<typename T>
@@ -59,9 +59,9 @@ class Diff
 		typedef std::vector<DiffOp<T>, WD2_ALLOCATOR<T> > DiffOpVector;
 
 		Diff(const ValueVector & from_lines, const ValueVector & to_lines);
-		
+
 		virtual void add_edit(const DiffOp<T> & edit) {
-			edits.push_back(edit); 
+			edits.push_back(edit);
 		}
 		unsigned size() { return edits.size(); }
 		DiffOp<T> & operator[](int i) {return edits[i];}
@@ -82,8 +82,8 @@ class Diff
  * diffutils-2.7, which can be found at:
  *	 ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz
  *
- * This implementation is largely due to Geoffrey T. Dairiki, who wrote this 
- * diff engine for phpwiki 1-3.3. It was then adopted by MediaWiki. 
+ * This implementation is largely due to Geoffrey T. Dairiki, who wrote this
+ * diff engine for phpwiki 1-3.3. It was then adopted by MediaWiki.
  *
  * Finally, it was ported to C++ by Tim Starling in February 2006
  *
@@ -91,7 +91,7 @@ class Diff
  */
 
 template<typename T>
-class _DiffEngine 
+class _DiffEngine
 {
 	public:
 		// Vectors
@@ -118,16 +118,16 @@ class _DiffEngine
 
 		_DiffEngine() : done(false) {}
 		void clear();
-		void diff (const ValueVector & from_lines, 
+		void diff (const ValueVector & from_lines,
 				const ValueVector & to_lines, Diff<T> & diff);
 		int _lcs_pos (int ypos);
 		void _compareseq (int xoff, int xlim, int yoff, int ylim);
-		void _shift_boundaries (const ValueVector & lines, BoolVector & changed, 
+		void _shift_boundaries (const ValueVector & lines, BoolVector & changed,
 				const BoolVector & other_changed);
 	protected:
-		int _diag (int xoff, int xlim, int yoff, int ylim, int nchunks, 
+		int _diag (int xoff, int xlim, int yoff, int ylim, int nchunks,
 				IntPairVector & seps);
-		
+
 		BoolVector xchanged, ychanged;
 		PointerVector xv, yv;
 		IntVector xind, yind;
@@ -142,7 +142,7 @@ class _DiffEngine
 // _DiffEngine implementation
 //-----------------------------------------------------------------------------
 template<typename T>
-void _DiffEngine<T>::clear() 
+void _DiffEngine<T>::clear()
 {
 	xchanged.clear();
 	ychanged.clear();
@@ -156,8 +156,8 @@ void _DiffEngine<T>::clear()
 }
 
 template<typename T>
-void _DiffEngine<T>::diff (const ValueVector & from_lines, 
-		const ValueVector & to_lines, Diff<T> & diff) 
+void _DiffEngine<T>::diff (const ValueVector & from_lines,
+		const ValueVector & to_lines, Diff<T> & diff)
 {
 	int n_from = (int)from_lines.size();
 	int n_to = (int)to_lines.size();
@@ -165,7 +165,7 @@ void _DiffEngine<T>::diff (const ValueVector & from_lines,
 	// If this diff engine has been used before for a diff, clear the member variables
 	if (done) {
 		clear();
-	} 
+	}
 	xchanged.resize(n_from);
 	ychanged.resize(n_to);
 	seq.resize(std::max(n_from, n_to) + 1);
@@ -196,7 +196,7 @@ void _DiffEngine<T>::diff (const ValueVector & from_lines,
 		if ( (ychanged[yi] = (xhash.find(line) == xhash.end())) )
 			continue;
 		yhash.insert(line);
-		yv.push_back(&line);		
+		yv.push_back(&line);
 		yind.push_back(yi);
 	}
 	for (xi = skip; xi < n_from - endskip; xi++) {
@@ -271,8 +271,8 @@ void _DiffEngine<T>::diff (const ValueVector & from_lines,
  * of the portions it is going to specify.
  */
 template <typename T>
-int _DiffEngine<T>::_diag (int xoff, int xlim, int yoff, int ylim, int nchunks, 
-		IntPairVector & seps) 
+int _DiffEngine<T>::_diag (int xoff, int xlim, int yoff, int ylim, int nchunks,
+		IntPairVector & seps)
 {
 	using std::swap;
 	using std::make_pair;
@@ -307,7 +307,7 @@ int _DiffEngine<T>::_diag (int xoff, int xlim, int yoff, int ylim, int nchunks,
 	int x = xoff, x1, y1;
 	for (int chunk = 0; chunk < nchunks; chunk++) {
 		if (chunk > 0)
-			for (int i = 0; i <= lcs; i++) 
+			for (int i = 0; i <= lcs; i++)
 				ymids.at(i * nchunks + chunk-1) = seq[i];
 
 		x1 = xoff + (int)((numer + (xlim-xoff)*chunk) / nchunks);
@@ -325,12 +325,12 @@ int _DiffEngine<T>::_diag (int xoff, int xlim, int yoff, int ylim, int nchunks,
 #endif
 			IntVector::iterator y;
 			int k = 0;
-			
+
 			for (y = pMatches->begin(); y != pMatches->end(); ++y) {
 				if (!in_seq.count(*y)) {
 					k = _lcs_pos(*y);
 					assert(k > 0);
-					copy(ymids.begin() + (k-1) * nchunks, ymids.begin() + k * nchunks, 
+					copy(ymids.begin() + (k-1) * nchunks, ymids.begin() + k * nchunks,
 							ymids.begin() + k * nchunks);
 					++y;
 					break;
@@ -347,7 +347,7 @@ int _DiffEngine<T>::_diag (int xoff, int xlim, int yoff, int ylim, int nchunks,
 				} else if (!in_seq.count(*y)) {
 					k = _lcs_pos(*y);
 					assert(k > 0);
-					copy(ymids.begin() + (k-1) * nchunks, ymids.begin() + k * nchunks, 
+					copy(ymids.begin() + (k-1) * nchunks, ymids.begin() + k * nchunks,
 							ymids.begin() + k * nchunks);
 				}
 			}
@@ -356,7 +356,7 @@ int _DiffEngine<T>::_diag (int xoff, int xlim, int yoff, int ylim, int nchunks,
 
 	seps.clear();
 	seps.resize(nchunks + 1);
-	
+
 	seps[0] = flip ? make_pair(yoff, xoff) : make_pair(xoff, yoff);
 	IntVector::iterator ymid = ymids.begin() + lcs * nchunks;
 	for (int n = 0; n < nchunks - 1; n++) {
@@ -411,7 +411,7 @@ void _DiffEngine<T>::_compareseq (int xoff, int xlim, int yoff, int ylim) {
 
 	IntPairVector seps;
 	int lcs;
-	
+
 	// Slide down the bottom initial diagonal.
 	while (xoff < xlim && yoff < ylim && *xv[xoff] == *yv[yoff]) {
 		++xoff;
@@ -465,8 +465,8 @@ void _DiffEngine<T>::_compareseq (int xoff, int xlim, int yoff, int ylim) {
  * This is extracted verbatim from analyze.c (GNU diffutils-2.7).
  */
 template <typename T>
-void _DiffEngine<T>::_shift_boundaries (const ValueVector & lines, BoolVector & changed, 
-		const BoolVector & other_changed) 
+void _DiffEngine<T>::_shift_boundaries (const ValueVector & lines, BoolVector & changed,
+		const BoolVector & other_changed)
 {
 	int i = 0;
 	int j = 0;
diff --git a/DiffTest/Api.php b/DiffTest/Api.php
new file mode 100644
index 0000000..b6becdf
--- /dev/null
+++ b/DiffTest/Api.php
@@ -0,0 +1,13 @@
+<?php
+
+class Api {
+	public static function request( array $params ) {
+		global $apiUrl;
+
+		$params['format'] = 'json';
+		$query = http_build_query( $params );
+		$url = "$apiUrl?$query";
+		$response = file_get_contents( $url );
+		return json_decode( $response, true );
+	}
+}
\ No newline at end of file
diff --git a/DiffTest/Change.php b/DiffTest/Change.php
new file mode 100644
index 0000000..1f94a82
--- /dev/null
+++ b/DiffTest/Change.php
@@ -0,0 +1,43 @@
+<?php
+
+class Change {
+	public $page;
+	public $prevId, $nextId;
+	public $prev, $next;
+
+	public function __construct( $page, $prevId, $nextId ) {
+		$this->page = $page;
+		$this->prevId = $prevId;
+		$this->nextId = $nextId;
+	}
+
+	public function load() {
+		$data = Api::request(
+			array(
+				'action' => 'query',
+				'prop' => 'revisions',
+				'rvprop' => 'ids|content',
+				'revids' => "{$this->prevId}|{$this->nextId}",
+			)
+		);
+		foreach( $data['query']['pages'] as $page ) {
+			if ( $page['title'] != $this->page ) {
+				continue;
+			}
+			foreach ( $page['revisions'] as $rev ) {
+				$revid = $rev['revid'];
+				if ( !isset( $rev['*'] ) ) {
+					echo "Revision $revid not found\n";
+					return false;
+				}
+				$text = $rev['*'];
+				if ( $revid == $this->prevId ) {
+					$this->prev = $text;
+				} elseif ( $revid == $this->nextId ) {
+					$this->next = $text;
+				}
+			}
+		}
+		return !is_null( $this->prev ) && !is_null( $this->next );
+	}
+}
\ No newline at end of file
diff --git a/DiffTest/Differ.php b/DiffTest/Differ.php
new file mode 100644
index 0000000..6864481
--- /dev/null
+++ b/DiffTest/Differ.php
@@ -0,0 +1,34 @@
+<?php
+
+interface Differ {
+	function diff( $a, $b );
+}
+
+class TableDiffer implements Differ {
+	public function diff( $a, $b ) {
+		return '<table>'
+			. wikidiff2_do_diff( $a, $b, 2 )
+			. '</table>';
+	}
+}
+
+class InlineDiffer implements Differ {
+	public function diff( $a, $b ) {
+		return wikidiff2_inline_diff( $a, $b, 2 );
+	}
+}
+
+class BothDiffer implements Differ {
+	private $table, $inline;
+
+	public function __construct() {
+		$this->table = new TableDiffer;
+		$this->inline = new InlineDiffer;
+	}
+
+	public function diff( $a, $b ) {
+		return $this->table->diff( $a, $b )
+			. $this->inline->diff( $a, $b );
+	}
+}
+
diff --git a/DiffTest/test.php b/DiffTest/test.php
new file mode 100644
index 0000000..a405811
--- /dev/null
+++ b/DiffTest/test.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * wikidiff2 PHP extension test suite. Loads a lot of real changes
+ * from Wikipedia and generates diffs of it.
+ *
+ * License: WTFPL
+ */
+
+
+if ( !function_exists( 'wikidiff2_inline_diff' ) ) {
+	die( "wikidiff2 not found, nothing to test\n" );
+}
+ini_set( 'user_agent', 'Hi, Domas!' );
+// Bail out early in case of any problems
+error_reporting( E_ALL | E_STRICT );
+set_error_handler( function( $errno , $errstr ) {
+	echo htmlspecialchars( $errstr );
+	die ( 1 );
+} );
+
+echo <<<HTML
+<html>
+<title>Diff changes</title>
+<style>
+body {
+	font-family: sans-serif;
+}
+
+table,
+td {
+	border:1px solid #000
+}
+
+ins,
+del {
+	padding-left: 0;
+	color: black;
+	text-decoration: none;
+}
+
+span {
+	margin-right: 2px;
+}
+
+ins {
+	background-color: #75C877;
+}
+
+del {
+	background-color: #E07076;
+}
+</style>
+<body>
+HTML;
+
+
+require 'Api.php';
+require 'Change.php';
+require 'Differ.php';
+
+$differ = new BothDiffer;
+
+$site = "http://en.wikipedia.org/w";
+$apiUrl = "$site/api.php";
+$indexUrl = "$site/index.php";
+
+$recentChanges = Api::request( array(
+	'action' => 'query',
+	'list' => 'recentchanges',
+	'rctype' => 'edit',
+	'rclimit' => 'max',
+) );
+
+$changes = array();
+foreach ( $recentChanges['query']['recentchanges'] as $rc ) {
+	$changes[] = new Change( $rc['title'], $rc['old_revid'], $rc['revid'] );
+}
+
+$count = count( $changes );
+echo "<h1>Found $count changes</h1>\n";
+
+$count = 0;
+$numProcessed = 0;
+$totalTime = 0;
+foreach ( $changes as $change ) {
+	$id = sprintf( "%04d", $count );
+	$page = htmlspecialchars( $change->page );
+	echo "\n<h2>[$id] {$page}</h2>\n";
+	if ( !$change->load() ) {
+		echo "<b>Not all content loaded, skipping</b><br>\n";
+	}
+	$time = microtime( true );
+	$diff = $differ->diff( $change->prev, $change->next );
+	$time = microtime( true ) - $time;
+	$totalTime += $time;
+	$numProcessed++;
+	echo "Diffed in {$time}s<br>\n";
+	$url = htmlspecialchars( "$indexUrl?diff={$change->nextId}&oldid={$change->prevId}" );
+	echo "<a href='$url'>$url</a>";
+
+	echo $diff;
+
+	$count++;
+}
+
+$avg = $numProcessed ? $totalTime / $numProcessed : 0;
+
+echo <<<HTML
+<table>
+<tr><td>Total processed</td><td>$numProcessed</td></tr>
+<tr><td>Average diff time</td><td>$avg</td></tr>
+</table>
+</html>
+HTML;
diff --git a/InlineDiff.cpp b/InlineDiff.cpp
new file mode 100644
index 0000000..3fa941c
--- /dev/null
+++ b/InlineDiff.cpp
@@ -0,0 +1,91 @@
+#include "InlineDiff.h"
+
+void InlineDiff::printAdd(const String& line)
+{
+	printWrappedLine("<div class=\"mw-diff-inline-added\"><ins>", line, "</ins></div>\n");
+}
+
+void InlineDiff::printDelete(const String& line)
+{
+	printWrappedLine("<div class=\"mw-diff-inline-deleted\"><del>", line, "</del></div>\n");
+}
+
+void InlineDiff::printWordDiff(const String& text1, const String& text2)
+{
+	WordVector words1, words2;
+
+	explodeWords(text1, words1);
+	explodeWords(text2, words2);
+	WordDiff worddiff(words1, words2);
+	String word;
+
+	result += "<div class=\"mw-diff-inline-changed\">";
+	for (unsigned i = 0; i < worddiff.size(); ++i) {
+		DiffOp<Word> & op = worddiff[i];
+		int n, j;
+		if (op.op == DiffOp<Word>::copy) {
+			n = op.from.size();
+			for (j=0; j<n; j++) {
+				op.from[j]->get_whole(word);
+				printText(word);
+			}
+		} else if (op.op == DiffOp<Word>::del) {
+			n = op.from.size();
+			result += "<del>";
+			for (j=0; j<n; j++) {
+				op.from[j]->get_whole(word);
+				printText(word);
+			}
+			result += "</del>";
+		} else if (op.op == DiffOp<Word>::add) {
+			n = op.to.size();
+			result += "<ins>";
+			for (j=0; j<n; j++) {
+				op.to[j]->get_whole(word);
+				printText(word);
+			}
+			result += "</ins>";
+		} else if (op.op == DiffOp<Word>::change) {
+			n = op.from.size();
+			result += "<del>";
+			for (j=0; j<n; j++) {
+				op.from[j]->get_whole(word);
+				printText(word);
+			}
+			result += "</del>";
+			n = op.to.size();
+			result += "<ins>";
+			for (j=0; j<n; j++) {
+				op.to[j]->get_whole(word);
+				printText(word);
+			}
+			result += "</ins>";
+		}
+	}
+	result += "</div>\n";
+}
+
+void InlineDiff::printBlockHeader(int leftLine, int rightLine)
+{
+	char buf[256]; // should be plenty
+	snprintf(buf, sizeof(buf),
+		"<div class=\"mw-diff-inline-header\"><!-- LINES %u,%u --></div>\n",
+		leftLine, rightLine);
+	result += buf;
+}
+
+void InlineDiff::printContext(const String & input)
+{
+	printWrappedLine("<div class=\"mw-diff-inline-context\">", input, "</div>\n");
+}
+
+void InlineDiff::printWrappedLine(const char* pre, const String& line, const char* post)
+{
+	result += pre;
+	if (line.empty()) {
+		result += " ";
+	} else {
+		printText(line);
+	}
+	result += post;
+}
diff --git a/InlineDiff.h b/InlineDiff.h
new file mode 100644
index 0000000..01304ca
--- /dev/null
+++ b/InlineDiff.h
@@ -0,0 +1,18 @@
+#ifndef INLINEDIFF_H
+#define INLINEDIFF_H
+
+#include "Wikidiff2.h"
+
+class InlineDiff: public Wikidiff2 {
+	public:
+	protected:
+		void printAdd(const String& line);
+		void printDelete(const String& line);
+		void printWordDiff(const String& text1, const String& text2);
+		void printBlockHeader(int leftLine, int rightLine);
+		void printContext(const String& input);
+
+		void printWrappedLine(const char* pre, const String& line, const char* post);
+};
+
+#endif
diff --git a/README b/README
index 67dea59..f4e14f4 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-Wikidiff2 is partly based on the original wikidiff, partly on DifferenceEngine.php, and partly my own work. It performs word-level (space-delimited) diffs on general text, and character-level diffs on text composed of characters from the Japanese and Thai alphabets and the unified han. Japanese, Chinese and Thai do not use spaces to separate words. The input is assumed to be UTF-8 encoded. Invalid UTF-8 sequences will be passed through with no error issued, but it is recommended that the [...]
+Wikidiff2 is partly based on the original wikidiff, partly on DifferenceEngine.php, and partly my own work. It performs word-level (space-delimited) diffs on general text, and character-level diffs on text composed of characters from the Japanese and Thai alphabets and the unified han. Japanese, Chinese and Thai do not use spaces to separate words. The input is assumed to be UTF-8 encoded. Invalid UTF-8 may cause undesirable operation, such as truncation of the output, so the input shoul [...]
 
 The output is an HTML fragment -- a number of HTML table rows with the rest of the document structure omitted. The characters "<", ">" and "&" will be HTML-escaped in the output.
 
@@ -13,7 +13,14 @@ These pairs together give 85.9% coverage of DiffEngine.h. The remaining untested
 
 These files are 2.3MB each, and give a worst-case performance test. Performance in the worst case is sensitive to the performance of the associative array class used to cross-reference the strings. I tried using an STL map and a Judy array. The Judy array gave an 11% improvement in execution time over the map, which could probably be increased to 15% with further optimisation work. I don't consider that to be a sufficient improvement to warrant adding a library dependency, but the code h [...]
 
-Wikidiff2 is a PHP extension. To compile and install it:
+Wikidiff2 is a PHP extension.
+
+It requires the following library:
+
+* libthai, a Thai language support library
+  http://linux.thai.net/plone/TLWG/libthai/
+
+To compile and install it:
 
 $ phpize
 $ ./configure
@@ -22,6 +29,9 @@ $ sudo make install
 
 == Changelog ==
 
+2013-08-07
+* (bug 52616) Use <ins> and <del> for insertions and deletions
+
 2012-01-03
 * (bug 26354) Add class to dummy cells containing  
 * (bug 25697) Add   to empty context lines
diff --git a/TableDiff.cpp b/TableDiff.cpp
new file mode 100644
index 0000000..f613e9d
--- /dev/null
+++ b/TableDiff.cpp
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include "Wikidiff2.h"
+#include "TableDiff.h"
+
+void TableDiff::printAdd(const String & line)
+{
+	result += "<tr>\n"
+		"  <td colspan=\"2\" class=\"diff-empty\"> </td>\n"
+		"  <td class=\"diff-marker\">+</td>\n"
+		"  <td class=\"diff-addedline\">";
+	printTextWithDiv(line);
+	result += "</td>\n</tr>\n";
+}
+
+void TableDiff::printDelete(const String & line)
+{
+	result += "<tr>\n"
+		"  <td class=\"diff-marker\">−</td>\n"
+		"  <td class=\"diff-deletedline\">";
+	printTextWithDiv(line);
+	result += "</td>\n"
+		"  <td colspan=\"2\" class=\"diff-empty\"> </td>\n"
+		"</tr>\n";
+}
+
+void TableDiff::printWordDiff(const String & text1, const String & text2)
+{
+	WordVector words1, words2;
+
+	explodeWords(text1, words1);
+	explodeWords(text2, words2);
+	WordDiff worddiff(words1, words2);
+
+	//debugPrintWordDiff(worddiff);
+
+	// print twice; first for left side, then for right side
+	result += "<tr>\n"
+		"  <td class=\"diff-marker\">−</td>\n"
+		"  <td class=\"diff-deletedline\"><div>";
+	printWordDiffSide(worddiff, false);
+	result += "</div></td>\n"
+		"  <td class=\"diff-marker\">+</td>\n"
+		"  <td class=\"diff-addedline\"><div>";
+	printWordDiffSide(worddiff, true);
+	result += "</div></td>\n"
+		"</tr>\n";
+}
+
+void TableDiff::printWordDiffSide(WordDiff &worddiff, bool added)
+{
+	String word;
+	for (unsigned i = 0; i < worddiff.size(); ++i) {
+		DiffOp<Word> & op = worddiff[i];
+		int n, j;
+		if (op.op == DiffOp<Word>::copy) {
+			n = op.from.size();
+			if (added) {
+				for (j=0; j<n; j++) {
+					op.to[j]->get_whole(word);
+					printText(word);
+				}
+			} else {
+				for (j=0; j<n; j++) {
+					op.from[j]->get_whole(word);
+					printText(word);
+				}
+			}
+		} else if (!added && (op.op == DiffOp<Word>::del || op.op == DiffOp<Word>::change)) {
+			n = op.from.size();
+			result += "<del class=\"diffchange diffchange-inline\">";
+			for (j=0; j<n; j++) {
+				op.from[j]->get_whole(word);
+				printText(word);
+			}
+			result += "</del>";
+		} else if (added && (op.op == DiffOp<Word>::add || op.op == DiffOp<Word>::change)) {
+			n = op.to.size();
+			result += "<ins class=\"diffchange diffchange-inline\">";
+			for (j=0; j<n; j++) {
+				op.to[j]->get_whole(word);
+				printText(word);
+			}
+			result += "</ins>";
+		}
+	}
+}
+
+void TableDiff::printTextWithDiv(const String & input)
+{
+	// Wrap string in a <div> if it's not empty
+	if (input.size() > 0) {
+		result.append("<div>");
+		printText(input);
+		result.append("</div>");
+	}
+}
+
+void TableDiff::printBlockHeader(int leftLine, int rightLine)
+{
+	char buf[256]; // should be plenty
+	snprintf(buf, sizeof(buf),
+		"<tr>\n"
+		"  <td colspan=\"2\" class=\"diff-lineno\"><!--LINE %u--></td>\n"
+		"  <td colspan=\"2\" class=\"diff-lineno\"><!--LINE %u--></td>\n"
+		"</tr>\n",
+		leftLine, rightLine);
+	result += buf;
+}
+
+void TableDiff::printContext(const String & input)
+{
+	result +=
+		"<tr>\n"
+		"  <td class=\"diff-marker\"> </td>\n"
+		"  <td class=\"diff-context\">";
+	printTextWithDiv(input);
+	result +=
+		"</td>\n"
+		"  <td class=\"diff-marker\"> </td>\n"
+		"  <td class=\"diff-context\">";
+	printTextWithDiv(input);
+	result += "</td>\n</tr>\n";
+}
diff --git a/TableDiff.h b/TableDiff.h
new file mode 100644
index 0000000..0a3adc6
--- /dev/null
+++ b/TableDiff.h
@@ -0,0 +1,19 @@
+#ifndef TABLEDIFF_H
+#define TABLEDIFF_H
+
+#include "Wikidiff2.h"
+
+class TableDiff: public Wikidiff2 {
+	public:
+	protected:
+		void printAdd(const String& line);
+		void printDelete(const String& line);
+		void printWordDiff(const String& text1, const String & text2);
+		void printTextWithDiv(const String& input);
+		void printBlockHeader(int leftLine, int rightLine);
+		void printContext(const String& input);
+
+		void printWordDiffSide(WordDiff& worddiff, bool added);
+};
+
+#endif
diff --git a/wikidiff2.cpp b/Wikidiff2.cpp
similarity index 70%
rename from wikidiff2.cpp
rename to Wikidiff2.cpp
index d075869..5234dc1 100644
--- a/wikidiff2.cpp
+++ b/Wikidiff2.cpp
@@ -1,24 +1,24 @@
 /**
- * Diff formatter, based on code by Steinar H. Gunderson, converted to work with the 
+ * Diff formatter, based on code by Steinar H. Gunderson, converted to work with the
  * Dairiki diff engine by Tim Starling
- * 
+ *
  * GPL.
  */
 
 #include <stdio.h>
 #include <string.h>
-#include "wikidiff2.h"
+#include "Wikidiff2.h"
 #include <thai/thailib.h>
 #include <thai/thwchar.h>
 #include <thai/thbrk.h>
 
-void Wikidiff2::diffLines(const StringVector & lines1, const StringVector & lines2, 
+
+void Wikidiff2::diffLines(const StringVector & lines1, const StringVector & lines2,
 		int numContextLines)
 {
 	// first do line-level diff
 	StringDiff linediff(lines1, lines2);
-	
-	int ctx = 0;
+
 	int from_index = 1, to_index = 1;
 
 	// Should a line number be printed before the next context line?
@@ -29,13 +29,9 @@ void Wikidiff2::diffLines(const StringVector & lines1, const StringVector & line
 		int n, j, n1, n2;
 		// Line 1 changed, show heading with no leading context
 		if (linediff[i].op != DiffOp<String>::copy && i == 0) {
-			result += 
-				"<tr>\n"
-				"  <td colspan=\"2\" class=\"diff-lineno\"><!--LINE 1--></td>\n"
-				"  <td colspan=\"2\" class=\"diff-lineno\"><!--LINE 1--></td>\n"
-				"</tr>\n";
+			printBlockHeader(1, 1);
 		}
-			
+
 		switch (linediff[i].op) {
 			case DiffOp<String>::add:
 				// inserted lines
@@ -60,29 +56,10 @@ void Wikidiff2::diffLines(const StringVector & lines1, const StringVector & line
 					if ((i != 0 && j < numContextLines) /*trailing*/
 							|| (i != linediff.size() - 1 && j >= n - numContextLines)) /*leading*/ {
 						if (showLineNumber) {
-							// Print Line: heading
-							char buf[256]; // should be plenty
-							snprintf(buf, 256,
-								"<tr>\n"
-								"  <td colspan=\"2\" class=\"diff-lineno\"><!--LINE %u--></td>\n"
-								"  <td colspan=\"2\" class=\"diff-lineno\"><!--LINE %u--></td>\n"
-								"</tr>\n",
-								from_index, to_index);
-							result += buf;
+							printBlockHeader(from_index, to_index);
 							showLineNumber = false;
 						}
-						// Print context
-						result += 
-							"<tr>\n"
-							"  <td class=\"diff-marker\"> </td>\n"
-							"  <td class=\"diff-context\">";
-						printTextWithDiv(*linediff[i].from[j]);
-						result += 
-							"</td>\n"
-							"  <td class=\"diff-marker\"> </td>\n"
-							"  <td class=\"diff-context\">";
-						printTextWithDiv(*linediff[i].from[j]);
-						result += "</td>\n</tr>\n";
+						printContext(*linediff[i].from[j]);
 					} else {
 						showLineNumber = true;
 					}
@@ -116,54 +93,10 @@ void Wikidiff2::diffLines(const StringVector & lines1, const StringVector & line
 	}
 }
 
-void Wikidiff2::printAdd(const String & line) 
-{
-	result += "<tr>\n"
-		"  <td colspan=\"2\" class=\"diff-empty\"> </td>\n"
-		"  <td class=\"diff-marker\">+</td>\n"
-		"  <td class=\"diff-addedline\">";
-	printTextWithDiv(line);
-	result += "</td>\n</tr>\n";
-}
-
-void Wikidiff2::printDelete(const String & line)
-{
-	result += "<tr>\n"
-		"  <td class=\"diff-marker\">−</td>\n"
-		"  <td class=\"diff-deletedline\">";
-	printTextWithDiv(line);
-	result += "</td>\n"
-		"  <td colspan=\"2\" class=\"diff-empty\"> </td>\n"
-		"</tr>\n";
-}
-
-void Wikidiff2::printWordDiff(const String & text1, const String & text2)
-{
-	WordVector words1, words2;
-
-	explodeWords(text1, words1);
-	explodeWords(text2, words2);
-	WordDiff worddiff(words1, words2);
-	
-	//debugPrintWordDiff(worddiff);
-	
-	// print twice; first for left side, then for right side
-	result += "<tr>\n"
-		"  <td class=\"diff-marker\">−</td>\n"
-		"  <td class=\"diff-deletedline\"><div>";
-	printWordDiffSide(worddiff, false);
-	result += "</div></td>\n"
-		"  <td class=\"diff-marker\">+</td>\n"
-		"  <td class=\"diff-addedline\"><div>";
-	printWordDiffSide(worddiff, true);
-	result += "</div></td>\n"
-		"</tr>\n";
-}
-
 void Wikidiff2::debugPrintWordDiff(WordDiff & worddiff)
 {
 	for (unsigned i = 0; i < worddiff.size(); ++i) {
-		DiffOp<Word> & op = worddiff[i];	
+		DiffOp<Word> & op = worddiff[i];
 		switch (op.op) {
 			case DiffOp<Word>::copy:
 				result += "Copy\n";
@@ -205,55 +138,6 @@ void Wikidiff2::debugPrintWordDiff(WordDiff & worddiff)
 	}
 }
 
-void Wikidiff2::printWordDiffSide(WordDiff &worddiff, bool added)
-{
-	String word;
-	for (unsigned i = 0; i < worddiff.size(); ++i) {
-		DiffOp<Word> & op = worddiff[i];
-		int n, j;
-		if (op.op == DiffOp<Word>::copy) {
-			n = op.from.size();
-			if (added) {
-				for (j=0; j<n; j++) {
-					op.to[j]->get_whole(word);
-					printText(word);
-				}
-			} else {
-				for (j=0; j<n; j++) {
-					op.from[j]->get_whole(word);
-					printText(word);
-				}
-			}
-		} else if (!added && (op.op == DiffOp<Word>::del || op.op == DiffOp<Word>::change)) {
-			n = op.from.size();
-			result += "<span class=\"diffchange diffchange-inline\">";
-			for (j=0; j<n; j++) {
-				op.from[j]->get_whole(word);
-				printText(word);
-			}
-			result += "</span>";
-		} else if (added && (op.op == DiffOp<Word>::add || op.op == DiffOp<Word>::change)) {
-			n = op.to.size();
-			result += "<span class=\"diffchange diffchange-inline\">";
-			for (j=0; j<n; j++) {
-				op.to[j]->get_whole(word);
-				printText(word);
-			}
-			result += "</span>";
-		}
-	}
-}
-
-void Wikidiff2::printTextWithDiv(const String & input)
-{
-	// Wrap string in a <div> if it's not empty
-	if (input.size() > 0) {
-		result.append("<div>");
-		printText(input);
-		result.append("</div>");
-	}
-}
-
 void Wikidiff2::printText(const String & input)
 {
 	size_t start = 0;
@@ -283,10 +167,10 @@ void Wikidiff2::printText(const String & input)
 
 // Weak UTF-8 decoder
 // Will return garbage on invalid input (overshort sequences, overlong sequences, etc.)
-int Wikidiff2::nextUtf8Char(String::const_iterator & p, String::const_iterator & charStart, 
+int Wikidiff2::nextUtf8Char(String::const_iterator & p, String::const_iterator & charStart,
 		String::const_iterator end)
 {
-	int c;
+	int c = 0;
 	unsigned char byte;
 	int seqLength = 0;
 	charStart = p;
@@ -326,11 +210,11 @@ int Wikidiff2::nextUtf8Char(String::const_iterator & p, String::const_iterator &
 
 // Split a string into words
 //
-// TODO: I think the best way to do this would be to use ICU BreakIterator 
-// instead of libthai + DIY. Basically you'd run BreakIterators from several 
+// TODO: I think the best way to do this would be to use ICU BreakIterator
+// instead of libthai + DIY. Basically you'd run BreakIterators from several
 // different locales (en, th, ja) and merge the results, i.e. if a break occurs
-// in any locale at a given position, split the string. I don't know if the 
-// quality of the Thai dictionary in ICU matches the one in libthai, we would 
+// in any locale at a given position, split the string. I don't know if the
+// quality of the Thai dictionary in ICU matches the one in libthai, we would
 // have to check this somehow.
 void Wikidiff2::explodeWords(const String & text, WordVector &words)
 {
@@ -342,7 +226,7 @@ void Wikidiff2::explodeWords(const String & text, WordVector &words)
 
 	// Decode the UTF-8 in the string.
 	// * Save the character sizes (in bytes)
-	// * Convert the string to TIS-620, which is the internal character set of libthai. 
+	// * Convert the string to TIS-620, which is the internal character set of libthai.
 	// * Save the character offsets of any break positions (same format as libthai).
 
 	String tisText, charSizes;
@@ -385,13 +269,13 @@ void Wikidiff2::explodeWords(const String & text, WordVector &words)
 		IntVector thaiBreakPositions;
 		tisText += '\0';
 		thaiBreakPositions.resize(tisText.size());
-		int numBreaks = th_brk((const thchar_t*)(tisText.data()), 
+		int numBreaks = th_brk((const thchar_t*)(tisText.data()),
 				&thaiBreakPositions[0], thaiBreakPositions.size());
 		thaiBreakPositions.resize(numBreaks);
 		breaks.insert(thaiBreakPositions.begin(), thaiBreakPositions.end());
 	}
 
-	// Add a fake end-of-string character and have a break on it, so that the 
+	// Add a fake end-of-string character and have a break on it, so that the
 	// last word gets added without special handling
 	breaks.insert(charSizes.size());
 	charSizes += (char)0;
@@ -431,7 +315,7 @@ void Wikidiff2::explodeLines(const String & text, StringVector &lines)
 	while (ptr != text.end()) {
 		String::const_iterator ptr2 = std::find(ptr, text.end(), '\n');
 		lines.push_back(String(ptr, ptr2));
-		
+
 		ptr = ptr2;
 		if (ptr != text.end()) {
 			++ptr;
@@ -444,7 +328,7 @@ const Wikidiff2::String & Wikidiff2::execute(const String & text1, const String
 	// Allocate some result space to avoid excessive copying
 	result.clear();
 	result.reserve(text1.size() + text2.size() + 10000);
-	
+
 	// Split input strings into lines
 	StringVector lines1;
 	StringVector lines2;
@@ -457,4 +341,3 @@ const Wikidiff2::String & Wikidiff2::execute(const String & text1, const String
 	// Return a reference to the result buffer
 	return result;
 }
-
diff --git a/wikidiff2.h b/Wikidiff2.h
similarity index 69%
rename from wikidiff2.h
rename to Wikidiff2.h
index d714514..358b73b 100644
--- a/wikidiff2.h
+++ b/Wikidiff2.h
@@ -3,12 +3,12 @@
 
 #define MAX_DIFF_LINE 10000
 
-/** Set WD2_USE_STD_ALLOCATOR to compile for standalone (non-PHP) operation */
-#ifdef WD2_USE_STD_ALLOCATOR
-#define WD2_ALLOCATOR std::allocator
+/** Set WD2_USE_STD_ALLOCATOR depending on whether we're compiling as a PHP module or not */
+#if defined(HAVE_CONFIG_H)
+	#define WD2_ALLOCATOR PhpAllocator
+	#include "php_cpp_allocator.h"
 #else
-#define WD2_ALLOCATOR PhpAllocator
-#include "php_cpp_allocator.h"
+	#define WD2_ALLOCATOR std::allocator
 #endif
 
 #include "DiffEngine.h"
@@ -35,26 +35,27 @@ class Wikidiff2 {
 	protected:
 		String result;
 
-		void diffLines(const StringVector & lines1, const StringVector & lines2, 
+		virtual void diffLines(const StringVector & lines1, const StringVector & lines2,
 				int numContextLines);
-		void printAdd(const String & line);
-		void printDelete(const String & line);
-		void printWordDiff(const String & text1, const String & text2);
-		void printWordDiffSide(WordDiff &worddiff, bool added);
-		void printTextWithDiv(const String & input);
+		virtual void printAdd(const String & line) = 0;
+		virtual void printDelete(const String & line) = 0;
+		virtual void printWordDiff(const String & text1, const String & text2) = 0;
+		virtual void printBlockHeader(int leftLine, int rightLine) = 0;
+		virtual void printContext(const String & input) = 0;
+
 		void printText(const String & input);
 		inline bool isLetter(int ch);
 		inline bool isSpace(int ch);
 		void debugPrintWordDiff(WordDiff & worddiff);
 
-		int nextUtf8Char(String::const_iterator & p, String::const_iterator & charStart, 
+		int nextUtf8Char(String::const_iterator & p, String::const_iterator & charStart,
 				String::const_iterator end);
 
 		void explodeWords(const String & text, WordVector &tokens);
 		void explodeLines(const String & text, StringVector &lines);
 };
 
-bool Wikidiff2::isLetter(int ch)
+inline bool Wikidiff2::isLetter(int ch)
 {
 	// Standard alphanumeric
 	if ((ch >= '0' && ch <= '9') ||
@@ -73,12 +74,12 @@ bool Wikidiff2::isLetter(int ch)
 	return true;
 }
 
-bool Wikidiff2::isSpace(int ch)
+inline bool Wikidiff2::isSpace(int ch)
 {
 	return ch == ' ' || ch == '\t';
 }
 
-const Wikidiff2::String & Wikidiff2::getResult() const
+inline const Wikidiff2::String & Wikidiff2::getResult() const
 {
 	return result;
 }
diff --git a/Word.h b/Word.h
index 5d447aa..1950bc3 100644
--- a/Word.h
+++ b/Word.h
@@ -3,12 +3,12 @@
 
 #include <string>
 #include <algorithm>
-#include "wikidiff2.h"
+#include "Wikidiff2.h"
 
 // a small class to accomodate word-level diffs; basically, a body and an
 // optional suffix (the latter consisting of a single whitespace), where
 // only the bodies are compared on operator==.
-// 
+//
 // This class stores iterators pointing to the line string, this is to avoid
 // excessive allocation calls. To avoid invalidation, the source string should
 // not be changed or destroyed.
@@ -16,21 +16,21 @@ class Word {
 public:
 	typedef std::basic_string<char, std::char_traits<char>, WD2_ALLOCATOR<char> > String;
 	typedef String::const_iterator Iterator;
-	
+
 	Iterator bodyStart;
 	Iterator bodyEnd;
 	Iterator suffixEnd;
-	
+
 	/**
 	  * The body is the character sequence [bs, be)
 	  * The whitespace suffix is the character sequence [be, se)
 	  */
-	Word(Iterator bs, Iterator be, Iterator se) 
+	Word(Iterator bs, Iterator be, Iterator se)
 		: bodyStart(bs), bodyEnd(be), suffixEnd(se)
 	{}
 
 	bool operator== (const Word &w) const {
-		return (bodyEnd - bodyStart == w.bodyEnd - w.bodyStart) 
+		return (bodyEnd - bodyStart == w.bodyEnd - w.bodyStart)
 			&& std::equal(bodyStart, bodyEnd, w.bodyStart);
 	}
 	bool operator!=(const Word &w) const {
diff --git a/config.cmake b/config.cmake
new file mode 100644
index 0000000..8e55658
--- /dev/null
+++ b/config.cmake
@@ -0,0 +1,3 @@
+HHVM_EXTENSION(wikidiff2 hhvm_wikidiff2.cpp Wikidiff2.cpp InlineDiff.cpp TableDiff.cpp)
+HHVM_SYSTEMLIB(wikidiff2 ext_wikidiff2.php)
+target_link_libraries(wikidiff2 libthai.so)
diff --git a/config.m4 b/config.m4
index 0904d50..b848398 100644
--- a/config.m4
+++ b/config.m4
@@ -37,5 +37,5 @@ if test "$PHP_WIKIDIFF2" != "no"; then
   PHP_SUBST(WIKIDIFF2_SHARED_LIBADD)
   AC_DEFINE(HAVE_WIKIDIFF2, 1, [ ])
   export CXXFLAGS="-Wno-write-strings $CXXFLAGS"
-  PHP_NEW_EXTENSION(wikidiff2, php_wikidiff2.cpp wikidiff2.cpp, $ext_shared)
+  PHP_NEW_EXTENSION(wikidiff2, php_wikidiff2.cpp Wikidiff2.cpp TableDiff.cpp InlineDiff.cpp, $ext_shared)
 fi
diff --git a/debian/changelog b/debian/changelog
index 6547265..3edd0ec 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+php-wikidiff2 (1.2-1) precise-wikimedia; urgency=low
+
+  * Added new function, wikidiff2_inline_diff(), for one-column diffs
+
+ -- Max Semenik <msemenik at wikimedia.org>  Mon, 09 Dec 2013 21:56:00 +0000
+
+php-wikidiff2 (1.1.2-2) precise-wikimedia; urgency=low
+
+  * Fixed incorrect path in wikidiff2.ini
+
+ -- Tim Starling <tstarling at wikimedia.org>  Tue, 08 Jan 2013 14:30:53 +1100
+
 php-wikidiff2 (1.1.2-1) lucid-wikimedia; urgency=low
   * Fixed bug 26354 (added class to dummy cells containing  )
   * Fixed bug 25697 (empty context lines not showing)
diff --git a/debian/conffiles b/debian/conffiles
deleted file mode 100644
index 413aa96..0000000
--- a/debian/conffiles
+++ /dev/null
@@ -1 +0,0 @@
-/etc/php5/conf.d/wikidiff2.ini
diff --git a/debian/control b/debian/control
index 2a3abdb..2dd289e 100644
--- a/debian/control
+++ b/debian/control
@@ -7,6 +7,6 @@ Standards-Version: 3.7.2
 
 Package: php-wikidiff2
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, php5-common, libthai0
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${php:Depends}, php5-common, libthai0
 Description: MediaWiki diff plugin for PHP 5
  Faster diff plugin for MediaWiki under PHP 5
diff --git a/debian/copyright b/debian/copyright
index 81aca02..acbd0e3 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,22 +1,7 @@
-This package was debianized by unknown <brion at wikimedia.org> on
-Tue, 21 Aug 2007 18:03:07 +0000.
-
-It was downloaded from <fill in http/ftp site>
-
-Upstream Author: <put author(s) name and email here>
-
-Copyright: <put the year(s) of the copyright, and the names of the
-            copyright holder(s) here>
-
-License:
-
-<Put the license of the package here>
-
-
-The Debian packaging is (C) 2007, unknown <brion at wikimedia.org> and
-is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
-
-
-# Please also look if there are files or directories which have a
-# different copyright/license attached and list them here.
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: php-wikidiff2
+Source: http://gerrit.wikimedia.org/r/mediawiki/php/wikidiff2
 
+Files: *
+Copyright: 2006-2014 Wikimedia Foundation
+License: GPL2
diff --git a/debian/rules b/debian/rules
index 072b34f..ca31f7c 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,6 @@
 #!/usr/bin/make -f
 
-# The PHP header files are not designed to be run with C++, they hit this 
+# The PHP header files are not designed to be run with C++, they hit this
 # warning a lot.
 CXXFLAGS=-Wno-write-strings
 
@@ -20,3 +20,7 @@ override_dh_auto_install:
 	INSTALL_ROOT=$(CURDIR)/debian/php-wikidiff2 make install
 	install -m 0755 -d $(CURDIR)/debian/php-wikidiff2/etc/php5/conf.d
 	install -m 0644 wikidiff2.ini $(CURDIR)/debian/php-wikidiff2/etc/php5/conf.d/wikidiff2.ini
+
+override_dh_gencontrol:
+	echo "php:Depends=phpapi-$(shell php-config5 --phpapi)" >> debian/php-wikidiff2.substvars
+	dh_gencontrol
diff --git a/ext_wikidiff2.php b/ext_wikidiff2.php
new file mode 100644
index 0000000..d69d94a
--- /dev/null
+++ b/ext_wikidiff2.php
@@ -0,0 +1,6 @@
+<?hh
+<<__Native>>
+function wikidiff2_do_diff(string $text1, string $text2, int $numContextLines): string;
+
+<<__Native>>
+function wikidiff2_inline_diff(string $text1, string $text2, int $numContextLines): string;
diff --git a/hhvm_wikidiff2.cpp b/hhvm_wikidiff2.cpp
new file mode 100644
index 0000000..4b533e3
--- /dev/null
+++ b/hhvm_wikidiff2.cpp
@@ -0,0 +1,76 @@
+/* $Id$ */
+
+#include "hphp/runtime/base/base-includes.h"
+#include "hphp/util/alloc.h"
+#include "Wikidiff2.h"
+#include "TableDiff.h"
+#include "InlineDiff.h"
+
+#include <string>
+
+namespace HPHP {
+
+/* {{{ proto string wikidiff2_do_diff(string text1, string text2, int numContextLines)
+ *
+ * Warning: the input text must be valid UTF-8! Do not pass user input directly
+ * to this function.
+ */
+static String HHVM_FUNCTION(wikidiff2_do_diff,
+	const String& text1,
+	const String& text2,
+	int64_t numContextLines)
+{
+    String result;
+	try {
+		TableDiff wikidiff2;
+		Wikidiff2::String text1String(text1.c_str());
+		Wikidiff2::String text2String(text2.c_str());
+		result = wikidiff2.execute(text1String, text2String, numContextLines);
+	} catch (OutOfMemoryException &e) {
+		raise_error("Out of memory in wikidiff2_do_diff().");
+	} catch (...) {
+		raise_error("Unknown exception in wikidiff2_do_diff().");
+	}
+	return result;
+}
+
+/* {{{ proto string wikidiff2_inline_diff(string text1, string text2, int numContextLines)
+ *
+ * Warning: the input text must be valid UTF-8! Do not pass user input directly
+ * to this function.
+ */
+static String HHVM_FUNCTION(wikidiff2_inline_diff,
+	const String& text1,
+	const String& text2,
+	int64_t numContextLines)
+{
+    String result;
+	try {
+		InlineDiff wikidiff2;
+		Wikidiff2::String text1String(text1.c_str());
+		Wikidiff2::String text2String(text2.c_str());
+		result = wikidiff2.execute(text1String, text2String, numContextLines);
+	} catch (OutOfMemoryException &e) {
+		raise_error("Out of memory in wikidiff2_do_diff().");
+	} catch (...) {
+		raise_error("Unknown exception in wikidiff2_do_diff().");
+	}
+	return result;
+}
+
+static class Wikidiff2Extension : public Extension {
+	public:
+		Wikidiff2Extension() : Extension("wikidiff2") {}
+		virtual void moduleInit() {
+			HHVM_FE(wikidiff2_do_diff);
+			HHVM_FE(wikidiff2_inline_diff);
+			loadSystemlib();
+		}
+} s_wikidiff2_extension;
+
+HHVM_GET_MODULE(wikidiff2)
+
+} // namespace HPHP
+
+
+
diff --git a/php_wikidiff2.cpp b/php_wikidiff2.cpp
index ea063b7..48e9d93 100644
--- a/php_wikidiff2.cpp
+++ b/php_wikidiff2.cpp
@@ -8,12 +8,15 @@
 #include "php_ini.h"
 #include "ext/standard/info.h"
 #include "php_wikidiff2.h"
-#include "wikidiff2.h"
+#include "Wikidiff2.h"
+#include "TableDiff.h"
+#include "InlineDiff.h"
 
 static int le_wikidiff2;
 
 zend_function_entry wikidiff2_functions[] = {
-	PHP_FE(wikidiff2_do_diff,	NULL)
+	PHP_FE(wikidiff2_do_diff,     NULL)
+	PHP_FE(wikidiff2_inline_diff, NULL)
 	{NULL, NULL, NULL}
 };
 
@@ -26,11 +29,11 @@ zend_module_entry wikidiff2_module_entry = {
 	wikidiff2_functions,
 	PHP_MINIT(wikidiff2),
 	PHP_MSHUTDOWN(wikidiff2),
-	PHP_RINIT(wikidiff2),	
+	PHP_RINIT(wikidiff2),
 	PHP_RSHUTDOWN(wikidiff2),
 	PHP_MINFO(wikidiff2),
 #if ZEND_MODULE_API_NO >= 20010901
-	"0.1",
+	"0.2",
 #endif
 	STANDARD_MODULE_PROPERTIES
 };
@@ -69,7 +72,10 @@ PHP_MINFO_FUNCTION(wikidiff2)
 }
 
 /* {{{ proto string wikidiff2_do_diff(string text1, string text2, int numContextLines)
-    */
+ *
+ * Warning: the input text must be valid UTF-8! Do not pass user input directly
+ * to this function.
+ */
 PHP_FUNCTION(wikidiff2_do_diff)
 {
 	char *text1 = NULL;
@@ -79,7 +85,7 @@ PHP_FUNCTION(wikidiff2_do_diff)
 	int text2_len;
 	long numContextLines;
 
-	if (zend_parse_parameters(argc TSRMLS_CC, "ssl", &text1, &text1_len, &text2, 
+	if (zend_parse_parameters(argc TSRMLS_CC, "ssl", &text1, &text1_len, &text2,
 		&text2_len, &numContextLines) == FAILURE)
 	{
 		return;
@@ -87,7 +93,7 @@ PHP_FUNCTION(wikidiff2_do_diff)
 
 
 	try {
-		Wikidiff2 wikidiff2;
+		TableDiff wikidiff2;
 		Wikidiff2::String text1String(text1, text1_len);
 		Wikidiff2::String text2String(text2, text2_len);
 		const Wikidiff2::String & ret = wikidiff2.execute(text1String, text2String, numContextLines);
@@ -98,6 +104,41 @@ PHP_FUNCTION(wikidiff2_do_diff)
 		zend_error(E_WARNING, "Unknown exception in wikidiff2_do_diff().");
 	}
 }
+
+/* {{{ proto string wikidiff2_inline_diff(string text1, string text2, int numContextLines)
+ *
+ * Warning: the input text must be valid UTF-8! Do not pass user input directly
+ * to this function.
+ */
+PHP_FUNCTION(wikidiff2_inline_diff)
+{
+	char *text1 = NULL;
+	char *text2 = NULL;
+	int argc = ZEND_NUM_ARGS();
+	int text1_len;
+	int text2_len;
+	long numContextLines;
+
+	if (zend_parse_parameters(argc TSRMLS_CC, "ssl", &text1, &text1_len, &text2,
+		&text2_len, &numContextLines) == FAILURE)
+	{
+		return;
+	}
+
+
+	try {
+		InlineDiff wikidiff2;
+		Wikidiff2::String text1String(text1, text1_len);
+		Wikidiff2::String text2String(text2, text2_len);
+		const Wikidiff2::String& ret = wikidiff2.execute(text1String, text2String, numContextLines);
+		RETURN_STRINGL( const_cast<char*>(ret.data()), ret.size(), 1);
+	} catch (std::bad_alloc &e) {
+		zend_error(E_WARNING, "Out of memory in wikidiff2_inline_diff().");
+	} catch (...) {
+		zend_error(E_WARNING, "Unknown exception in wikidiff2_inline_diff().");
+	}
+}
+
 /* }}} */
 
 
diff --git a/php_wikidiff2.h b/php_wikidiff2.h
index ec45e39..973233f 100644
--- a/php_wikidiff2.h
+++ b/php_wikidiff2.h
@@ -43,6 +43,7 @@ PHP_RSHUTDOWN_FUNCTION(wikidiff2);
 PHP_MINFO_FUNCTION(wikidiff2);
 
 PHP_FUNCTION(wikidiff2_do_diff);
+PHP_FUNCTION(wikidiff2_inline_diff);
 
 
 
diff --git a/tests/001.phpt b/tests/001.phpt
index 55f7171..36195b7 100644
--- a/tests/001.phpt
+++ b/tests/001.phpt
@@ -386,9 +386,9 @@ print wikidiff2_do_diff( $x, $y, 2 );
 </tr>
 <tr>
   <td class="diff-marker">−</td>
-  <td class="diff-deletedline"><div>blah blah blah <span class="diffchange diffchange-inline">1</span></div></td>
+  <td class="diff-deletedline"><div>blah blah blah <del class="diffchange diffchange-inline">1</del></div></td>
   <td class="diff-marker">+</td>
-  <td class="diff-addedline"><div>blah blah blah <span class="diffchange diffchange-inline">2</span></div></td>
+  <td class="diff-addedline"><div>blah blah blah <ins class="diffchange diffchange-inline">2</ins></div></td>
 </tr>
 <tr>
   <td class="diff-marker"> </td>
diff --git a/tests/003.phpt b/tests/003.phpt
index cdfba6e..2bd90fa 100644
--- a/tests/003.phpt
+++ b/tests/003.phpt
@@ -28,7 +28,7 @@ print wikidiff2_do_diff( $x, $y, 2 );
 </tr>
 <tr>
   <td class="diff-marker">−</td>
-  <td class="diff-deletedline"><div><span class="diffchange diffchange-inline">!!FUZZY!!</span>Rajaa</div></td>
+  <td class="diff-deletedline"><div><del class="diffchange diffchange-inline">!!FUZZY!!</del>Rajaa</div></td>
   <td class="diff-marker">+</td>
   <td class="diff-addedline"><div>Rajaa</div></td>
 </tr>
diff --git a/tests/004.phpt b/tests/004.phpt
new file mode 100644
index 0000000..32594d4
--- /dev/null
+++ b/tests/004.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Diff test D: inline diffs
+--SKIPIF--
+<?php if (!extension_loaded("wikidiff2")) print "skip"; ?>
+--FILE--
+<?php
+$x = <<<EOT
+foo bar
+
+baz
+quux
+bang
+EOT;
+
+#---------------------------------------------------
+
+$y = <<<EOT
+foo test
+baz
+test
+
+bang
+EOT;
+
+#---------------------------------------------------
+
+print wikidiff2_inline_diff( $x, $y, 2 );
+
+?>
+--EXPECT--
+<div class="mw-diff-inline-header"><!-- LINES 1,1 --></div>
+<div class="mw-diff-inline-changed">foo <del>bar</del><ins>test</ins></div>
+<div class="mw-diff-inline-deleted"><del> </del></div>
+<div class="mw-diff-inline-context">baz</div>
+<div class="mw-diff-inline-changed"><del>quux</del><ins>test</ins></div>
+<div class="mw-diff-inline-added"><ins> </ins></div>
+<div class="mw-diff-inline-context">bang</div>
+
diff --git a/wikidiff2.ini b/wikidiff2.ini
index a981944..2e5751a 100644
--- a/wikidiff2.ini
+++ b/wikidiff2.ini
@@ -1 +1 @@
-extension=php_wikidiff2.so
+extension=wikidiff2.so

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/wikidiff2.git



More information about the Pkg-mediawiki-commits mailing list