TextObjects now accept a single token as initializer

This commit is contained in:
Holger Rapp 2011-07-24 18:29:31 +02:00
parent ad0059bc2d
commit 9608346e77
2 changed files with 64 additions and 62 deletions

View File

@ -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 }}}

View File

@ -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)