From 5a1f036db3cfdfd2506f71ec749335ca2b7664e0 Mon Sep 17 00:00:00 2001 From: Zev Benjamin Date: Fri, 31 May 2013 16:33:26 -0400 Subject: [PATCH] Use Diff Match Patch instead of difflib for HTML diffing Diff Match Patch provides more human-readable diffs. For example, try replacing "mouse" with "sofas". (imported from commit 7ced81202ce85d5ef69888c59912e3e44c38cfc8) --- zephyr/lib/html_diff.py | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/zephyr/lib/html_diff.py b/zephyr/lib/html_diff.py index c169989e39..fb4f869260 100644 --- a/zephyr/lib/html_diff.py +++ b/zephyr/lib/html_diff.py @@ -1,4 +1,4 @@ -import difflib +from diff_match_patch import diff_match_patch import platform import logging @@ -66,22 +66,39 @@ def verify_html(html): return True def highlight_html_differences(s1, s2): - sm = difflib.SequenceMatcher(lambda c: c in " \t\v\n", s1, s2, autojunk=False) + differ = diff_match_patch() + ops = differ.diff_main(s1, s2) + differ.diff_cleanupSemantic(ops) retval = '' in_tag = False - for op, i1, i2, j1, j2 in sm.get_opcodes(): - if op == 'replace': - chunks, in_tag = chunkize(s2[j1:j2], in_tag) + idx = 0 + while idx < len(ops): + op, text = ops[idx] + next_op = None + if idx != len(ops) - 1: + next_op, next_text = ops[idx + 1] + if op == diff_match_patch.DIFF_DELETE and next_op == diff_match_patch.DIFF_INSERT: + # Replace operation + chunks, in_tag = chunkize(next_text, in_tag) retval += highlight_chunks(chunks, highlight_replaced) - elif op == 'delete': + idx += 1 + elif op == diff_match_patch.DIFF_INSERT and next_op == diff_match_patch.DIFF_DELETE: + # Replace operation + # I have no idea whether diff_match_patch generates inserts followed + # by deletes, but it doesn't hurt to handle them + chunks, in_tag = chunkize(text, in_tag) + retval += highlight_chunks(chunks, highlight_replaced) + idx += 1 + elif op == diff_match_patch.DIFF_DELETE: retval += highlight_deleted(' ') - elif op == 'insert': - chunks, in_tag = chunkize(s2[j1:j2], in_tag) + elif op == diff_match_patch.DIFF_INSERT: + chunks, in_tag = chunkize(text, in_tag) retval += highlight_chunks(chunks, highlight_inserted) - elif op == 'equal': - chunks, in_tag = chunkize(s2[j1:j2], in_tag) - retval += s2[j1:j2] + elif op == diff_match_patch.DIFF_EQUAL: + chunks, in_tag = chunkize(text, in_tag) + retval += text + idx += 1 if not verify_html(retval): from zephyr.lib.actions import internal_send_message