Merged global snippets branch from Ryan

This commit is contained in:
Holger Rapp 2010-08-17 13:30:59 +02:00
commit 564c2af59c
8 changed files with 184 additions and 115 deletions

View File

@ -4,41 +4,40 @@
##############
# NICE BOXES #
##############
snippet box "A nice box with the current comment symbol" b
`!p
global !p
def cs(snip):
c = '#'
cs = vim.eval("&commentstring")
cs = snip.opt("&commentstring")
if len(cs) == 3:
c = cs[0]
snip.locals["c"] = c
return c
endglobal
snippet box "A nice box with the current comment symbol" b
`!p
c = cs(snip)
snip.rv = (len(t[1])+4)*c
snip.locals["bar"] = snip.rv
bar = snip.rv
snip += c + ' '`${1:content}`!p
c = snip.locals["c"]
snip.rv = ' ' + c
snip += snip.locals["bar"]`
snip += bar`
$0
endsnippet
snippet bbox "A nice box over the full width" b
`!p
c = '#'
cs = vim.eval("&commentstring")
if len(cs) == 3:
c = cs[0]
snip.locals["c"] = c
snip.locals["bar"] = 75*c
c = cs(snip)
bar = 75*c
snip.rv = snip.locals["bar"]
snip.rv = bar
snip += c + " " + (71-len(t[1]))/2*' '
`${1:content}`!p
c = snip.locals["c"]
a = 71-len(t[1])
snip.rv = (a/2 + a%2) * " " + " " + c
snip += snip.locals["bar"]`
snip += bar`
$0
endsnippet

View File

@ -1,35 +1,28 @@
# Snippets for VIM Help Files
global !p
def sec_title(snip, t):
file_start = snip.fn.split('.')[0]
sec_name = t[1].strip("1234567890. ").lower().replace(' ', '-')
return ("*%s-%s*" % (file_start, sec_name)).rjust(77-len(t[1]))
endglobal
snippet sec "Section marker" b
=============================================================================
${1:SECTION}`!p
file_start = snip.fn.split('.')[0]
sec_name = t[1].strip("1234567890. ").lower().replace(' ', '-')
snip.rv = ("*%s-%s*" % (file_start, sec_name)).rjust(77-len(t[1]))`
${1:SECTION}`!p snip.rv = sec_title(snip, t)`
$0
endsnippet
snippet ssec "Sub section marker" b
${1:Subsection}`!p
file_start = snip.fn.split('.')[0]
sec_name = t[1].strip("1234567890. ").lower().replace(' ', '-')
sec_title = ("*%s-%s*" % (file_start, sec_name)).rjust(77-len(t[1]))
snip.rv = sec_title
${1:Subsection}`!p snip.rv = sec_title(snip, t)
snip += "-"*len(t[1])`
$0
endsnippet
snippet sssec "Subsub Section marker" b
${1:SubSubsection}:`!p
file_start = fn.split('.')[0]
sec_name = t[1].strip("1234567890. ").lower().replace(' ', '-')
sec_title = ("*%s-%s*" % (file_start, sec_name)).rjust(77-len(t[1]))
snip.rv = sec_title`
${1:SubSubsection}:`!p snip.rv = sec_title(snip, t)`
$0
endsnippet

View File

