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:
Holger Rapp 2012-01-21 12:42:03 +01:00
parent cf2c2ff5bc
commit 89f720c91c
5 changed files with 92 additions and 54 deletions

View File

@ -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>"

View File

@ -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

View File

@ -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

View File

@ -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
View File

@ -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 {{{#