diff --git a/requirements.txt b/requirements.txt
index ad5b2027..ffa8388a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -18,6 +18,7 @@ pygments>=1.6
django-sites==0.4
Markdown==2.4
fn==0.2.13
+diff-match-patch==20110725.1
# Comment it if you are using python >= 3.4
enum34==0.9.23
diff --git a/taiga/mdrender/service.py b/taiga/mdrender/service.py
index 460a601c..fb6c9ba9 100644
--- a/taiga/mdrender/service.py
+++ b/taiga/mdrender/service.py
@@ -32,6 +32,9 @@ def _make_extensions_list(wikilinks_config=None):
"codehilite"]
+import diff_match_patch
+
+
def cache_by_sha(func):
@functools.wraps(func)
def _decorator(project, text):
@@ -71,5 +74,23 @@ def render(project, text):
renderer = F() >> F(_preprocessors, project) >> F(_render_markdown, project) >> F(_postprocessors, project)
return renderer(text)
+class DiffMatchPatch(diff_match_patch.diff_match_patch):
+ def diff_pretty_html(self, diffs):
+ html = []
+ for (op, data) in diffs:
+ text = (data.replace("&", "&").replace("<", "<")
+ .replace(">", ">").replace("\n", "
"))
+ if op == self.DIFF_INSERT:
+ html.append("%s" % text)
+ elif op == self.DIFF_DELETE:
+ html.append("%s" % text)
+ elif op == self.DIFF_EQUAL:
+ html.append("%s" % text)
+ return "".join(html)
-__all__ = ['render']
+def get_diff_of_htmls(html1, html2):
+ diffutil = DiffMatchPatch()
+ diff = diffutil.diff_main(html1, html2)
+ return diffutil.diff_pretty_html(diff)
+
+__all__ = ['render', 'get_diff_of_htmls']
diff --git a/taiga/projects/history/services.py b/taiga/projects/history/services.py
index c4d677a2..d1756e53 100644
--- a/taiga/projects/history/services.py
+++ b/taiga/projects/history/services.py
@@ -39,6 +39,7 @@ from django.contrib.contenttypes.models import ContentType
from .models import HistoryType
from taiga.mdrender.service import render as mdrender
+from taiga.mdrender.service import get_diff_of_htmls
# Type that represents a freezed object
FrozenObj = namedtuple("FrozenObj", ["key", "snapshot"])
@@ -155,6 +156,13 @@ def make_diff(oldobj:FrozenObj, newobj:FrozenObj) -> FrozenDiff:
if key not in first:
diff[key] = (not_found_value, second[key])
+ if "description" in diff:
+ description_diff = get_diff_of_htmls(
+ diff["description"][0],
+ diff["description"][1]
+ )
+ diff["description_diff"] = (not_found_value, description_diff)
+
return FrozenDiff(newobj.key, diff, newobj.snapshot)