@ -2,6 +2,14 @@
# TextMate Snippets #
###########################################################################
global !p
def x(snip):
if snip.ft.startswith("x"):
snip.rv = '/'
else:
snip.rv = ""
endglobal
############
# Doctypes #
############
@ -112,12 +120,12 @@ endsnippet
# HTML TAGS #
#############
snippet input "Input with Label"
<label for="${2:${1/[[:alpha:]]+|( )/(?1:_:\L$0)/g}}">$1</label><input type="${3:text/submit/hidden/button}" name="${4:$2}" value="$5"${6: id="${7:$2}"}`!p if snip.ft.startswith("x"): snip.rv = '/'`>
<label for="${2:${1/[[:alpha:]]+|( )/(?1:_:\L$0)/g}}">$1</label><input type="${3:text/submit/hidden/button}" name="${4:$2}" value="$5"${6: id="${7:$2}"}`!p x(snip)`>
endsnippet
snippet input "XHTML <input>"
<input type="${1:text/submit/hidden/button}" name="${2:some_name}" value="$3"${4: id="${5:$2}"}`!p if snip.ft.startswith("x"): snip.rv = '/'`>
<input type="${1:text/submit/hidden/button}" name="${2:some_name}" value="$3"${4: id="${5:$2}"}`!p x(snip)`>
endsnippet
@ -143,7 +151,7 @@ snippet mailto "XHTML <a mailto: >"
endsnippet
snippet base "XHTML <base>"
<base href="$1"${2: target="$3"}`!p if snip.ft.startswith("x"): snip.rv = '/'`>
<base href="$1"${2: target="$3"}`!p x(snip)`>
endsnippet
snippet body "XHTML <body>"
@ -166,7 +174,7 @@ snip.rv = (snip.basename or 'unnamed') + '_submit'
`}" method="${2:get}" accept-charset="utf-8">
$0
<p><input type="submit" value="Continue →"`!p if snip.ft.startswith("x"): snip.rv = '/'`></p>
<p><input type="submit" value="Continue →"`!p x(snip)`></p>
</form>
endsnippet
@ -176,18 +184,18 @@ endsnippet
snippet head "XHTML <head>"
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"`!p if snip.ft.startswith("x"): snip.rv = '/'`>
<meta http-equiv="Content-type" content="text/html; charset=utf-8"`!p x(snip)`>
<title>${1:`!p snip.rv = snip.basename or "Page Title"`}</title>
$0
</head>
endsnippet
snippet link "XHTML <link>"
<link rel="${1:stylesheet}" href="${2:/css/master.css}" type="text/css" media="${3:screen}" title="${4:no title}" charset="${5:utf-8}"`!p if snip.ft.startswith("x"): snip.rv = '/'`>
<link rel="${1:stylesheet}" href="${2:/css/master.css}" type="text/css" media="${3:screen}" title="${4:no title}" charset="${5:utf-8}"`!p x(snip)`>
endsnippet
snippet meta "XHTML <meta>"
<meta name="${1:name}" content="${2:content}"`!p if snip.ft.startswith("x"): snip.rv = '/'`>
<meta name="${1:name}" content="${2:content}"`!p x(snip)`>
endsnippet
snippet scriptsrc "XHTML <script src...>"
@ -227,15 +235,15 @@ endsnippet
snippet movie "Embed QT movie (movie)" b
<object width="$2" height="$3" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab">
<param name="src" value="$1"`!p snip.locals['xhtml'] = snip.ft.startswith("x") and "/" or ""; snip.rv = snip.locals['xhtml']`>
<param name="controller" value="$4"`!p snip.rv = snip.locals['xhtml']`>
<param name="autoplay" value="$5"`!p snip.rv = snip.locals['xhtml']`>
<param name="src" value="$1"`!p x(snip)`>
<param name="controller" value="$4"`!p x(snip)`>
<param name="autoplay" value="$5"`!p x(snip)`>
<embed src="${1:movie.mov}"
width="${2:320}" height="${3:240}"
controller="${4:true}" autoplay="${5:true}"
scale="tofit" cache="true"
pluginspage="http://www.apple.com/quicktime/download/"
`!p snip.rv = snip.locals['xhtml']`>
`!p x(snip)`>
</object>
endsnippet

View File

@ -23,15 +23,9 @@ endsnippet
# "g:ultisnips_python_style" which, if set to "doxygen" will use doxygen
# style comments in docstrings.
snippet class "smart class" b
class ${1:MyClass}(${2:object}):
""" ${3:Docstring for $1 }"""
def __init__(self$4):
""" ${5:TODO: Fill me in}`!p
snip >> 2
args = [arg.split('=')[0].strip() for arg in t[4].split(',') if arg]
global !p
def get_args(arglist, snip):
args = [arg.split('=')[0].strip() for arg in arglist.split(',') if arg]
args = [arg for arg in args if arg and arg != "self"]
if args:
@ -43,6 +37,19 @@ for arg in args:
snip += "@param %s TODO" % arg
else:
snip += ":%s: TODO" % arg
return args
endglobal
snippet class "smart class" b
class ${1:MyClass}(${2:object}):
""" ${3:Docstring for $1 }"""
def __init__(self$4):
""" ${5:TODO: Fill me in}`!p
snip.rv = ""
snip >> 2
args = get_args(t[4], snip)
if args:
snip += '"""'
@ -65,24 +72,14 @@ def ${1:function}(${2:self}):
snip.rv = "" # Force update
snip >> 1
args = [arg.split('=')[0].strip() for arg in t[2].split(',') if arg]
args = [arg for arg in args if arg and arg != "self"]
if args:
snip += ""
snip.locals["style"] = style = snip.opt("g:ultisnips_python_style", "normal")
for arg in args:
if style == "doxygen":
snip += "@param %s TODO" % arg
else:
snip += ":%s: TODO" % arg
args = get_args(t[2], snip)
`${4:
`!p
snip.rv = "" # Force update
style = snip.locals["style"]
style = snip.opt("g:ultisnips_python_style", "normal")
if style == "doxygen":
snip.rv = "@return"
else:

