diff --git a/pythonx/UltiSnips/snippet/definition/_base.py b/pythonx/UltiSnips/snippet/definition/_base.py index 6b73e4e..a19cf61 100644 --- a/pythonx/UltiSnips/snippet/definition/_base.py +++ b/pythonx/UltiSnips/snippet/definition/_base.py @@ -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() diff --git a/pythonx/UltiSnips/snippet/source/file/ultisnips.py b/pythonx/UltiSnips/snippet/source/file/ultisnips.py index d503c84..16eba94 100644 --- a/pythonx/UltiSnips/snippet/source/file/ultisnips.py +++ b/pythonx/UltiSnips/snippet/source/file/ultisnips.py @@ -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) diff --git a/pythonx/UltiSnips/snippet_manager.py b/pythonx/UltiSnips/snippet_manager.py index 06810d1..ff65368 100644 --- a/pythonx/UltiSnips/snippet_manager.py +++ b/pythonx/UltiSnips/snippet_manager.py @@ -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 diff --git a/pythonx/UltiSnips/text_objects/_snippet_instance.py b/pythonx/UltiSnips/text_objects/_snippet_instance.py index d5dfc64..99b86ed 100644 --- a/pythonx/UltiSnips/text_objects/_snippet_instance.py +++ b/pythonx/UltiSnips/text_objects/_snippet_instance.py @@ -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 diff --git a/syntax/snippets.vim b/syntax/snippets.vim index aa2da1b..bebd041 100644 --- a/syntax/snippets.vim +++ b/syntax/snippets.vim @@ -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