Be less clever again about Where to check for changes.
- Remove duplicate lines from last and current text. Still, this needs to traverse the whole buffer. - Removed functionality from VimState that had nothing to do with 'State'.
This commit is contained in:
parent
2bddcdb76c
commit
36a1bc1c17
@ -1,6 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# TODO: Currently Caches whole buffer. Is this really needed?
|
||||
# TODO: Currently searches whole buffer. Is this really needed?
|
||||
|
||||
import edit_distance
|
||||
from debug import debug
|
||||
|
||||
@ -62,6 +65,134 @@ def echom(mes, *args):
|
||||
mes = mes % args
|
||||
vim.command('echom %s' % vim_string(mes))
|
||||
|
||||
# TODO: this function should be moved
|
||||
def select_span(r):
|
||||
_unmap_select_mode_mapping()
|
||||
|
||||
delta = r.end - r.start
|
||||
lineno, col = r.start.line, r.start.col
|
||||
|
||||
set_vim_cursor(lineno + 1, col)
|
||||
|
||||
# Case 1: Zero Length Tabstops
|
||||
if delta.line == delta.col == 0:
|
||||
if col == 0 or vim.eval("mode()") != 'i' and \
|
||||
col < len(as_unicode(vim.current.buffer[lineno])):
|
||||
feedkeys(r"\<Esc>i")
|
||||
else:
|
||||
feedkeys(r"\<Esc>a")
|
||||
else:
|
||||
# Case 2a: Non zero length and inclusive selection
|
||||
# TODO: check with exclusive selection
|
||||
# If a tabstop immediately starts with a newline, the selection
|
||||
# must start after the last character in the current line. But if
|
||||
# we are in insert mode and <Esc> out of it, we cannot go past the
|
||||
# last character with move_one_right and therefore cannot
|
||||
# visual-select this newline. We have to hack around this by adding
|
||||
# an extra space which we can select. Note that this problem could
|
||||
# be circumvent by selecting the tab backwards (that is starting
|
||||
# at the end); one would not need to modify the line for this. This creates other
|
||||
# trouble though
|
||||
if col >= len(as_unicode(vim.current.buffer[lineno])):
|
||||
vim.current.buffer[lineno] += " "
|
||||
|
||||
if delta.line:
|
||||
move_lines = "%ij" % delta.line
|
||||
else:
|
||||
move_lines = ""
|
||||
# Depending on the current mode and position, we
|
||||
# might need to move escape out of the mode and this
|
||||
# will move our cursor one left
|
||||
if col != 0 and vim.eval("mode()") == 'i':
|
||||
move_one_right = "l"
|
||||
else:
|
||||
move_one_right = ""
|
||||
|
||||
# After moving to the correct line, we go back to column 0
|
||||
# and select right from there. Note that the we have to select
|
||||
# one column less since vim's visual selection is including the
|
||||
# ending while Python slicing is excluding the ending.
|
||||
if r.end.col == 0:
|
||||
# Selecting should end at beginning of line -> Select the
|
||||
# previous line till its end
|
||||
do_select = "k$"
|
||||
elif r.end.col > 1:
|
||||
do_select = "0%il" % (r.end.col-1)
|
||||
else:
|
||||
do_select = "0"
|
||||
|
||||
move_cmd = LangMapTranslator().translate(
|
||||
r"\<Esc>%sv%s%s\<c-g>" % (move_one_right, move_lines, do_select)
|
||||
)
|
||||
|
||||
feedkeys(move_cmd)
|
||||
|
||||
|
||||
# TODO: this function should be moved
|
||||
def _unmap_select_mode_mapping():
|
||||
"""This function unmaps select mode mappings if so wished by the user.
|
||||
Removes select mode mappings that can actually be typed by the user
|
||||
(ie, ignores things like <Plug>).
|
||||
"""
|
||||
if int(vim.eval("g:UltiSnipsRemoveSelectModeMappings")):
|
||||
ignores = vim.eval("g:UltiSnipsMappingsToIgnore") + ['UltiSnips']
|
||||
|
||||
for option in ("<buffer>", ""):
|
||||
# Put all smaps into a var, and then read the var
|
||||
vim.command(r"redir => _tmp_smaps | silent smap %s " % option +
|
||||
"| redir END")
|
||||
|
||||
# Check if any mappings where found
|
||||
all_maps = list(filter(len, vim.eval(r"_tmp_smaps").splitlines()))
|
||||
if (len(all_maps) == 1 and all_maps[0][0] not in " sv"):
|
||||
# "No maps found". String could be localized. Hopefully
|
||||
# it doesn't start with any of these letters in any
|
||||
# language
|
||||
continue
|
||||
|
||||
# Only keep mappings that should not be ignored
|
||||
maps = [m for m in all_maps if
|
||||
not any(i in m for i in ignores) and len(m.strip())]
|
||||
|
||||
for m in maps:
|
||||
# The first three chars are the modes, that might be listed.
|
||||
# We are not interested in them here.
|
||||
trig = m[3:].split()[0]
|
||||
|
||||
# The bar separates commands
|
||||
if trig[-1] == "|":
|
||||
trig = trig[:-1] + "<Bar>"
|
||||
|
||||
# Special ones
|
||||
if trig[0] == "<":
|
||||
add = False
|
||||
# Only allow these
|
||||
for valid in ["Tab", "NL", "CR", "C-Tab", "BS"]:
|
||||
if trig == "<%s>" % valid:
|
||||
add = True
|
||||
if not add:
|
||||
continue
|
||||
|
||||
# UltiSnips remaps <BS>. Keep this around.
|
||||
if trig == "<BS>":
|
||||
continue
|
||||
|
||||
# Actually unmap it
|
||||
try:
|
||||
cmd = ("silent! sunmap %s %s") % (option, trig)
|
||||
vim.command(cmd)
|
||||
except:
|
||||
# Bug 908139: ignore unmaps that fail because of
|
||||
# unprintable characters. This is not ideal because we
|
||||
# will not be able to unmap lhs with any unprintable
|
||||
# character. If the lhs stats with a printable
|
||||
# character this will leak to the user when he tries to
|
||||
# type this character as a first in a selected tabstop.
|
||||
# This case should be rare enough to not bother us
|
||||
# though.
|
||||
pass
|
||||
|
||||
|
||||
class _SnippetDictionary(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._added = []
|
||||
@ -499,68 +630,6 @@ class VimState(object):
|
||||
self._lline = self._cline
|
||||
self._cline = as_unicode(vim.current.buffer[line])
|
||||
|
||||
def select_span(self, r):
|
||||
self._unmap_select_mode_mapping()
|
||||
|
||||
delta = r.end - r.start
|
||||
lineno, col = r.start.line, r.start.col
|
||||
|
||||
set_vim_cursor(lineno + 1, col)
|
||||
|
||||
# Case 1: Zero Length Tabstops
|
||||
if delta.line == delta.col == 0:
|
||||
if col == 0 or vim.eval("mode()") != 'i' and \
|
||||
col < len(as_unicode(vim.current.buffer[lineno])):
|
||||
feedkeys(r"\<Esc>i")
|
||||
else:
|
||||
feedkeys(r"\<Esc>a")
|
||||
else:
|
||||
# Case 2a: Non zero length and inclusive selection
|
||||
# TODO: check with exclusive selection
|
||||
# If a tabstop immediately starts with a newline, the selection
|
||||
# must start after the last character in the current line. But if
|
||||
# we are in insert mode and <Esc> out of it, we cannot go past the
|
||||
# last character with move_one_right and therefore cannot
|
||||
# visual-select this newline. We have to hack around this by adding
|
||||
# an extra space which we can select. Note that this problem could
|
||||
# be circumvent by selecting the tab backwards (that is starting
|
||||
# at the end); one would not need to modify the line for this. This creates other
|
||||
# trouble though
|
||||
if col >= len(as_unicode(vim.current.buffer[lineno])):
|
||||
vim.current.buffer[lineno] += " "
|
||||
|
||||
if delta.line:
|
||||
move_lines = "%ij" % delta.line
|
||||
else:
|
||||
move_lines = ""
|
||||
# Depending on the current mode and position, we
|
||||
# might need to move escape out of the mode and this
|
||||
# will move our cursor one left
|
||||
if col != 0 and vim.eval("mode()") == 'i':
|
||||
move_one_right = "l"
|
||||
else:
|
||||
move_one_right = ""
|
||||
|
||||
# After moving to the correct line, we go back to column 0
|
||||
# and select right from there. Note that the we have to select
|
||||
# one column less since vim's visual selection is including the
|
||||
# ending while Python slicing is excluding the ending.
|
||||
if r.end.col == 0:
|
||||
# Selecting should end at beginning of line -> Select the
|
||||
# previous line till its end
|
||||
do_select = "k$"
|
||||
elif r.end.col > 1:
|
||||
do_select = "0%il" % (r.end.col-1)
|
||||
else:
|
||||
do_select = "0"
|
||||
|
||||
move_cmd = LangMapTranslator().translate(
|
||||
r"\<Esc>%sv%s%s\<c-g>" % (move_one_right, move_lines, do_select)
|
||||
)
|
||||
|
||||
feedkeys(move_cmd)
|
||||
|
||||
|
||||
def buf_changed(self):
|
||||
return self._text_changed
|
||||
buf_changed = property(buf_changed)
|
||||
@ -590,68 +659,6 @@ class VimState(object):
|
||||
###########################
|
||||
# Private functions below #
|
||||
###########################
|
||||
def _unmap_select_mode_mapping(self):
|
||||
"""This function unmaps select mode mappings if so wished by the user.
|
||||
Removes select mode mappings that can actually be typed by the user
|
||||
(ie, ignores things like <Plug>).
|
||||
"""
|
||||
if int(vim.eval("g:UltiSnipsRemoveSelectModeMappings")):
|
||||
ignores = vim.eval("g:UltiSnipsMappingsToIgnore") + ['UltiSnips']
|
||||
|
||||
for option in ("<buffer>", ""):
|
||||
# Put all smaps into a var, and then read the var
|
||||
vim.command(r"redir => _tmp_smaps | silent smap %s " % option +
|
||||
"| redir END")
|
||||
|
||||
# Check if any mappings where found
|
||||
all_maps = list(filter(len, vim.eval(r"_tmp_smaps").splitlines()))
|
||||
if (len(all_maps) == 1 and all_maps[0][0] not in " sv"):
|
||||
# "No maps found". String could be localized. Hopefully
|
||||
# it doesn't start with any of these letters in any
|
||||
# language
|
||||
continue
|
||||
|
||||
# Only keep mappings that should not be ignored
|
||||
maps = [m for m in all_maps if
|
||||
not any(i in m for i in ignores) and len(m.strip())]
|
||||
|
||||
for m in maps:
|
||||
# The first three chars are the modes, that might be listed.
|
||||
# We are not interested in them here.
|
||||
trig = m[3:].split()[0]
|
||||
|
||||
# The bar separates commands
|
||||
if trig[-1] == "|":
|
||||
trig = trig[:-1] + "<Bar>"
|
||||
|
||||
# Special ones
|
||||
if trig[0] == "<":
|
||||
add = False
|
||||
# Only allow these
|
||||
for valid in ["Tab", "NL", "CR", "C-Tab", "BS"]:
|
||||
if trig == "<%s>" % valid:
|
||||
add = True
|
||||
if not add:
|
||||
continue
|
||||
|
||||
# UltiSnips remaps <BS>. Keep this around.
|
||||
if trig == "<BS>":
|
||||
continue
|
||||
|
||||
# Actually unmap it
|
||||
try:
|
||||
cmd = ("silent! sunmap %s %s") % (option, trig)
|
||||
vim.command(cmd)
|
||||
except:
|
||||
# Bug 908139: ignore unmaps that fail because of
|
||||
# unprintable characters. This is not ideal because we
|
||||
# will not be able to unmap lhs with any unprintable
|
||||
# character. If the lhs stats with a printable
|
||||
# character this will leak to the user when he tries to
|
||||
# type this character as a first in a selected tabstop.
|
||||
# This case should be rare enough to not bother us
|
||||
# though.
|
||||
pass
|
||||
|
||||
class SnippetManager(object):
|
||||
def __init__(self):
|
||||
@ -797,64 +804,30 @@ class SnippetManager(object):
|
||||
ct = map(as_unicode, vim.current.buffer)
|
||||
lt = map(as_unicode, self._lvb[:])
|
||||
|
||||
cache = 10 # TODO: increase
|
||||
c0 = min(self._vstate.pos.line, self._vstate.ppos.line)
|
||||
c1 = max(self._vstate.pos.line, self._vstate.ppos.line)
|
||||
lt_span = [0, len(lt)]
|
||||
ct_span = [0, len(ct)]
|
||||
initial_line = 0
|
||||
|
||||
def is_prefix(a, b):
|
||||
"""x: wieviele man vorne von a abtrennen muss, y: wieviele dnan gleich sind"""
|
||||
for y in range(len(b)-1, 0, -1):
|
||||
for x in range(0, len(a)-1):
|
||||
if a[x:x+y] == b[:y]:
|
||||
return x, y
|
||||
return None, None
|
||||
# Cut down on lines searched for changes. Start from behind and
|
||||
# remove all equal lines. Then do the same from the front.
|
||||
while (lt[lt_span[1]-1] == ct[ct_span[1]-1] and
|
||||
(lt_span[0] < lt_span[1]) and
|
||||
(ct_span[0] < ct_span[1])):
|
||||
ct_span[1] -= 1
|
||||
lt_span[1] -= 1
|
||||
while (lt[lt_span[0]] == ct[ct_span[0]] and
|
||||
(lt_span[0] < lt_span[1]) and
|
||||
(ct_span[0] < ct_span[1])):
|
||||
ct_span[0] += 1
|
||||
lt_span[0] += 1
|
||||
initial_line += 1
|
||||
ct_span[0] = max(0, ct_span[0] - 1)
|
||||
lt_span[0] = max(0, lt_span[0] - 1)
|
||||
initial_line = max(0, initial_line - 1)
|
||||
|
||||
def is_suffix(a, b):
|
||||
return is_prefix(a[::-1], b[::-1])
|
||||
|
||||
sl = max(0, c0 - cache)
|
||||
el = c1 + cache
|
||||
ctb = ct[sl:el+1]
|
||||
ltb = lt[sl:el+1]
|
||||
|
||||
assert(sl == 0) # TODO
|
||||
|
||||
xs, ys = is_prefix(ctb, ltb) # TODO: stupid name for function
|
||||
debug("xs: %r, ys: %r" % (xs, ys))
|
||||
xe, ye = is_suffix(ctb, ltb)
|
||||
debug("xe: %r, ye: %r" % (xe, ye))
|
||||
lt_span = (0, sys.maxint)
|
||||
ct_span = (0, sys.maxint)
|
||||
if xs is not None and xe is not None:
|
||||
assert(xs == 0 and xe == 0) # TODO
|
||||
fdl_front = ys
|
||||
fdl_back = len(vim.current.buffer) - ye - 1
|
||||
if fdl_back < fdl_front:
|
||||
overlap = fdl_front - fdl_back
|
||||
debug("overlap: %r" % (overlap))
|
||||
ys -= overlap
|
||||
lt_span = (ys + xs - 1, len(ltb) - ye - xe)
|
||||
ct_span = (ys - 1, fdl_back + 1)
|
||||
|
||||
|
||||
debug("all lt: %r" % (lt))#[sl:el+1]))
|
||||
debug("all ct: %r" % (ct))#[sl:el+1]))
|
||||
|
||||
# TODO
|
||||
# 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 = lt[lt_span[0]:lt_span[1]]
|
||||
ct = ct[ct_span[0]:ct_span[1]]
|
||||
debug("lt: %r" % (lt))
|
||||
debug("ct: %r" % (ct))
|
||||
debug("lt_span: %r, ct_span: %r" % (lt_span, ct_span))
|
||||
|
||||
lt = '\n'.join(lt)
|
||||
ct = '\n'.join(ct)
|
||||
rv = edit_distance.edit_script(lt, ct, lt_span[0])
|
||||
debug("rv: %r" % (rv,))
|
||||
self._csnippets[0].edited(rv)
|
||||
lt = '\n'.join(lt[lt_span[0]:lt_span[1]])
|
||||
ct = '\n'.join(ct[ct_span[0]:ct_span[1]])
|
||||
self._csnippets[0].edited(edit_distance.edit_script(lt, ct, initial_line))
|
||||
|
||||
self._check_if_still_inside_snippet()
|
||||
if self._csnippets:
|
||||
@ -929,7 +902,7 @@ class SnippetManager(object):
|
||||
if self._cs:
|
||||
self._ctab = self._cs.select_next_tab(backwards)
|
||||
if self._ctab:
|
||||
self._vstate.select_span(self._ctab.span)
|
||||
select_span(self._ctab.span)
|
||||
jumped = True
|
||||
if self._ctab.no == 0:
|
||||
self._current_snippet_is_done()
|
||||
|
@ -6,8 +6,6 @@ import sys
|
||||
|
||||
# TODO: check test cases here. They are not up to date
|
||||
|
||||
from .debug import debug
|
||||
|
||||
def edit_script(a, b, sline = 0):
|
||||
d = defaultdict(list)
|
||||
seen = defaultdict(lambda: sys.maxint)
|
||||
|
6
test.py
6
test.py
@ -24,6 +24,8 @@
|
||||
# The testsuite will use ``screen`` to inject commands into the Vim under test,
|
||||
# and will compare the resulting output to expected results.
|
||||
#
|
||||
#
|
||||
# TODO: visual line selection -> replace with more, less and == amount of lines
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
@ -819,7 +821,6 @@ class TabStop_Shell_TextInNextLine(_VimTest):
|
||||
wanted = "hi hallo\nWeiterand more"
|
||||
class TabStop_Shell_InDefValue_Leave(_VimTest):
|
||||
skip_on_windows = True
|
||||
sleeptime = 0.09 # Do this very slowly
|
||||
snippets = ("test", "Hallo ${1:now `echo fromecho`} end")
|
||||
keys = "test" + EX + JF + "and more"
|
||||
wanted = "Hallo now fromecho endand more"
|
||||
@ -841,7 +842,6 @@ class TabStop_Shell_TestEscapedCharsAndShellVars_Overwrite(_VimTest):
|
||||
|
||||
class TabStop_Shell_ShebangPython(_VimTest):
|
||||
skip_on_windows = True
|
||||
sleeptime = 0.09 # Do this very slowly
|
||||
snippets = ("test", """Hallo ${1:now `#!/usr/bin/env python
|
||||
print "Hallo Welt"
|
||||
`} end""")
|
||||
@ -1432,7 +1432,6 @@ class Transformation_OptionReplaceGlobalMatchInReplace_ECR(_VimTest):
|
||||
keys = "test" + EX + "a, nice, building"
|
||||
wanted = "a, nice, building a, nice, building"
|
||||
class TransformationUsingBackspaceToDeleteDefaultValueInFirstTab_ECR(_VimTest):
|
||||
sleeptime = 0.09 # Do this very slowly
|
||||
snippets = ("test", "snip ${1/.+/(?0:m1)/} ${2/.+/(?0:m2)/} "
|
||||
"${1:default} ${2:def}")
|
||||
keys = "test" + EX + BS + JF + "hi"
|
||||
@ -1787,7 +1786,6 @@ class Multiple_ManySnippetsOneTrigger_ECR(_VimTest):
|
||||
("test", "Case28", "This is Case 28"),
|
||||
("test", "Case29", "This is Case 29"),
|
||||
) #}}}
|
||||
sleeptime = 0.09 # Do this very slowly
|
||||
keys = "test" + EX + " " + ESC + ESC + "ahi"
|
||||
wanted = "testhi"
|
||||
# End: Selecting Between Same Triggers #}}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user