Become a little smarter about the area that actually changed in an edit

This commit is contained in:
Holger Rapp 2012-01-19 12:57:48 +01:00
parent 7e05d49bce
commit a483218f70
2 changed files with 72 additions and 15 deletions

View File

@ -794,21 +794,23 @@ class SnippetManager(object):
self._vstate.update()
if self._csnippets:
abs_end = self._vstate.pos
abs_start = self._vstate.ppos
if abs_end < abs_start:
abs_start, abs_end = abs_end, abs_start
abs_start = Position(0,0) # TODO
abs_end = Position(len(vim.current.buffer)-1, 10000)
span = Span(abs_start, abs_end)
ct = map(as_unicode, vim.current.buffer)
lt = map(as_unicode, self._lvb[:])
lt_span, ct_span = edit_distance.line_diffs(lt, ct)
debug("lt: %r" % (lt))
debug("ct: %r" % (ct))
debug("lt_span: %r, ct_span: %r" % (lt_span, ct_span))
# TODO
# ct = TextBuffer('\n'.join(vim.current.buffer))[span]
# lt = self._lvb[span]
ct = as_unicode('\n').join(map(as_unicode, vim.current.buffer))
lt = as_unicode(self._lvb)
# start_line = min(self._vstate.pos.line, self._vstate.ppos.line)
# ct = as_unicode('\n').join(map(as_unicode, vim.current.buffer[start_line:]))
# lt = as_unicode('\n').join(self._lvb[start_line:])
lt = '\n'.join(lt[lt_span[0]:lt_span[1]+1])
ct = '\n'.join(ct[ct_span[0]:ct_span[1]+1])
debug("lt: %r, ct: %r" % (lt, ct))
rv = edit_distance.edit_script(lt, ct, abs_start.line, abs_start.col)
rv = edit_distance.edit_script(lt, ct, min(lt_span[0], ct_span[0]))
debug("rv: %r" % (rv,))
self._csnippets[0].edited(rv)
self._check_if_still_inside_snippet()

View File

@ -7,11 +7,66 @@ import sys
# TODO: check test cases here. They are not up to date
def edit_script(a, b, sline = 0, scol = 0):
from .debug import debug
def line_diffs(a, b, sline = 0):
d = defaultdict(list)
seen = defaultdict(lambda: sys.maxint)
d[0] = [ (0,0,sline,scol, ()) ]
d[0] = [ (0,0,sline, ()) ]
cost = 0
while True:
while len(d[cost]):
x, y, line, what = d[cost].pop()
if x == len(a) and y == len(b):
# Find first span of changes in both buffers
x_min, x_max = sys.maxint, -sys.maxint
y_min, y_max = sys.maxint, -sys.maxint
debug("what: %r" % (what,))
for cmd,x,y in what:
if cmd == 'D':
x_min = min(x_min, x)
x_max = max(x_max, x)
elif cmd == 'I':
x_max = max(x_max, x-1 if x > 0 else 0)
x_min = min(x_min, x-1 if x > 0 else 0)
# y_min = min(y_min, line)
y_min = min(y_min, y-1 if y > 0 else 0)
y_max = max(y_max, y)
elif cmd == "M":
x_min = min(x_min, x)
x_max = max(x_max, x)
y_min = min(y_min, y)
y_max = max(y_max, y)
return (x_min, x_max), (y_min, y_max)
# TODO: line == y
if x < len(a) and y < len(b) and len(a[x]) == len(b[y]) and \
a[x] == b[y]: # Equal lines
if seen[x+1,y+1] > cost:
seen[x+1,y+1] = cost
if x != y:
d[cost].append((x+1,y+1,line+1, what + (('M', x,y),))) # TODO: match only debug
else:
d[cost].append((x+1,y+1,line+1, what)) # TODO: match only debug
if x < len(a): # Delete
if seen[x+1,y] > cost + 1 + x:
seen[x+1,y] = cost + 1 + x
d[cost+1+x].append((x+1,y, line, what + (('D', x, y),)))
if y < len(b): # Insert
if seen[x,y+1] > cost + 1 + y:
seen[x,y+1] = cost + 1 + y
d[cost+1+y].append((x,y+1,line+1, what + (('I', x, y),)))
cost += 1
def edit_script(a, b, sline = 0):
d = defaultdict(list)
seen = defaultdict(lambda: sys.maxint)
d[0] = [ (0,0,sline, 0, ()) ]
# TODO: needs some doku
cost = 0
@ -23,7 +78,7 @@ def edit_script(a, b, sline = 0, scol = 0):
#print "%r: %r" % (cost, sumarized)
x, y, line, col, what = d[cost].pop()
if a[x:] == b[y:]: ## TODO: try out is
if a[x:] == b[y:]:
#print "cost: %r" % (cost)
return what