View File

@ -15,6 +15,7 @@ UltiSnips *snippet* *snippets* *UltiSnips*
4.3.1 Shellcode |UltiSnips-shellcode|
4.3.2 VimScript |UltiSnips-vimscript|
4.3.3 Python |UltiSnips-python|
4.3.4 Global Snippets |UltiSnips-globals|
4.4 Tab Stops and Placeholders |UltiSnips-tabstops|
4.6 Mirrors |UltiSnips-mirrors|
4.7 Transformations |UltiSnips-transformations|
@ -202,7 +203,7 @@ snippet on. The options currently supported are >
match. The regular expression MUST be surrounded like a multi-word
trigger (see above) even if it doesn't have any spaces. The resulting
match is also passed to any python code blocks in your snippet
definition in the as "snips.local['match']".
definition as the local variable "match".
4.2 Plaintext snippets *UltiSnips-plaintext-snippets*
----------------------
@ -281,7 +282,7 @@ which can be used: >
fn - The current filename
path - The complete path to the current file
t - The values of the placeholders, t[1] -> current text of ${1} and so on
snip - Provides easy indentation handling, and snippet-local variables.
snip - Provides easy indentation handling.
The snip object provides the following methods: >
@ -307,10 +308,6 @@ The snip object provides the following methods: >
The snip object provides some properties as well: >
snip.locals:
Is a dictionary which is available to any python block inside the
snippet.
snip.rv:
the text that will fill this python block's position, it always starts
out as an empty string. This deprecates the "res" variable.
@ -339,6 +336,7 @@ easier: >
snip += line:
is equivalent to "snip.rv += '\n' + snip.mkline(line)"
Any variables set in a python block can be used in any following blocks.
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
following snippet mirrors the first Tab Stops value on the same line in
@ -352,6 +350,29 @@ endsnippet
wow<tab>Hello World ->
Hello World HELLO WORLD
4.3.4 Global Snippets: *UltiSnips-globals*
Global snippets provide a way to take common code out of snippets. Currently,
only python code is supported. The result of executing the contents of the
snippet is put into the globals of each python block in the snippet file. To
create a global snippet, you use the keyword "global" in place of "snippet",
and for python code, you use "!p" for the trigger, for example, the following
is identical to the previous example, except that "upper_right" can be reused:
------------------- SNIP -------------------
global !p
def upper_right(inp):
return (75 - 2 * len(inp))*' ' + inp.upper()
endglobal
snippet wow
${1:Text}`!p snip.rv = upper_right(t[1])`
endsnippet
------------------- SNAP -------------------
wow<tab>Hello World ->
Hello World HELLO WORLD
4.4 Tab Stops and Placeholders *UltiSnips-tabstops* *UltiSnips-placeholders*
------------------------------

View File

