From 2060e06e7c81c123562d67d139c2d0126397549e Mon Sep 17 00:00:00 2001 From: Phillip Berndt Date: Wed, 13 Jul 2011 14:07:44 +0200 Subject: [PATCH 1/4] =?UTF-8?q?Added=20a=20script=20for=20automated=20snip?= =?UTF-8?q?mate=20=E2=86=92=20UltiSnips=20snippet=20conversion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/get_snipmate_snippets.py | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100755 utils/get_snipmate_snippets.py diff --git a/utils/get_snipmate_snippets.py b/utils/get_snipmate_snippets.py new file mode 100755 index 0000000..5606a51 --- /dev/null +++ b/utils/get_snipmate_snippets.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" + Convert snipmate compatible snippets to UltiSnips compatible snippets + by Phillip Berndt +""" +import sys +import re +import os + +def global_code_as_required(content): + " Return some global code for the resulting snippet. Only python support here.. " + if "`!p snip.rv = Filename" in content: + return "import os\n" + \ + """def Filename(fn, *args): + filename = os.path.splitext(fn)[0] + if filename == "": + return args[1] if len(args) == 2 else "" + return filename if len(args) == 0 or args[0] == "" else args[1].replace("$1", filename) + """ + +def convert_snippet_contents(content): + " If the snippet contains snipmate style substitutions, convert them to ultisnips style " + content = re.sub("`\s*Filename\(", "`!p snip.rv = Filename(fn, ", content) + content = re.sub("`(?!!)([^`]+`)", "`!v \g<1>", content) + return content + +def convert_snippet_file(source): + " One file per filetype " + retval = "" + state = 0 + for line in open(source).readlines(): + # Ignore empty lines + if line.strip() == "": + continue + # The rest of the handlig is stateful + if state == 0: + # Find snippet start + if line[:8] == "snippet ": + snippet_info = re.match("(\S+)\s*(.*)", line[8:]) + if not snippet_info: + print >> sys.stderr, "Warning: Malformed snippet\n %s\n" % line + continue + retval += 'snippet %s "%s"' % (snippet_info.group(1), snippet_info.group(2) if snippet_info.group(2) else snippet_info.group(1)) + "\n" + state = 1 + snippet = "" + elif state == 1: + # First line of snippet: Get indentation + whitespace = re.search("^\s+", line) + if not whitespace: + print >> sys.stderr, "Warning: Malformed snippet, content not indented.\n" + retval += "endsnippet\n\n" + state = 0 + else: + whitespace = whitespace.group(0) + snippet += line[len(whitespace):] + state = 2 + elif state == 2: + # In snippet: Check if indentation level is the same. If not, snippet has ended + if line[:len(whitespace)] != whitespace: + retval += convert_snippet_contents(snippet) + "endsnippet\n\n" + state = 0 + else: + snippet += line[len(whitespace):] + if state == 2: + retval += convert_snippet_contents(snippet) + "endsnippet\n\n" + return retval + +def convert_snippet(source): + " One file per snippet " + name = os.path.basename(source)[:-8] + return 'snippet %s "%s"' % (name, name) + "\n" + \ + convert_snippet_contents(open(source).read()) + \ + "\nendsnippet\n" + +def convert_snippets(source): + if os.path.isdir(source): + return "\n".join((convert_snippet(os.path.join(source, x)) for x in os.listdir(source) if x[-8:] == ".snippet")) + else: + return convert_snippet_file(source) + +if __name__ == '__main__': + if len(sys.argv) not in (3, 2): + print >> sys.stderr, "Syntax: get_snipmate_snippets.py [target file]" + print >> sys.stderr + sys.exit(1) + if len(sys.argv) == 2: + source = sys.argv[1] + target = sys.stdout + else: + source, target = sys.argv[1:] + target = open(target, "w") + + snippets = convert_snippets(source) + global_code = global_code_as_required(snippets) + if global_code: + print >> target, "global !p\n%s\nendglobal\n" % global_code + print >> target, snippets From 281781fcee848d18ddcaa9e49271a2e257871826 Mon Sep 17 00:00:00 2001 From: Phillip Berndt Date: Wed, 13 Jul 2011 14:19:17 +0200 Subject: [PATCH 2/4] Added snipmate's Filename() helper to UltiSnips.vim --- plugin/UltiSnips.vim | 9 +++++++++ utils/get_snipmate_snippets.py | 17 +---------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index bd7f464..8e3a9fb 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -12,6 +12,15 @@ if exists('did_UltiSnips_vim') || &cp || version < 700 || !has("python") finish endif +" Snipmate compatibilty: Filename function, taken from +" snipMate.vim {{{ +fun! Filename(...) + let filename = expand('%:t:r') + if filename == '' | return a:0 == 2 ? a:2 : '' | endif + return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g') +endf +" }}} + " Global Variables {{{ " The trigger used to expand a snippet. diff --git a/utils/get_snipmate_snippets.py b/utils/get_snipmate_snippets.py index 5606a51..668dff8 100755 --- a/utils/get_snipmate_snippets.py +++ b/utils/get_snipmate_snippets.py @@ -8,21 +8,9 @@ import sys import re import os -def global_code_as_required(content): - " Return some global code for the resulting snippet. Only python support here.. " - if "`!p snip.rv = Filename" in content: - return "import os\n" + \ - """def Filename(fn, *args): - filename = os.path.splitext(fn)[0] - if filename == "": - return args[1] if len(args) == 2 else "" - return filename if len(args) == 0 or args[0] == "" else args[1].replace("$1", filename) - """ - def convert_snippet_contents(content): " If the snippet contains snipmate style substitutions, convert them to ultisnips style " - content = re.sub("`\s*Filename\(", "`!p snip.rv = Filename(fn, ", content) - content = re.sub("`(?!!)([^`]+`)", "`!v \g<1>", content) + content = re.sub("`([^`]+`)", "`!v \g<1>", content) return content def convert_snippet_file(source): @@ -92,7 +80,4 @@ if __name__ == '__main__': target = open(target, "w") snippets = convert_snippets(source) - global_code = global_code_as_required(snippets) - if global_code: - print >> target, "global !p\n%s\nendglobal\n" % global_code print >> target, snippets From d08b58cf39ed0c58eca7b644f32e2b721b359dbf Mon Sep 17 00:00:00 2001 From: Phillip Berndt Date: Wed, 13 Jul 2011 14:23:21 +0200 Subject: [PATCH 3/4] Some of snipmates snippets also require one to have g:snips_author defined --- plugin/UltiSnips.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index 8e3a9fb..439bb79 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -14,6 +14,7 @@ endif " Snipmate compatibilty: Filename function, taken from " snipMate.vim {{{ +let g:snips_author = "John Doe" fun! Filename(...) let filename = expand('%:t:r') if filename == '' | return a:0 == 2 ? a:2 : '' | endif From 8276ec9b947a8f238d5b4fff571e56ca327f2a56 Mon Sep 17 00:00:00 2001 From: Phillip Berndt Date: Thu, 14 Jul 2011 12:24:14 +0200 Subject: [PATCH 4/4] Use argparse in the snipmate conversion script, renamed that script to convert_snipmate_snippets, removed the snipmate compatibility code from UltiSnips.vim and placed it into it's own file, fixed a bug where the user's value of g:snips_author was overwritten --- plugin/UltiSnips.vim | 10 ------- plugin/snipMate_compatibility.vim | 28 +++++++++++++++++++ ...ippets.py => convert_snipmate_snippets.py} | 23 +++++++++------ 3 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 plugin/snipMate_compatibility.vim rename utils/{get_snipmate_snippets.py => convert_snipmate_snippets.py} (72%) diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim index 439bb79..bd7f464 100644 --- a/plugin/UltiSnips.vim +++ b/plugin/UltiSnips.vim @@ -12,16 +12,6 @@ if exists('did_UltiSnips_vim') || &cp || version < 700 || !has("python") finish endif -" Snipmate compatibilty: Filename function, taken from -" snipMate.vim {{{ -let g:snips_author = "John Doe" -fun! Filename(...) - let filename = expand('%:t:r') - if filename == '' | return a:0 == 2 ? a:2 : '' | endif - return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g') -endf -" }}} - " Global Variables {{{ " The trigger used to expand a snippet. diff --git a/plugin/snipMate_compatibility.vim b/plugin/snipMate_compatibility.vim new file mode 100644 index 0000000..f88c25b --- /dev/null +++ b/plugin/snipMate_compatibility.vim @@ -0,0 +1,28 @@ +" File: snipMate_compatibility.vim +" Author: Phillip Berndt +" Description: Snipmate compatibility helper functions for UltiSnips +" +" Snipmate defines a function named Filename and a variable called +" g:snips_author for use in snippet subtitutions. See +" https://github.com/msanders/snipmate.vim/blob/master/doc/snipMate.txt +" for details. +" + +if exists('did_UltiSnips_snipmate_compatibility') + finish +endif +let did_UltiSnips_snipmate_compatibility = 1 + +" Define g:snips_author; some snipmate snippets use this +if ! exists('g:snips_author') + let g:snips_author = "John Doe" +endif + +" Filename function, taken from snipMate.vim {{{ +fun! Filename(...) + let filename = expand('%:t:r') + if filename == '' | return a:0 == 2 ? a:2 : '' | endif + return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g') +endf +" }}} + diff --git a/utils/get_snipmate_snippets.py b/utils/convert_snipmate_snippets.py similarity index 72% rename from utils/get_snipmate_snippets.py rename to utils/convert_snipmate_snippets.py index 668dff8..cc9f999 100755 --- a/utils/get_snipmate_snippets.py +++ b/utils/convert_snipmate_snippets.py @@ -7,6 +7,7 @@ import sys import re import os +import argparse def convert_snippet_contents(content): " If the snippet contains snipmate style substitutions, convert them to ultisnips style " @@ -68,16 +69,20 @@ def convert_snippets(source): return convert_snippet_file(source) if __name__ == '__main__': - if len(sys.argv) not in (3, 2): - print >> sys.stderr, "Syntax: get_snipmate_snippets.py [target file]" - print >> sys.stderr + # Parse command line + argsp = argparse.ArgumentParser(description="Convert snipmate compatible snippets to UltiSnips' file format", + epilog="example:\n %s drupal/ drupal.snippets\n will convert all drupal specific snippets from snipmate into one file drupal.snippets" % sys.argv[0], + formatter_class=argparse.RawDescriptionHelpFormatter) + argsp.add_argument("source", help="Source directory for one filetype or a snippets file") + argsp.add_argument("target", help="File to write the resulting snippets into. If omitted, the snippets will be written to stdout.", nargs="?", default="-") + args = argsp.parse_args() + + source = args.source + try: + target = sys.stdout if args.target == "-" else open(args.target, "w") + except IOError: + print >> sys.stderr, "Error: Failed to open output file %s for writing" % args.target sys.exit(1) - if len(sys.argv) == 2: - source = sys.argv[1] - target = sys.stdout - else: - source, target = sys.argv[1:] - target = open(target, "w") snippets = convert_snippets(source) print >> target, snippets