proof of concept for context snips

This commit is contained in:
Stanislav Seletskiy 2015-02-16 21:17:40 +06:00
parent aeb2e24204
commit b3aec07053
5 changed files with 62 additions and 6 deletions

View File

@ -4,6 +4,7 @@
"""Snippet representation after parsing."""
import re
import vim
from UltiSnips import _vim
from UltiSnips.compatibility import as_unicode
@ -43,7 +44,7 @@ class SnippetDefinition(object):
_TABS = re.compile(r"^\t*")
def __init__(self, priority, trigger, value, description,
options, globals, location):
options, globals, location, context):
self._priority = int(priority)
self._trigger = as_unicode(trigger)
self._value = as_unicode(value)
@ -53,6 +54,8 @@ class SnippetDefinition(object):
self._last_re = None
self._globals = globals
self._location = location
self._context_code = context
self._context = None
# Make sure that we actually match our trigger in case we are
# immediately expanded.
@ -78,6 +81,32 @@ class SnippetDefinition(object):
return match
return False
def _context_match(self):
current = vim.current
# skip on empty buffer
if len(current.buffer) == 1 and current.buffer[0] == "":
return
code = "\n".join([
'import re, os, vim, string, random',
'\n'.join(self._globals.get('!p', [])).replace('\r\n', '\n'),
'ctx["match"] = ' + self._context_code,
''
])
context = {'match': False}
locals = {
'ctx': context,
'w': current.window,
'b': current.buffer,
'l': current.window.cursor[0],
'c': current.window.cursor[1],
}
exec(code, locals)
return context["match"]
def has_option(self, opt):
"""Check if the named option is set."""
return opt in self._opts
@ -109,6 +138,11 @@ class SnippetDefinition(object):
"""Where this snippet was defined."""
return self._location
@property
def context(self):
"""Returns matched context."""
return self._context
def matches(self, trigger):
"""Returns True if this snippet matches 'trigger'."""
# If user supplies both "w" and "i", it should perhaps be an
@ -152,6 +186,12 @@ class SnippetDefinition(object):
if text_before.strip(' \t') != '':
self._matched = ''
return False
if match and self._context_code:
self._context = self._context_match()
print(match, self._trigger, self._context)
match = self._context != None
return match
def could_match(self, trigger):
@ -236,7 +276,8 @@ class SnippetDefinition(object):
snippet_instance = SnippetInstance(
self, parent, initial_text, start, end, visual_content,
last_re=self._last_re, globals=self._globals)
last_re=self._last_re, globals=self._globals,
context=self._context)
self.instantiate(snippet_instance, initial_text, indent)
snippet_instance.update_textobjects()

View File

@ -65,12 +65,21 @@ def _handle_snippet_or_global(filename, line, lines, python_globals, priority):
# Get and strip options if they exist
remain = line[len(snip):].strip()
words = remain.split()
if len(words) > 2:
# second to last word ends with a quote
if '"' not in words[-1] and words[-2][-1] == '"':
opts = words[-1]
remain = remain[:-len(opts) - 1].rstrip()
if 'x' in opts:
left = remain[:-1].rfind('"')
if left != -1 and left != 0:
context, remain = remain[left:].strip('"'), remain[:left]
else:
context = None
# Get and strip description if it exists
remain = remain.strip()
if len(remain.split()) > 1 and remain[-1] == '"':
@ -105,7 +114,8 @@ def _handle_snippet_or_global(filename, line, lines, python_globals, priority):
elif snip == 'snippet':
return 'snippet', (UltiSnipsSnippetDefinition(priority, trig, content,
descr, opts, python_globals,
'%s:%i' % (filename, start_line_index)),)
'%s:%i' % (filename, start_line_index),
context),)
else:
return 'error', ("Invalid snippet type: '%s'" % snip, lines.line_index)

View File

@ -475,6 +475,7 @@ class SnippetManager(object):
elif feedkey:
_vim.command('return %s' % _vim.escape(feedkey))
@err_to_scratch_buffer
def _snips(self, before, partial):
"""Returns all the snippets for the given text before the cursor.
@ -572,6 +573,10 @@ class SnippetManager(object):
if not before:
return False
snippets = self._snips(before, False)
# prefer snippets with context if any
snippets_with_context = [s for s in snippets if s.context]
if snippets_with_context:
snippets = snippets_with_context
if not snippets:
# No snippet found
return False

View File

@ -21,7 +21,7 @@ class SnippetInstance(EditableTextObject):
# pylint:disable=protected-access
def __init__(self, snippet, parent, initial_text,
start, end, visual_content, last_re, globals):
start, end, visual_content, last_re, globals, context):
if start is None:
start = Position(0, 0)
if end is None:
@ -29,7 +29,7 @@ class SnippetInstance(EditableTextObject):
self.snippet = snippet
self._cts = 0
self.locals = {'match': last_re}
self.locals = {'match': last_re, 'context': context}
self.globals = globals
self.visual_content = visual_content

View File

@ -78,7 +78,7 @@ syn match snipSnippetTrigger ,".\{-}"\ze\%(\s\+"\%(\s*\S\)\@=[^"]*\%("\s\+[^"[:s
syn match snipSnippetTriggerInvalid ,\S\@=.\{-}\S\ze\%(\s\+"[^"]*\%("\s\+[^"[:space:]]\+\s*\|"\s*\)\=\|\s*\)$, contained nextgroup=snipSnippetDocString skipwhite
syn match snipSnippetDocString ,"[^"]*\%("\ze\s*\%(\s[^"[:space:]]\+\s*\)\=\)\=$, contained nextgroup=snipSnippetOptions skipwhite
syn match snipSnippetOptions ,\S\+, contained contains=snipSnippetOptionFlag
syn match snipSnippetOptionFlag ,[biwrts], contained
syn match snipSnippetOptionFlag ,[biwrtsmx], contained
" Command substitution {{{4