Moving towards Snippet providers.
Removed parsing responsibilities from SnippetManager and instead put them into the new module providers. Renamed private methods on SnippetManager that are not meant to be called by external libraries to start with _. Refactored tests so that expected failures can be tested and therefore removed the testing flag from SnippetManager.
This commit is contained in:
parent
a9d946135f
commit
2eb82d127b
@ -100,7 +100,7 @@ function! s:compensate_for_pum()
|
||||
""" to explicitly check for the presence of the popup menu, and update
|
||||
""" the vim-state accordingly.
|
||||
if pumvisible()
|
||||
exec g:_uspy "UltiSnips_Manager.cursor_moved()"
|
||||
exec g:_uspy "UltiSnips_Manager._cursor_moved()"
|
||||
endif
|
||||
endfunction
|
||||
|
||||
@ -108,9 +108,9 @@ function! UltiSnips#Edit(...)
|
||||
if a:0 == 1 && a:1 != ''
|
||||
let type = a:1
|
||||
else
|
||||
exec g:_uspy "vim.command(\"let type = '%s'\" % UltiSnips_Manager.primary_filetype)"
|
||||
exec g:_uspy "vim.command(\"let type = '%s'\" % UltiSnips_Manager._primary_filetype)"
|
||||
endif
|
||||
exec g:_uspy "vim.command(\"let file = '%s'\" % UltiSnips_Manager.file_to_edit(vim.eval(\"type\")))"
|
||||
exec g:_uspy "vim.command(\"let file = '%s'\" % UltiSnips_Manager._file_to_edit(vim.eval(\"type\")))"
|
||||
|
||||
let mode = 'e'
|
||||
if exists('g:UltiSnipsEditSplit')
|
||||
@ -212,7 +212,7 @@ function! UltiSnips#SnippetsInCurrentScope()
|
||||
endfunction
|
||||
|
||||
function! UltiSnips#SaveLastVisualSelection()
|
||||
exec g:_uspy "UltiSnips_Manager.save_last_visual_selection()"
|
||||
exec g:_uspy "UltiSnips_Manager._save_last_visual_selection()"
|
||||
return ""
|
||||
endfunction
|
||||
|
||||
@ -257,15 +257,15 @@ endfunction
|
||||
|
||||
|
||||
function! UltiSnips#CursorMoved()
|
||||
exec g:_uspy "UltiSnips_Manager.cursor_moved()"
|
||||
exec g:_uspy "UltiSnips_Manager._cursor_moved()"
|
||||
endf
|
||||
|
||||
function! UltiSnips#LeavingBuffer()
|
||||
exec g:_uspy "UltiSnips_Manager.leaving_buffer()"
|
||||
exec g:_uspy "UltiSnips_Manager._leaving_buffer()"
|
||||
endf
|
||||
|
||||
function! UltiSnips#LeavingInsertMode()
|
||||
exec g:_uspy "UltiSnips_Manager.leaving_insert_mode()"
|
||||
exec g:_uspy "UltiSnips_Manager._leaving_insert_mode()"
|
||||
endfunction
|
||||
" }}}
|
||||
|
||||
|
@ -346,11 +346,6 @@ file: >
|
||||
" Traverse in reverse order
|
||||
let g:UltiSnipsDontReverseSearchPath="0"
|
||||
|
||||
By default, whenever a snippet expand is triggered, UltiSnips will check for
|
||||
modifications to the snippet file associated with the filetype and reload it
|
||||
if necessary. This behavior can be disabled as follows: >
|
||||
let g:UltiSnipsDoHash=0
|
||||
|
||||
|UltiSnips-adding-snippets| explains which files are parsed for a given filetype.
|
||||
|
||||
|
||||
|
10
pythonx/UltiSnips/providers/__init__.py
Executable file
10
pythonx/UltiSnips/providers/__init__.py
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
"""Sources of snippet definitions."""
|
||||
|
||||
# TODO(sirver): these should register themselves with the Manager, so that
|
||||
# other plugins can extend them more easily.
|
||||
from UltiSnips.providers.snippet_file import UltiSnipsFileProvider, \
|
||||
base_snippet_files_for
|
||||
from UltiSnips.providers.added_snippets_provider import AddedSnippetsProvider
|
59
pythonx/UltiSnips/providers/_base.py
Executable file
59
pythonx/UltiSnips/providers/_base.py
Executable file
@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
"""Base class for snippet providers."""
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
from UltiSnips.providers._snippet_dictionary import SnippetDictionary
|
||||
|
||||
class SnippetProvider(object):
|
||||
"""See module docstring."""
|
||||
|
||||
def __init__(self):
|
||||
self._snippets = defaultdict(SnippetDictionary)
|
||||
|
||||
def get_snippets(self, filetypes, before, possible):
|
||||
"""Returns the snippets for all 'filetypes' (in order) and their
|
||||
parents matching the text 'before'. If 'possible' is true, a partial
|
||||
match is enough."""
|
||||
found_snippets = []
|
||||
for ft in filetypes:
|
||||
found_snippets += self._find_snippets(ft, before, possible)
|
||||
|
||||
# Search if any of the snippets overwrites the previous
|
||||
# Dictionary allows O(1) access for easy overwrites
|
||||
snippets = {}
|
||||
for snip in found_snippets:
|
||||
if (snip.trigger not in snippets) or snip.overwrites_previous:
|
||||
snippets[snip.trigger] = []
|
||||
snippets[snip.trigger].append(snip)
|
||||
|
||||
# Transform dictionary into flat list of snippets
|
||||
selected_snippets = set(
|
||||
[item for sublist in snippets.values() for item in sublist])
|
||||
# Return snippets to their original order
|
||||
snippets = [snip for snip in found_snippets if
|
||||
snip in selected_snippets]
|
||||
|
||||
return snippets
|
||||
|
||||
def _find_snippets(self, ft, trigger, potentially=False, seen=None):
|
||||
"""Find snippets matching 'trigger' for 'ft'. If 'potentially' is True,
|
||||
partial matches are enough."""
|
||||
snips = self._snippets.get(ft, None)
|
||||
if not snips:
|
||||
return []
|
||||
if not seen:
|
||||
seen = set()
|
||||
seen.add(ft)
|
||||
parent_results = []
|
||||
# TODO(sirver): extends information is not bound to one
|
||||
# provider. It should be tracked further up.
|
||||
for parent_ft in snips.extends:
|
||||
if parent_ft not in seen:
|
||||
seen.add(parent_ft)
|
||||
parent_results += self._find_snippets(parent_ft, trigger,
|
||||
potentially, seen)
|
||||
return parent_results + snips.get_matching_snippets(
|
||||
trigger, potentially)
|
@ -6,14 +6,13 @@
|
||||
import hashlib
|
||||
import os
|
||||
|
||||
|
||||
def _hash_file(path):
|
||||
"""Returns a hashdigest of 'path'"""
|
||||
if not os.path.isfile(path):
|
||||
return False
|
||||
return hashlib.sha1(open(path, "rb").read()).hexdigest()
|
||||
|
||||
|
||||
# TODO(sirver): This class should not hash any files nor keep track of extends.
|
||||
class SnippetDictionary(object):
|
||||
"""See module docstring."""
|
||||
|
14
pythonx/UltiSnips/providers/added_snippets_provider.py
Executable file
14
pythonx/UltiSnips/providers/added_snippets_provider.py
Executable file
@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
"""Handles manually added snippets (i.e. not in a file)."""
|
||||
|
||||
from UltiSnips.providers._base import SnippetProvider
|
||||
|
||||
class AddedSnippetsProvider(SnippetProvider):
|
||||
"""See module docstring."""
|
||||
|
||||
# TODO(sirver): filename makes no sense here. Is it even used?
|
||||
def add_snippet(self, ft, snippet, filename):
|
||||
"""Adds the given 'snippet' for 'ft'."""
|
||||
self._snippets[ft].add_snippet(snippet, filename)
|
182
pythonx/UltiSnips/providers/snippet_file.py
Executable file
182
pythonx/UltiSnips/providers/snippet_file.py
Executable file
@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
"""Code to provide access to UltiSnips files from disk."""
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
from UltiSnips.providers._base import SnippetProvider
|
||||
from UltiSnips.providers.ultisnips_file import parse_snippets_file
|
||||
from UltiSnips.snippet_definition import SnippetDefinition
|
||||
import UltiSnips._vim as _vim
|
||||
|
||||
def _plugin_dir():
|
||||
"""Calculates the plugin directory for UltiSnips."""
|
||||
directory = __file__
|
||||
for _ in range(10):
|
||||
directory = os.path.dirname(directory)
|
||||
if (os.path.isdir(os.path.join(directory, "plugin")) and
|
||||
os.path.isdir(os.path.join(directory, "doc"))):
|
||||
return directory
|
||||
raise Exception("Unable to find the plugin directory.")
|
||||
|
||||
def _snippets_dir_is_before_plugin_dir():
|
||||
""" Returns True if the snippets directory comes before the plugin
|
||||
directory in Vim's runtime path. False otherwise.
|
||||
"""
|
||||
paths = [os.path.realpath(os.path.expanduser(p)).rstrip(os.path.sep)
|
||||
for p in _vim.eval("&runtimepath").split(',')]
|
||||
home = _vim.eval("$HOME")
|
||||
def vim_path_index(suffix):
|
||||
"""Returns index of 'suffix' in 'paths' or -1 if it is not found."""
|
||||
path = os.path.realpath(os.path.join(home, suffix)).rstrip(os.path.sep)
|
||||
try:
|
||||
return paths.index(path)
|
||||
except ValueError:
|
||||
return -1
|
||||
try:
|
||||
real_vim_path_index = max(
|
||||
vim_path_index(".vim"), vim_path_index("vimfiles"))
|
||||
plugin_path_index = paths.index(_plugin_dir())
|
||||
return plugin_path_index < real_vim_path_index
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def _should_reverse_search_path():
|
||||
""" If the user defined g:UltiSnipsDontReverseSearchPath then return True
|
||||
or False based on the value of that variable, else defer to
|
||||
_snippets_dir_is_before_plugin_dir to determine whether this is True or
|
||||
False.
|
||||
"""
|
||||
if _vim.eval("exists('g:UltiSnipsDontReverseSearchPath')") != "0":
|
||||
return _vim.eval("g:UltiSnipsDontReverseSearchPath") != "0"
|
||||
return not _snippets_dir_is_before_plugin_dir()
|
||||
|
||||
|
||||
def base_snippet_files_for(ft, default=True):
|
||||
"""Returns a list of snippet files matching the given filetype (ft).
|
||||
If default is set to false, it doesn't include shipped files.
|
||||
|
||||
Searches through each path in 'runtimepath' in reverse order,
|
||||
in each of these, it searches each directory name listed in
|
||||
'g:UltiSnipsSnippetDirectories' in order, then looks for files in these
|
||||
directories called 'ft.snippets' or '*_ft.snippets' replacing ft with
|
||||
the filetype.
|
||||
"""
|
||||
if _vim.eval("exists('b:UltiSnipsSnippetDirectories')") == "1":
|
||||
snippet_dirs = _vim.eval("b:UltiSnipsSnippetDirectories")
|
||||
else:
|
||||
snippet_dirs = _vim.eval("g:UltiSnipsSnippetDirectories")
|
||||
|
||||
paths = _vim.eval("&runtimepath").split(',')
|
||||
if _should_reverse_search_path():
|
||||
paths = paths[::-1]
|
||||
|
||||
base_snippets = os.path.realpath(os.path.join(_plugin_dir(), "UltiSnips"))
|
||||
ret = []
|
||||
for rtp in paths:
|
||||
for snippet_dir in snippet_dirs:
|
||||
pth = os.path.realpath(os.path.expanduser(
|
||||
os.path.join(rtp, snippet_dir)))
|
||||
patterns = ["%s.snippets", "%s_*.snippets", os.path.join("%s", "*")]
|
||||
if not default and pth == base_snippets:
|
||||
patterns.remove("%s.snippets")
|
||||
|
||||
for pattern in patterns:
|
||||
for fn in glob.glob(os.path.join(pth, pattern % ft)):
|
||||
if fn not in ret:
|
||||
ret.append(fn)
|
||||
return ret
|
||||
|
||||
class SnippetSyntaxError(RuntimeError):
|
||||
"""Thrown when a syntax error is found in a file."""
|
||||
def __init__(self, filename, line_index, msg):
|
||||
RuntimeError.__init__(self, "%s in %s:%d" % (
|
||||
msg, filename, line_index))
|
||||
|
||||
class UltiSnipsFileProvider(SnippetProvider):
|
||||
"""Manages all snippets definitons found in rtp."""
|
||||
|
||||
def get_snippets(self, filetypes, before, possible):
|
||||
for ft in filetypes:
|
||||
self._ensure_loaded(ft)
|
||||
|
||||
return SnippetProvider.get_snippets(self, filetypes, before, possible)
|
||||
|
||||
def _ensure_loaded(self, ft, already_loaded=None):
|
||||
"""Make sure that the snippets for 'ft' and everything it extends are
|
||||
loaded."""
|
||||
if not already_loaded:
|
||||
already_loaded = set()
|
||||
|
||||
if ft in already_loaded:
|
||||
return
|
||||
already_loaded.add(ft)
|
||||
|
||||
if self._needs_update(ft):
|
||||
self._load_snippets_for(ft)
|
||||
|
||||
for parent in self._snippets[ft].extends:
|
||||
self._ensure_loaded(parent, already_loaded)
|
||||
|
||||
def _needs_update(self, ft):
|
||||
"""Returns true if any files for 'ft' have changed and must be
|
||||
reloaded."""
|
||||
if ft not in self._snippets:
|
||||
return True
|
||||
elif self._snippets[ft].has_any_file_changed():
|
||||
return True
|
||||
else:
|
||||
cur_snips = set(base_snippet_files_for(ft))
|
||||
old_snips = set(self._snippets[ft].files)
|
||||
if cur_snips - old_snips:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _load_snippets_for(self, ft):
|
||||
"""Load all snippets for the given 'ft'."""
|
||||
if ft in self._snippets:
|
||||
del self._snippets[ft]
|
||||
for fn in base_snippet_files_for(ft):
|
||||
self._parse_snippets(ft, fn)
|
||||
# Now load for the parents
|
||||
for parent_ft in self._snippets[ft].extends:
|
||||
if parent_ft not in self._snippets:
|
||||
self._load_snippets_for(parent_ft)
|
||||
|
||||
def _parse_snippets(self, ft, filename):
|
||||
"""Parse the file 'filename' for the given 'ft' and watch it for
|
||||
changes in the future. 'file_data' can be injected in tests."""
|
||||
self._snippets[ft].addfile(filename)
|
||||
file_data = open(filename, "r").read()
|
||||
for event, data in parse_snippets_file(file_data):
|
||||
if event == "error":
|
||||
msg, line_index = data
|
||||
filename = _vim.eval("""fnamemodify(%s, ":~:.")""" %
|
||||
_vim.escape(filename))
|
||||
raise SnippetSyntaxError(filename, line_index, msg)
|
||||
elif event == "clearsnippets":
|
||||
triggers, = data
|
||||
self._snippets[ft].clear_snippets(triggers)
|
||||
elif event == "extends":
|
||||
# TODO(sirver): extends information is more global
|
||||
# than one snippet provider.
|
||||
filetypes, = data
|
||||
self._add_extending_info(ft, filetypes)
|
||||
elif event == "snippet":
|
||||
trigger, value, description, options, globals = data
|
||||
self._snippets[ft].add_snippet(
|
||||
SnippetDefinition(trigger, value, description, options,
|
||||
globals), filename
|
||||
)
|
||||
else:
|
||||
assert False, "Unhandled %s: %r" % (event, data)
|
||||
|
||||
def _add_extending_info(self, ft, parents):
|
||||
"""Add the list of 'parents' as being extended by the 'ft'."""
|
||||
sd = self._snippets[ft]
|
||||
for parent in parents:
|
||||
if parent in sd.extends:
|
||||
continue
|
||||
sd.extends.append(parent)
|
@ -33,7 +33,7 @@ def _words_for_line(trigger, before, num_words=None):
|
||||
return before[len(before_words):].strip()
|
||||
|
||||
|
||||
class Snippet(object):
|
||||
class SnippetDefinition(object):
|
||||
"""Represents a snippet as parsed from a file."""
|
||||
|
||||
_INDENT = re.compile(r"^[ \t]*")
|
||||
@ -49,7 +49,7 @@ class Snippet(object):
|
||||
self._globals = globals
|
||||
|
||||
def __repr__(self):
|
||||
return "Snippet(%s,%s,%s)" % (
|
||||
return "SnippetDefinition(%s,%s,%s)" % (
|
||||
self._trigger, self._description, self._opts)
|
||||
|
||||
def _re_match(self, trigger):
|
@ -5,17 +5,15 @@
|
||||
|
||||
from collections import defaultdict
|
||||
from functools import wraps
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import traceback
|
||||
|
||||
from UltiSnips._diff import diff, guess_edit
|
||||
from UltiSnips.compatibility import as_unicode
|
||||
from UltiSnips.position import Position
|
||||
from UltiSnips.snippet import Snippet
|
||||
from UltiSnips.snippet_definitions import parse_snippets_file
|
||||
from UltiSnips.snippet_dictionary import SnippetDictionary
|
||||
from UltiSnips.providers import UltiSnipsFileProvider, \
|
||||
base_snippet_files_for, AddedSnippetsProvider
|
||||
from UltiSnips.snippet_definition import SnippetDefinition
|
||||
from UltiSnips.vim_state import VimState, VisualContentPreserver
|
||||
import UltiSnips._vim as _vim
|
||||
|
||||
@ -40,86 +38,6 @@ def _ask_snippets(snippets):
|
||||
except KeyboardInterrupt:
|
||||
return None
|
||||
|
||||
def _base_snippet_files_for(ft, default=True):
|
||||
"""Returns a list of snippet files matching the given filetype (ft).
|
||||
If default is set to false, it doesn't include shipped files.
|
||||
|
||||
Searches through each path in 'runtimepath' in reverse order,
|
||||
in each of these, it searches each directory name listed in
|
||||
'g:UltiSnipsSnippetDirectories' in order, then looks for files in these
|
||||
directories called 'ft.snippets' or '*_ft.snippets' replacing ft with
|
||||
the filetype.
|
||||
"""
|
||||
|
||||
if _vim.eval("exists('b:UltiSnipsSnippetDirectories')") == "1":
|
||||
snippet_dirs = _vim.eval("b:UltiSnipsSnippetDirectories")
|
||||
else:
|
||||
snippet_dirs = _vim.eval("g:UltiSnipsSnippetDirectories")
|
||||
base_snippets = os.path.realpath(os.path.join(
|
||||
__file__, "../../../UltiSnips"))
|
||||
ret = []
|
||||
|
||||
paths = _vim.eval("&runtimepath").split(',')
|
||||
|
||||
if _should_reverse_search_path():
|
||||
paths = paths[::-1]
|
||||
|
||||
for rtp in paths:
|
||||
for snippet_dir in snippet_dirs:
|
||||
pth = os.path.realpath(os.path.expanduser(
|
||||
os.path.join(rtp, snippet_dir)))
|
||||
patterns = ["%s.snippets", "%s_*.snippets", os.path.join("%s", "*")]
|
||||
if not default and pth == base_snippets:
|
||||
patterns.remove("%s.snippets")
|
||||
|
||||
for pattern in patterns:
|
||||
for fn in glob.glob(os.path.join(pth, pattern % ft)):
|
||||
if fn not in ret:
|
||||
ret.append(fn)
|
||||
return ret
|
||||
|
||||
|
||||
def _plugin_dir():
|
||||
"""Calculates the plugin directory for UltiSnips."""
|
||||
directory = __file__
|
||||
for _ in range(10):
|
||||
directory = os.path.dirname(directory)
|
||||
if (os.path.isdir(os.path.join(directory, "plugin")) and
|
||||
os.path.isdir(os.path.join(directory, "doc"))):
|
||||
return directory
|
||||
raise Exception("Unable to find the plugin directory.")
|
||||
|
||||
def _snippets_dir_is_before_plugin_dir():
|
||||
""" Returns True if the snippets directory comes before the plugin
|
||||
directory in Vim's runtime path. False otherwise.
|
||||
"""
|
||||
paths = [os.path.realpath(os.path.expanduser(p)).rstrip(os.path.sep)
|
||||
for p in _vim.eval("&runtimepath").split(',')]
|
||||
home = _vim.eval("$HOME")
|
||||
def vim_path_index(suffix):
|
||||
"""Returns index of 'suffix' in 'paths' or -1 if it is not found."""
|
||||
path = os.path.realpath(os.path.join(home, suffix)).rstrip(os.path.sep)
|
||||
try:
|
||||
return paths.index(path)
|
||||
except ValueError:
|
||||
return -1
|
||||
try:
|
||||
real_vim_path_index = max(
|
||||
vim_path_index(".vim"), vim_path_index("vimfiles"))
|
||||
plugin_path_index = paths.index(_plugin_dir())
|
||||
return plugin_path_index < real_vim_path_index
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
def _should_reverse_search_path():
|
||||
""" If the user defined g:UltiSnipsDontReverseSearchPath then return True
|
||||
or False based on the value of that variable, else defer to
|
||||
_snippets_dir_is_before_plugin_dir to determine whether this is True or
|
||||
False.
|
||||
"""
|
||||
if _vim.eval("exists('g:UltiSnipsDontReverseSearchPath')") != "0":
|
||||
return _vim.eval("g:UltiSnipsDontReverseSearchPath") != "0"
|
||||
return not _snippets_dir_is_before_plugin_dir()
|
||||
|
||||
def err_to_scratch_buffer(func):
|
||||
"""Decorator that will catch any Exception that 'func' throws and displays
|
||||
@ -137,13 +55,14 @@ https://bugs.launchpad.net/ultisnips/+filebug.
|
||||
Following is the full stack trace:
|
||||
"""
|
||||
msg += traceback.format_exc()
|
||||
self.leaving_buffer() # Vim sends no WinLeave msg here.
|
||||
# Vim sends no WinLeave msg here.
|
||||
self._leaving_buffer() # pylint:disable=protected-access
|
||||
_vim.new_scratch_buffer(msg)
|
||||
return wrapper
|
||||
|
||||
|
||||
# TODO(sirver): This class has too many responsibilities - it should not also
|
||||
# care for the parsing and managing of parsed snippets.
|
||||
# TODO(sirver): This class is still too long. It should only contain public
|
||||
# facing methods, most of the private methods should be moved outside of it.
|
||||
class SnippetManager(object):
|
||||
"""The main entry point for all UltiSnips functionality. All Vim functions
|
||||
call methods in this class."""
|
||||
@ -154,21 +73,7 @@ class SnippetManager(object):
|
||||
self.backward_trigger = backward_trigger
|
||||
self._supertab_keys = None
|
||||
self._csnippets = []
|
||||
self.reset()
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def reset(self, test_error=False):
|
||||
"""Reset the class to the state it had directly after creation."""
|
||||
self._vstate = VimState()
|
||||
self._test_error = test_error
|
||||
self._snippets = defaultdict(SnippetDictionary)
|
||||
self._filetypes = defaultdict(lambda: ['all'])
|
||||
self._visual_content = VisualContentPreserver()
|
||||
|
||||
while len(self._csnippets):
|
||||
self._current_snippet_is_done()
|
||||
|
||||
self._reinit()
|
||||
self._reset()
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def jump_forwards(self):
|
||||
@ -188,12 +93,28 @@ class SnippetManager(object):
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def expand(self):
|
||||
"""Trie to expand a snippet at the current position."""
|
||||
"""Try to expand a snippet at the current position."""
|
||||
_vim.command("let g:ulti_expand_res = 1")
|
||||
if not self._try_expand():
|
||||
_vim.command("let g:ulti_expand_res = 0")
|
||||
self._handle_failure(self.expand_trigger)
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def expand_or_jump(self):
|
||||
"""
|
||||
This function is used for people who wants to have the same trigger for
|
||||
expansion and forward jumping. It first tries to expand a snippet, if
|
||||
this fails, it tries to jump forward.
|
||||
"""
|
||||
_vim.command('let g:ulti_expand_or_jump_res = 1')
|
||||
rv = self._try_expand()
|
||||
if not rv:
|
||||
_vim.command('let g:ulti_expand_or_jump_res = 2')
|
||||
rv = self._jump()
|
||||
if not rv:
|
||||
_vim.command('let g:ulti_expand_or_jump_res = 0')
|
||||
self._handle_failure(self.expand_trigger)
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def snippets_in_current_scope(self):
|
||||
"""Returns the snippets that could be expanded to Vim as a global
|
||||
@ -210,7 +131,7 @@ class SnippetManager(object):
|
||||
key = as_unicode(snip.trigger)
|
||||
description = as_unicode(description)
|
||||
|
||||
#remove surrounding "" or '' in snippet description if it exists
|
||||
# remove surrounding "" or '' in snippet description if it exists
|
||||
if len(description) > 2:
|
||||
if (description[0] == description[-1] and
|
||||
description[0] in "'\""):
|
||||
@ -246,37 +167,12 @@ class SnippetManager(object):
|
||||
|
||||
return True
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def expand_or_jump(self):
|
||||
"""
|
||||
This function is used for people who wants to have the same trigger for
|
||||
expansion and forward jumping. It first tries to expand a snippet, if
|
||||
this fails, it tries to jump forward.
|
||||
"""
|
||||
_vim.command('let g:ulti_expand_or_jump_res = 1')
|
||||
rv = self._try_expand()
|
||||
if not rv:
|
||||
_vim.command('let g:ulti_expand_or_jump_res = 2')
|
||||
rv = self._jump()
|
||||
if not rv:
|
||||
_vim.command('let g:ulti_expand_or_jump_res = 0')
|
||||
self._handle_failure(self.expand_trigger)
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def save_last_visual_selection(self):
|
||||
"""
|
||||
This is called when the expand trigger is pressed in visual mode.
|
||||
Our job is to remember everything between '< and '> and pass it on to
|
||||
${VISUAL} in case it will be needed.
|
||||
"""
|
||||
self._visual_content.conserve()
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def add_snippet(self, trigger, value, description,
|
||||
options, ft="all", globals=None, fn=None):
|
||||
"""Add a snippet to the list of known snippets of the given 'ft'."""
|
||||
self._snippets[ft].add_snippet(
|
||||
Snippet(trigger, value, description, options, globals or {}), fn
|
||||
self._added_snippets_provider.add_snippet(ft, SnippetDefinition(
|
||||
trigger, value, description, options, globals or {}), fn
|
||||
)
|
||||
|
||||
@err_to_scratch_buffer
|
||||
@ -287,7 +183,7 @@ class SnippetManager(object):
|
||||
globals = {}
|
||||
|
||||
before = _vim.buf.line_till_cursor
|
||||
snip = Snippet(trigger, value, description, options, globals)
|
||||
snip = SnippetDefinition(trigger, value, description, options, globals)
|
||||
|
||||
if not trigger or snip.matches(before):
|
||||
self._do_snippet(snip, before)
|
||||
@ -295,8 +191,28 @@ class SnippetManager(object):
|
||||
else:
|
||||
return False
|
||||
|
||||
def reset_buffer_filetypes(self):
|
||||
"""Reset the filetypes for the current buffer."""
|
||||
if _vim.buf.number in self._filetypes:
|
||||
del self._filetypes[_vim.buf.number]
|
||||
|
||||
def add_buffer_filetypes(self, ft):
|
||||
"""Checks for changes in the list of snippet files or the contents of
|
||||
the snippet files and reloads them if necessary. """
|
||||
buf_fts = self._filetypes[_vim.buf.number]
|
||||
idx = -1
|
||||
for ft in ft.split("."):
|
||||
ft = ft.strip()
|
||||
if not ft:
|
||||
continue
|
||||
try:
|
||||
idx = buf_fts.index(ft)
|
||||
except ValueError:
|
||||
self._filetypes[_vim.buf.number].insert(idx + 1, ft)
|
||||
idx += 1
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def cursor_moved(self):
|
||||
def _cursor_moved(self):
|
||||
"""Called whenever the cursor moved."""
|
||||
self._vstate.remember_position()
|
||||
if _vim.eval("mode()") not in 'in':
|
||||
@ -360,40 +276,40 @@ class SnippetManager(object):
|
||||
self._csnippets[0].update_textobjects()
|
||||
self._vstate.remember_buffer(self._csnippets[0])
|
||||
|
||||
def leaving_buffer(self):
|
||||
@err_to_scratch_buffer
|
||||
def _reset(self):
|
||||
"""Reset the class to the state it had directly after creation."""
|
||||
self._vstate = VimState()
|
||||
self._filetypes = defaultdict(lambda: ['all'])
|
||||
self._visual_content = VisualContentPreserver()
|
||||
self._snippet_providers = [
|
||||
AddedSnippetsProvider(),
|
||||
UltiSnipsFileProvider()
|
||||
]
|
||||
self._added_snippets_provider = self._snippet_providers[0]
|
||||
|
||||
while len(self._csnippets):
|
||||
self._current_snippet_is_done()
|
||||
|
||||
self._reinit()
|
||||
|
||||
@err_to_scratch_buffer
|
||||
def _save_last_visual_selection(self):
|
||||
"""
|
||||
This is called when the expand trigger is pressed in visual mode.
|
||||
Our job is to remember everything between '< and '> and pass it on to
|
||||
${VISUAL} in case it will be needed.
|
||||
"""
|
||||
self._visual_content.conserve()
|
||||
|
||||
|
||||
def _leaving_buffer(self):
|
||||
"""Called when the user switches tabs/windows/buffers. It basically
|
||||
means that all snippets must be properly terminated."""
|
||||
while len(self._csnippets):
|
||||
self._current_snippet_is_done()
|
||||
self._reinit()
|
||||
|
||||
###################################
|
||||
# Private/Protect Functions Below #
|
||||
###################################
|
||||
def _report_error(self, msg):
|
||||
"""Shows 'msg' as error to the user."""
|
||||
msg = _vim.escape("UltiSnips: " + msg)
|
||||
if self._test_error:
|
||||
msg = msg.replace('"', r'\"')
|
||||
msg = msg.replace('|', r'\|')
|
||||
_vim.command("let saved_pos=getpos('.')")
|
||||
_vim.command("$:put =%s" % msg)
|
||||
_vim.command("call setpos('.', saved_pos)")
|
||||
elif False:
|
||||
_vim.command("echohl WarningMsg")
|
||||
_vim.command("echomsg %s" % msg)
|
||||
_vim.command("echohl None")
|
||||
else:
|
||||
_vim.command("echoerr %s" % msg)
|
||||
|
||||
def _add_extending_info(self, ft, parents):
|
||||
"""Add the list of 'parents' as being extended by the 'ft'."""
|
||||
sd = self._snippets[ft]
|
||||
for parent in parents:
|
||||
if parent in sd.extends:
|
||||
continue
|
||||
sd.extends.append(parent)
|
||||
|
||||
def _reinit(self):
|
||||
"""Resets transient state."""
|
||||
self._ctab = None
|
||||
@ -440,7 +356,7 @@ class SnippetManager(object):
|
||||
self._ignore_movements = True
|
||||
return jumped
|
||||
|
||||
def leaving_insert_mode(self):
|
||||
def _leaving_insert_mode(self):
|
||||
"""Called whenever we leave the insert mode."""
|
||||
self._vstate.restore_unnamed_register()
|
||||
|
||||
@ -484,28 +400,10 @@ class SnippetManager(object):
|
||||
before the cursor. If possible is True, then get all
|
||||
possible matches.
|
||||
"""
|
||||
self._ensure_all_loaded()
|
||||
filetypes = self._filetypes[_vim.buf.number][::-1]
|
||||
|
||||
found_snippets = []
|
||||
for ft in filetypes:
|
||||
found_snippets += self._find_snippets(ft, before, possible)
|
||||
|
||||
# Search if any of the snippets overwrites the previous
|
||||
# Dictionary allows O(1) access for easy overwrites
|
||||
snippets = {}
|
||||
for snip in found_snippets:
|
||||
if (snip.trigger not in snippets) or snip.overwrites_previous:
|
||||
snippets[snip.trigger] = []
|
||||
snippets[snip.trigger].append(snip)
|
||||
|
||||
# Transform dictionary into flat list of snippets
|
||||
selected_snippets = set(
|
||||
[item for sublist in snippets.values() for item in sublist])
|
||||
# Return snippets to their original order
|
||||
snippets = [snip for snip in found_snippets if
|
||||
snip in selected_snippets]
|
||||
|
||||
snippets = []
|
||||
for provider in self._snippet_providers:
|
||||
snippets.extend(provider.get_snippets(filetypes, before, possible))
|
||||
return snippets
|
||||
|
||||
def _do_snippet(self, snippet, before):
|
||||
@ -574,39 +472,15 @@ class SnippetManager(object):
|
||||
return None
|
||||
return self._csnippets[-1]
|
||||
|
||||
def _parse_snippets(self, ft, filename, file_data=None):
|
||||
"""Parse the file 'filename' for the given 'ft' and watch it for
|
||||
changes in the future. 'file_data' can be injected in tests."""
|
||||
self._snippets[ft].addfile(filename)
|
||||
if file_data is None:
|
||||
file_data = open(filename, "r").read()
|
||||
for event, data in parse_snippets_file(file_data):
|
||||
if event == "error":
|
||||
msg, line_index = data
|
||||
filename = _vim.eval("""fnamemodify(%s, ":~:.")""" %
|
||||
_vim.escape(filename))
|
||||
self._report_error("%s in %s(%d)" % (msg, filename, line_index))
|
||||
break
|
||||
elif event == "clearsnippets":
|
||||
triggers, = data
|
||||
self._snippets[ft].clear_snippets(triggers)
|
||||
elif event == "extends":
|
||||
filetypes, = data
|
||||
self._add_extending_info(ft, filetypes)
|
||||
elif event == "snippet":
|
||||
trigger, value, descr, opts, globals = data
|
||||
self.add_snippet(trigger, value, descr,
|
||||
opts, ft, globals, filename)
|
||||
else:
|
||||
assert False, "Unhandled %s: %r" % (event, data)
|
||||
|
||||
@property
|
||||
def primary_filetype(self):
|
||||
def _primary_filetype(self):
|
||||
"""This filetype will be edited when UltiSnipsEdit is called without
|
||||
any arguments."""
|
||||
return self._filetypes[_vim.buf.number][0]
|
||||
|
||||
def file_to_edit(self, ft): # pylint: disable=no-self-use
|
||||
# TODO(sirver): this should talk directly to the UltiSnipsFileProvider.
|
||||
def _file_to_edit(self, ft): # pylint: disable=no-self-use
|
||||
""" Gets a file to edit based on the given filetype.
|
||||
If no filetype is given, uses the current filetype from Vim.
|
||||
|
||||
@ -617,7 +491,7 @@ class SnippetManager(object):
|
||||
# This method is not using self, but is called by UltiSnips.vim and is
|
||||
# therefore in this class because it is the facade to Vim.
|
||||
edit = None
|
||||
existing = _base_snippet_files_for(ft, False)
|
||||
existing = base_snippet_files_for(ft, False)
|
||||
filename = ft + ".snippets"
|
||||
|
||||
if _vim.eval("exists('g:UltiSnipsSnippetsDir')") == "1":
|
||||
@ -644,95 +518,3 @@ class SnippetManager(object):
|
||||
|
||||
edit = os.path.join(path, filename)
|
||||
return edit
|
||||
|
||||
def _load_snippets_for(self, ft):
|
||||
"""Load all snippets for the given 'ft'."""
|
||||
if ft in self._snippets:
|
||||
del self._snippets[ft]
|
||||
for fn in _base_snippet_files_for(ft):
|
||||
self._parse_snippets(ft, fn)
|
||||
# Now load for the parents
|
||||
for parent_ft in self._snippets[ft].extends:
|
||||
if parent_ft not in self._snippets:
|
||||
self._load_snippets_for(parent_ft)
|
||||
|
||||
def _needs_update(self, ft):
|
||||
"""Returns true if any files for 'ft' have changed and must be
|
||||
reloaded."""
|
||||
do_hash = _vim.eval('exists("g:UltiSnipsDoHash")') == "0" \
|
||||
or _vim.eval("g:UltiSnipsDoHash") != "0"
|
||||
|
||||
if ft not in self._snippets:
|
||||
return True
|
||||
elif do_hash and self._snippets[ft].has_any_file_changed():
|
||||
return True
|
||||
elif do_hash:
|
||||
cur_snips = set(_base_snippet_files_for(ft))
|
||||
old_snips = set(self._snippets[ft].files)
|
||||
if cur_snips - old_snips:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _ensure_loaded(self, ft, checked=None):
|
||||
"""Make sure that the snippets for 'ft' and everything it extends are
|
||||
loaded."""
|
||||
if not checked:
|
||||
checked = set([ft])
|
||||
elif ft in checked:
|
||||
return
|
||||
else:
|
||||
checked.add(ft)
|
||||
|
||||
if self._needs_update(ft):
|
||||
self._load_snippets_for(ft)
|
||||
|
||||
for parent in self._snippets[ft].extends:
|
||||
self._ensure_loaded(parent, checked)
|
||||
|
||||
def _ensure_all_loaded(self):
|
||||
"""Make sure that all filetypes fur the current buffer are loaded."""
|
||||
for ft in self._filetypes[_vim.buf.number]:
|
||||
self._ensure_loaded(ft)
|
||||
|
||||
def reset_buffer_filetypes(self):
|
||||
"""Reset the filetypes for the current buffer."""
|
||||
if _vim.buf.number in self._filetypes:
|
||||
del self._filetypes[_vim.buf.number]
|
||||
|
||||
def add_buffer_filetypes(self, ft):
|
||||
"""Checks for changes in the list of snippet files or the contents of
|
||||
the snippet files and reloads them if necessary. """
|
||||
buf_fts = self._filetypes[_vim.buf.number]
|
||||
idx = -1
|
||||
for ft in ft.split("."):
|
||||
ft = ft.strip()
|
||||
if not ft:
|
||||
continue
|
||||
try:
|
||||
idx = buf_fts.index(ft)
|
||||
except ValueError:
|
||||
self._filetypes[_vim.buf.number].insert(idx + 1, ft)
|
||||
idx += 1
|
||||
|
||||
def _find_snippets(self, ft, trigger, potentially=False, seen=None):
|
||||
"""Find snippets matching trigger
|
||||
|
||||
ft - file type to search
|
||||
trigger - trigger to match against
|
||||
potentially - also returns snippets that could potentially match; that
|
||||
is which triggers start with the current trigger
|
||||
"""
|
||||
snips = self._snippets.get(ft, None)
|
||||
if not snips:
|
||||
return []
|
||||
if not seen:
|
||||
seen = set()
|
||||
seen.add(ft)
|
||||
parent_results = []
|
||||
for parent_ft in snips.extends:
|
||||
if parent_ft not in seen:
|
||||
seen.add(parent_ft)
|
||||
parent_results += self._find_snippets(parent_ft, trigger,
|
||||
potentially, seen)
|
||||
return parent_results + snips.get_matching_snippets(
|
||||
trigger, potentially)
|
||||
|
181
test.py
181
test.py
@ -31,16 +31,18 @@
|
||||
|
||||
# pylint: skip-file
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
import time
|
||||
import re
|
||||
import platform
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
from textwrap import dedent
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
|
||||
try:
|
||||
import unidecode
|
||||
@ -66,20 +68,21 @@ LS = "@" # List snippets
|
||||
EX = "\t" # EXPAND
|
||||
EA = "#" # Expand anonymous
|
||||
|
||||
# Some VIM functions
|
||||
COMPL_KW = chr(24)+chr(14)
|
||||
COMPL_ACCEPT = chr(25)
|
||||
|
||||
NUMBER_OF_RETRIES_FOR_EACH_TEST = 4
|
||||
|
||||
def RunningOnWindows():
|
||||
def running_on_windows():
|
||||
if platform.system() == "Windows":
|
||||
return "Does not work on Windows."
|
||||
|
||||
def NoUnidecodeAvailable():
|
||||
def no_unidecode_available():
|
||||
if not UNIDECODE_IMPORTED:
|
||||
return "unidecode is not available."
|
||||
|
||||
def random_string(n):
|
||||
return ''.join(random.choice(string.ascii_lowercase) for x in range(n))
|
||||
|
||||
class VimInterface:
|
||||
def focus(title=None):
|
||||
@ -220,7 +223,7 @@ class VimInterfaceWindows(VimInterface):
|
||||
|
||||
class _VimTest(unittest.TestCase):
|
||||
snippets = ("dummy", "donotdefine")
|
||||
snippets_test_file = ("", "", "") # file type, file name, file content
|
||||
snippets_test_file = ("", "") # filetype, file content
|
||||
text_before = " --- some text before --- \n\n"
|
||||
text_after = "\n\n --- some text after --- "
|
||||
expected_error = ""
|
||||
@ -256,7 +259,8 @@ class _VimTest(unittest.TestCase):
|
||||
def check_output(self):
|
||||
wanted = self.text_before + self.wanted + self.text_after
|
||||
if self.expected_error:
|
||||
wanted = wanted + "\n" + self.expected_error
|
||||
self.assertRegexpMatches(self.output, self.expected_error)
|
||||
return
|
||||
for i in range(NUMBER_OF_RETRIES_FOR_EACH_TEST):
|
||||
if self.output != wanted:
|
||||
# Redo this, but slower
|
||||
@ -273,6 +277,18 @@ class _VimTest(unittest.TestCase):
|
||||
def _options_off(self):
|
||||
pass
|
||||
|
||||
def _create_snippet_file(self, ft, content):
|
||||
"""Create a snippet file and makes sure that it is found on the
|
||||
runtimepath to be parsed."""
|
||||
self._temporary_directory = tempfile.mkdtemp(prefix="UltiSnips_Test")
|
||||
snippet_dir = random_string(20)
|
||||
abs_snippet_dir = os.path.join(self._temporary_directory, snippet_dir)
|
||||
os.mkdir(abs_snippet_dir)
|
||||
with open(os.path.join(abs_snippet_dir, "%s.snippets" % ft), "w") as snippet_file:
|
||||
snippet_file.write(dedent(content + "\n"))
|
||||
self.vim.send(":let g:UltiSnipsSnippetDirectories=['%s']\n" % snippet_dir)
|
||||
self.vim.send(""":set runtimepath=$VIMRUNTIME,%s,.\n""" % self._temporary_directory)
|
||||
|
||||
def setUp(self):
|
||||
reason_for_skipping = self.skip_if()
|
||||
if reason_for_skipping is not None:
|
||||
@ -285,9 +301,9 @@ class _VimTest(unittest.TestCase):
|
||||
self.send(":silent! close\n")
|
||||
|
||||
# Reset UltiSnips
|
||||
self.send_py("UltiSnips_Manager.reset(test_error=True)")
|
||||
self.send_py("UltiSnips_Manager._reset()")
|
||||
|
||||
# Make it unlikely that we do not parse any shipped snippets
|
||||
# Make it unlikely that we do parse any shipped snippets.
|
||||
self.send(":let g:UltiSnipsSnippetDirectories=['<un_def_ined>']\n")
|
||||
|
||||
# Clear the buffer
|
||||
@ -308,10 +324,10 @@ class _VimTest(unittest.TestCase):
|
||||
self.send_py("UltiSnips_Manager.add_snippet(%r, %r, %r, %r)" %
|
||||
(sv, content, description, options))
|
||||
|
||||
ft, fn, file_data = self.snippets_test_file
|
||||
ft, file_data = self.snippets_test_file
|
||||
self._temporary_directory = ""
|
||||
if ft:
|
||||
self.send_py("UltiSnips_Manager._parse_snippets(%r, %r, %r)" %
|
||||
(ft, fn, dedent(file_data + '\n')))
|
||||
self._create_snippet_file(ft, file_data)
|
||||
|
||||
if not self.interrupt:
|
||||
# Enter insert mode
|
||||
@ -336,18 +352,17 @@ class _VimTest(unittest.TestCase):
|
||||
|
||||
self.output = self.vim.get_buffer_data()
|
||||
|
||||
def tearDown(self):
|
||||
if self._temporary_directory:
|
||||
self.vim.send(""":set runtimepath=$VIMRUNTIME,.\n""")
|
||||
shutil.rmtree(self._temporary_directory)
|
||||
|
||||
###########################################################################
|
||||
# BEGINNING OF TEST #
|
||||
###########################################################################
|
||||
# Snippet Definition Parsing {{{#
|
||||
class _PS_Base(_VimTest):
|
||||
def _options_on(self):
|
||||
self.send(":let UltiSnipsDoHash=0\n")
|
||||
def _options_off(self):
|
||||
self.send(":unlet UltiSnipsDoHash\n")
|
||||
|
||||
class ParseSnippets_SimpleSnippet(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_SimpleSnippet(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet testsnip "Test Snippet" b!
|
||||
This is a test snippet!
|
||||
endsnippet
|
||||
@ -355,39 +370,33 @@ class ParseSnippets_SimpleSnippet(_PS_Base):
|
||||
keys = "testsnip" + EX
|
||||
wanted = "This is a test snippet!"
|
||||
|
||||
class ParseSnippets_MissingEndSnippet(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_MissingEndSnippet(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet testsnip "Test Snippet" b!
|
||||
This is a test snippet!
|
||||
""")
|
||||
keys = "testsnip" + EX
|
||||
wanted = "testsnip" + EX
|
||||
expected_error = dedent("""
|
||||
UltiSnips: Missing 'endsnippet' for 'testsnip' in test_file(4)
|
||||
""").strip()
|
||||
expected_error = r"Missing 'endsnippet' for 'testsnip' in \S+:4"
|
||||
|
||||
class ParseSnippets_UnknownDirective(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_UnknownDirective(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
unknown directive
|
||||
""")
|
||||
keys = "testsnip" + EX
|
||||
wanted = "testsnip" + EX
|
||||
expected_error = dedent("""
|
||||
UltiSnips: Invalid line 'unknown directive' in test_file(2)
|
||||
""").strip()
|
||||
expected_error = r"Invalid line 'unknown directive' in \S+:2"
|
||||
|
||||
class ParseSnippets_ExtendsWithoutFiletype(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_ExtendsWithoutFiletype(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
extends
|
||||
""")
|
||||
keys = "testsnip" + EX
|
||||
wanted = "testsnip" + EX
|
||||
expected_error = dedent("""
|
||||
UltiSnips: 'extends' without file types in test_file(2)
|
||||
""").strip()
|
||||
expected_error = r"'extends' without file types in \S+:2"
|
||||
|
||||
class ParseSnippets_ClearAll(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_ClearAll(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet testsnip "Test snippet"
|
||||
This is a test.
|
||||
endsnippet
|
||||
@ -397,8 +406,8 @@ class ParseSnippets_ClearAll(_PS_Base):
|
||||
keys = "testsnip" + EX
|
||||
wanted = "testsnip" + EX
|
||||
|
||||
class ParseSnippets_ClearOne(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_ClearOne(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet testsnip "Test snippet"
|
||||
This is a test.
|
||||
endsnippet
|
||||
@ -412,8 +421,8 @@ class ParseSnippets_ClearOne(_PS_Base):
|
||||
keys = "toclear" + EX + "\n" + "testsnip" + EX
|
||||
wanted = "toclear" + EX + "\n" + "This is a test."
|
||||
|
||||
class ParseSnippets_ClearTwo(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_ClearTwo(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet testsnip "Test snippet"
|
||||
This is a test.
|
||||
endsnippet
|
||||
@ -428,8 +437,8 @@ class ParseSnippets_ClearTwo(_PS_Base):
|
||||
wanted = "toclear" + EX + "\n" + "testsnip" + EX
|
||||
|
||||
|
||||
class _ParseSnippets_MultiWord(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class _ParseSnippets_MultiWord(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet /test snip/
|
||||
This is a test.
|
||||
endsnippet
|
||||
@ -452,8 +461,8 @@ class ParseSnippets_MultiWord_Description_Option(_ParseSnippets_MultiWord):
|
||||
keys = "snippet test" + EX
|
||||
wanted = "This is yet another test."
|
||||
|
||||
class _ParseSnippets_MultiWord_RE(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class _ParseSnippets_MultiWord_RE(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet /[d-f]+/ "" r
|
||||
az test
|
||||
endsnippet
|
||||
@ -476,16 +485,16 @@ class ParseSnippets_MultiWord_RE3(_ParseSnippets_MultiWord_RE):
|
||||
keys = "test test test" + EX
|
||||
wanted = "re-test"
|
||||
|
||||
class ParseSnippets_MultiWord_Quotes(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_MultiWord_Quotes(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet "test snip"
|
||||
This is a test.
|
||||
endsnippet
|
||||
""")
|
||||
keys = "test snip" + EX
|
||||
wanted = "This is a test."
|
||||
class ParseSnippets_MultiWord_WithQuotes(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_MultiWord_WithQuotes(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet !"test snip"!
|
||||
This is a test.
|
||||
endsnippet
|
||||
@ -493,32 +502,28 @@ class ParseSnippets_MultiWord_WithQuotes(_PS_Base):
|
||||
keys = '"test snip"' + EX
|
||||
wanted = "This is a test."
|
||||
|
||||
class ParseSnippets_MultiWord_NoContainer(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_MultiWord_NoContainer(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet test snip
|
||||
This is a test.
|
||||
endsnippet
|
||||
""")
|
||||
keys = "test snip" + EX
|
||||
wanted = keys
|
||||
expected_error = dedent("""
|
||||
UltiSnips: Invalid multiword trigger: 'test snip' in test_file(2)
|
||||
""").strip()
|
||||
expected_error = "Invalid multiword trigger: 'test snip' in \S+:2"
|
||||
|
||||
class ParseSnippets_MultiWord_UnmatchedContainer(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_MultiWord_UnmatchedContainer(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
snippet !inv snip/
|
||||
This is a test.
|
||||
endsnippet
|
||||
""")
|
||||
keys = "inv snip" + EX
|
||||
wanted = keys
|
||||
expected_error = dedent("""
|
||||
UltiSnips: Invalid multiword trigger: '!inv snip/' in test_file(2)
|
||||
""").strip()
|
||||
expected_error = "Invalid multiword trigger: '!inv snip/' in \S+:2"
|
||||
|
||||
class ParseSnippets_Global_Python(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_Global_Python(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
global !p
|
||||
def tex(ins):
|
||||
return "a " + ins + " b"
|
||||
@ -535,8 +540,8 @@ class ParseSnippets_Global_Python(_PS_Base):
|
||||
keys = "ab" + EX + "\nac" + EX
|
||||
wanted = "x a bob b y\nx a jon b y"
|
||||
|
||||
class ParseSnippets_Global_Local_Python(_PS_Base):
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
class ParseSnippets_Global_Local_Python(_VimTest):
|
||||
snippets_test_file = ("all", r"""
|
||||
global !p
|
||||
def tex(ins):
|
||||
return "a " + ins + " b"
|
||||
@ -855,43 +860,43 @@ class TabStopNavigatingInInsertModeSimple_ExceptCorrectResult(_VimTest):
|
||||
# End: TabStop Tests #}}}
|
||||
# ShellCode Interpolation {{{#
|
||||
class TabStop_Shell_SimpleExample(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", "hi `echo hallo` you!")
|
||||
keys = "test" + EX + "and more"
|
||||
wanted = "hi hallo you!and more"
|
||||
class TabStop_Shell_WithUmlauts(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", "hi `echo höüäh` you!")
|
||||
keys = "test" + EX + "and more"
|
||||
wanted = "hi höüäh you!and more"
|
||||
class TabStop_Shell_TextInNextLine(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", "hi `echo hallo`\nWeiter")
|
||||
keys = "test" + EX + "and more"
|
||||
wanted = "hi hallo\nWeiterand more"
|
||||
class TabStop_Shell_InDefValue_Leave(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", "Hallo ${1:now `echo fromecho`} end")
|
||||
keys = "test" + EX + JF + "and more"
|
||||
wanted = "Hallo now fromecho endand more"
|
||||
class TabStop_Shell_InDefValue_Overwrite(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", "Hallo ${1:now `echo fromecho`} end")
|
||||
keys = "test" + EX + "overwrite" + JF + "and more"
|
||||
wanted = "Hallo overwrite endand more"
|
||||
class TabStop_Shell_TestEscapedChars_Overwrite(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", r"""`echo \`echo "\\$hi"\``""")
|
||||
keys = "test" + EX
|
||||
wanted = "$hi"
|
||||
class TabStop_Shell_TestEscapedCharsAndShellVars_Overwrite(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", r"""`hi="blah"; echo \`echo "$hi"\``""")
|
||||
keys = "test" + EX
|
||||
wanted = "blah"
|
||||
|
||||
class TabStop_Shell_ShebangPython(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = ("test", """Hallo ${1:now `#!/usr/bin/env python
|
||||
print "Hallo Welt"
|
||||
`} end""")
|
||||
@ -1497,12 +1502,12 @@ class Transformation_CleverTransformLongLower_ExceptCorrectResult(_VimTest):
|
||||
wanted = "HALLO hallo"
|
||||
|
||||
class Transformation_SimpleCaseAsciiResult(_VimTest):
|
||||
skip_if = lambda self: NoUnidecodeAvailable()
|
||||
skip_if = lambda self: no_unidecode_available()
|
||||
snippets = ("ascii", "$1 ${1/(.*)/$1/a}")
|
||||
keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€"
|
||||
wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoiEEACOIEU"
|
||||
class Transformation_LowerCaseAsciiResult(_VimTest):
|
||||
skip_if = lambda self: NoUnidecodeAvailable()
|
||||
skip_if = lambda self: no_unidecode_available()
|
||||
snippets = ("ascii", "$1 ${1/(.*)/\L$1\E/a}")
|
||||
keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€"
|
||||
wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoieeacoieu"
|
||||
@ -1909,9 +1914,9 @@ class RecTabStops_MirroredZeroTS_ECR(_VimTest):
|
||||
keys = "m" + EX + "m1" + EX + "one" + JF + "two" + \
|
||||
JF + "three" + JF + "four" + JF + "end"
|
||||
wanted = "[ [ one three three two ] four ]end"
|
||||
class RecTabStops_ChildTriggerContainsParentTextObjects(_PS_Base):
|
||||
class RecTabStops_ChildTriggerContainsParentTextObjects(_VimTest):
|
||||
# https://bugs.launchpad.net/ultisnips/+bug/1191617
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
snippets_test_file = ("all", r"""
|
||||
global !p
|
||||
def complete(t, opts):
|
||||
if t:
|
||||
@ -2085,7 +2090,7 @@ class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand2(_VimTest):
|
||||
keys = "-test" + EX
|
||||
wanted = "-Expand me!"
|
||||
class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand3(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = (("test", "Expand me!", "", "i"), )
|
||||
keys = "ßßtest" + EX
|
||||
wanted = "ßßExpand me!"
|
||||
@ -2409,7 +2414,7 @@ class RecTabStopsWithExpandtab_SpecialIndentProblem_ECR(_ExpandTabs):
|
||||
# changes made 'manually', while the other vim version seem to do so. Since
|
||||
# the fault is not with UltiSnips, we simply skip this test on windows
|
||||
# completely.
|
||||
skip_if = lambda self: RunningOnWindows()
|
||||
skip_if = lambda self: running_on_windows()
|
||||
snippets = (
|
||||
("m1", "Something"),
|
||||
("m", "\t$0"),
|
||||
@ -2443,10 +2448,10 @@ class ProperIndenting_AutoIndentAndNewline_ECR(_VimTest):
|
||||
def _options_off(self):
|
||||
self.send(":set noautoindent\n")
|
||||
# Test for bug 1073816
|
||||
class ProperIndenting_FirstLineInFile_ECR(_PS_Base):
|
||||
class ProperIndenting_FirstLineInFile_ECR(_VimTest):
|
||||
text_before = ""
|
||||
text_after = ""
|
||||
snippets_test_file = ("all", "test_file", r"""
|
||||
snippets_test_file = ("all", r"""
|
||||
global !p
|
||||
def complete(t, opts):
|
||||
if t:
|
||||
@ -2565,7 +2570,7 @@ hi4Hello"""
|
||||
|
||||
# Test for bug 871357 #
|
||||
class TestLangmapWithUtf8_ExceptCorrectResult(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows() # SendKeys can't send UTF characters
|
||||
skip_if = lambda self: running_on_windows() # SendKeys can't send UTF characters
|
||||
snippets = ("testme",
|
||||
"""my snipped ${1:some_default}
|
||||
and a mirror: $1
|
||||
@ -2971,7 +2976,7 @@ class Snippet_With_DoubleQuote_List(_VimTest):
|
||||
# End: Quotes in Snippets #}}}
|
||||
# Umlauts and Special Chars {{{#
|
||||
class _UmlautsBase(_VimTest):
|
||||
skip_if = lambda self: RunningOnWindows() # SendKeys can't send UTF characters
|
||||
skip_if = lambda self: running_on_windows() # SendKeys can't send UTF characters
|
||||
|
||||
class Snippet_With_Umlauts_List(_UmlautsBase):
|
||||
snippets = _snip_quote('ü')
|
||||
|
Loading…
Reference in New Issue
Block a user