TextObjects now accept a single token as initializer
This commit is contained in:
parent
ad0059bc2d
commit
9608346e77
@ -103,6 +103,7 @@ def _parse_till_unescaped_char(stream, char):
|
|||||||
# Tokens {{{
|
# Tokens {{{
|
||||||
class Token(object):
|
class Token(object):
|
||||||
def __init__(self, gen, indent):
|
def __init__(self, gen, indent):
|
||||||
|
self.initial_text = ""
|
||||||
self.start = gen.pos
|
self.start = gen.pos
|
||||||
self._parse(gen, indent)
|
self._parse(gen, indent)
|
||||||
self.end = gen.pos
|
self.end = gen.pos
|
||||||
@ -123,11 +124,11 @@ class TabStopToken(Token):
|
|||||||
|
|
||||||
if stream.peek() is ":":
|
if stream.peek() is ":":
|
||||||
stream.next()
|
stream.next()
|
||||||
self.default_text = _parse_till_closing_brace(stream)
|
self.initial_text = _parse_till_closing_brace(stream)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "TabStopToken(%r,%r,%r,%r)" % (
|
return "TabStopToken(%r,%r,%r,%r)" % (
|
||||||
self.start, self.end, self.no, self.default_text
|
self.start, self.end, self.no, self.initial_text
|
||||||
)
|
)
|
||||||
|
|
||||||
class TransformationToken(Token):
|
class TransformationToken(Token):
|
||||||
@ -164,6 +165,7 @@ class MirrorToken(Token):
|
|||||||
return klass.CHECK.match(stream.peek(10)) != None
|
return klass.CHECK.match(stream.peek(10)) != None
|
||||||
|
|
||||||
def _parse(self, stream, indent):
|
def _parse(self, stream, indent):
|
||||||
|
# TODO: why not parse number?
|
||||||
self.no = ""
|
self.no = ""
|
||||||
stream.next() # $
|
stream.next() # $
|
||||||
while not stream.exhausted and stream.peek() in string.digits:
|
while not stream.exhausted and stream.peek() in string.digits:
|
||||||
@ -184,13 +186,11 @@ class EscapeCharToken(Token):
|
|||||||
|
|
||||||
def _parse(self, stream, indent):
|
def _parse(self, stream, indent):
|
||||||
stream.next() # \
|
stream.next() # \
|
||||||
self.char = stream.next()
|
self.initial_text = stream.next()
|
||||||
|
|
||||||
|
|
||||||
# TODO: get rid of those __repr__ maybe
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "EscapeCharToken(%r,%r,%r)" % (
|
return "EscapeCharToken(%r,%r,%r)" % (
|
||||||
self.start, self.end, self.char
|
self.start, self.end, self.initial_text
|
||||||
)
|
)
|
||||||
|
|
||||||
class ShellCodeToken(Token):
|
class ShellCodeToken(Token):
|
||||||
@ -200,12 +200,12 @@ class ShellCodeToken(Token):
|
|||||||
|
|
||||||
def _parse(self, stream, indent):
|
def _parse(self, stream, indent):
|
||||||
stream.next() # `
|
stream.next() # `
|
||||||
self.content = _parse_till_unescaped_char(stream, '`')
|
self.code = _parse_till_unescaped_char(stream, '`')
|
||||||
|
|
||||||
# TODO: get rid of those __repr__ maybe
|
# TODO: get rid of those __repr__ maybe
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "ShellCodeToken(%r,%r,%r)" % (
|
return "ShellCodeToken(%r,%r,%r)" % (
|
||||||
self.start, self.end, self.content
|
self.start, self.end, self.code
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: identical to VimLCodeToken
|
# TODO: identical to VimLCodeToken
|
||||||
@ -222,25 +222,25 @@ class PythonCodeToken(Token):
|
|||||||
if stream.peek() in '\t ':
|
if stream.peek() in '\t ':
|
||||||
stream.next()
|
stream.next()
|
||||||
|
|
||||||
content = _parse_till_unescaped_char(stream, '`')
|
code = _parse_till_unescaped_char(stream, '`')
|
||||||
|
|
||||||
# TODO: stupid to pass the indent down even if only python
|
# TODO: stupid to pass the indent down even if only python
|
||||||
# needs it. Stupid to indent beforehand.
|
# needs it. Stupid to indent beforehand.
|
||||||
|
|
||||||
# Strip the indent if any
|
# Strip the indent if any
|
||||||
if len(indent):
|
if len(indent):
|
||||||
lines = content.splitlines()
|
lines = code.splitlines()
|
||||||
self.content = lines[0] + '\n'
|
self.code = lines[0] + '\n'
|
||||||
self.content += '\n'.join([l[len(indent):]
|
self.code += '\n'.join([l[len(indent):]
|
||||||
for l in lines[1:]])
|
for l in lines[1:]])
|
||||||
else:
|
else:
|
||||||
self.content = content
|
self.code = code
|
||||||
self.indent = indent
|
self.indent = indent
|
||||||
|
|
||||||
# TODO: get rid of those __repr__ maybe
|
# TODO: get rid of those __repr__ maybe
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "PythonCodeToken(%r,%r,%r)" % (
|
return "PythonCodeToken(%r,%r,%r)" % (
|
||||||
self.start, self.end, self.content
|
self.start, self.end, self.code
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -254,12 +254,11 @@ class VimLCodeToken(Token):
|
|||||||
def _parse(self, stream, indent):
|
def _parse(self, stream, indent):
|
||||||
for i in range(4):
|
for i in range(4):
|
||||||
stream.next() # `!v
|
stream.next() # `!v
|
||||||
self.content = _parse_till_unescaped_char(stream, '`')
|
self.code = _parse_till_unescaped_char(stream, '`')
|
||||||
|
|
||||||
# TODO: get rid of those __repr__ maybe
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "VimLCodeToken(%r,%r,%r)" % (
|
return "VimLCodeToken(%r,%r,%r)" % (
|
||||||
self.start, self.end, self.content
|
self.start, self.end, self.code
|
||||||
)
|
)
|
||||||
# End: Tokens }}}
|
# End: Tokens }}}
|
||||||
|
|
||||||
|
@ -121,26 +121,29 @@ class TextObject(object):
|
|||||||
This base class represents any object in the text
|
This base class represents any object in the text
|
||||||
that has a span in any ways
|
that has a span in any ways
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, start, end, initial_text):
|
def __init__(self, parent, token, end = None, initial_text = ""):
|
||||||
self._start = start
|
|
||||||
self._end = end
|
|
||||||
|
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
|
|
||||||
|
if end is not None: # Took 4 arguments
|
||||||
|
self._start = token
|
||||||
|
self._end = end
|
||||||
|
self._current_text = TextBuffer(initial_text)
|
||||||
|
else: # Initialize from token
|
||||||
|
self._start = token.start
|
||||||
|
self._end = token.end
|
||||||
|
self._current_text = TextBuffer(token.initial_text)
|
||||||
|
|
||||||
self._childs = []
|
self._childs = []
|
||||||
self._tabstops = {}
|
self._tabstops = {}
|
||||||
|
|
||||||
if parent is not None:
|
if parent is not None:
|
||||||
parent._add_child(self)
|
parent._add_child(self)
|
||||||
|
|
||||||
self._current_text = TextBuffer(initial_text)
|
|
||||||
|
|
||||||
self._cts = 0
|
self._cts = 0
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __cmp__(self, other):
|
||||||
return cmp(self._start, other._start)
|
return cmp(self._start, other._start)
|
||||||
|
|
||||||
|
|
||||||
##############
|
##############
|
||||||
# PROPERTIES #
|
# PROPERTIES #
|
||||||
##############
|
##############
|
||||||
@ -268,7 +271,6 @@ class TextObject(object):
|
|||||||
|
|
||||||
return max(posible_sol)
|
return max(posible_sol)
|
||||||
|
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
# Private/Protected functions #
|
# Private/Protected functions #
|
||||||
###############################
|
###############################
|
||||||
@ -328,7 +330,6 @@ class EscapedChar(TextObject):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class StartMarker(TextObject):
|
class StartMarker(TextObject):
|
||||||
"""
|
"""
|
||||||
This class only remembers it's starting position. It is used to
|
This class only remembers it's starting position. It is used to
|
||||||
@ -337,15 +338,15 @@ class StartMarker(TextObject):
|
|||||||
"""
|
"""
|
||||||
def __init__(self, start):
|
def __init__(self, start):
|
||||||
end = Position(start.line, start.col)
|
end = Position(start.line, start.col)
|
||||||
TextObject.__init__(self, None, start, end, "")
|
TextObject.__init__(self, None, start, end)
|
||||||
|
|
||||||
|
|
||||||
class Mirror(TextObject):
|
class Mirror(TextObject):
|
||||||
"""
|
"""
|
||||||
A Mirror object mirrors a TabStop that is, text is repeated here
|
A Mirror object mirrors a TabStop that is, text is repeated here
|
||||||
"""
|
"""
|
||||||
def __init__(self, parent, ts, start, end):
|
def __init__(self, parent, ts, token):
|
||||||
TextObject.__init__(self, parent, start, end, "")
|
TextObject.__init__(self, parent, token)
|
||||||
|
|
||||||
self._ts = ts
|
self._ts = ts
|
||||||
|
|
||||||
@ -357,19 +358,19 @@ class Mirror(TextObject):
|
|||||||
|
|
||||||
|
|
||||||
class Transformation(Mirror):
|
class Transformation(Mirror):
|
||||||
def __init__(self, parent, ts, start, end, s, r, options):
|
def __init__(self, parent, ts, token):
|
||||||
Mirror.__init__(self, parent, ts, start, end)
|
Mirror.__init__(self, parent, ts, token)
|
||||||
|
|
||||||
flags = 0
|
flags = 0
|
||||||
self._match_this_many = 1
|
self._match_this_many = 1
|
||||||
if options:
|
if token.options:
|
||||||
if "g" in options:
|
if "g" in token.options:
|
||||||
self._match_this_many = 0
|
self._match_this_many = 0
|
||||||
if "i" in options:
|
if "i" in token.options:
|
||||||
flags |= re.IGNORECASE
|
flags |= re.IGNORECASE
|
||||||
|
|
||||||
self._find = re.compile(s, flags | re.DOTALL)
|
self._find = re.compile(token.search, flags | re.DOTALL)
|
||||||
self._replace = _CleverReplace(r)
|
self._replace = _CleverReplace(token.replace)
|
||||||
|
|
||||||
def _do_update(self):
|
def _do_update(self):
|
||||||
t = self._ts.current_text
|
t = self._ts.current_text
|
||||||
@ -380,9 +381,8 @@ class Transformation(Mirror):
|
|||||||
return "Transformation(%s -> %s)" % (self._start, self._end)
|
return "Transformation(%s -> %s)" % (self._start, self._end)
|
||||||
|
|
||||||
class ShellCode(TextObject):
|
class ShellCode(TextObject):
|
||||||
def __init__(self, parent, start, end, code):
|
def __init__(self, parent, token):
|
||||||
|
code = token.code.replace("\\`", "`")
|
||||||
code = code.replace("\\`", "`")
|
|
||||||
|
|
||||||
# Write the code to a temporary file
|
# Write the code to a temporary file
|
||||||
handle, path = tempfile.mkstemp(text=True)
|
handle, path = tempfile.mkstemp(text=True)
|
||||||
@ -401,16 +401,17 @@ class ShellCode(TextObject):
|
|||||||
|
|
||||||
os.unlink(path)
|
os.unlink(path)
|
||||||
|
|
||||||
TextObject.__init__(self, parent, start, end, output)
|
token.initial_text = output
|
||||||
|
TextObject.__init__(self, parent, token)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "ShellCode(%s -> %s)" % (self._start, self._end)
|
return "ShellCode(%s -> %s)" % (self._start, self._end)
|
||||||
|
|
||||||
class VimLCode(TextObject):
|
class VimLCode(TextObject):
|
||||||
def __init__(self, parent, start, end, code):
|
def __init__(self, parent, token):
|
||||||
self._code = code.replace("\\`", "`").strip()
|
self._code = token.code.replace("\\`", "`").strip()
|
||||||
|
|
||||||
TextObject.__init__(self, parent, start, end, "")
|
TextObject.__init__(self, parent, token)
|
||||||
|
|
||||||
def _do_update(self):
|
def _do_update(self):
|
||||||
self.current_text = str(vim.eval(self._code))
|
self.current_text = str(vim.eval(self._code))
|
||||||
@ -567,9 +568,9 @@ class SnippetUtil(object):
|
|||||||
|
|
||||||
|
|
||||||
class PythonCode(TextObject):
|
class PythonCode(TextObject):
|
||||||
def __init__(self, parent, start, end, code, indent=""):
|
def __init__(self, parent, token):
|
||||||
|
|
||||||
code = code.replace("\\`", "`")
|
code = token.code.replace("\\`", "`")
|
||||||
|
|
||||||
# Find our containing snippet for snippet local data
|
# Find our containing snippet for snippet local data
|
||||||
snippet = parent
|
snippet = parent
|
||||||
@ -578,7 +579,7 @@ class PythonCode(TextObject):
|
|||||||
snippet = snippet._parent
|
snippet = snippet._parent
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
snippet = None
|
snippet = None
|
||||||
self._snip = SnippetUtil(indent)
|
self._snip = SnippetUtil(token.indent)
|
||||||
self._locals = snippet.locals
|
self._locals = snippet.locals
|
||||||
|
|
||||||
self._globals = {}
|
self._globals = {}
|
||||||
@ -588,7 +589,7 @@ class PythonCode(TextObject):
|
|||||||
# 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
|
||||||
|
|
||||||
TextObject.__init__(self, parent, start, end, "")
|
TextObject.__init__(self, parent, token)
|
||||||
|
|
||||||
|
|
||||||
def _do_update(self):
|
def _do_update(self):
|
||||||
@ -626,9 +627,13 @@ class TabStop(TextObject):
|
|||||||
This is the most important TextObject. A TabStop is were the cursor
|
This is the most important TextObject. A TabStop is were the cursor
|
||||||
comes to rest when the user taps through the Snippet.
|
comes to rest when the user taps through the Snippet.
|
||||||
"""
|
"""
|
||||||
def __init__(self, no, parent, start, end, default_text = ""):
|
def __init__(self, parent, token, start = None, end = None):
|
||||||
TextObject.__init__(self, parent, start, end, default_text)
|
if start is not None:
|
||||||
self._no = no
|
self._no = token
|
||||||
|
TextObject.__init__(self, parent, start, end)
|
||||||
|
else:
|
||||||
|
TextObject.__init__(self, parent, token)
|
||||||
|
self._no = token.no
|
||||||
|
|
||||||
def no(self):
|
def no(self):
|
||||||
return self._no
|
return self._no
|
||||||
@ -675,7 +680,7 @@ class SnippetInstance(TextObject):
|
|||||||
col -= self.start.col
|
col -= self.start.col
|
||||||
start = Position(delta.line, col)
|
start = Position(delta.line, col)
|
||||||
end = Position(delta.line, col)
|
end = Position(delta.line, col)
|
||||||
ts = TabStop(0, self, start, end, "")
|
ts = TabStop(self, 0, start, end)
|
||||||
self._add_tabstop(0,ts)
|
self._add_tabstop(0,ts)
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
@ -734,6 +739,7 @@ class _TOParser(object):
|
|||||||
self._indent = indent
|
self._indent = indent
|
||||||
self.current_to = parent
|
self.current_to = parent
|
||||||
self.text = text
|
self.text = text
|
||||||
|
debug("text: %s" % (text))
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
seen_ts = {}
|
seen_ts = {}
|
||||||
@ -750,18 +756,18 @@ class _TOParser(object):
|
|||||||
# TODO: maybe we can get rid of _get_tabstop and _add_tabstop
|
# TODO: maybe we can get rid of _get_tabstop and _add_tabstop
|
||||||
if token.no not in seen_ts:
|
if token.no not in seen_ts:
|
||||||
debug("token.start: %s, token.end: %s" % (token.start, token.end))
|
debug("token.start: %s, token.end: %s" % (token.start, token.end))
|
||||||
ts = TabStop(token.no, parent, token.start, token.end)
|
ts = TabStop(parent, token)
|
||||||
seen_ts[token.no] = ts
|
seen_ts[token.no] = ts
|
||||||
parent._add_tabstop(token.no,ts)
|
parent._add_tabstop(token.no,ts)
|
||||||
else:
|
else:
|
||||||
Mirror(parent, seen_ts[token.no], token.start, token.end)
|
Mirror(parent, seen_ts[token.no], token)
|
||||||
|
|
||||||
# TODO: third phase: associate tabstops with Transformations
|
# TODO: third phase: associate tabstops with Transformations
|
||||||
for parent, token in tokens:
|
for parent, token in tokens:
|
||||||
if isinstance(token, TransformationToken):
|
if isinstance(token, TransformationToken):
|
||||||
if token.no not in seen_ts:
|
if token.no not in seen_ts:
|
||||||
raise RuntimeError("Tabstop %i is not known" % t._ts)
|
raise RuntimeError("Tabstop %i is not known" % t._ts)
|
||||||
Transformation(parent, seen_ts[token.no], token.start, token.end, token.search, token.replace, token.options)
|
Transformation(parent, seen_ts[token.no], token)
|
||||||
# TODO: check if all associations have been done properly. Also add a testcase for this!
|
# TODO: check if all associations have been done properly. Also add a testcase for this!
|
||||||
|
|
||||||
def _parse(self, all_tokens, seen_ts):
|
def _parse(self, all_tokens, seen_ts):
|
||||||
@ -772,21 +778,18 @@ class _TOParser(object):
|
|||||||
all_tokens.append((self.current_to, token))
|
all_tokens.append((self.current_to, token))
|
||||||
|
|
||||||
if isinstance(token, TabStopToken):
|
if isinstance(token, TabStopToken):
|
||||||
# TODO: could also take the token directly
|
ts = TabStop(self.current_to, token)
|
||||||
debug("token.start: %s, token.end: %s" % (token.start, token.end))
|
|
||||||
ts = TabStop(token.no, self.current_to,
|
|
||||||
token.start, token.end, token.default_text)
|
|
||||||
seen_ts[token.no] = ts
|
seen_ts[token.no] = ts
|
||||||
self.current_to._add_tabstop(token.no,ts)
|
self.current_to._add_tabstop(token.no,ts)
|
||||||
|
|
||||||
k = _TOParser(ts, ts.current_text, self._indent)
|
k = _TOParser(ts, ts.current_text, self._indent)
|
||||||
k._parse(all_tokens, seen_ts)
|
k._parse(all_tokens, seen_ts)
|
||||||
elif isinstance(token, EscapeCharToken):
|
elif isinstance(token, EscapeCharToken):
|
||||||
EscapedChar(self.current_to, token.start, token.end, token.char)
|
EscapedChar(self.current_to, token)
|
||||||
elif isinstance(token, ShellCodeToken):
|
elif isinstance(token, ShellCodeToken):
|
||||||
ShellCode(self.current_to, token.start, token.end, token.content)
|
ShellCode(self.current_to, token)
|
||||||
elif isinstance(token, PythonCodeToken):
|
elif isinstance(token, PythonCodeToken):
|
||||||
PythonCode(self.current_to, token.start, token.end, token.content, token.indent)
|
PythonCode(self.current_to, token)
|
||||||
elif isinstance(token, VimLCodeToken):
|
elif isinstance(token, VimLCodeToken):
|
||||||
VimLCode(self.current_to, token.start, token.end, token.content)
|
VimLCode(self.current_to, token)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user