mirror of https://github.com/zulip/zulip.git
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)
This commit is contained in:
parent
1af0d5b942
commit
5a1f036db3
|
@ -1,4 +1,4 @@
|
||||||
import difflib
|
from diff_match_patch import diff_match_patch
|
||||||
import platform
|
import platform
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
@ -66,22 +66,39 @@ def verify_html(html):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def highlight_html_differences(s1, s2):
|
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 = ''
|
retval = ''
|
||||||
in_tag = False
|
in_tag = False
|
||||||
|
|
||||||
for op, i1, i2, j1, j2 in sm.get_opcodes():
|
idx = 0
|
||||||
if op == 'replace':
|
while idx < len(ops):
|
||||||
chunks, in_tag = chunkize(s2[j1:j2], in_tag)
|
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)
|
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(' ')
|
retval += highlight_deleted(' ')
|
||||||
elif op == 'insert':
|
elif op == diff_match_patch.DIFF_INSERT:
|
||||||
chunks, in_tag = chunkize(s2[j1:j2], in_tag)
|
chunks, in_tag = chunkize(text, in_tag)
|
||||||
retval += highlight_chunks(chunks, highlight_inserted)
|
retval += highlight_chunks(chunks, highlight_inserted)
|
||||||
elif op == 'equal':
|
elif op == diff_match_patch.DIFF_EQUAL:
|
||||||
chunks, in_tag = chunkize(s2[j1:j2], in_tag)
|
chunks, in_tag = chunkize(text, in_tag)
|
||||||
retval += s2[j1:j2]
|
retval += text
|
||||||
|
idx += 1
|
||||||
|
|
||||||
if not verify_html(retval):
|
if not verify_html(retval):
|
||||||
from zephyr.lib.actions import internal_send_message
|
from zephyr.lib.actions import internal_send_message
|
||||||
|
|
Loading…
Reference in New Issue