proof of concept for context snips
This commit is contained in:
parent
aeb2e24204
commit
b3aec07053
@ -4,6 +4,7 @@
|
|||||||
"""Snippet representation after parsing."""
|
"""Snippet representation after parsing."""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
import vim
|
||||||
|
|
||||||
from UltiSnips import _vim
|
from UltiSnips import _vim
|
||||||
from UltiSnips.compatibility import as_unicode
|
from UltiSnips.compatibility import as_unicode
|
||||||
@ -43,7 +44,7 @@ class SnippetDefinition(object):
|
|||||||
_TABS = re.compile(r"^\t*")
|
_TABS = re.compile(r"^\t*")
|
||||||
|
|
||||||
def __init__(self, priority, trigger, value, description,
|
def __init__(self, priority, trigger, value, description,
|
||||||
options, globals, location):
|
options, globals, location, context):
|
||||||
self._priority = int(priority)
|
self._priority = int(priority)
|
||||||
self._trigger = as_unicode(trigger)
|
self._trigger = as_unicode(trigger)
|
||||||
self._value = as_unicode(value)
|
self._value = as_unicode(value)
|
||||||
@ -53,6 +54,8 @@ class SnippetDefinition(object):
|
|||||||
self._last_re = None
|
self._last_re = None
|
||||||
self._globals = globals
|
self._globals = globals
|
||||||
self._location = location
|
self._location = location
|
||||||
|
self._context_code = context
|
||||||
|
self._context = None
|
||||||
|
|
||||||
# Make sure that we actually match our trigger in case we are
|
# Make sure that we actually match our trigger in case we are
|
||||||
# immediately expanded.
|
# immediately expanded.
|
||||||
@ -78,6 +81,32 @@ class SnippetDefinition(object):
|
|||||||
return match
|
return match
|
||||||
return False
|
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):
|
def has_option(self, opt):
|
||||||
"""Check if the named option is set."""
|
"""Check if the named option is set."""
|
||||||
return opt in self._opts
|
return opt in self._opts
|
||||||
@ -109,6 +138,11 @@ class SnippetDefinition(object):
|
|||||||
"""Where this snippet was defined."""
|
"""Where this snippet was defined."""
|
||||||
return self._location
|
return self._location
|
||||||
|
|
||||||
|
@property
|
||||||
|
def context(self):
|
||||||
|
"""Returns matched context."""
|
||||||
|
return self._context
|
||||||
|
|
||||||
def matches(self, trigger):
|
def matches(self, trigger):
|
||||||
"""Returns True if this snippet matches 'trigger'."""
|
"""Returns True if this snippet matches 'trigger'."""
|
||||||
# If user supplies both "w" and "i", it should perhaps be an
|
# If user supplies both "w" and "i", it should perhaps be an
|
||||||
@ -152,6 +186,12 @@ class SnippetDefinition(object):
|
|||||||
if text_before.strip(' \t') != '':
|
if text_before.strip(' \t') != '':
|
||||||
self._matched = ''
|
self._matched = ''
|
||||||
return False
|
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
|
return match
|
||||||
|
|
||||||
def could_match(self, trigger):
|
def could_match(self, trigger):
|
||||||
@ -236,7 +276,8 @@ class SnippetDefinition(object):
|
|||||||
|
|
||||||
snippet_instance = SnippetInstance(
|
snippet_instance = SnippetInstance(
|
||||||
self, parent, initial_text, start, end, visual_content,
|
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)
|
self.instantiate(snippet_instance, initial_text, indent)
|
||||||
|
|
||||||
snippet_instance.update_textobjects()
|
snippet_instance.update_textobjects()
|
||||||
|
@ -65,12 +65,21 @@ def _handle_snippet_or_global(filename, line, lines, python_globals, priority):
|
|||||||
# Get and strip options if they exist
|
# Get and strip options if they exist
|
||||||
remain = line[len(snip):].strip()
|
remain = line[len(snip):].strip()
|
||||||
words = remain.split()
|
words = remain.split()
|
||||||
|
|
||||||
if len(words) > 2:
|
if len(words) > 2:
|
||||||
# second to last word ends with a quote
|
# second to last word ends with a quote
|
||||||
if '"' not in words[-1] and words[-2][-1] == '"':
|
if '"' not in words[-1] and words[-2][-1] == '"':
|
||||||
opts = words[-1]
|
opts = words[-1]
|
||||||
remain = remain[:-len(opts) - 1].rstrip()
|
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
|
# Get and strip description if it exists
|
||||||
remain = remain.strip()
|
remain = remain.strip()
|
||||||
if len(remain.split()) > 1 and remain[-1] == '"':
|
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':
|
elif snip == 'snippet':
|
||||||
return 'snippet', (UltiSnipsSnippetDefinition(priority, trig, content,
|
return 'snippet', (UltiSnipsSnippetDefinition(priority, trig, content,
|
||||||
descr, opts, python_globals,
|
descr, opts, python_globals,
|
||||||
'%s:%i' % (filename, start_line_index)),)
|
'%s:%i' % (filename, start_line_index),
|
||||||
|
context),)
|
||||||
else:
|
else:
|
||||||
return 'error', ("Invalid snippet type: '%s'" % snip, lines.line_index)
|
return 'error', ("Invalid snippet type: '%s'" % snip, lines.line_index)
|
||||||
|
|
||||||
|
@ -475,6 +475,7 @@ class SnippetManager(object):
|
|||||||
elif feedkey:
|
elif feedkey:
|
||||||
_vim.command('return %s' % _vim.escape(feedkey))
|
_vim.command('return %s' % _vim.escape(feedkey))
|
||||||
|
|
||||||
|
@err_to_scratch_buffer
|
||||||
def _snips(self, before, partial):
|
def _snips(self, before, partial):
|
||||||
"""Returns all the snippets for the given text before the cursor.
|
"""Returns all the snippets for the given text before the cursor.
|
||||||
|
|
||||||
@ -572,6 +573,10 @@ class SnippetManager(object):
|
|||||||
if not before:
|
if not before:
|
||||||
return False
|
return False
|
||||||
snippets = self._snips(before, 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:
|
if not snippets:
|
||||||
# No snippet found
|
# No snippet found
|
||||||
return False
|
return False
|
||||||
|
@ -21,7 +21,7 @@ class SnippetInstance(EditableTextObject):
|
|||||||
# pylint:disable=protected-access
|
# pylint:disable=protected-access
|
||||||
|
|
||||||
def __init__(self, snippet, parent, initial_text,
|
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:
|
if start is None:
|
||||||
start = Position(0, 0)
|
start = Position(0, 0)
|
||||||
if end is None:
|
if end is None:
|
||||||
@ -29,7 +29,7 @@ class SnippetInstance(EditableTextObject):
|
|||||||
self.snippet = snippet
|
self.snippet = snippet
|
||||||
self._cts = 0
|
self._cts = 0
|
||||||
|
|
||||||
self.locals = {'match': last_re}
|
self.locals = {'match': last_re, 'context': context}
|
||||||
self.globals = globals
|
self.globals = globals
|
||||||
self.visual_content = visual_content
|
self.visual_content = visual_content
|
||||||
|
|
||||||
|
@ -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 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 snipSnippetDocString ,"[^"]*\%("\ze\s*\%(\s[^"[:space:]]\+\s*\)\=\)\=$, contained nextgroup=snipSnippetOptions skipwhite
|
||||||
syn match snipSnippetOptions ,\S\+, contained contains=snipSnippetOptionFlag
|
syn match snipSnippetOptions ,\S\+, contained contains=snipSnippetOptionFlag
|
||||||
syn match snipSnippetOptionFlag ,[biwrts], contained
|
syn match snipSnippetOptionFlag ,[biwrtsmx], contained
|
||||||
|
|
||||||
" Command substitution {{{4
|
" Command substitution {{{4
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user