1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-24 09:20:06 +08:00
SpaceVim/bundle/vim-mundo/autoload/mundo/diff.py
2020-10-31 15:52:34 +08:00

106 lines
3.5 KiB
Python

import difflib
import itertools
# one line diff functions.
def one_line_diff_str(before,after,mx=15,pre=2):
"""
Return a summary of the differences between two strings, concatenated.
Parameters:
before - string before.
after - after string.
mx - the max number of strings.
pre - number of characters to show before diff (context)
Returns a string no longer than 'mx'.
"""
old = one_line_diff(before,after)
result = ''
firstEl = True
# TODO instead of using +addition+ and -subtraction- it'd be nice to be able
# to highlight the change w/o requiring the +/- chars.
for v in old:
# if the first element doesn't have a change, then don't include it.
v = escape_returns(v)
if firstEl:
firstEl = False
# add in pre character context:
if not (v.startswith('+') or v.startswith('-')) and result == '':
v = v[-pre:]
# when we're going to be bigger than our max limit, lets ensure that the
# trailing +/- appears in the text:
if len(result) + len(v) > mx:
if v.startswith('+') or v.startswith('-'):
result += v[:mx - len(result) - 1]
result += v[0]
break
result += v
return result
def escape_returns(result):
return result.replace('\n','\\n').replace('\r','\\r').replace('\t','\\t')
def one_line_diff(before, after):
"""
Return a summary of the differences between two arbitrary strings.
Returns a list of strings, summarizing all the changes.
"""
a, b, result = [], [], []
for line in itertools.chain(itertools.islice(
difflib.unified_diff(before.splitlines(),
after.splitlines()), 2, None), ['@@']):
if line.startswith('@@'):
result.extend(one_line_diff_raw('\n'.join(a), '\n'.join(b)))
a, b = [], []
continue
if not line.startswith('+'):
a.append(line[1:])
if not line.startswith('-'):
b.append(line[1:])
if after.endswith('\n') and not before.endswith('\n'):
if result:
result[-1] = result[-1][:-1] + '\n+'
else:
result = ['+\n+']
return result
def one_line_diff_raw(before,after):
s = difflib.SequenceMatcher(None,before,after)
results = []
for tag, i1, i2, j1, j2 in s.get_opcodes():
#print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" % (tag, i1, i2, before[i1:i2], j1, j2, after[j1:j2]))
if tag == 'equal':
_append_result(results,{
'equal': after[j1:j2]
})
if tag == 'insert':
_append_result(results,{
'plus': after[j1:j2]
})
elif tag == 'delete':
_append_result(results,{
'minus': before[i1:i2]
})
elif tag == 'replace':
_append_result(results,{
'minus': before[j1:j2],
'plus': after[j1:j2]
})
final_results = []
# finally, create a human readable string of information.
for v in results:
if 'minus' in v and 'plus' in v and len(v['minus']) > 0 and len(v['plus']) > 0:
final_results.append("-%s-+%s+"% (v['minus'],v['plus']))
elif 'minus' in v and len(v['minus']) > 0:
final_results.append("-%s-"% (v['minus']))
elif 'plus' in v and len(v['plus']) > 0:
final_results.append("+%s+"% (v['plus']))
elif 'equal' in v:
final_results.append("%s"% (v['equal']))
return final_results
def _append_result(results,val):
results.append(val)