use a helper object, rather than replacing 'res', also provide 'snippet-local' variables

This commit is contained in:
rygwdn@gmail.com 2010-05-16 19:34:44 -03:00
parent e8125051d3
commit 513a635c51
3 changed files with 99 additions and 45 deletions

View File

@ -20,30 +20,34 @@ endsnippet
########## ##########
snippet class "smart class" b snippet class "smart class" b
class ${1:MyClass}(${2:object}): class ${1:MyClass}(${2:object}):
""" ${3:Docstring for $1} """ """ ${3:Docstring for $1 }"""
def __init__(self$4): def __init__(self$4):
""" ${5:TODO: Fill me in} """ ${5:TODO: Fill me in}`!p
`!p res = ""
res.clear() print "test"
res.shift(2) snip.reset_indent()
snip.shift(2)
args = [arg.split('=')[0].strip() for arg in t[4].split(',') if arg] args = [arg.split('=')[0].strip() for arg in t[4].split(',') if arg]
args = [arg for arg in args if arg and arg != "self"] args = [arg for arg in args if arg and arg != "self"]
if args: if args:
res.write_line() res += snip.mkline('\n')
for arg in args: for arg in args:
res.write_line(":%s: description" % arg) res += snip.mkline(":%s: description" % arg)
res.write_line('"""') if args:
res += snip.mkline('"""')
else:
res += snip.mkline(' """', '')
if t[2] != "object": if t[2] != "object":
res.write_line(t[2] + ".__init__(self)\n") res += snip.mkline(t[2] + ".__init__(self)\n")
for arg in args: for arg in args:
res.write_line("self._%s = %s\n" % (arg, arg)) res += snip.mkline("self._%s = %s" % (arg, arg))
` `
$0 $0
endsnippet endsnippet
@ -51,18 +55,19 @@ endsnippet
snippet def "smart def" b snippet def "smart def" b
def ${1:function}(${2:self}): def ${1:function}(${2:self}):
""" ${3:TODO: Docstring for $1} """ ${3:TODO: Docstring for $1}
`!p `!p res = ""
res.clear() snip.reset_indent()
args = [arg.split('=')[0].strip() for arg in t[2].split(',') if arg.strip()] args = [arg.split('=')[0].strip() for arg in t[2].split(',') if arg.strip()]
args = [arg for arg in args if arg and arg != "self"] args = [arg for arg in args if arg and arg != "self"]
if args: if args:
res.write_line() res += snip.mkline()
res.shift() snip.shift()
for arg in args: for arg in args:
res.write_line(":%s: description" % arg) res += snip.mkline(":%s: description" % arg)
` `
:returns: description :returns: description
""" """

View File

@ -271,7 +271,28 @@ can be used: >
t - The values of the placeholders, t[1] -> current text of ${1} and so on t - The values of the placeholders, t[1] -> current text of ${1} and so on
cur - The current text of the placeholder. You can check if this is != "" cur - The current text of the placeholder. You can check if this is != ""
to make sure that the interpolation is only done once to make sure that the interpolation is only done once
ind - The indentation text appearing before the first line of the snippet snip - Provides easy indentation handling, and snippet-local variables.
The snip variable provides four methods >
snip.mkline(line="", indent=None):
Returns a line ready to be appended to the result. If indent
is None, then mkline prepends spaces and/or tabs appropriate to the
current tabstop and expandtab variables.
snip.shift(amount=1):
Shifts the default indentatation level used by mkline right by the
number of spaces defined by shiftwidth, 'amount' times.
snip.unshift(amount=1):
Shifts the default indentatation level used by mkline left by the
number of spaces defined by shiftwidth, 'amount' times.
snip.reset_indent():
Resets the indentation level to its initial value.
The snip variable also acts as dictionary which can be accessed by any of the
python code in the snippet.
Also, the vim, re, os, string and random modules are already imported inside Also, the vim, re, os, string and random modules are already imported inside
the snippet code. This allows for very flexible snippets. For example, the the snippet code. This allows for very flexible snippets. For example, the

View File

