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
|
""" to explicitly check for the presence of the popup menu, and update
|
||||||
""" the vim-state accordingly.
|
""" the vim-state accordingly.
|
||||||
if pumvisible()
|
if pumvisible()
|
||||||
exec g:_uspy "UltiSnips_Manager.cursor_moved()"
|
exec g:_uspy "UltiSnips_Manager._cursor_moved()"
|
||||||
endif
|
endif
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@ -108,9 +108,9 @@ function! UltiSnips#Edit(...)
|
|||||||
if a:0 == 1 && a:1 != ''
|
if a:0 == 1 && a:1 != ''
|
||||||
let type = a:1
|
let type = a:1
|
||||||
else
|
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
|
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'
|
let mode = 'e'
|
||||||
if exists('g:UltiSnipsEditSplit')
|
if exists('g:UltiSnipsEditSplit')
|
||||||
@ -212,7 +212,7 @@ function! UltiSnips#SnippetsInCurrentScope()
|
|||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! UltiSnips#SaveLastVisualSelection()
|
function! UltiSnips#SaveLastVisualSelection()
|
||||||
exec g:_uspy "UltiSnips_Manager.save_last_visual_selection()"
|
exec g:_uspy "UltiSnips_Manager._save_last_visual_selection()"
|
||||||
return ""
|
return ""
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@ -257,15 +257,15 @@ endfunction
|
|||||||
|
|
||||||
|
|
||||||
function! UltiSnips#CursorMoved()
|
function! UltiSnips#CursorMoved()
|
||||||
exec g:_uspy "UltiSnips_Manager.cursor_moved()"
|
exec g:_uspy "UltiSnips_Manager._cursor_moved()"
|
||||||
endf
|
endf
|
||||||
|
|
||||||
function! UltiSnips#LeavingBuffer()
|
function! UltiSnips#LeavingBuffer()
|
||||||
exec g:_uspy "UltiSnips_Manager.leaving_buffer()"
|
exec g:_uspy "UltiSnips_Manager._leaving_buffer()"
|
||||||
endf
|
endf
|
||||||
|
|
||||||
function! UltiSnips#LeavingInsertMode()
|
function! UltiSnips#LeavingInsertMode()
|
||||||
exec g:_uspy "UltiSnips_Manager.leaving_insert_mode()"
|
exec g:_uspy "UltiSnips_Manager._leaving_insert_mode()"
|
||||||
endfunction
|
endfunction
|
||||||
" }}}
|
" }}}
|
||||||
|
|
||||||
|
@ -346,11 +346,6 @@ file: >
|
|||||||
" Traverse in reverse order
|
" Traverse in reverse order
|
||||||
let g:UltiSnipsDontReverseSearchPath="0"
|
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.
|
|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 hashlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def _hash_file(path):
|
def _hash_file(path):
|
||||||
"""Returns a hashdigest of 'path'"""
|
"""Returns a hashdigest of 'path'"""
|
||||||
if not os.path.isfile(path):
|
if not os.path.isfile(path):
|
||||||
return False
|
return False
|
||||||
return hashlib.sha1(open(path, "rb").read()).hexdigest()
|
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):
|
class SnippetDictionary(object):
|
||||||
"""See module docstring."""
|
"""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()
|
return before[len(before_words):].strip()
|
||||||
|
|
||||||
|
|
||||||
class Snippet(object):
|
class SnippetDefinition(object):
|
||||||
"""Represents a snippet as parsed from a file."""
|
"""Represents a snippet as parsed from a file."""
|
||||||
|
|
||||||
_INDENT = re.compile(r"^[ \t]*")
|
_INDENT = re.compile(r"^[ \t]*")
|
||||||
@ -49,7 +49,7 @@ class Snippet(object):
|
|||||||
self._globals = globals
|
self._globals = globals
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Snippet(%s,%s,%s)" % (
|
return "SnippetDefinition(%s,%s,%s)" % (
|
||||||
self._trigger, self._description, self._opts)
|
self._trigger, self._description, self._opts)
|
||||||
|
|
||||||
def _re_match(self, trigger):
|
def _re_match(self, trigger):
|
@ -5,17 +5,15 @@
|
|||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
import glob
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from UltiSnips._diff import diff, guess_edit
|
from UltiSnips._diff import diff, guess_edit
|
||||||
from UltiSnips.compatibility import as_unicode
|
from UltiSnips.compatibility import as_unicode
|
||||||
from UltiSnips.position import Position
|
from UltiSnips.position import Position
|
||||||
from UltiSnips.snippet import Snippet
|
from UltiSnips.providers import UltiSnipsFileProvider, \
|
||||||
from UltiSnips.snippet_definitions import parse_snippets_file
|
base_snippet_files_for, AddedSnippetsProvider
|
||||||
from UltiSnips.snippet_dictionary import SnippetDictionary
|
from UltiSnips.snippet_definition import SnippetDefinition
|
||||||
from UltiSnips.vim_state import VimState, VisualContentPreserver
|
from UltiSnips.vim_state import VimState, VisualContentPreserver
|
||||||
import UltiSnips._vim as _vim
|
import UltiSnips._vim as _vim
|
||||||
|
|
||||||
@ -40,86 +38,6 @@ def _ask_snippets(snippets):
|
|||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
return None
|
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):
|
def err_to_scratch_buffer(func):
|
||||||
"""Decorator that will catch any Exception that 'func' throws and displays
|
"""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:
|
Following is the full stack trace:
|
||||||
"""
|
"""
|
||||||
msg += traceback.format_exc()
|
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)
|
_vim.new_scratch_buffer(msg)
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
# TODO(sirver): This class has too many responsibilities - it should not also
|
# TODO(sirver): This class is still too long. It should only contain public
|
||||||
# care for the parsing and managing of parsed snippets.
|
# facing methods, most of the private methods should be moved outside of it.
|
||||||
class SnippetManager(object):
|
class SnippetManager(object):
|
||||||
"""The main entry point for all UltiSnips functionality. All Vim functions
|
"""The main entry point for all UltiSnips functionality. All Vim functions
|
||||||
call methods in this class."""
|
call methods in this class."""
|
||||||
@ -154,21 +73,7 @@ class SnippetManager(object):
|
|||||||
self.backward_trigger = backward_trigger
|
self.backward_trigger = backward_trigger
|
||||||
self._supertab_keys = None
|
self._supertab_keys = None
|
||||||
self._csnippets = []
|
self._csnippets = []
|
||||||
self.reset()
|
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()
|
|
||||||
|
|
||||||
@err_to_scratch_buffer
|
@err_to_scratch_buffer
|
||||||
def jump_forwards(self):
|
def jump_forwards(self):
|
||||||
@ -188,12 +93,28 @@ class SnippetManager(object):
|
|||||||
|
|
||||||
@err_to_scratch_buffer
|
@err_to_scratch_buffer
|
||||||
def expand(self):
|
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")
|
_vim.command("let g:ulti_expand_res = 1")
|
||||||
if not self._try_expand():
|
if not self._try_expand():
|
||||||
_vim.command("let g:ulti_expand_res = 0")
|
_vim.command("let g:ulti_expand_res = 0")
|
||||||
self._handle_failure(self.expand_trigger)
|
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
|
@err_to_scratch_buffer
|
||||||
def snippets_in_current_scope(self):
|
def snippets_in_current_scope(self):
|
||||||
"""Returns the snippets that could be expanded to Vim as a global
|
"""Returns the snippets that could be expanded to Vim as a global
|
||||||
@ -246,37 +167,12 @@ class SnippetManager(object):
|
|||||||
|
|
||||||
return True
|
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
|
@err_to_scratch_buffer
|
||||||
def add_snippet(self, trigger, value, description,
|
def add_snippet(self, trigger, value, description,
|
||||||
options, ft="all", globals=None, fn=None):
|
options, ft="all", globals=None, fn=None):
|
||||||
"""Add a snippet to the list of known snippets of the given 'ft'."""
|
"""Add a snippet to the list of known snippets of the given 'ft'."""
|
||||||
self._snippets[ft].add_snippet(
|
self._added_snippets_provider.add_snippet(ft, SnippetDefinition(
|
||||||
Snippet(trigger, value, description, options, globals or {}), fn
|
trigger, value, description, options, globals or {}), fn
|
||||||
)
|
)
|
||||||
|
|
||||||
@err_to_scratch_buffer
|
@err_to_scratch_buffer
|
||||||
@ -287,7 +183,7 @@ class SnippetManager(object):
|
|||||||
globals = {}
|
globals = {}
|
||||||
|
|
||||||
before = _vim.buf.line_till_cursor
|
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):
|
if not trigger or snip.matches(before):
|
||||||
self._do_snippet(snip, before)
|
self._do_snippet(snip, before)
|
||||||
@ -295,8 +191,28 @@ class SnippetManager(object):
|
|||||||
else:
|
else:
|
||||||
return False
|
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
|
@err_to_scratch_buffer
|
||||||
def cursor_moved(self):
|
def _cursor_moved(self):
|
||||||
"""Called whenever the cursor moved."""
|
"""Called whenever the cursor moved."""
|
||||||
self._vstate.remember_position()
|
self._vstate.remember_position()
|
||||||
if _vim.eval("mode()") not in 'in':
|
if _vim.eval("mode()") not in 'in':
|
||||||
@ -360,40 +276,40 @@ class SnippetManager(object):
|
|||||||
self._csnippets[0].update_textobjects()
|
self._csnippets[0].update_textobjects()
|
||||||
self._vstate.remember_buffer(self._csnippets[0])
|
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
|
"""Called when the user switches tabs/windows/buffers. It basically
|
||||||
means that all snippets must be properly terminated."""
|
means that all snippets must be properly terminated."""
|
||||||
while len(self._csnippets):
|
while len(self._csnippets):
|
||||||
self._current_snippet_is_done()
|
self._current_snippet_is_done()
|
||||||
self._reinit()
|
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):
|
def _reinit(self):
|
||||||
"""Resets transient state."""
|
"""Resets transient state."""
|
||||||
self._ctab = None
|
self._ctab = None
|
||||||
@ -440,7 +356,7 @@ class SnippetManager(object):
|
|||||||
self._ignore_movements = True
|
self._ignore_movements = True
|
||||||
return jumped
|
return jumped
|
||||||
|
|
||||||
def leaving_insert_mode(self):
|
def _leaving_insert_mode(self):
|
||||||
"""Called whenever we leave the insert mode."""
|
"""Called whenever we leave the insert mode."""
|
||||||
self._vstate.restore_unnamed_register()
|
self._vstate.restore_unnamed_register()
|
||||||
|
|
||||||
@ -484,28 +400,10 @@ class SnippetManager(object):
|
|||||||
before the cursor. If possible is True, then get all
|
before the cursor. If possible is True, then get all
|
||||||
possible matches.
|
possible matches.
|
||||||
"""
|
"""
|
||||||
self._ensure_all_loaded()
|
|
||||||
filetypes = self._filetypes[_vim.buf.number][::-1]
|
filetypes = self._filetypes[_vim.buf.number][::-1]
|
||||||
|
snippets = []
|
||||||
found_snippets = []
|
for provider in self._snippet_providers:
|
||||||
for ft in filetypes:
|
snippets.extend(provider.get_snippets(filetypes, before, possible))
|
||||||
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
|
return snippets
|
||||||
|
|
||||||
def _do_snippet(self, snippet, before):
|
def _do_snippet(self, snippet, before):
|
||||||
@ -574,39 +472,15 @@ class SnippetManager(object):
|
|||||||
return None
|
return None
|
||||||
return self._csnippets[-1]
|
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
|
@property
|
||||||
def primary_filetype(self):
|
def _primary_filetype(self):
|
||||||
"""This filetype will be edited when UltiSnipsEdit is called without
|
"""This filetype will be edited when UltiSnipsEdit is called without
|
||||||
any arguments."""
|
any arguments."""
|
||||||
return self._filetypes[_vim.buf.number][0]
|
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.
|
""" Gets a file to edit based on the given filetype.
|
||||||
If no filetype is given, uses the current filetype from Vim.
|
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
|
# 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.
|
# therefore in this class because it is the facade to Vim.
|
||||||
edit = None
|
edit = None
|
||||||
existing = _base_snippet_files_for(ft, False)
|
existing = base_snippet_files_for(ft, False)
|
||||||
filename = ft + ".snippets"
|
filename = ft + ".snippets"
|
||||||
|
|
||||||
if _vim.eval("exists('g:UltiSnipsSnippetsDir')") == "1":
|
if _vim.eval("exists('g:UltiSnipsSnippetsDir')") == "1":
|
||||||
@ -644,95 +518,3 @@ class SnippetManager(object):
|
|||||||
|
|
||||||
edit = os.path.join(path, filename)
|
edit = os.path.join(path, filename)
|
||||||
return edit
|
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
|
# pylint: skip-file
|
||||||
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
import unittest
|
|
||||||
import time
|
|
||||||
import re
|
|
||||||
import platform
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from textwrap import dedent
|
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:
|
try:
|
||||||
import unidecode
|
import unidecode
|
||||||
@ -66,20 +68,21 @@ LS = "@" # List snippets
|
|||||||
EX = "\t" # EXPAND
|
EX = "\t" # EXPAND
|
||||||
EA = "#" # Expand anonymous
|
EA = "#" # Expand anonymous
|
||||||
|
|
||||||
# Some VIM functions
|
|
||||||
COMPL_KW = chr(24)+chr(14)
|
COMPL_KW = chr(24)+chr(14)
|
||||||
COMPL_ACCEPT = chr(25)
|
COMPL_ACCEPT = chr(25)
|
||||||
|
|
||||||
NUMBER_OF_RETRIES_FOR_EACH_TEST = 4
|
NUMBER_OF_RETRIES_FOR_EACH_TEST = 4
|
||||||
|
|
||||||
def RunningOnWindows():
|
def running_on_windows():
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
return "Does not work on Windows."
|
return "Does not work on Windows."
|
||||||
|
|
||||||
def NoUnidecodeAvailable():
|
def no_unidecode_available():
|
||||||
if not UNIDECODE_IMPORTED:
|
if not UNIDECODE_IMPORTED:
|
||||||
return "unidecode is not available."
|
return "unidecode is not available."
|
||||||
|
|
||||||
|
def random_string(n):
|
||||||
|
return ''.join(random.choice(string.ascii_lowercase) for x in range(n))
|
||||||
|
|
||||||
class VimInterface:
|
class VimInterface:
|
||||||
def focus(title=None):
|
def focus(title=None):
|
||||||
@ -220,7 +223,7 @@ class VimInterfaceWindows(VimInterface):
|
|||||||
|
|
||||||
class _VimTest(unittest.TestCase):
|
class _VimTest(unittest.TestCase):
|
||||||
snippets = ("dummy", "donotdefine")
|
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_before = " --- some text before --- \n\n"
|
||||||
text_after = "\n\n --- some text after --- "
|
text_after = "\n\n --- some text after --- "
|
||||||
expected_error = ""
|
expected_error = ""
|
||||||
@ -256,7 +259,8 @@ class _VimTest(unittest.TestCase):
|
|||||||
def check_output(self):
|
def check_output(self):
|
||||||
wanted = self.text_before + self.wanted + self.text_after
|
wanted = self.text_before + self.wanted + self.text_after
|
||||||
if self.expected_error:
|
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):
|
for i in range(NUMBER_OF_RETRIES_FOR_EACH_TEST):
|
||||||
if self.output != wanted:
|
if self.output != wanted:
|
||||||
# Redo this, but slower
|
# Redo this, but slower
|
||||||
@ -273,6 +277,18 @@ class _VimTest(unittest.TestCase):
|
|||||||
def _options_off(self):
|
def _options_off(self):
|
||||||
pass
|
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):
|
def setUp(self):
|
||||||
reason_for_skipping = self.skip_if()
|
reason_for_skipping = self.skip_if()
|
||||||
if reason_for_skipping is not None:
|
if reason_for_skipping is not None:
|
||||||
@ -285,9 +301,9 @@ class _VimTest(unittest.TestCase):
|
|||||||
self.send(":silent! close\n")
|
self.send(":silent! close\n")
|
||||||
|
|
||||||
# Reset UltiSnips
|
# 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")
|
self.send(":let g:UltiSnipsSnippetDirectories=['<un_def_ined>']\n")
|
||||||
|
|
||||||
# Clear the buffer
|
# Clear the buffer
|
||||||
@ -308,10 +324,10 @@ class _VimTest(unittest.TestCase):
|
|||||||
self.send_py("UltiSnips_Manager.add_snippet(%r, %r, %r, %r)" %
|
self.send_py("UltiSnips_Manager.add_snippet(%r, %r, %r, %r)" %
|
||||||
(sv, content, description, options))
|
(sv, content, description, options))
|
||||||
|
|
||||||
ft, fn, file_data = self.snippets_test_file
|
ft, file_data = self.snippets_test_file
|
||||||
|
self._temporary_directory = ""
|
||||||
if ft:
|
if ft:
|
||||||
self.send_py("UltiSnips_Manager._parse_snippets(%r, %r, %r)" %
|
self._create_snippet_file(ft, file_data)
|
||||||
(ft, fn, dedent(file_data + '\n')))
|
|
||||||
|
|
||||||
if not self.interrupt:
|
if not self.interrupt:
|
||||||
# Enter insert mode
|
# Enter insert mode
|
||||||
@ -336,18 +352,17 @@ class _VimTest(unittest.TestCase):
|
|||||||
|
|
||||||
self.output = self.vim.get_buffer_data()
|
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 #
|
# BEGINNING OF TEST #
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Snippet Definition Parsing {{{#
|
# Snippet Definition Parsing {{{#
|
||||||
class _PS_Base(_VimTest):
|
class ParseSnippets_SimpleSnippet(_VimTest):
|
||||||
def _options_on(self):
|
snippets_test_file = ("all", r"""
|
||||||
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"""
|
|
||||||
snippet testsnip "Test Snippet" b!
|
snippet testsnip "Test Snippet" b!
|
||||||
This is a test snippet!
|
This is a test snippet!
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -355,39 +370,33 @@ class ParseSnippets_SimpleSnippet(_PS_Base):
|
|||||||
keys = "testsnip" + EX
|
keys = "testsnip" + EX
|
||||||
wanted = "This is a test snippet!"
|
wanted = "This is a test snippet!"
|
||||||
|
|
||||||
class ParseSnippets_MissingEndSnippet(_PS_Base):
|
class ParseSnippets_MissingEndSnippet(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet testsnip "Test Snippet" b!
|
snippet testsnip "Test Snippet" b!
|
||||||
This is a test snippet!
|
This is a test snippet!
|
||||||
""")
|
""")
|
||||||
keys = "testsnip" + EX
|
keys = "testsnip" + EX
|
||||||
wanted = "testsnip" + EX
|
wanted = "testsnip" + EX
|
||||||
expected_error = dedent("""
|
expected_error = r"Missing 'endsnippet' for 'testsnip' in \S+:4"
|
||||||
UltiSnips: Missing 'endsnippet' for 'testsnip' in test_file(4)
|
|
||||||
""").strip()
|
|
||||||
|
|
||||||
class ParseSnippets_UnknownDirective(_PS_Base):
|
class ParseSnippets_UnknownDirective(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
unknown directive
|
unknown directive
|
||||||
""")
|
""")
|
||||||
keys = "testsnip" + EX
|
keys = "testsnip" + EX
|
||||||
wanted = "testsnip" + EX
|
wanted = "testsnip" + EX
|
||||||
expected_error = dedent("""
|
expected_error = r"Invalid line 'unknown directive' in \S+:2"
|
||||||
UltiSnips: Invalid line 'unknown directive' in test_file(2)
|
|
||||||
""").strip()
|
|
||||||
|
|
||||||
class ParseSnippets_ExtendsWithoutFiletype(_PS_Base):
|
class ParseSnippets_ExtendsWithoutFiletype(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
extends
|
extends
|
||||||
""")
|
""")
|
||||||
keys = "testsnip" + EX
|
keys = "testsnip" + EX
|
||||||
wanted = "testsnip" + EX
|
wanted = "testsnip" + EX
|
||||||
expected_error = dedent("""
|
expected_error = r"'extends' without file types in \S+:2"
|
||||||
UltiSnips: 'extends' without file types in test_file(2)
|
|
||||||
""").strip()
|
|
||||||
|
|
||||||
class ParseSnippets_ClearAll(_PS_Base):
|
class ParseSnippets_ClearAll(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet testsnip "Test snippet"
|
snippet testsnip "Test snippet"
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -397,8 +406,8 @@ class ParseSnippets_ClearAll(_PS_Base):
|
|||||||
keys = "testsnip" + EX
|
keys = "testsnip" + EX
|
||||||
wanted = "testsnip" + EX
|
wanted = "testsnip" + EX
|
||||||
|
|
||||||
class ParseSnippets_ClearOne(_PS_Base):
|
class ParseSnippets_ClearOne(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet testsnip "Test snippet"
|
snippet testsnip "Test snippet"
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -412,8 +421,8 @@ class ParseSnippets_ClearOne(_PS_Base):
|
|||||||
keys = "toclear" + EX + "\n" + "testsnip" + EX
|
keys = "toclear" + EX + "\n" + "testsnip" + EX
|
||||||
wanted = "toclear" + EX + "\n" + "This is a test."
|
wanted = "toclear" + EX + "\n" + "This is a test."
|
||||||
|
|
||||||
class ParseSnippets_ClearTwo(_PS_Base):
|
class ParseSnippets_ClearTwo(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet testsnip "Test snippet"
|
snippet testsnip "Test snippet"
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -428,8 +437,8 @@ class ParseSnippets_ClearTwo(_PS_Base):
|
|||||||
wanted = "toclear" + EX + "\n" + "testsnip" + EX
|
wanted = "toclear" + EX + "\n" + "testsnip" + EX
|
||||||
|
|
||||||
|
|
||||||
class _ParseSnippets_MultiWord(_PS_Base):
|
class _ParseSnippets_MultiWord(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet /test snip/
|
snippet /test snip/
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -452,8 +461,8 @@ class ParseSnippets_MultiWord_Description_Option(_ParseSnippets_MultiWord):
|
|||||||
keys = "snippet test" + EX
|
keys = "snippet test" + EX
|
||||||
wanted = "This is yet another test."
|
wanted = "This is yet another test."
|
||||||
|
|
||||||
class _ParseSnippets_MultiWord_RE(_PS_Base):
|
class _ParseSnippets_MultiWord_RE(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet /[d-f]+/ "" r
|
snippet /[d-f]+/ "" r
|
||||||
az test
|
az test
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -476,16 +485,16 @@ class ParseSnippets_MultiWord_RE3(_ParseSnippets_MultiWord_RE):
|
|||||||
keys = "test test test" + EX
|
keys = "test test test" + EX
|
||||||
wanted = "re-test"
|
wanted = "re-test"
|
||||||
|
|
||||||
class ParseSnippets_MultiWord_Quotes(_PS_Base):
|
class ParseSnippets_MultiWord_Quotes(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet "test snip"
|
snippet "test snip"
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
""")
|
""")
|
||||||
keys = "test snip" + EX
|
keys = "test snip" + EX
|
||||||
wanted = "This is a test."
|
wanted = "This is a test."
|
||||||
class ParseSnippets_MultiWord_WithQuotes(_PS_Base):
|
class ParseSnippets_MultiWord_WithQuotes(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet !"test snip"!
|
snippet !"test snip"!
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
@ -493,32 +502,28 @@ class ParseSnippets_MultiWord_WithQuotes(_PS_Base):
|
|||||||
keys = '"test snip"' + EX
|
keys = '"test snip"' + EX
|
||||||
wanted = "This is a test."
|
wanted = "This is a test."
|
||||||
|
|
||||||
class ParseSnippets_MultiWord_NoContainer(_PS_Base):
|
class ParseSnippets_MultiWord_NoContainer(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet test snip
|
snippet test snip
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
""")
|
""")
|
||||||
keys = "test snip" + EX
|
keys = "test snip" + EX
|
||||||
wanted = keys
|
wanted = keys
|
||||||
expected_error = dedent("""
|
expected_error = "Invalid multiword trigger: 'test snip' in \S+:2"
|
||||||
UltiSnips: Invalid multiword trigger: 'test snip' in test_file(2)
|
|
||||||
""").strip()
|
|
||||||
|
|
||||||
class ParseSnippets_MultiWord_UnmatchedContainer(_PS_Base):
|
class ParseSnippets_MultiWord_UnmatchedContainer(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
snippet !inv snip/
|
snippet !inv snip/
|
||||||
This is a test.
|
This is a test.
|
||||||
endsnippet
|
endsnippet
|
||||||
""")
|
""")
|
||||||
keys = "inv snip" + EX
|
keys = "inv snip" + EX
|
||||||
wanted = keys
|
wanted = keys
|
||||||
expected_error = dedent("""
|
expected_error = "Invalid multiword trigger: '!inv snip/' in \S+:2"
|
||||||
UltiSnips: Invalid multiword trigger: '!inv snip/' in test_file(2)
|
|
||||||
""").strip()
|
|
||||||
|
|
||||||
class ParseSnippets_Global_Python(_PS_Base):
|
class ParseSnippets_Global_Python(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
global !p
|
global !p
|
||||||
def tex(ins):
|
def tex(ins):
|
||||||
return "a " + ins + " b"
|
return "a " + ins + " b"
|
||||||
@ -535,8 +540,8 @@ class ParseSnippets_Global_Python(_PS_Base):
|
|||||||
keys = "ab" + EX + "\nac" + EX
|
keys = "ab" + EX + "\nac" + EX
|
||||||
wanted = "x a bob b y\nx a jon b y"
|
wanted = "x a bob b y\nx a jon b y"
|
||||||
|
|
||||||
class ParseSnippets_Global_Local_Python(_PS_Base):
|
class ParseSnippets_Global_Local_Python(_VimTest):
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
global !p
|
global !p
|
||||||
def tex(ins):
|
def tex(ins):
|
||||||
return "a " + ins + " b"
|
return "a " + ins + " b"
|
||||||
@ -855,43 +860,43 @@ class TabStopNavigatingInInsertModeSimple_ExceptCorrectResult(_VimTest):
|
|||||||
# End: TabStop Tests #}}}
|
# End: TabStop Tests #}}}
|
||||||
# ShellCode Interpolation {{{#
|
# ShellCode Interpolation {{{#
|
||||||
class TabStop_Shell_SimpleExample(_VimTest):
|
class TabStop_Shell_SimpleExample(_VimTest):
|
||||||
skip_if = lambda self: RunningOnWindows()
|
skip_if = lambda self: running_on_windows()
|
||||||
snippets = ("test", "hi `echo hallo` you!")
|
snippets = ("test", "hi `echo hallo` you!")
|
||||||
keys = "test" + EX + "and more"
|
keys = "test" + EX + "and more"
|
||||||
wanted = "hi hallo you!and more"
|
wanted = "hi hallo you!and more"
|
||||||
class TabStop_Shell_WithUmlauts(_VimTest):
|
class TabStop_Shell_WithUmlauts(_VimTest):
|
||||||
skip_if = lambda self: RunningOnWindows()
|
skip_if = lambda self: running_on_windows()
|
||||||
snippets = ("test", "hi `echo höüäh` you!")
|
snippets = ("test", "hi `echo höüäh` you!")
|
||||||
keys = "test" + EX + "and more"
|
keys = "test" + EX + "and more"
|
||||||
wanted = "hi höüäh you!and more"
|
wanted = "hi höüäh you!and more"
|
||||||
class TabStop_Shell_TextInNextLine(_VimTest):
|
class TabStop_Shell_TextInNextLine(_VimTest):
|
||||||
skip_if = lambda self: RunningOnWindows()
|
skip_if = lambda self: running_on_windows()
|
||||||
snippets = ("test", "hi `echo hallo`\nWeiter")
|
snippets = ("test", "hi `echo hallo`\nWeiter")
|
||||||
keys = "test" + EX + "and more"
|
keys = "test" + EX + "and more"
|
||||||
wanted = "hi hallo\nWeiterand more"
|
wanted = "hi hallo\nWeiterand more"
|
||||||
class TabStop_Shell_InDefValue_Leave(_VimTest):
|
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")
|
snippets = ("test", "Hallo ${1:now `echo fromecho`} end")
|
||||||
keys = "test" + EX + JF + "and more"
|
keys = "test" + EX + JF + "and more"
|
||||||
wanted = "Hallo now fromecho endand more"
|
wanted = "Hallo now fromecho endand more"
|
||||||
class TabStop_Shell_InDefValue_Overwrite(_VimTest):
|
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")
|
snippets = ("test", "Hallo ${1:now `echo fromecho`} end")
|
||||||
keys = "test" + EX + "overwrite" + JF + "and more"
|
keys = "test" + EX + "overwrite" + JF + "and more"
|
||||||
wanted = "Hallo overwrite endand more"
|
wanted = "Hallo overwrite endand more"
|
||||||
class TabStop_Shell_TestEscapedChars_Overwrite(_VimTest):
|
class TabStop_Shell_TestEscapedChars_Overwrite(_VimTest):
|
||||||
skip_if = lambda self: RunningOnWindows()
|
skip_if = lambda self: running_on_windows()
|
||||||
snippets = ("test", r"""`echo \`echo "\\$hi"\``""")
|
snippets = ("test", r"""`echo \`echo "\\$hi"\``""")
|
||||||
keys = "test" + EX
|
keys = "test" + EX
|
||||||
wanted = "$hi"
|
wanted = "$hi"
|
||||||
class TabStop_Shell_TestEscapedCharsAndShellVars_Overwrite(_VimTest):
|
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"\``""")
|
snippets = ("test", r"""`hi="blah"; echo \`echo "$hi"\``""")
|
||||||
keys = "test" + EX
|
keys = "test" + EX
|
||||||
wanted = "blah"
|
wanted = "blah"
|
||||||
|
|
||||||
class TabStop_Shell_ShebangPython(_VimTest):
|
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
|
snippets = ("test", """Hallo ${1:now `#!/usr/bin/env python
|
||||||
print "Hallo Welt"
|
print "Hallo Welt"
|
||||||
`} end""")
|
`} end""")
|
||||||
@ -1497,12 +1502,12 @@ class Transformation_CleverTransformLongLower_ExceptCorrectResult(_VimTest):
|
|||||||
wanted = "HALLO hallo"
|
wanted = "HALLO hallo"
|
||||||
|
|
||||||
class Transformation_SimpleCaseAsciiResult(_VimTest):
|
class Transformation_SimpleCaseAsciiResult(_VimTest):
|
||||||
skip_if = lambda self: NoUnidecodeAvailable()
|
skip_if = lambda self: no_unidecode_available()
|
||||||
snippets = ("ascii", "$1 ${1/(.*)/$1/a}")
|
snippets = ("ascii", "$1 ${1/(.*)/$1/a}")
|
||||||
keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€"
|
keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€"
|
||||||
wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoiEEACOIEU"
|
wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoiEEACOIEU"
|
||||||
class Transformation_LowerCaseAsciiResult(_VimTest):
|
class Transformation_LowerCaseAsciiResult(_VimTest):
|
||||||
skip_if = lambda self: NoUnidecodeAvailable()
|
skip_if = lambda self: no_unidecode_available()
|
||||||
snippets = ("ascii", "$1 ${1/(.*)/\L$1\E/a}")
|
snippets = ("ascii", "$1 ${1/(.*)/\L$1\E/a}")
|
||||||
keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€"
|
keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€"
|
||||||
wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoieeacoieu"
|
wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoieeacoieu"
|
||||||
@ -1909,9 +1914,9 @@ class RecTabStops_MirroredZeroTS_ECR(_VimTest):
|
|||||||
keys = "m" + EX + "m1" + EX + "one" + JF + "two" + \
|
keys = "m" + EX + "m1" + EX + "one" + JF + "two" + \
|
||||||
JF + "three" + JF + "four" + JF + "end"
|
JF + "three" + JF + "four" + JF + "end"
|
||||||
wanted = "[ [ one three three two ] four ]end"
|
wanted = "[ [ one three three two ] four ]end"
|
||||||
class RecTabStops_ChildTriggerContainsParentTextObjects(_PS_Base):
|
class RecTabStops_ChildTriggerContainsParentTextObjects(_VimTest):
|
||||||
# https://bugs.launchpad.net/ultisnips/+bug/1191617
|
# https://bugs.launchpad.net/ultisnips/+bug/1191617
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
global !p
|
global !p
|
||||||
def complete(t, opts):
|
def complete(t, opts):
|
||||||
if t:
|
if t:
|
||||||
@ -2085,7 +2090,7 @@ class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand2(_VimTest):
|
|||||||
keys = "-test" + EX
|
keys = "-test" + EX
|
||||||
wanted = "-Expand me!"
|
wanted = "-Expand me!"
|
||||||
class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand3(_VimTest):
|
class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand3(_VimTest):
|
||||||
skip_if = lambda self: RunningOnWindows()
|
skip_if = lambda self: running_on_windows()
|
||||||
snippets = (("test", "Expand me!", "", "i"), )
|
snippets = (("test", "Expand me!", "", "i"), )
|
||||||
keys = "ßßtest" + EX
|
keys = "ßßtest" + EX
|
||||||
wanted = "ßßExpand me!"
|
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
|
# 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
|
# the fault is not with UltiSnips, we simply skip this test on windows
|
||||||
# completely.
|
# completely.
|
||||||
skip_if = lambda self: RunningOnWindows()
|
skip_if = lambda self: running_on_windows()
|
||||||
snippets = (
|
snippets = (
|
||||||
("m1", "Something"),
|
("m1", "Something"),
|
||||||
("m", "\t$0"),
|
("m", "\t$0"),
|
||||||
@ -2443,10 +2448,10 @@ class ProperIndenting_AutoIndentAndNewline_ECR(_VimTest):
|
|||||||
def _options_off(self):
|
def _options_off(self):
|
||||||
self.send(":set noautoindent\n")
|
self.send(":set noautoindent\n")
|
||||||
# Test for bug 1073816
|
# Test for bug 1073816
|
||||||
class ProperIndenting_FirstLineInFile_ECR(_PS_Base):
|
class ProperIndenting_FirstLineInFile_ECR(_VimTest):
|
||||||
text_before = ""
|
text_before = ""
|
||||||
text_after = ""
|
text_after = ""
|
||||||
snippets_test_file = ("all", "test_file", r"""
|
snippets_test_file = ("all", r"""
|
||||||
global !p
|
global !p
|
||||||
def complete(t, opts):
|
def complete(t, opts):
|
||||||
if t:
|
if t:
|
||||||
@ -2565,7 +2570,7 @@ hi4Hello"""
|
|||||||
|
|
||||||
# Test for bug 871357 #
|
# Test for bug 871357 #
|
||||||
class TestLangmapWithUtf8_ExceptCorrectResult(_VimTest):
|
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",
|
snippets = ("testme",
|
||||||
"""my snipped ${1:some_default}
|
"""my snipped ${1:some_default}
|
||||||
and a mirror: $1
|
and a mirror: $1
|
||||||
@ -2971,7 +2976,7 @@ class Snippet_With_DoubleQuote_List(_VimTest):
|
|||||||
# End: Quotes in Snippets #}}}
|
# End: Quotes in Snippets #}}}
|
||||||
# Umlauts and Special Chars {{{#
|
# Umlauts and Special Chars {{{#
|
||||||
class _UmlautsBase(_VimTest):
|
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):
|
class Snippet_With_Umlauts_List(_UmlautsBase):
|
||||||
snippets = _snip_quote('ü')
|
snippets = _snip_quote('ü')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user