164 lines
5.2 KiB
Python
164 lines
5.2 KiB
Python
|
#!/usr/bin/env python
|
||
|
# encoding: utf-8
|
||
|
|
||
|
"""Some classes to conserve Vim's state for comparing over time."""
|
||
|
|
||
|
from collections import deque, namedtuple
|
||
|
|
||
|
from UltiSnips import _vim
|
||
|
from UltiSnips.compatibility import as_unicode, byte2col
|
||
|
from UltiSnips.position import Position
|
||
|
|
||
|
_Placeholder = namedtuple('_FrozenPlaceholder', ['current_text', 'start', 'end'])
|
||
|
|
||
|
class VimPosition(Position):
|
||
|
|
||
|
"""Represents the current position in the buffer, together with some status
|
||
|
variables that might change our decisions down the line."""
|
||
|
|
||
|
def __init__(self):
|
||
|
pos = _vim.buf.cursor
|
||
|
self._mode = _vim.eval('mode()')
|
||
|
Position.__init__(self, pos.line, pos.col)
|
||
|
|
||
|
@property
|
||
|
def mode(self):
|
||
|
"""Returns the mode() this position was created."""
|
||
|
return self._mode
|
||
|
|
||
|
|
||
|
class VimState(object):
|
||
|
|
||
|
"""Caches some state information from Vim to better guess what editing
|
||
|
tasks the user might have done in the last step."""
|
||
|
|
||
|
def __init__(self):
|
||
|
self._poss = deque(maxlen=5)
|
||
|
self._lvb = None
|
||
|
|
||
|
self._text_to_expect = ''
|
||
|
self._unnamed_reg_cached = False
|
||
|
|
||
|
# We store the cached value of the unnamed register in Vim directly to
|
||
|
# avoid any Unicode issues with saving and restoring the unnamed
|
||
|
# register across the Python bindings. The unnamed register can contain
|
||
|
# data that cannot be coerced to Unicode, and so a simple vim.eval('@"')
|
||
|
# fails badly. Keeping the cached value in Vim directly, sidesteps the
|
||
|
# problem.
|
||
|
_vim.command('let g:_ultisnips_unnamed_reg_cache = ""')
|
||
|
|
||
|
def remember_unnamed_register(self, text_to_expect):
|
||
|
"""Save the unnamed register.
|
||
|
|
||
|
'text_to_expect' is text that we expect
|
||
|
to be contained in the register the next time this method is called -
|
||
|
this could be text from the tabstop that was selected and might have
|
||
|
been overwritten. We will not cache that then.
|
||
|
|
||
|
"""
|
||
|
self._unnamed_reg_cached = True
|
||
|
escaped_text = self._text_to_expect.replace("'", "''")
|
||
|
res = int(_vim.eval('@" != ' + "'" + escaped_text + "'"))
|
||
|
if res:
|
||
|
_vim.command('let g:_ultisnips_unnamed_reg_cache = @"')
|
||
|
self._text_to_expect = text_to_expect
|
||
|
|
||
|
def restore_unnamed_register(self):
|
||
|
"""Restores the unnamed register and forgets what we cached."""
|
||
|
if not self._unnamed_reg_cached:
|
||
|
return
|
||
|
_vim.command('let @" = g:_ultisnips_unnamed_reg_cache')
|
||
|
self._unnamed_reg_cached = False
|
||
|
|
||
|
def remember_position(self):
|
||
|
"""Remember the current position as a previous pose."""
|
||
|
self._poss.append(VimPosition())
|
||
|
|
||
|
def remember_buffer(self, to):
|
||
|
"""Remember the content of the buffer and the position."""
|
||
|
self._lvb = _vim.buf[to.start.line:to.end.line + 1]
|
||
|
self._lvb_len = len(_vim.buf)
|
||
|
self.remember_position()
|
||
|
|
||
|
@property
|
||
|
def diff_in_buffer_length(self):
|
||
|
"""Returns the difference in the length of the current buffer compared
|
||
|
to the remembered."""
|
||
|
return len(_vim.buf) - self._lvb_len
|
||
|
|
||
|
@property
|
||
|
def pos(self):
|
||
|
"""The last remembered position."""
|
||
|
return self._poss[-1]
|
||
|
|
||
|
@property
|
||
|
def ppos(self):
|
||
|
"""The second to last remembered position."""
|
||
|
return self._poss[-2]
|
||
|
|
||
|
@property
|
||
|
def remembered_buffer(self):
|
||
|
"""The content of the remembered buffer."""
|
||
|
return self._lvb[:]
|
||
|
|
||
|
|
||
|
class VisualContentPreserver(object):
|
||
|
|
||
|
"""Saves the current visual selection and the selection mode it was done in
|
||
|
(e.g. line selection, block selection or regular selection.)"""
|
||
|
|
||
|
def __init__(self):
|
||
|
self.reset()
|
||
|
|
||
|
def reset(self):
|
||
|
"""Forget the preserved state."""
|
||
|
self._mode = ''
|
||
|
self._text = as_unicode('')
|
||
|
self._placeholder = None
|
||
|
|
||
|
def conserve(self):
|
||
|
"""Save the last visual selection ond the mode it was made in."""
|
||
|
sl, sbyte = map(int,
|
||
|
(_vim.eval("""line("'<")"""), _vim.eval("""col("'<")""")))
|
||
|
el, ebyte = map(int,
|
||
|
(_vim.eval("""line("'>")"""), _vim.eval("""col("'>")""")))
|
||
|
sc = byte2col(sl, sbyte - 1)
|
||
|
ec = byte2col(el, ebyte - 1)
|
||
|
self._mode = _vim.eval('visualmode()')
|
||
|
|
||
|
_vim_line_with_eol = lambda ln: _vim.buf[ln] + '\n'
|
||
|
|
||
|
if sl == el:
|
||
|
text = _vim_line_with_eol(sl - 1)[sc:ec + 1]
|
||
|
else:
|
||
|
text = _vim_line_with_eol(sl - 1)[sc:]
|
||
|
for cl in range(sl, el - 1):
|
||
|
text += _vim_line_with_eol(cl)
|
||
|
text += _vim_line_with_eol(el - 1)[:ec + 1]
|
||
|
self._text = text
|
||
|
|
||
|
def conserve_placeholder(self, placeholder):
|
||
|
if placeholder:
|
||
|
self._placeholder = _Placeholder(
|
||
|
placeholder.current_text,
|
||
|
placeholder.start,
|
||
|
placeholder.end
|
||
|
)
|
||
|
else:
|
||
|
self._placeholder = None
|
||
|
|
||
|
@property
|
||
|
def text(self):
|
||
|
"""The conserved text."""
|
||
|
return self._text
|
||
|
|
||
|
@property
|
||
|
def mode(self):
|
||
|
"""The conserved visualmode()."""
|
||
|
return self._mode
|
||
|
|
||
|
@property
|
||
|
def placeholder(self):
|
||
|
"""Returns latest selected placeholder."""
|
||
|
return self._placeholder
|