More linting and refactorings mainly in _transformation.py.
This commit is contained in:
parent
63021206cd
commit
c67a59f579
2
pylintrc
2
pylintrc
@ -55,7 +55,7 @@ disable=
|
|||||||
output-format=text
|
output-format=text
|
||||||
|
|
||||||
# Tells whether to display a full report or only the messages
|
# Tells whether to display a full report or only the messages
|
||||||
reports=no
|
reports=yes
|
||||||
|
|
||||||
|
|
||||||
[BASIC]
|
[BASIC]
|
||||||
|
@ -12,7 +12,7 @@ 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.geometry import Position
|
from UltiSnips.position import Position
|
||||||
from UltiSnips.snippet import Snippet
|
from UltiSnips.snippet import Snippet
|
||||||
from UltiSnips.snippet_dictionary import SnippetDictionary
|
from UltiSnips.snippet_dictionary import SnippetDictionary
|
||||||
from UltiSnips.snippets_file_parser import SnippetsFileParser
|
from UltiSnips.snippets_file_parser import SnippetsFileParser
|
||||||
@ -155,7 +155,6 @@ 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
|
@err_to_scratch_buffer
|
||||||
@ -163,7 +162,7 @@ class SnippetManager(object):
|
|||||||
"""Reset the class to the state it had directly after creation."""
|
"""Reset the class to the state it had directly after creation."""
|
||||||
self._vstate = VimState()
|
self._vstate = VimState()
|
||||||
self._test_error = test_error
|
self._test_error = test_error
|
||||||
self._snippets = {}
|
self._snippets = defaultdict(lambda: SnippetDictionary())
|
||||||
self._filetypes = defaultdict(lambda: ['all'])
|
self._filetypes = defaultdict(lambda: ['all'])
|
||||||
self._visual_content = VisualContentPreserver()
|
self._visual_content = VisualContentPreserver()
|
||||||
|
|
||||||
@ -277,27 +276,14 @@ class SnippetManager(object):
|
|||||||
"""
|
"""
|
||||||
self._visual_content.conserve()
|
self._visual_content.conserve()
|
||||||
|
|
||||||
# TODO(sirver): replace through defaultdict
|
|
||||||
def snippet_dict(self, ft):
|
|
||||||
"""Makes sure that ft is in self._snippets."""
|
|
||||||
if ft not in self._snippets:
|
|
||||||
self._snippets[ft] = SnippetDictionary()
|
|
||||||
return self._snippets[ft]
|
|
||||||
|
|
||||||
@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.snippet_dict(ft).add_snippet(
|
self._snippets[ft].add_snippet(
|
||||||
Snippet(trigger, value, description, options, globals or {}), fn
|
Snippet(trigger, value, description, options, globals or {}), fn
|
||||||
)
|
)
|
||||||
|
|
||||||
@err_to_scratch_buffer
|
|
||||||
def add_snippet_file(self, ft, path):
|
|
||||||
"""Add a file to be watched for changes to the 'ft' snippet dict."""
|
|
||||||
sd = self.snippet_dict(ft)
|
|
||||||
sd.addfile(path)
|
|
||||||
|
|
||||||
@err_to_scratch_buffer
|
@err_to_scratch_buffer
|
||||||
def expand_anon(self, value, trigger="", description="",
|
def expand_anon(self, value, trigger="", description="",
|
||||||
options="", globals=None):
|
options="", globals=None):
|
||||||
@ -326,7 +312,7 @@ class SnippetManager(object):
|
|||||||
@err_to_scratch_buffer
|
@err_to_scratch_buffer
|
||||||
def add_extending_info(self, ft, parents):
|
def add_extending_info(self, ft, parents):
|
||||||
"""Add the list of 'parents' as being extended by the 'ft'."""
|
"""Add the list of 'parents' as being extended by the 'ft'."""
|
||||||
sd = self.snippet_dict(ft)
|
sd = self._snippets[ft]
|
||||||
for parent in parents:
|
for parent in parents:
|
||||||
if parent in sd.extends:
|
if parent in sd.extends:
|
||||||
continue
|
continue
|
||||||
@ -616,8 +602,9 @@ class SnippetManager(object):
|
|||||||
return self._csnippets[-1]
|
return self._csnippets[-1]
|
||||||
|
|
||||||
def _parse_snippets(self, ft, filename, file_data=None):
|
def _parse_snippets(self, ft, filename, file_data=None):
|
||||||
"""Parse the file 'filename' for the given 'ft'."""
|
"""Parse the file 'filename' for the given 'ft' and watch it for
|
||||||
self.add_snippet_file(ft, filename)
|
changes in the future."""
|
||||||
|
self._snippets[ft].addfile(filename)
|
||||||
SnippetsFileParser(ft, filename, self, file_data).parse()
|
SnippetsFileParser(ft, filename, self, file_data).parse()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -667,7 +654,7 @@ class SnippetManager(object):
|
|||||||
|
|
||||||
def _load_snippets_for(self, ft):
|
def _load_snippets_for(self, ft):
|
||||||
"""Load all snippets for the given 'ft'."""
|
"""Load all snippets for the given 'ft'."""
|
||||||
self.snippet_dict(ft).reset()
|
del self._snippets[ft]
|
||||||
for fn in _base_snippet_files_for(ft):
|
for fn in _base_snippet_files_for(ft):
|
||||||
self._parse_snippets(ft, fn)
|
self._parse_snippets(ft, fn)
|
||||||
# Now load for the parents
|
# Now load for the parents
|
||||||
@ -683,11 +670,11 @@ class SnippetManager(object):
|
|||||||
|
|
||||||
if ft not in self._snippets:
|
if ft not in self._snippets:
|
||||||
return True
|
return True
|
||||||
elif do_hash and self.snippet_dict(ft).needs_update():
|
elif do_hash and self._snippets[ft].has_any_file_changed():
|
||||||
return True
|
return True
|
||||||
elif do_hash:
|
elif do_hash:
|
||||||
cur_snips = set(_base_snippet_files_for(ft))
|
cur_snips = set(_base_snippet_files_for(ft))
|
||||||
old_snips = set(self.snippet_dict(ft).files)
|
old_snips = set(self._snippets[ft].files)
|
||||||
if cur_snips - old_snips:
|
if cur_snips - old_snips:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -705,7 +692,7 @@ class SnippetManager(object):
|
|||||||
if self._needs_update(ft):
|
if self._needs_update(ft):
|
||||||
self._load_snippets_for(ft)
|
self._load_snippets_for(ft)
|
||||||
|
|
||||||
for parent in self.snippet_dict(ft).extends:
|
for parent in self._snippets[ft].extends:
|
||||||
self._ensure_loaded(parent, checked)
|
self._ensure_loaded(parent, checked)
|
||||||
|
|
||||||
def _ensure_all_loaded(self):
|
def _ensure_all_loaded(self):
|
||||||
@ -746,12 +733,12 @@ class SnippetManager(object):
|
|||||||
if not snips:
|
if not snips:
|
||||||
return []
|
return []
|
||||||
if not seen:
|
if not seen:
|
||||||
seen = []
|
seen = set()
|
||||||
seen.append(ft)
|
seen.add(ft)
|
||||||
parent_results = []
|
parent_results = []
|
||||||
for parent_ft in snips.extends:
|
for parent_ft in snips.extends:
|
||||||
if parent_ft not in seen:
|
if parent_ft not in seen:
|
||||||
seen.append(parent_ft)
|
seen.add(parent_ft)
|
||||||
parent_results += self._find_snippets(parent_ft, trigger,
|
parent_results += self._find_snippets(parent_ft, trigger,
|
||||||
potentially, seen)
|
potentially, seen)
|
||||||
return parent_results + snips.get_matching_snippets(
|
return parent_results + snips.get_matching_snippets(
|
||||||
|
@ -5,7 +5,7 @@ from collections import defaultdict
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from UltiSnips import _vim
|
from UltiSnips import _vim
|
||||||
from UltiSnips.geometry import Position
|
from UltiSnips.position import Position
|
||||||
|
|
||||||
def is_complete_edit(initial_line, a, b, cmds):
|
def is_complete_edit(initial_line, a, b, cmds):
|
||||||
buf = a[:]
|
buf = a[:]
|
||||||
@ -171,4 +171,3 @@ def diff(a, b, sline = 0):
|
|||||||
(("D",line, col, a[x]),) )
|
(("D",line, col, a[x]),) )
|
||||||
)
|
)
|
||||||
cost += 1
|
cost += 1
|
||||||
|
|
||||||
|
@ -8,9 +8,9 @@ import re
|
|||||||
import vim # pylint:disable=import-error
|
import vim # pylint:disable=import-error
|
||||||
from vim import error # pylint:disable=import-error,unused-import
|
from vim import error # pylint:disable=import-error,unused-import
|
||||||
|
|
||||||
from UltiSnips.geometry import Position
|
|
||||||
from UltiSnips.compatibility import col2byte, byte2col, \
|
from UltiSnips.compatibility import col2byte, byte2col, \
|
||||||
as_unicode, as_vimencoding
|
as_unicode, as_vimencoding
|
||||||
|
from UltiSnips.position import Position
|
||||||
|
|
||||||
class VimBuffer(object):
|
class VimBuffer(object):
|
||||||
"""Wrapper around the current Vim buffer."""
|
"""Wrapper around the current Vim buffer."""
|
||||||
|
@ -1,36 +1,43 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
|
"""Convenience methods that help with debugging. They should never be used in
|
||||||
|
production code."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from UltiSnips.compatibility import as_unicode
|
from UltiSnips.compatibility import as_unicode
|
||||||
|
|
||||||
dump_filename = "/tmp/file.txt" if not sys.platform.lower().startswith("win") \
|
DUMP_FILENAME = "/tmp/file.txt" if not sys.platform.lower().startswith("win") \
|
||||||
else "C:/windows/temp/ultisnips.txt"
|
else "C:/windows/temp/ultisnips.txt"
|
||||||
with open(dump_filename, "w") as dump_file:
|
with open(DUMP_FILENAME, "w"):
|
||||||
pass # clears the file
|
pass # clears the file
|
||||||
|
|
||||||
def echo_to_hierarchy(to):
|
def echo_to_hierarchy(text_object):
|
||||||
par = to
|
"""Outputs the given 'text_object' and its childs hierarchically."""
|
||||||
while par._parent: par = par._parent
|
# pylint:disable=protected-access
|
||||||
|
parent = text_object
|
||||||
def _do_print(to, indent=""):
|
while parent._parent:
|
||||||
debug(indent + as_unicode(to))
|
parent = parent._parent
|
||||||
|
|
||||||
|
def _do_print(text_object, indent=""):
|
||||||
|
"""prints recursively."""
|
||||||
|
debug(indent + as_unicode(text_object))
|
||||||
try:
|
try:
|
||||||
for c in to._childs:
|
for child in text_object._childs:
|
||||||
_do_print(c, indent=indent + " ")
|
_do_print(child, indent=indent + " ")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
_do_print(parent)
|
||||||
|
|
||||||
_do_print(par)
|
def debug(msg):
|
||||||
|
"""Dumb 'msg' into the debug file."""
|
||||||
def debug(s):
|
msg = as_unicode(msg)
|
||||||
s = as_unicode(s)
|
with open(DUMP_FILENAME, "ab") as dump_file:
|
||||||
with open(dump_filename, "ab") as dump_file:
|
dump_file.write((msg + '\n').encode("utf-8"))
|
||||||
dump_file.write((s + '\n').encode("utf-8"))
|
|
||||||
|
|
||||||
def print_stack():
|
def print_stack():
|
||||||
|
"""Dump a stack trace into the debug file."""
|
||||||
import traceback
|
import traceback
|
||||||
with open(dump_filename, "ab") as dump_file:
|
with open(DUMP_FILENAME, "ab") as dump_file:
|
||||||
traceback.print_stack(file=dump_file)
|
traceback.print_stack(file=dump_file)
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# encoding: utf-8
|
|
||||||
|
|
||||||
class Position(object):
|
|
||||||
def __init__(self, line, col):
|
|
||||||
self.line = line
|
|
||||||
self.col = col
|
|
||||||
|
|
||||||
def col():
|
|
||||||
def fget(self):
|
|
||||||
return self._col
|
|
||||||
def fset(self, value):
|
|
||||||
self._col = value
|
|
||||||
return locals()
|
|
||||||
col = property(**col())
|
|
||||||
|
|
||||||
def line():
|
|
||||||
doc = "Zero base line numbers"
|
|
||||||
def fget(self):
|
|
||||||
return self._line
|
|
||||||
def fset(self, value):
|
|
||||||
self._line = value
|
|
||||||
return locals()
|
|
||||||
line = property(**line())
|
|
||||||
|
|
||||||
def move(self, pivot, diff):
|
|
||||||
"""pivot is the position of the first changed
|
|
||||||
character, diff is how text after it moved"""
|
|
||||||
if self < pivot: return
|
|
||||||
if diff.line == 0:
|
|
||||||
if self.line == pivot.line:
|
|
||||||
self.col += diff.col
|
|
||||||
elif diff.line > 0:
|
|
||||||
if self.line == pivot.line:
|
|
||||||
self.col += diff.col - pivot.col
|
|
||||||
self.line += diff.line
|
|
||||||
else:
|
|
||||||
self.line += diff.line
|
|
||||||
if self.line == pivot.line:
|
|
||||||
self.col += - diff.col + pivot.col
|
|
||||||
|
|
||||||
|
|
||||||
def __add__(self,pos):
|
|
||||||
if not isinstance(pos,Position):
|
|
||||||
raise TypeError("unsupported operand type(s) for +: " \
|
|
||||||
"'Position' and %s" % type(pos))
|
|
||||||
|
|
||||||
return Position(self.line + pos.line, self.col + pos.col)
|
|
||||||
|
|
||||||
def __sub__(self,pos):
|
|
||||||
if not isinstance(pos,Position):
|
|
||||||
raise TypeError("unsupported operand type(s) for +: " \
|
|
||||||
"'Position' and %s" % type(pos))
|
|
||||||
return Position(self.line - pos.line, self.col - pos.col)
|
|
||||||
|
|
||||||
def diff(self,pos):
|
|
||||||
if not isinstance(pos,Position):
|
|
||||||
raise TypeError("unsupported operand type(s) for +: " \
|
|
||||||
"'Position' and %s" % type(pos))
|
|
||||||
if self.line == pos.line:
|
|
||||||
return Position(0, self.col - pos.col)
|
|
||||||
else:
|
|
||||||
if self > pos:
|
|
||||||
return Position(self.line - pos.line, self.col)
|
|
||||||
else:
|
|
||||||
return Position(self.line - pos.line, pos.col)
|
|
||||||
return Position(self.line - pos.line, self.col - pos.col)
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return (self._line, self._col) == (other._line, other._col)
|
|
||||||
def __ne__(self, other):
|
|
||||||
return (self._line, self._col) != (other._line, other._col)
|
|
||||||
def __lt__(self, other):
|
|
||||||
return (self._line, self._col) < (other._line, other._col)
|
|
||||||
def __le__(self, other):
|
|
||||||
return (self._line, self._col) <= (other._line, other._col)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "(%i,%i)" % (self._line, self._col)
|
|
65
pythonx/UltiSnips/position.py
Normal file
65
pythonx/UltiSnips/position.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
"""Represents a Position in a text file: (0 based line index, 0 based column
|
||||||
|
index) and provides methods for moving them around."""
|
||||||
|
|
||||||
|
class Position(object):
|
||||||
|
"""See module docstring."""
|
||||||
|
|
||||||
|
def __init__(self, line, col):
|
||||||
|
self.line = line
|
||||||
|
self.col = col
|
||||||
|
|
||||||
|
def move(self, pivot, delta):
|
||||||
|
"""'pivot' is the position of the first changed character, 'delta' is
|
||||||
|
how text after it moved"""
|
||||||
|
if self < pivot:
|
||||||
|
return
|
||||||
|
if delta.line == 0:
|
||||||
|
if self.line == pivot.line:
|
||||||
|
self.col += delta.col
|
||||||
|
elif delta.line > 0:
|
||||||
|
if self.line == pivot.line:
|
||||||
|
self.col += delta.col - pivot.col
|
||||||
|
self.line += delta.line
|
||||||
|
else:
|
||||||
|
self.line += delta.line
|
||||||
|
if self.line == pivot.line:
|
||||||
|
self.col += - delta.col + pivot.col
|
||||||
|
|
||||||
|
def delta(self, pos):
|
||||||
|
"""Returns the difference that the cursor must move to come from 'pos'
|
||||||
|
to us."""
|
||||||
|
assert isinstance(pos, Position)
|
||||||
|
if self.line == pos.line:
|
||||||
|
return Position(0, self.col - pos.col)
|
||||||
|
else:
|
||||||
|
if self > pos:
|
||||||
|
return Position(self.line - pos.line, self.col)
|
||||||
|
else:
|
||||||
|
return Position(self.line - pos.line, pos.col)
|
||||||
|
return Position(self.line - pos.line, self.col - pos.col)
|
||||||
|
|
||||||
|
def __add__(self, pos):
|
||||||
|
assert isinstance(pos, Position)
|
||||||
|
return Position(self.line + pos.line, self.col + pos.col)
|
||||||
|
|
||||||
|
def __sub__(self, pos):
|
||||||
|
assert isinstance(pos, Position)
|
||||||
|
return Position(self.line - pos.line, self.col - pos.col)
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return (self.line, self.col) == (other.line, other.col)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return (self.line, self.col) != (other.line, other.col)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return (self.line, self.col) < (other.line, other.col)
|
||||||
|
|
||||||
|
def __le__(self, other):
|
||||||
|
return (self.line, self.col) <= (other.line, other.col)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "(%i,%i)" % (self.line, self.col)
|
@ -1,6 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
|
"""Implements a container for parsed snippets."""
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@ -13,26 +15,27 @@ def _hash_file(path):
|
|||||||
|
|
||||||
|
|
||||||
class SnippetDictionary(object):
|
class SnippetDictionary(object):
|
||||||
def __init__(self, *args, **kwargs):
|
"""See module docstring."""
|
||||||
self._added = []
|
|
||||||
self.reset()
|
|
||||||
|
|
||||||
def reset(self):
|
def __init__(self):
|
||||||
self._snippets = []
|
self._added = []
|
||||||
self._extends = []
|
self._extends = []
|
||||||
self._files = {}
|
self._files = {}
|
||||||
|
self._snippets = []
|
||||||
|
|
||||||
def add_snippet(self, s, fn=None):
|
def add_snippet(self, snippet, filename):
|
||||||
if fn:
|
"""Add 'snippet' to this dictionary. If 'filename' is given, also watch
|
||||||
self._snippets.append(s)
|
the original file for changes."""
|
||||||
|
if filename:
|
||||||
if fn not in self.files:
|
self._snippets.append(snippet)
|
||||||
self.addfile(fn)
|
if filename not in self.files:
|
||||||
|
self.addfile(filename)
|
||||||
else:
|
else:
|
||||||
self._added.append(s)
|
self._added.append(snippet)
|
||||||
|
|
||||||
def get_matching_snippets(self, trigger, potentially):
|
def get_matching_snippets(self, trigger, potentially):
|
||||||
"""Returns all snippets matching the given trigger."""
|
"""Returns all snippets matching the given trigger. If 'potentially' is
|
||||||
|
true, returns all that could_match()."""
|
||||||
if not potentially:
|
if not potentially:
|
||||||
return [s for s in self.snippets if s.matches(trigger)]
|
return [s for s in self.snippets if s.matches(trigger)]
|
||||||
else:
|
else:
|
||||||
@ -40,40 +43,43 @@ class SnippetDictionary(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def snippets(self):
|
def snippets(self):
|
||||||
|
"""Returns all snippets in this dictionary."""
|
||||||
return self._added + self._snippets
|
return self._added + self._snippets
|
||||||
|
|
||||||
def clear_snippets(self, triggers=[]):
|
def clear_snippets(self, triggers=None):
|
||||||
"""Remove all snippets that match each trigger in triggers.
|
"""Remove all snippets that match each trigger in 'triggers'. When
|
||||||
When triggers is empty, removes all snippets.
|
'triggers' is None, empties this dictionary completely."""
|
||||||
"""
|
if triggers is None:
|
||||||
|
triggers = []
|
||||||
if triggers:
|
if triggers:
|
||||||
for t in triggers:
|
for trigger in triggers:
|
||||||
for s in self.get_matching_snippets(t, potentially=False):
|
for snippet in self.get_matching_snippets(trigger, False):
|
||||||
if s in self._snippets:
|
if snippet in self._snippets:
|
||||||
self._snippets.remove(s)
|
self._snippets.remove(snippet)
|
||||||
if s in self._added:
|
if snippet in self._added:
|
||||||
self._added.remove(s)
|
self._added.remove(snippet)
|
||||||
else:
|
else:
|
||||||
self._snippets = []
|
self._snippets = []
|
||||||
self._added = []
|
self._added = []
|
||||||
|
|
||||||
@property
|
|
||||||
def files(self):
|
|
||||||
return self._files
|
|
||||||
|
|
||||||
def addfile(self, path):
|
def addfile(self, path):
|
||||||
|
"""Add this file to the files we read triggers from."""
|
||||||
self.files[path] = _hash_file(path)
|
self.files[path] = _hash_file(path)
|
||||||
|
|
||||||
def needs_update(self):
|
def has_any_file_changed(self):
|
||||||
|
"""Returns True if any of our watched files has changed since we read
|
||||||
|
it last."""
|
||||||
for path, hash in self.files.items():
|
for path, hash in self.files.items():
|
||||||
if not hash or hash != _hash_file(path):
|
if not hash or hash != _hash_file(path):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def extends():
|
@property
|
||||||
def fget(self):
|
def files(self):
|
||||||
|
"""All files we have read snippets from."""
|
||||||
|
return self._files
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extends(self):
|
||||||
|
"""The list of filetypes this filetype extends."""
|
||||||
return self._extends
|
return self._extends
|
||||||
def fset(self, value):
|
|
||||||
self._extends = value
|
|
||||||
return locals()
|
|
||||||
extends = property(**extends())
|
|
||||||
|
@ -2,15 +2,14 @@
|
|||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
import os.path as p, sys; sys.path.append(p.join(p.dirname(__file__), ".."))
|
|
||||||
|
|
||||||
from geometry import Position
|
from position import Position
|
||||||
|
|
||||||
class _MPBase(object):
|
class _MPBase(object):
|
||||||
def runTest(self):
|
def runTest(self):
|
||||||
obj = Position(*self.obj)
|
obj = Position(*self.obj)
|
||||||
for pivot, diff, wanted in self.steps:
|
for pivot, delta, wanted in self.steps:
|
||||||
obj.move(Position(*pivot), Position(*diff))
|
obj.move(Position(*pivot), Position(*delta))
|
||||||
self.assertEqual(Position(*wanted), obj)
|
self.assertEqual(Position(*wanted), obj)
|
||||||
|
|
||||||
class MovePosition_DelSameLine(_MPBase, unittest.TestCase):
|
class MovePosition_DelSameLine(_MPBase, unittest.TestCase):
|
@ -6,7 +6,7 @@ import unittest
|
|||||||
import os.path as p, sys; sys.path.append(p.join(p.dirname(__file__), ".."))
|
import os.path as p, sys; sys.path.append(p.join(p.dirname(__file__), ".."))
|
||||||
|
|
||||||
from _diff import diff, guess_edit
|
from _diff import diff, guess_edit
|
||||||
from geometry import Position
|
from position import Position
|
||||||
|
|
||||||
|
|
||||||
def transform(a, cmds):
|
def transform(a, cmds):
|
||||||
@ -184,7 +184,3 @@ if __name__ == '__main__':
|
|||||||
unittest.main()
|
unittest.main()
|
||||||
# k = TestEditScript()
|
# k = TestEditScript()
|
||||||
# unittest.TextTestRunner().run(k)
|
# unittest.TextTestRunner().run(k)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"""Base classes for all text objects."""
|
"""Base classes for all text objects."""
|
||||||
|
|
||||||
import UltiSnips._vim as _vim
|
import UltiSnips._vim as _vim
|
||||||
from UltiSnips.geometry import Position
|
from UltiSnips.position import Position
|
||||||
|
|
||||||
def _calc_end(text, start):
|
def _calc_end(text, start):
|
||||||
"""Calculate the end position of the 'text' starting at 'start."""
|
"""Calculate the end position of the 'text' starting at 'start."""
|
||||||
@ -126,7 +126,7 @@ class TextObject(object):
|
|||||||
if self._parent:
|
if self._parent:
|
||||||
self._parent._child_has_moved(
|
self._parent._child_has_moved(
|
||||||
self._parent._childs.index(self), min(old_end, self._end),
|
self._parent._childs.index(self), min(old_end, self._end),
|
||||||
self._end.diff(old_end)
|
self._end.delta(old_end)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _update(self, done):
|
def _update(self, done):
|
||||||
|
@ -9,8 +9,9 @@ definitions into logical units called Tokens.
|
|||||||
import string
|
import string
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from UltiSnips.geometry import Position
|
|
||||||
from UltiSnips.compatibility import as_unicode
|
from UltiSnips.compatibility import as_unicode
|
||||||
|
from UltiSnips.position import Position
|
||||||
|
from UltiSnips.escaping import unescape
|
||||||
|
|
||||||
class _TextIterator(object):
|
class _TextIterator(object):
|
||||||
"""Helper class to make iterating over text easier."""
|
"""Helper class to make iterating over text easier."""
|
||||||
@ -55,19 +56,6 @@ class _TextIterator(object):
|
|||||||
"""Current position in the text."""
|
"""Current position in the text."""
|
||||||
return Position(self._line, self._col)
|
return Position(self._line, self._col)
|
||||||
|
|
||||||
def _unescape(text):
|
|
||||||
"""Removes escaping from 'text'."""
|
|
||||||
rv = ""
|
|
||||||
i = 0
|
|
||||||
while i < len(text):
|
|
||||||
if i+1 < len(text) and text[i] == '\\':
|
|
||||||
rv += text[i+1]
|
|
||||||
i += 1
|
|
||||||
else:
|
|
||||||
rv += text[i]
|
|
||||||
i += 1
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def _parse_number(stream):
|
def _parse_number(stream):
|
||||||
"""
|
"""
|
||||||
Expects the stream to contain a number next, returns the number
|
Expects the stream to contain a number next, returns the number
|
||||||
@ -178,7 +166,7 @@ class VisualToken(Token):
|
|||||||
if stream.peek() == ":":
|
if stream.peek() == ":":
|
||||||
stream.next()
|
stream.next()
|
||||||
self.alternative_text, char = _parse_till_unescaped_char(stream, '/}')
|
self.alternative_text, char = _parse_till_unescaped_char(stream, '/}')
|
||||||
self.alternative_text = _unescape(self.alternative_text)
|
self.alternative_text = unescape(self.alternative_text)
|
||||||
|
|
||||||
if char == '/': # Transformation going on
|
if char == '/': # Transformation going on
|
||||||
try:
|
try:
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
from UltiSnips.geometry import Position
|
|
||||||
from UltiSnips.text_objects._lexer import tokenize, EscapeCharToken, VisualToken, \
|
from UltiSnips.text_objects._lexer import tokenize, EscapeCharToken, VisualToken, \
|
||||||
TransformationToken, TabStopToken, MirrorToken, PythonCodeToken, \
|
TransformationToken, TabStopToken, MirrorToken, PythonCodeToken, \
|
||||||
VimLCodeToken, ShellCodeToken
|
VimLCodeToken, ShellCodeToken
|
||||||
|
from UltiSnips.position import Position
|
||||||
from UltiSnips.text_objects._escaped_char import EscapedChar
|
from UltiSnips.text_objects._escaped_char import EscapedChar
|
||||||
from UltiSnips.text_objects._mirror import Mirror
|
from UltiSnips.text_objects._mirror import Mirror
|
||||||
from UltiSnips.text_objects._python_code import PythonCode
|
from UltiSnips.text_objects._python_code import PythonCode
|
||||||
|
@ -1,48 +1,46 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
|
"""Implements `!p ` interpolation."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
import UltiSnips._vim as _vim
|
|
||||||
from UltiSnips.compatibility import as_unicode
|
from UltiSnips.compatibility import as_unicode
|
||||||
from UltiSnips.indent_util import IndentUtil
|
from UltiSnips.indent_util import IndentUtil
|
||||||
|
|
||||||
from UltiSnips.text_objects._base import NoneditableTextObject
|
from UltiSnips.text_objects._base import NoneditableTextObject
|
||||||
|
import UltiSnips._vim as _vim
|
||||||
|
|
||||||
|
|
||||||
class _Tabs(object):
|
class _Tabs(object):
|
||||||
|
"""Allows access to tabstop content via t[] inside of python code."""
|
||||||
def __init__(self, to):
|
def __init__(self, to):
|
||||||
self._to = to
|
self._to = to
|
||||||
|
|
||||||
def __getitem__(self, no):
|
def __getitem__(self, no):
|
||||||
ts = self._to._get_tabstop(self._to, int(no))
|
ts = self._to._get_tabstop(self._to, int(no)) # pylint:disable=protected-access
|
||||||
if ts is None:
|
if ts is None:
|
||||||
return ""
|
return ""
|
||||||
return ts.current_text
|
return ts.current_text
|
||||||
|
|
||||||
_VisualContent = namedtuple('_VisualContent', ['mode', 'text'])
|
_VisualContent = namedtuple('_VisualContent', ['mode', 'text'])
|
||||||
|
|
||||||
|
|
||||||
class SnippetUtil(object):
|
class SnippetUtil(object):
|
||||||
""" Provides easy access to indentation, etc.
|
"""Provides easy access to indentation, etc. This is the 'snip' object in
|
||||||
"""
|
python code."""
|
||||||
|
|
||||||
def __init__(self, initial_indent, vmode, vtext):
|
def __init__(self, initial_indent, vmode, vtext):
|
||||||
self._ind = IndentUtil()
|
self._ind = IndentUtil()
|
||||||
self._visual = _VisualContent(vmode, vtext)
|
self._visual = _VisualContent(vmode, vtext)
|
||||||
|
|
||||||
self._initial_indent = self._ind.indent_to_spaces(initial_indent)
|
self._initial_indent = self._ind.indent_to_spaces(initial_indent)
|
||||||
|
|
||||||
self._reset("")
|
self._reset("")
|
||||||
|
|
||||||
def _reset(self, cur):
|
def _reset(self, cur):
|
||||||
"""Gets the snippet ready for another update.
|
"""Gets the snippet ready for another update.
|
||||||
|
|
||||||
:cur: the new value for c.
|
:cur: the new value for c.
|
||||||
"""
|
"""
|
||||||
self._ind.reset()
|
self._ind.reset()
|
||||||
self._c = cur
|
self._cur = cur
|
||||||
self._rv = ""
|
self._rv = ""
|
||||||
self._changed = False
|
self._changed = False
|
||||||
self.reset_indent()
|
self.reset_indent()
|
||||||
@ -95,36 +93,31 @@ class SnippetUtil(object):
|
|||||||
|
|
||||||
# Utility methods
|
# Utility methods
|
||||||
@property
|
@property
|
||||||
def fn(self):
|
def fn(self): # pylint:disable=no-self-use,invalid-name
|
||||||
"""The filename."""
|
"""The filename."""
|
||||||
return _vim.eval('expand("%:t")') or ""
|
return _vim.eval('expand("%:t")') or ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def basename(self):
|
def basename(self): # pylint:disable=no-self-use
|
||||||
"""The filename without extension."""
|
"""The filename without extension."""
|
||||||
return _vim.eval('expand("%:t:r")') or ""
|
return _vim.eval('expand("%:t:r")') or ""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ft(self):
|
def ft(self): # pylint:disable=invalid-name
|
||||||
"""The filetype."""
|
"""The filetype."""
|
||||||
return self.opt("&filetype", "")
|
return self.opt("&filetype", "")
|
||||||
|
|
||||||
# Necessary stuff
|
@property
|
||||||
def rv():
|
def rv(self): # pylint:disable=invalid-name
|
||||||
""" The return value.
|
"""The return value. The text to insert at the location of the
|
||||||
This is a list of lines to insert at the
|
placeholder."""
|
||||||
location of the placeholder.
|
|
||||||
|
|
||||||
Deprecates res.
|
|
||||||
"""
|
|
||||||
def fget(self):
|
|
||||||
return self._rv
|
return self._rv
|
||||||
|
|
||||||
def fset(self, value):
|
@rv.setter
|
||||||
|
def rv(self, value): # pylint:disable=invalid-name
|
||||||
|
"""See getter."""
|
||||||
self._changed = True
|
self._changed = True
|
||||||
self._rv = value
|
self._rv = value
|
||||||
return locals()
|
|
||||||
rv = property(**rv())
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _rv_changed(self):
|
def _rv_changed(self):
|
||||||
@ -132,19 +125,16 @@ class SnippetUtil(object):
|
|||||||
return self._changed
|
return self._changed
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def c(self):
|
def c(self): # pylint:disable=invalid-name
|
||||||
""" The current text of the placeholder.
|
"""The current text of the placeholder."""
|
||||||
|
return self._cur
|
||||||
Deprecates cur.
|
|
||||||
"""
|
|
||||||
return self._c
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def v(self):
|
def v(self): # pylint:disable=invalid-name
|
||||||
"""Content of visual expansions"""
|
"""Content of visual expansions"""
|
||||||
return self._visual
|
return self._visual
|
||||||
|
|
||||||
def opt(self, option, default=None):
|
def opt(self, option, default=None): # pylint:disable=no-self-use
|
||||||
"""Gets a Vim variable."""
|
"""Gets a Vim variable."""
|
||||||
if _vim.eval("exists('%s')" % option) == "1":
|
if _vim.eval("exists('%s')" % option) == "1":
|
||||||
try:
|
try:
|
||||||
@ -153,10 +143,9 @@ class SnippetUtil(object):
|
|||||||
pass
|
pass
|
||||||
return default
|
return default
|
||||||
|
|
||||||
# Syntatic sugar
|
|
||||||
def __add__(self, value):
|
def __add__(self, value):
|
||||||
"""Appends the given line to rv using mkline."""
|
"""Appends the given line to rv using mkline."""
|
||||||
self.rv += '\n' # handles the first line properly
|
self.rv += '\n' # pylint:disable=invalid-name
|
||||||
self.rv += self.mkline(value)
|
self.rv += self.mkline(value)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -170,6 +159,8 @@ class SnippetUtil(object):
|
|||||||
|
|
||||||
|
|
||||||
class PythonCode(NoneditableTextObject):
|
class PythonCode(NoneditableTextObject):
|
||||||
|
"""See module docstring."""
|
||||||
|
|
||||||
def __init__(self, parent, token):
|
def __init__(self, parent, token):
|
||||||
code = token.code.replace("\\`", "`")
|
code = token.code.replace("\\`", "`")
|
||||||
|
|
||||||
@ -178,16 +169,16 @@ class PythonCode(NoneditableTextObject):
|
|||||||
while snippet:
|
while snippet:
|
||||||
try:
|
try:
|
||||||
self._locals = snippet.locals
|
self._locals = snippet.locals
|
||||||
t = snippet.visual_content.text
|
text = snippet.visual_content.text
|
||||||
m = snippet.visual_content.mode
|
mode = snippet.visual_content.mode
|
||||||
break
|
break
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
snippet = snippet._parent
|
snippet = snippet._parent # pylint:disable=protected-access
|
||||||
self._snip = SnippetUtil(token.indent, m, t)
|
self._snip = SnippetUtil(token.indent, mode, text)
|
||||||
|
|
||||||
self._globals = {}
|
self._globals = {}
|
||||||
globals = snippet.globals.get("!p", [])
|
globals = snippet.globals.get("!p", [])
|
||||||
exec("\n".join(globals).replace("\r\n", "\n"), self._globals)
|
exec("\n".join(globals).replace("\r\n", "\n"), self._globals) # pylint:disable=exec-used
|
||||||
|
|
||||||
# Add Some convenience to the code
|
# Add Some convenience to the code
|
||||||
self._code = "import re, os, vim, string, random\n" + code
|
self._code = "import re, os, vim, string, random\n" + code
|
||||||
@ -201,7 +192,7 @@ class PythonCode(NoneditableTextObject):
|
|||||||
fn = os.path.basename(path)
|
fn = os.path.basename(path)
|
||||||
|
|
||||||
ct = self.current_text
|
ct = self.current_text
|
||||||
self._snip._reset(ct)
|
self._snip._reset(ct) # pylint:disable=protected-access
|
||||||
local_d = self._locals
|
local_d = self._locals
|
||||||
|
|
||||||
local_d.update({
|
local_d.update({
|
||||||
@ -213,10 +204,10 @@ class PythonCode(NoneditableTextObject):
|
|||||||
'snip': self._snip,
|
'snip': self._snip,
|
||||||
})
|
})
|
||||||
|
|
||||||
exec(self._code, self._globals, local_d)
|
exec(self._code, self._globals, local_d) # pylint:disable=exec-used
|
||||||
|
|
||||||
rv = as_unicode(
|
rv = as_unicode(
|
||||||
self._snip.rv if self._snip._rv_changed
|
self._snip.rv if self._snip._rv_changed # pylint:disable=protected-access
|
||||||
else as_unicode(local_d['res'])
|
else as_unicode(local_d['res'])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,9 +5,8 @@
|
|||||||
user expands a snippet, a SnippetInstance is created to keep track of the
|
user expands a snippet, a SnippetInstance is created to keep track of the
|
||||||
corresponding TextObjects. The Snippet itself is also a TextObject. """
|
corresponding TextObjects. The Snippet itself is also a TextObject. """
|
||||||
|
|
||||||
from UltiSnips.geometry import Position
|
from UltiSnips.position import Position
|
||||||
import UltiSnips._vim as _vim
|
import UltiSnips._vim as _vim
|
||||||
|
|
||||||
from UltiSnips.text_objects._base import EditableTextObject, \
|
from UltiSnips.text_objects._base import EditableTextObject, \
|
||||||
NoneditableTextObject
|
NoneditableTextObject
|
||||||
from UltiSnips.text_objects._parser import TOParser
|
from UltiSnips.text_objects._parser import TOParser
|
||||||
|
@ -1,109 +1,105 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
|
"""Implements TabStop transformations."""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from UltiSnips.text_objects._mirror import Mirror
|
from UltiSnips.text_objects._mirror import Mirror
|
||||||
|
from UltiSnips.escaping import unescape, fill_in_whitespace
|
||||||
|
|
||||||
# flag used to display only one time the lack of unidecode
|
def _find_closing_brace(string, start_pos):
|
||||||
UNIDECODE_ALERT_RAISED = False
|
"""Finds the corresponding closing brace after start_pos."""
|
||||||
|
|
||||||
class _CleverReplace(object):
|
|
||||||
"""
|
|
||||||
This class mimics TextMates replace syntax
|
|
||||||
"""
|
|
||||||
_DOLLAR = re.compile(r"\$(\d+)", re.DOTALL)
|
|
||||||
_SIMPLE_CASEFOLDINGS = re.compile(r"\\([ul].)", re.DOTALL)
|
|
||||||
_LONG_CASEFOLDINGS = re.compile(r"\\([UL].*?)\\E", re.DOTALL)
|
|
||||||
_CONDITIONAL = re.compile(r"\(\?(\d+):", re.DOTALL)
|
|
||||||
|
|
||||||
_UNESCAPE = re.compile(r'\\[^ntrab]')
|
|
||||||
_SCHARS_ESCPAE = re.compile(r'\\[ntrab]')
|
|
||||||
|
|
||||||
def __init__(self, s):
|
|
||||||
self._s = s
|
|
||||||
|
|
||||||
def _scase_folding(self, m):
|
|
||||||
if m.group(1)[0] == 'u':
|
|
||||||
return m.group(1)[-1].upper()
|
|
||||||
else:
|
|
||||||
return m.group(1)[-1].lower()
|
|
||||||
def _lcase_folding(self, m):
|
|
||||||
if m.group(1)[0] == 'U':
|
|
||||||
return m.group(1)[1:].upper()
|
|
||||||
else:
|
|
||||||
return m.group(1)[1:].lower()
|
|
||||||
|
|
||||||
def _replace_conditional(self, match, v):
|
|
||||||
def _find_closingbrace(v,start_pos):
|
|
||||||
bracks_open = 1
|
bracks_open = 1
|
||||||
for idx, c in enumerate(v[start_pos:]):
|
for idx, char in enumerate(string[start_pos:]):
|
||||||
if c == '(':
|
if char == '(':
|
||||||
if v[idx+start_pos-1] != '\\':
|
if string[idx+start_pos-1] != '\\':
|
||||||
bracks_open += 1
|
bracks_open += 1
|
||||||
elif c == ')':
|
elif char == ')':
|
||||||
if v[idx+start_pos-1] != '\\':
|
if string[idx+start_pos-1] != '\\':
|
||||||
bracks_open -= 1
|
bracks_open -= 1
|
||||||
if not bracks_open:
|
if not bracks_open:
|
||||||
return start_pos+idx+1
|
return start_pos+idx+1
|
||||||
m = self._CONDITIONAL.search(v)
|
|
||||||
|
|
||||||
def _part_conditional(v):
|
def _split_conditional(string):
|
||||||
|
"""Split the given conditional 'string' into its arguments."""
|
||||||
bracks_open = 0
|
bracks_open = 0
|
||||||
args = []
|
args = []
|
||||||
carg = ""
|
carg = ""
|
||||||
for idx, c in enumerate(v):
|
for idx, char in enumerate(string):
|
||||||
if c == '(':
|
if char == '(':
|
||||||
if v[idx-1] != '\\':
|
if string[idx-1] != '\\':
|
||||||
bracks_open += 1
|
bracks_open += 1
|
||||||
elif c == ')':
|
elif char == ')':
|
||||||
if v[idx-1] != '\\':
|
if string[idx-1] != '\\':
|
||||||
bracks_open -= 1
|
bracks_open -= 1
|
||||||
elif c == ':' and not bracks_open and not v[idx-1] == '\\':
|
elif char == ':' and not bracks_open and not string[idx-1] == '\\':
|
||||||
args.append(carg)
|
args.append(carg)
|
||||||
carg = ""
|
carg = ""
|
||||||
continue
|
continue
|
||||||
carg += c
|
carg += char
|
||||||
args.append(carg)
|
args.append(carg)
|
||||||
return args
|
return args
|
||||||
|
|
||||||
while m:
|
def _replace_conditional(match, string):
|
||||||
start = m.start()
|
"""Replaces a conditional match in a transformation."""
|
||||||
end = _find_closingbrace(v,start+4)
|
conditional_match = _CONDITIONAL.search(string)
|
||||||
args = _part_conditional(v[start+4:end-1])
|
while conditional_match:
|
||||||
|
start = conditional_match.start()
|
||||||
|
end = _find_closing_brace(string, start+4)
|
||||||
|
args = _split_conditional(string[start+4:end-1])
|
||||||
rv = ""
|
rv = ""
|
||||||
if match.group(int(m.group(1))):
|
if match.group(int(conditional_match.group(1))):
|
||||||
rv = self._unescape(self._replace_conditional(match,args[0]))
|
rv = unescape(_replace_conditional(match, args[0]))
|
||||||
elif len(args) > 1:
|
elif len(args) > 1:
|
||||||
rv = self._unescape(self._replace_conditional(match,args[1]))
|
rv = unescape(_replace_conditional(match, args[1]))
|
||||||
|
string = string[:start] + rv + string[end:]
|
||||||
|
conditional_match = _CONDITIONAL.search(string)
|
||||||
|
return string
|
||||||
|
|
||||||
v = v[:start] + rv + v[end:]
|
_ONE_CHAR_CASE_SWITCH = re.compile(r"\\([ul].)", re.DOTALL)
|
||||||
|
_LONG_CASEFOLDINGS = re.compile(r"\\([UL].*?)\\E", re.DOTALL)
|
||||||
|
_DOLLAR = re.compile(r"\$(\d+)", re.DOTALL)
|
||||||
|
_CONDITIONAL = re.compile(r"\(\?(\d+):", re.DOTALL)
|
||||||
|
class _CleverReplace(object):
|
||||||
|
"""Mimics TextMates replace syntax."""
|
||||||
|
|
||||||
m = self._CONDITIONAL.search(v)
|
def __init__(self, expression):
|
||||||
return v
|
self._expression = expression
|
||||||
|
|
||||||
def _unescape(self, v):
|
|
||||||
return self._UNESCAPE.subn(lambda m: m.group(0)[-1], v)[0]
|
|
||||||
def _schar_escape(self, v):
|
|
||||||
return self._SCHARS_ESCPAE.subn(lambda m: eval(r"'\%s'" % m.group(0)[-1]), v)[0]
|
|
||||||
|
|
||||||
def replace(self, match):
|
def replace(self, match):
|
||||||
start, end = match.span()
|
"""Replaces 'match' through the correct replacement string."""
|
||||||
|
transformed = self._expression
|
||||||
tv = self._s
|
|
||||||
|
|
||||||
# Replace all $? with capture groups
|
# Replace all $? with capture groups
|
||||||
tv = self._DOLLAR.subn(lambda m: match.group(int(m.group(1))), tv)[0]
|
transformed = _DOLLAR.subn(
|
||||||
|
lambda m: match.group(int(m.group(1))), transformed)[0]
|
||||||
|
|
||||||
# Replace CaseFoldings
|
# Replace Case switches
|
||||||
tv = self._SIMPLE_CASEFOLDINGS.subn(self._scase_folding, tv)[0]
|
def _one_char_case_change(match):
|
||||||
tv = self._LONG_CASEFOLDINGS.subn(self._lcase_folding, tv)[0]
|
"""Replaces one character case changes."""
|
||||||
tv = self._replace_conditional(match, tv)
|
if match.group(1)[0] == 'u':
|
||||||
|
return match.group(1)[-1].upper()
|
||||||
|
else:
|
||||||
|
return match.group(1)[-1].lower()
|
||||||
|
transformed = _ONE_CHAR_CASE_SWITCH.subn(
|
||||||
|
_one_char_case_change, transformed)[0]
|
||||||
|
|
||||||
return self._unescape(self._schar_escape(tv))
|
def _multi_char_case_change(match):
|
||||||
|
"""Replaces multi character case changes."""
|
||||||
|
if match.group(1)[0] == 'U':
|
||||||
|
return match.group(1)[1:].upper()
|
||||||
|
else:
|
||||||
|
return match.group(1)[1:].lower()
|
||||||
|
transformed = _LONG_CASEFOLDINGS.subn(
|
||||||
|
_multi_char_case_change, transformed)[0]
|
||||||
|
transformed = _replace_conditional(match, transformed)
|
||||||
|
return unescape(fill_in_whitespace(transformed))
|
||||||
|
|
||||||
|
# flag used to display only one time the lack of unidecode
|
||||||
|
UNIDECODE_ALERT_RAISED = False
|
||||||
class TextObjectTransformation(object):
|
class TextObjectTransformation(object):
|
||||||
|
"""Base class for Transformations and ${VISUAL}."""
|
||||||
|
|
||||||
def __init__(self, token):
|
def __init__(self, token):
|
||||||
self._convert_to_ascii = False
|
self._convert_to_ascii = False
|
||||||
|
|
||||||
@ -125,20 +121,26 @@ class TextObjectTransformation(object):
|
|||||||
self._replace = _CleverReplace(token.replace)
|
self._replace = _CleverReplace(token.replace)
|
||||||
|
|
||||||
def _transform(self, text):
|
def _transform(self, text):
|
||||||
global UNIDECODE_ALERT_RAISED
|
"""Do the actual transform on the given text."""
|
||||||
|
global UNIDECODE_ALERT_RAISED # pylint:disable=global-statement
|
||||||
if self._convert_to_ascii:
|
if self._convert_to_ascii:
|
||||||
try:
|
try:
|
||||||
import unidecode
|
import unidecode
|
||||||
text = unidecode.unidecode(text)
|
text = unidecode.unidecode(text)
|
||||||
except Exception as e:
|
except Exception: # pylint:disable=broad-except
|
||||||
if UNIDECODE_ALERT_RAISED == False:
|
if UNIDECODE_ALERT_RAISED == False:
|
||||||
UNIDECODE_ALERT_RAISED = True
|
UNIDECODE_ALERT_RAISED = True
|
||||||
sys.stderr.write("Please install unidecode python package in order to be able to make ascii conversions.\n")
|
sys.stderr.write(
|
||||||
|
"Please install unidecode python package in order to "
|
||||||
|
"be able to make ascii conversions.\n")
|
||||||
if self._find is None:
|
if self._find is None:
|
||||||
return text
|
return text
|
||||||
return self._find.subn(self._replace.replace, text, self._match_this_many)[0]
|
return self._find.subn(
|
||||||
|
self._replace.replace, text, self._match_this_many)[0]
|
||||||
|
|
||||||
class Transformation(Mirror, TextObjectTransformation):
|
class Transformation(Mirror, TextObjectTransformation):
|
||||||
|
"""See module docstring."""
|
||||||
|
|
||||||
def __init__(self, parent, ts, token):
|
def __init__(self, parent, ts, token):
|
||||||
Mirror.__init__(self, parent, ts, token)
|
Mirror.__init__(self, parent, ts, token)
|
||||||
TextObjectTransformation.__init__(self, token)
|
TextObjectTransformation.__init__(self, token)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
|
|
||||||
from UltiSnips.compatibility import as_unicode, byte2col
|
from UltiSnips.compatibility import as_unicode, byte2col
|
||||||
from UltiSnips.geometry import Position
|
from UltiSnips.position import Position
|
||||||
import UltiSnips._vim as _vim
|
import UltiSnips._vim as _vim
|
||||||
|
|
||||||
class VimPosition(Position):
|
class VimPosition(Position):
|
||||||
|
2
test.py
2
test.py
@ -29,6 +29,8 @@
|
|||||||
# for this to work properly as SendKeys is a piece of chunk. (i.e. it sends
|
# for this to work properly as SendKeys is a piece of chunk. (i.e. it sends
|
||||||
# <F13> when you send a | symbol while using german key mappings)
|
# <F13> when you send a | symbol while using german key mappings)
|
||||||
|
|
||||||
|
# pylint: skip-file
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
Loading…
x
Reference in New Issue
Block a user