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