@ -197,6 +197,7 @@ class _TOParser(object):
############### ###############
def _parse_pythoncode(self): def _parse_pythoncode(self):
m = self._PYTHONCODE.search(self._v) m = self._PYTHONCODE.search(self._v)
print "sea: %s" % m
while m: while m:
self._handle_pythoncode(m) self._handle_pythoncode(m)
m = self._PYTHONCODE.search(self._v) m = self._PYTHONCODE.search(self._v)
@ -704,14 +705,25 @@ class _Tabs(object):
return "" return ""
return ts.current_text return ts.current_text
class PythonResult(object): class SnippetUtil(object):
""" Provides easy access to indentation, etc """ Provides easy access to indentation, and
for python snippets. """ snippet-local variables, which can be accessed by
any PythonCode object in the snippet.
"""
def __init__(self, initial_indent): def __init__(self, initial_indent, snippet=None):
self._initial_indent = initial_indent self._initial_indent = initial_indent
if snippet:
self._locals = snippet.locals
else:
self._locals = {}
self._shift = int(vim.eval("&sw")) self._shift = int(vim.eval("&sw"))
self.clear() self._et = (vim.eval("&expandtab") == "1")
self._ts = int(vim.eval("&ts"))
self._first = True # hack to make first line work right
self.reset_indent()
def shift(self, amount=1): def shift(self, amount=1):
""" Shifts the indentation level. """ Shifts the indentation level.
@ -731,35 +743,40 @@ class PythonResult(object):
except IndexError: except IndexError:
indent = "" indent = ""
def result(self): def mkline(self, line="", indent=None):
if vim.eval("&expandtab") == 0: """ Gets a properly set up line.
ts = int(vim.eval("&ts"))
for line in self.lines:
line[0] = line[0].replace(" " * ts, '\t')
return os.linesep.join([ind + line for ind, line in self.lines])
def write_line(self, line="", indent=None):
""" Adds a line to the result.
:line: the text to add :line: the text to add
:indent: the indentation to have at the beginning :indent: the indentation to have at the beginning
if None, it uses the default amount
""" """
if indent == None: if indent == None:
indent = self.indent indent = self.indent
if len(self.lines) == 0: # this deals with the fact that the first line is
# Deal with special case: first line is handled already # already properly indented
if self._first:
try: try:
indent = indent[len(self._initial_indent):] indent = indent[len(self._initial_indent):]
except IndexError: except IndexError:
indent = "" indent = ""
self.lines.append((indent, line)) self._first = False
def clear(self): if not self._et:
""" Clears the result. indent = indent.replace(" " * self._ts, '\t')
""" return indent + line + '\n'
self.lines = []
def reset_indent(self):
""" Clears the indentation. """
self.indent = self._initial_indent self.indent = self._initial_indent
self._first = True
def __getitem__(self, key):
""" Gets an item from the snippet. """
return self._locals[key]
def __setitem__(self, key, value):
""" Sets an item in the snippet locals. """
self._locals[key] = value
class PythonCode(TextObject): class PythonCode(TextObject):
@ -768,11 +785,19 @@ class PythonCode(TextObject):
code = code.replace("\\`", "`") code = code.replace("\\`", "`")
# Add Some convenience to the code # Add Some convenience to the code
snippet = parent
while snippet and not isinstance(snippet, SnippetInstance):
try:
snippet = snippet._parent
except AttributeError:
snippet = None
self._code = "import re, os, vim, string, random\n" + code self._code = "import re, os, vim, string, random\n" + code
self._res = PythonResult(indent) self._snip = SnippetUtil(indent, snippet)
TextObject.__init__(self, parent, start, end, "") TextObject.__init__(self, parent, start, end, "")
def _do_update(self): def _do_update(self):
path = vim.eval('expand("%")') path = vim.eval('expand("%")')
if path is None: if path is None:
@ -785,11 +810,12 @@ class PythonCode(TextObject):
'fn': fn, 'fn': fn,
'path': path, 'path': path,
'cur': ct, 'cur': ct,
'res': self._res, 'res': ct,
'snip' : self._snip,
} }
exec self._code in d exec self._code in d
self.current_text = str(self._res.result()) self.current_text = str(d["res"])
def __repr__(self): def __repr__(self):
@ -827,6 +853,8 @@ class SnippetInstance(TextObject):
if end is None: if end is None:
end = Position(0,0) end = Position(0,0)
self.locals = {}
TextObject.__init__(self, parent, start, end, initial_text) TextObject.__init__(self, parent, start, end, initial_text)
_TOParser(self, initial_text, indent).parse() _TOParser(self, initial_text, indent).parse()