Improved ${VISUAL} support
- make a difference between V and v selection - Keep proper indenting even when used inside other TextObjects
This commit is contained in:
parent
cf2c2ff5bc
commit
89f720c91c
@ -167,7 +167,7 @@ function! UltiSnips_MapKeys()
|
||||
exec "inoremap <silent> " . g:UltiSnipsJumpForwardTrigger . " <C-R>=UltiSnips_JumpForwards()<cr>"
|
||||
exec "snoremap <silent> " . g:UltiSnipsJumpForwardTrigger . " <Esc>:call UltiSnips_JumpForwards()<cr>"
|
||||
endif
|
||||
exec 'xnoremap ' . g:UltiSnipsExpandTrigger. ' <Esc>:call UltiSnips_SaveLastVisualSelection()<cr>gvs'
|
||||
exec 'xnoremap ' . g:UltiSnipsExpandTrigger. ' :call UltiSnips_SaveLastVisualSelection()<cr>gvs'
|
||||
exec "inoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <C-R>=UltiSnips_JumpBackwards()<cr>"
|
||||
exec "snoremap <silent> " . g:UltiSnipsJumpBackwardTrigger . " <Esc>:call UltiSnips_JumpBackwards()<cr>"
|
||||
exec "inoremap <silent> " . g:UltiSnipsListSnippets . " <C-R>=UltiSnips_ListSnippets()<cr>"
|
||||
|
@ -136,28 +136,15 @@ class TabStopToken(Token):
|
||||
|
||||
class VisualToken(Token):
|
||||
TOKEN = "${VISUAL}"
|
||||
CHECK = re.compile(r"^[ \t]*\${VISUAL}")
|
||||
|
||||
@classmethod
|
||||
def starts_here(klass, stream):
|
||||
return klass.CHECK.match(stream.peek(10000)) is not None
|
||||
return stream.peek(len(klass.TOKEN)) == klass.TOKEN
|
||||
|
||||
def _parse(self, stream, indent):
|
||||
self.leading_whitespace = ""
|
||||
while stream.peek() != self.TOKEN[0]:
|
||||
self.leading_whitespace += stream.next()
|
||||
|
||||
for i in range(len(self.TOKEN)):
|
||||
stream.next()
|
||||
|
||||
# Make sure that a ${VISUAL} at the end of a line behaves like a block
|
||||
# of text and does not introduce another line break.
|
||||
while 1:
|
||||
nc = stream.peek()
|
||||
if nc is None or nc not in '\r\n':
|
||||
break
|
||||
stream.next()
|
||||
|
||||
def __repr__(self):
|
||||
return "VisualToken(%r,%r)" % (
|
||||
self.start, self.end
|
||||
|
@ -1,6 +1,13 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
import re
|
||||
|
||||
import vim
|
||||
|
||||
from ..Compatibility import as_unicode
|
||||
from ..Util import IndentUtil
|
||||
|
||||
from ._base import NoneditableTextObject
|
||||
|
||||
class Visual(NoneditableTextObject):
|
||||
@ -9,30 +16,39 @@ class Visual(NoneditableTextObject):
|
||||
selected and insert it here. If there was no text visually selected,
|
||||
this will be the empty string
|
||||
"""
|
||||
def __init__(self, parent, token):
|
||||
# TODO: rework this: get indent directly from vim buffer and
|
||||
# only update once.
|
||||
__REPLACE_NON_WS = re.compile(r"[^ \t]")
|
||||
|
||||
def __init__(self, parent, token):
|
||||
# Find our containing snippet for visual_content
|
||||
snippet = parent
|
||||
while snippet:
|
||||
try:
|
||||
self._visual_content = snippet.visual_content.splitlines(True)
|
||||
self._text = snippet.visual_content.text
|
||||
self._mode = snippet.visual_content.mode
|
||||
break
|
||||
except AttributeError:
|
||||
snippet = snippet._parent
|
||||
|
||||
text = ""
|
||||
for idx, line in enumerate(self._visual_content):
|
||||
text += token.leading_whitespace
|
||||
text += line
|
||||
|
||||
self._text = text
|
||||
|
||||
NoneditableTextObject.__init__(self, parent, token, initial_text = self._text)
|
||||
NoneditableTextObject.__init__(self, parent, token)
|
||||
|
||||
def _update(self, done, not_done):
|
||||
self.overwrite(self._text)
|
||||
if self._mode != "v":
|
||||
# Keep the indent for Line/Block Selection
|
||||
text_before = as_unicode(vim.current.buffer[self.start.line])[:self.start.col]
|
||||
indent = self.__REPLACE_NON_WS.sub(" ", text_before)
|
||||
iu = IndentUtil()
|
||||
indent = iu.indent_to_spaces(indent)
|
||||
indent = iu.spaces_to_indent(indent)
|
||||
text = ""
|
||||
for idx, line in enumerate(self._text.splitlines(True)):
|
||||
if idx != 0:
|
||||
text += indent
|
||||
text += line
|
||||
text = text[:-1] # Strip final '\n'
|
||||
else:
|
||||
text = self._text
|
||||
|
||||
self.overwrite(text)
|
||||
self._parent._del_child(self)
|
||||
return True
|
||||
|
||||
|
@ -662,6 +662,43 @@ class VimState(object):
|
||||
# Private functions below #
|
||||
###########################
|
||||
|
||||
from debug import debug
|
||||
|
||||
class VisualContentPreserver(object):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
def reset(self):
|
||||
self._mode = ""
|
||||
self._text = as_unicode("")
|
||||
|
||||
def conserve(self):
|
||||
sl, sc = map(int, (vim.eval("""line("'<")"""), vim.eval("""virtcol("'<")""")))
|
||||
el, ec = map(int, (vim.eval("""line("'>")"""), vim.eval("""virtcol("'>")""")))
|
||||
self._mode = vim.eval("visualmode()")
|
||||
|
||||
def _vim_line_with_eol(ln):
|
||||
return as_unicode(vim.current.buffer[ln] + '\n')
|
||||
|
||||
if sl == el:
|
||||
text = _vim_line_with_eol(sl-1)[sc-1:ec]
|
||||
else:
|
||||
text = _vim_line_with_eol(sl-1)[sc-1:]
|
||||
for cl in range(sl,el-1):
|
||||
text += _vim_line_with_eol(cl)
|
||||
text += _vim_line_with_eol(el-1)[:ec]
|
||||
|
||||
self._text = text
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self._text
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
return self._mode
|
||||
|
||||
|
||||
class SnippetManager(object):
|
||||
def __init__(self):
|
||||
self._vstate = VimState()
|
||||
@ -676,7 +713,7 @@ class SnippetManager(object):
|
||||
self._lvb = TextBuffer("")
|
||||
self._test_error = test_error
|
||||
self._snippets = {}
|
||||
self._visual_content = as_unicode("")
|
||||
self._visual_content = VisualContentPreserver()
|
||||
|
||||
while len(self._csnippets):
|
||||
self._current_snippet_is_done()
|
||||
@ -738,21 +775,7 @@ class SnippetManager(object):
|
||||
Our job is to remember everything between '< and '> and pass it on to
|
||||
${VISUAL} in case it will be needed.
|
||||
"""
|
||||
sl, sc = map(int, (vim.eval("""line("'<")"""), vim.eval("""virtcol("'<")""")))
|
||||
el, ec = map(int, (vim.eval("""line("'>")"""), vim.eval("""virtcol("'>")""")))
|
||||
|
||||
def _vim_line_with_eol(ln):
|
||||
return as_unicode(vim.current.buffer[ln] + '\n')
|
||||
|
||||
if sl == el:
|
||||
text = _vim_line_with_eol(sl-1)[sc-1:ec]
|
||||
else:
|
||||
text = _vim_line_with_eol(sl-1)[sc-1:]
|
||||
for cl in range(sl,el-1):
|
||||
text += _vim_line_with_eol(cl)
|
||||
text += _vim_line_with_eol(el-1)[:ec]
|
||||
|
||||
self._visual_content = text
|
||||
self._visual_content.conserve()
|
||||
|
||||
def snippet_dict(self, ft):
|
||||
if ft not in self._snippets:
|
||||
@ -1045,14 +1068,14 @@ class SnippetManager(object):
|
||||
# TODO: private parts? maybe handle this in add_child
|
||||
si = snippet.launch(text_before, self._visual_content,
|
||||
self._cs._find_parent_for_new_to(start), start, end)
|
||||
self._visual_content = ""
|
||||
self._visual_content.reset()
|
||||
|
||||
self._csnippets.append(si)
|
||||
else:
|
||||
start = Position(lineno-1, len(text_before))
|
||||
end = Position(lineno-1, len(before))
|
||||
self._csnippets.append(snippet.launch(text_before, self._visual_content, None, start, end))
|
||||
self._visual_content = ""
|
||||
self._visual_content.reset()
|
||||
|
||||
self._ignore_movements = True
|
||||
self._lvb = TextBuffer('\n'.join(vim.current.buffer)) # TODO: no need to cache everything
|
||||
|
28
test.py
28
test.py
@ -1500,35 +1500,47 @@ class Visual_CrossOneLine(_VimTest):
|
||||
wanted = "bla hblub\n hellobi"
|
||||
|
||||
# TODO: with indent in default text
|
||||
class Visual_LineSelect(_VimTest):
|
||||
class Visual_LineSelect_Simple(_VimTest):
|
||||
snippets = ("test", "h${VISUAL}b")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX
|
||||
wanted = "hhello\nnice\nworld\nb"
|
||||
wanted = "hhello\n nice\n worldb"
|
||||
class Visual_InDefaultText_LineSelect_NoOverwrite(_VimTest):
|
||||
snippets = ("test", "h${1:bef${VISUAL}aft}b")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi"
|
||||
wanted = "hbefhello\nnice\nworld\naftbhi"
|
||||
wanted = "hbefhello\n nice\n worldaftbhi"
|
||||
class Visual_InDefaultText_LineSelect_Overwrite(_VimTest):
|
||||
snippets = ("test", "h${1:bef${VISUAL}aft}b")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "jup" + JF + "hi"
|
||||
wanted = "hjupbhi"
|
||||
class Visual_LineSelect_CheckIndent(_VimTest):
|
||||
class Visual_LineSelect_CheckIndentSimple(_VimTest):
|
||||
snippets = ("test", "beg\n\t${VISUAL}\nend")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX
|
||||
wanted = "beg\n\thello\n\tnice\n\tworld\nend"
|
||||
|
||||
class Visual_LineSelect_CheckIndentTwice(_VimTest):
|
||||
snippets = ("test", "beg\n\t${VISUAL}\nend")
|
||||
keys = " hello\n nice\n\tworld" + ESC + "Vkk" + EX + "test" + EX
|
||||
wanted = "beg\n\t hello\n\t nice\n\t\tworld\nend"
|
||||
class Visual_InDefaultText_IndentSpacesToTabstop_NoOverwrite(_VimTest):
|
||||
snippets = ("test", "h${1:beforea${VISUAL}aft}b")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi"
|
||||
wanted = "hbeforeahello\n\tnice\n\tworldaftbhi"
|
||||
class Visual_InDefaultText_IndentSpacesToTabstop_Overwrite(_VimTest):
|
||||
snippets = ("test", "h${1:beforea${VISUAL}aft}b")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "ups" + JF + "hi"
|
||||
wanted = "hupsbhi"
|
||||
class Visual_InDefaultText_IndentSpacesToTabstop_NoOverwrite1(_VimTest):
|
||||
snippets = ("test", "h${1:beforeaaa${VISUAL}aft}b")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi"
|
||||
wanted = "hbeforeaaahello\n\t nice\n\t worldaftbhi"
|
||||
|
||||
class Visual_LineSelect_WithTabStop(_VimTest):
|
||||
snippets = ("test", "beg\n\t${VISUAL}\n\t${1:here_we_go}\nend")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "super" + JF + "done"
|
||||
wanted = "beg\n\thello\n\tnice\n\tworld\n\tsuper\nenddone"
|
||||
|
||||
|
||||
|
||||
class Visual_LineSelect_CheckIndentWithTS_NoOverwrite(_VimTest):
|
||||
snippets = ("test", "beg\n\t${0:${VISUAL}}\nend")
|
||||
keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX
|
||||
wanted = "beg\n\thello\n\tnice\n\tworld\nend"
|
||||
# End: ${VISUAL} #}}}
|
||||
|
||||
# Recursive (Nested) Snippets {{{#
|
||||
|
Loading…
Reference in New Issue
Block a user