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
class ${1:MyClass}(${2:object}):
""" ${3:Docstring for $1} """
""" ${3:Docstring for $1 }"""
def __init__(self$4):
""" ${5:TODO: Fill me in}
`!p
res.clear()
res.shift(2)
""" ${5:TODO: Fill me in}`!p
res = ""
print "test"
snip.reset_indent()
snip.shift(2)
args = [arg.split('=')[0].strip() for arg in t[4].split(',') if arg]
args = [arg for arg in args if arg and arg != "self"]
if args:
res.write_line()
res += snip.mkline('\n')
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":
res.write_line(t[2] + ".__init__(self)\n")
res += snip.mkline(t[2] + ".__init__(self)\n")
for arg in args:
res.write_line("self._%s = %s\n" % (arg, arg))
res += snip.mkline("self._%s = %s" % (arg, arg))
`
$0
endsnippet
@ -51,18 +55,19 @@ endsnippet
snippet def "smart def" b
def ${1:function}(${2:self}):
""" ${3:TODO: Docstring for $1}
`!p
res.clear()
`!p res = ""
snip.reset_indent()
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"]
if args:
res.write_line()
res += snip.mkline()
res.shift()
snip.shift()
for arg in args:
res.write_line(":%s: description" % arg)
res += snip.mkline(":%s: description" % arg)
`
: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
cur - The current text of the placeholder. You can check if this is != ""
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
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):
m = self._PYTHONCODE.search(self._v)
print "sea: %s" % m
while m:
self._handle_pythoncode(m)
m = self._PYTHONCODE.search(self._v)
@ -704,14 +705,25 @@ class _Tabs(object):
return ""
return ts.current_text
class PythonResult(object):
""" Provides easy access to indentation, etc
for python snippets. """
class SnippetUtil(object):
""" Provides easy access to indentation, and
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
if snippet:
self._locals = snippet.locals
else:
self._locals = {}
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):
""" Shifts the indentation level.
@ -730,36 +742,41 @@ class PythonResult(object):
self.indent = self.indent[:by]
except IndexError:
indent = ""
def result(self):
if vim.eval("&expandtab") == 0:
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.
def mkline(self, line="", indent=None):
""" Gets a properly set up line.
:line: the text to add
:indent: the indentation to have at the beginning
if None, it uses the default amount
"""
if indent == None:
indent = self.indent
if len(self.lines) == 0:
# Deal with special case: first line is handled already
try:
indent = indent[len(self._initial_indent):]
except IndexError:
indent = ""
self.lines.append((indent, line))
# this deals with the fact that the first line is
# already properly indented
if self._first:
try:
indent = indent[len(self._initial_indent):]
except IndexError:
indent = ""
self._first = False
def clear(self):
""" Clears the result.
"""
self.lines = []
if not self._et:
indent = indent.replace(" " * self._ts, '\t')
return indent + line + '\n'
def reset_indent(self):
""" Clears the indentation. """
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):
@ -768,11 +785,19 @@ class PythonCode(TextObject):
code = code.replace("\\`", "`")
# 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._res = PythonResult(indent)
self._snip = SnippetUtil(indent, snippet)
TextObject.__init__(self, parent, start, end, "")
def _do_update(self):
path = vim.eval('expand("%")')
if path is None:
@ -785,11 +810,12 @@ class PythonCode(TextObject):
'fn': fn,
'path': path,
'cur': ct,
'res': self._res,
'res': ct,
'snip' : self._snip,
}
exec self._code in d
self.current_text = str(self._res.result())
self.current_text = str(d["res"])
def __repr__(self):
@ -827,6 +853,8 @@ class SnippetInstance(TextObject):
if end is None:
end = Position(0,0)
self.locals = {}
TextObject.__init__(self, parent, start, end, initial_text)
_TOParser(self, initial_text, indent).parse()