@ -705,17 +705,10 @@ class _Tabs(object):
return ts.current_text
class SnippetUtil(object):
""" Provides easy access to indentation, and
snippet-local variables, which can be accessed by
any PythonCode object in the snippet.
""" Provides easy access to indentation, etc.
"""
def __init__(self, initial_indent, cur="", snippet=None):
if snippet:
self._locals = snippet.locals
else:
self._locals = {}
def __init__(self, initial_indent, cur=""):
self._sw = int(vim.eval("&sw"))
self._sts = int(vim.eval("&sts"))
self._et = (vim.eval("&expandtab") == "1")
@ -842,11 +835,6 @@ class SnippetUtil(object):
"""
return self._c
@property
def locals(self):
""" Provides snippet local variables. """
return self._locals
def opt(self, option, default=None):
""" Gets a vim variable. """
if vim.eval("exists('%s')" % option) == "1":
@ -884,7 +872,12 @@ class PythonCode(TextObject):
snippet = snippet._parent
except AttributeError:
snippet = None
self._snip = SnippetUtil(indent, snippet=snippet)
self._snip = SnippetUtil(indent)
self._locals = snippet.locals
self._globals = {}
globals = snippet.globals.get("!p", [])
exec "\n".join(globals) in self._globals
# Add Some convenience to the code
self._code = "import re, os, vim, string, random\n" + code
@ -900,21 +893,23 @@ class PythonCode(TextObject):
ct = self.current_text
self._snip._reset(ct)
d = {
local_d = self._locals
local_d.update({
't': _Tabs(self),
'fn': fn,
'path': path,
'cur': ct,
'res': ct,
'snip' : self._snip,
}
})
exec self._code in d
exec self._code in self._globals, local_d
if self._snip._rv_changed:
self.current_text = self._snip.rv
else:
self.current_text = str(d["res"])
self.current_text = str(local_d["res"])
def __repr__(self):
return "PythonCode(%s -> %s)" % (self._start, self._end)
@ -945,13 +940,14 @@ class SnippetInstance(TextObject):
"""
# TODO: for beauty sake, start and end should come before initial text
def __init__(self, parent, indent, initial_text, start = None, end = None, last_re = None):
def __init__(self, parent, indent, initial_text, start = None, end = None, last_re = None, globals = None):
if start is None:
start = Position(0,0)
if end is None:
end = Position(0,0)
self.locals = {"match" : last_re}
self.globals = globals
TextObject.__init__(self, parent, start, end, initial_text)

View File

@ -63,6 +63,7 @@ class _SnippetsFileParser(object):
self._sm = snip_manager
self._ft = ft
self._fn = fn
self._globals = {}
if file_data is None:
self._lines = open(fn).readlines()
else:
@ -96,17 +97,17 @@ class _SnippetsFileParser(object):
self._idx += 1
return self._line()
def _parse_snippet(self):
line = self._line()
def _parse_first(self, line):
""" Parses the first line of the snippet definition. Returns the
snippet type, trigger, description, and options in a tuple in that
order.
"""
cdescr = ""
coptions = ""
cs = ""
# Ensure this is a snippet
snip = line.split()[0]
if snip != "snippet":
self._error("Expecting 'snippet' not: %s" % snip)
# Get and strip options if they exist
remain = line[len(snip):].lstrip()
@ -133,17 +134,37 @@ class _SnippetsFileParser(object):
else:
cs = cs[1:-1]
return (snip, cs, cdescr, coptions)
def _parse_snippet(self):
line = self._line()
(snip, trig, desc, opts) = self._parse_first(line)
end = "end" + snip
cv = ""
while self._goto_next_line():
line = self._line()
if line.rstrip() == "endsnippet":
if line.rstrip() == end:
cv = cv[:-1] # Chop the last newline
if cs:
self._sm.add_snippet(cs, cv, cdescr, coptions, self._ft)
break
cv += line
else:
self._error("Missing 'endsnippet' for %r" % cs)
self._error("Missing 'endsnippet' for %r" % trig)
return None
if not trig:
# there was an error
return None
elif snip == "global":
# add snippet contents to file globals
if trig not in self._globals:
self._globals[trig] = []
self._globals[trig].append(cv)
elif snip == "snippet":
self._sm.add_snippet(trig, cv, desc, opts, self._ft, self._globals)
else:
self._error("Invalid snippet type: '%s'" % snip)
def parse(self):
while self._line():
@ -154,7 +175,7 @@ class _SnippetsFileParser(object):
[ p.strip() for p in tail.split(',') ])
else:
self._error("'extends' without file types")
elif head == "snippet":
elif head in ("snippet", "global"):
self._parse_snippet()
elif head == "clearsnippets":
self._sm.clear_snippets(tail.split(), self._ft)
@ -168,13 +189,14 @@ class _SnippetsFileParser(object):
class Snippet(object):
_INDENT = re.compile(r"^[ \t]*")
def __init__(self, trigger, value, descr, options):
def __init__(self, trigger, value, descr, options, globals):
self._t = trigger
self._v = value
self._d = descr
self._opts = options
self._matched = ""
self._last_re = None
self._globals = globals
def __repr__(self):
return "Snippet(%s,%s,%s)" % (self._t,self._d,self._opts)
@ -337,10 +359,10 @@ class Snippet(object):
if parent is None:
return SnippetInstance(StartMarker(start), indent,
v, last_re = self._last_re)
v, last_re = self._last_re, globals = self._globals)
else:
return SnippetInstance(parent, indent, v, start,
end, last_re = self._last_re)
end, last_re = self._last_re, globals = self._globals)
class VimState(object):
def __init__(self):
@ -504,11 +526,11 @@ class SnippetManager(object):
if not rv:
self._handle_failure(self.expand_trigger)
def add_snippet(self, trigger, value, descr, options, ft = "all"):
def add_snippet(self, trigger, value, descr, options, ft = "all", globals = None):
if ft not in self._snippets:
self._snippets[ft] = _SnippetDictionary()
l = self._snippets[ft].add_snippet(
Snippet(trigger, value, descr, options)
Snippet(trigger, value, descr, options, globals or {})
)
def clear_snippets(self, triggers = [], ft = "all"):

41
test.py
View File

@ -739,8 +739,8 @@ class PythonCode_OptNoExists(_VimTest):
# locals
class PythonCode_Locals(_VimTest):
snippets = ("test", r"""hi `!p snip.locals["a"] = "test"
snip.rv = "nothing"` `!p snip.rv = snip.locals["a"]
snippets = ("test", r"""hi `!p a = "test"
snip.rv = "nothing"` `!p snip.rv = a
` End""")
keys = """test""" + EX
wanted = """hi nothing test End"""
@ -1468,14 +1468,14 @@ class SnippetOptions_Regex_Self_TextBefore(_Regex_Self):
wanted = "a." + EX
class SnippetOptions_Regex_PythonBlockMatch(_VimTest):
snippets = (r"([abc]+)([def]+)", r"""`!p m = snip.locals["match"]
snippets = (r"([abc]+)([def]+)", r"""`!p m = match
snip.rv += m.group(2)
snip.rv += m.group(1)
`""", "", "r")
keys = "test cabfed" + EX
wanted = "test fedcab"
class SnippetOptions_Regex_PythonBlockNoMatch(_VimTest):
snippets = (r"cabfed", r"""`!p snip.rv = snip.locals["match"] or "No match"`""")
snippets = (r"cabfed", r"""`!p snip.rv = match or "No match"`""")
keys = "test cabfed" + EX
wanted = "test No match"
@ -1805,6 +1805,39 @@ class ParseSnippets_MultiWord_UnmatchedContainer(_VimTest):
UltiSnips: Invalid multiword trigger: '!inv snip/' in test_file(2)
""").strip()
class ParseSnippets_Global_Python(_VimTest):
snippets_test_file = ("all", "test_file", r"""
global !p
def tex(ins):
return "a " + ins + " b"
endglobal
snippet ab
x `!p snip.rv = tex("bob")` y
endsnippet
snippet ac
x `!p snip.rv = tex("jon")` y
endsnippet
""")
keys = "ab" + EX + "\nac" + EX
wanted = "x a bob b y\nx a jon b y"
class ParseSnippets_Global_Local_Python(_VimTest):
snippets_test_file = ("all", "test_file", r"""
global !p
def tex(ins):
return "a " + ins + " b"
endglobal
snippet ab
x `!p first = tex("bob")
snip.rv = "first"` `!p snip.rv = first` y
endsnippet
""")
keys = "ab" + EX
wanted = "x first a bob b y"
###########################################################################
# END OF TEST #