diff --git a/vim/bundle/ultisnips/ChangeLog b/vim/bundle/ultisnips/ChangeLog index bd4331d..50f06ae 100644 --- a/vim/bundle/ultisnips/ChangeLog +++ b/vim/bundle/ultisnips/ChangeLog @@ -1,75 +1,90 @@ - - Support for ${VISUAL}. *UltiSnips-visual-placeholder* +version 2.1: + - Python interpolation access to text from visual selection via snip.v. + - Support for transformations of ${VISUAL} texts. + - New or improved snippets: python, tex, texmath, ruby, rails, html, django + +version 2.0: + - Backwards incompatible change: Support for normal mode editing. Snippets + are no longer exited when leaving insert mode but only by leaving the + text span of the snippets. This allows usage of normal mode commands and + autoformatting. It also increases compatibility with other plugins. + - Backwards incompatible change: Changed glob patterns for snippets to + behave more like Vim *UltiSnips-adding-snippets* + - Backwards incompatible change: Zero Tabstop is no longer removed in + nested snippets + - Support for ${VISUAL:default text} placeholder. *UltiSnips-visual-placeholder* - Improved handling of utf-8 characters in files and snippet definitions. - - Full support for :py3. UltiSnips now truly works with python >= 2.6. + - Full support for :py3. UltiSnips now works with python >= 2.6 or >= 3.2. + - New or improved snippets: python, all version 1.6: - - Significant speed improvements and a few bugs fixed. - - Better handling of non ASCII chars in snippets by assuming UTF-8 encoding - when no other information is available. - - Contributions for UltiSnips are now also accepted on GitHub: https://github.com/SirVer/ultisnips/ - - New or improved snippets: ruby, rails, xhtml + - Significant speed improvements and a few bugs fixed. + - Better handling of non ASCII chars in snippets by assuming UTF-8 encoding + when no other information is available. + - Contributions for UltiSnips are now also accepted on GitHub: https://github.com/SirVer/ultisnips/ + - New or improved snippets: ruby, rails, xhtml version 1.5: - - Some critical bug fixes for new vim versions. - - New or improved snippets: tex, texmath, python, jinja2, go, puppet, xhtml - - Configuration of search path for snippets *UltiSnips-snippet-search-path* - - New parser implementation: A little faster, more flexible and less bugged. + - Some critical bug fixes for new vim versions. + - New or improved snippets: tex, texmath, python, jinja2, go, puppet, xhtml + - Configuration of search path for snippets *UltiSnips-snippet-search-path* + - New parser implementation: A little faster, more flexible and less bugged. version 1.4: - - New or improved snippets: php, html, djangohtml, mako, lua - - Snippets are now listed alphabetically by their trigger, no longer in - order of appearance - - Snippet files are now automatically reloaded when they change. - - Support for other directory names for snippets beside - "UltiSnips" *UltiSnips-snippet-search-path* - - Errors are now shown in a scratch window. - - Now fully supports Windows with python >= 2.6. UltiSnips should now work - on all systems that Vim runs on. - - a syntax file was added for snippets files with nice highlighting. - - snippets definition files now have the filetype 'snippets'. It used to be - 'snippet'. + - New or improved snippets: php, html, djangohtml, mako, lua + - Snippets are now listed alphabetically by their trigger, no longer in + order of appearance + - Snippet files are now automatically reloaded when they change. + - Support for other directory names for snippets beside + "UltiSnips" *UltiSnips-snippet-search-path* + - Errors are now shown in a scratch window. + - Now fully supports Windows with python >= 2.6. UltiSnips should now work + on all systems that Vim runs on. + - a syntax file was added for snippets files with nice highlighting. + - snippets definition files now have the filetype 'snippets'. It used to be + 'snippet'. version 1.3: - - Erlang snippets (g0rdin) - - Other VimScripts can now define and immediately expand anonymous snippets - ( *UltiSnips_Anon* ) (Ryan Wooden) - - Other VimScripts can now define new snippets via a function - ( *UltiSnips_AddSnippet* ) (Ryan Wooden) - - New Snippets for eruby and rails (Ches Martin). - - A new Option 't' has been added to snippets that avoid expanding tabstops. - Be also more consistent with how indenting is handled. (Ryan Wooden) - - Added a ftplugin script for .snippets files. Syntax highlighting still - missing. (Rupa Deadwyler) - - Added UltiSnipsReset and UltiSnipsEdit (Idea by JCEB) + - Erlang snippets (g0rdin) + - Other VimScripts can now define and immediately expand anonymous snippets + ( *UltiSnips_Anon* ) (Ryan Wooden) + - Other VimScripts can now define new snippets via a function + ( *UltiSnips_AddSnippet* ) (Ryan Wooden) + - New Snippets for eruby and rails (Ches Martin). + - A new Option 't' has been added to snippets that avoid expanding tabstops. + Be also more consistent with how indenting is handled. (Ryan Wooden) + - Added a ftplugin script for .snippets files. Syntax highlighting still + missing. (Rupa Deadwyler) + - Added UltiSnipsReset and UltiSnipsEdit (Idea by JCEB) version 1.2: - - many bugs were fixed - - smode mappings for printable characters are now removed before expanding a - snippet. This is configurable. *UltiSnips-warning-smappings* - - all shipped snippets are now fully compatible with UltiSnips - - added support for global snippets which enhance python interpolation even - more *UltiSnips-globals* - - added support for multi word and regular expression triggers. Very - powerful in combination with python interpolation. - - Python interpolation became much more powerful *UltiSnips-python* - - added support for clearsnippets command *UltiSnips-clearing-snippets* - - added support for option w which is a little more strict than i. - - added support for listing of valid triggers. Defaults to . - - added support for option i (inword expansion) - - extends keyword is now supported on the first line of snippet files. This makes it easy to - define special cases, for example cpp extends c: a cpp trigger is useless - in c, but a c trigger is valuable for cpp. - - UltiSnips now adheres to expandtab and tabstop options of vim + - many bugs were fixed + - smode mappings for printable characters are now removed before expanding a + snippet. This is configurable. *UltiSnips-warning-smappings* + - all shipped snippets are now fully compatible with UltiSnips + - added support for global snippets which enhance python interpolation even + more *UltiSnips-globals* + - added support for multi word and regular expression triggers. Very + powerful in combination with python interpolation. + - Python interpolation became much more powerful *UltiSnips-python* + - added support for clearsnippets command *UltiSnips-clearing-snippets* + - added support for option w which is a little more strict than i. + - added support for listing of valid triggers. Defaults to . + - added support for option i (inword expansion) + - extends keyword is now supported on the first line of snippet files. This makes it easy to + define special cases, for example cpp extends c: a cpp trigger is useless + in c, but a c trigger is valuable for cpp. + - UltiSnips now adheres to expandtab and tabstop options of vim version 1.1: - - Made triggers configurable. You can also use the same trigger for - expanding and tabbing. The TextMate configuration and is now - possible. - - Conditional Inserts can now be nested - - Added support for b option. This only considers a snippet at the beginning - of a line ( *UltiSnips-adding-snippets* ) - - Added support for ! option. This overwrites previously defined snippets - with the same tab trigger ( *UltiSnips-adding-snippets* ) - - Support for dotted filetype syntax. Now snippets for more than one filetype - can be active ( *UltiSnips-adding-snippets* ) + - Made triggers configurable. You can also use the same trigger for + expanding and tabbing. The TextMate configuration and is now + possible. + - Conditional Inserts can now be nested + - Added support for b option. This only considers a snippet at the beginning + of a line ( *UltiSnips-adding-snippets* ) + - Added support for ! option. This overwrites previously defined snippets + with the same tab trigger ( *UltiSnips-adding-snippets* ) + - Support for dotted filetype syntax. Now snippets for more than one filetype + can be active ( *UltiSnips-adding-snippets* ) diff --git a/vim/bundle/ultisnips/README.rst b/vim/bundle/ultisnips/README.rst index a727f43..0e9889b 100644 --- a/vim/bundle/ultisnips/README.rst +++ b/vim/bundle/ultisnips/README.rst @@ -22,8 +22,12 @@ discussed in the video. * `Episode 1: What are snippets and do I need them?`__ * `Episode 2: Creating Basic Snippets`__ +* `Episode 3: What's new in version 2.0`__ +* `Episode 4: Python Interpolation`__ __ http://www.sirver.net/blog/2011/12/30/first-episode-of-ultisnips-screencast/ __ http://www.sirver.net/blog/2012/01/08/second-episode-of-ultisnips-screencast/ +__ http://www.sirver.net/blog/2012/02/05/third-episode-of-ultisnips-screencast/ +__ http://www.sirver.net/blog/2012/03/31/fourth-episode-of-ultisnips-screencast/ diff --git a/vim/bundle/ultisnips/UltiSnips/all.snippets b/vim/bundle/ultisnips/UltiSnips/all.snippets index cf64396..273c64d 100644 --- a/vim/bundle/ultisnips/UltiSnips/all.snippets +++ b/vim/bundle/ultisnips/UltiSnips/all.snippets @@ -5,47 +5,75 @@ # NICE BOXES # ############## global !p -def cs(snip): - c = '#' - cs = snip.opt("&commentstring") - if len(cs) == 3: - c = cs[0] - return c +import string, vim +def _parse_comments(s): + i = iter(s.split(",")) + + rv = [] + try: + while True: + n = i.next() + if n[0] == 's': + ctriple = [] + indent = "" + if n[1] in string.digits: + indent = " " * int(n[1]) + ctriple.append(n.split(":",1)[1]) + n = i.next() + assert(n[0] == 'm') + ctriple.append(n.split(":",1)[1]) + n = i.next() + assert(n[0] == 'e') + ctriple.append(n.split(":",1)[1]) + ctriple.append(indent) + rv.append(ctriple) + elif n[0] == 'b': + cm = n.split(":", 1)[1] + if len(cm) == 1: + rv.insert(0, (cm,cm,cm, "")) + except StopIteration: + return rv + +def make_box(twidth, bwidth = None): + if bwidth is None: + bwidth = twidth + 2 + b,m,e,i = _parse_comments(vim.eval("&comments"))[0] + sline = b + m + bwidth*m + 2*m + nspaces = (bwidth - twidth)//2 + mlines = i + m + " " + " "*nspaces + mlinee = " " + " "*(bwidth-twidth-nspaces) + m + eline = i + 2*m + bwidth*m + m + e + return sline, mlines, mlinee, eline endglobal snippet box "A nice box with the current comment symbol" b `!p -c = cs(snip) - -snip.rv = (len(t[1])+4)*c -bar = snip.rv -snip += c + ' '`${1:content}`!p - -snip.rv = ' ' + c -snip += bar` +box = make_box(len(t[1])) +snip.rv = box[0] + '\n' + box[1] +`${1:content}`!p +box = make_box(len(t[1])) +snip.rv = box[2] + '\n' + box[3]` $0 endsnippet snippet bbox "A nice box over the full width" b `!p -c = cs(snip) -bar = 75*c - -snip.rv = bar -snip += c + " " + (71-len(t[1]))/2*' ' +box = make_box(len(t[1]), 71) +snip.rv = box[0] + '\n' + box[1] `${1:content}`!p - -a = 71-len(t[1]) -snip.rv = (a/2 + a%2) * " " + " " + c -snip += bar` +box = make_box(len(t[1]), 71) +snip.rv = box[2] + '\n' + box[3]` $0 endsnippet ########################## # LOREM IPSUM GENERATORS # ########################## -snippet lorem "Lorem Ipsum - 50 Words" fb -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +snippet lorem "Lorem Ipsum - 50 Words" b +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod +tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At +vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, +no sea takimata sanctus est Lorem ipsum dolor sit amet. endsnippet # vim:ft=snippets: diff --git a/vim/bundle/ultisnips/UltiSnips/bindzone.snippets b/vim/bundle/ultisnips/UltiSnips/bindzone.snippets new file mode 100644 index 0000000..034ccde --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/bindzone.snippets @@ -0,0 +1,27 @@ +global !p +def newsoa(): + import datetime + now = datetime.datetime.now() + # return standard SOA formatted serial for today + return now.strftime("%Y%m%d00") +endglobal + +snippet zone "Bootstrap a new Bind zonefile" b +$TTL 86400 +@ IN SOA ${1:example.net}. ${2:hostmaster.$1}.( + `!p snip.rv = newsoa()`; serial + 21600; refresh every 6 hours + 3600; retry after one hour + 604800; expire after a week + 86400 ); minimum TTL of 1 day + + IN NS ns01.$1. + IN MX 10 mail.$1. + +ns01.$1 IN A +mail.$1 IN A +endsnippet + +snippet A "Insert A Record" b +${1:hostname} IN A ${2:ip} +endsnippet diff --git a/vim/bundle/ultisnips/UltiSnips/c.snippets b/vim/bundle/ultisnips/UltiSnips/c.snippets index 1c62d0b..532fe17 100644 --- a/vim/bundle/ultisnips/UltiSnips/c.snippets +++ b/vim/bundle/ultisnips/UltiSnips/c.snippets @@ -8,6 +8,12 @@ snippet def "#ifndef ... #define ... #endif" #endif endsnippet +snippet #if "#if #endif" !b +#if ${1:0} +${VISUAL:code}$0 +#endif +endsnippet + snippet inc "#include local header (inc)" #include "${1:`!p snip.rv = snip.basename + '.h'`}" endsnippet diff --git a/vim/bundle/ultisnips/UltiSnips/coffee.snippets b/vim/bundle/ultisnips/UltiSnips/coffee.snippets new file mode 100644 index 0000000..8f347f1 --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/coffee.snippets @@ -0,0 +1,90 @@ +# From the TextMate bundle + +snippet fun "Function" b +${1:name} = (${2:args}) -> + ${0:# body...} +endsnippet + +snippet bfun "Function (bound)" b +${1:(${2:args}) }=> + ${0:# body...} +endsnippet + +snippet if "If" b +if ${1:condition} + ${0:# body...} +endsnippet + +snippet ife "If .. Else" b +if ${1:condition} + ${2:# body...} +else + ${3:# body...} +endsnippet + +snippet elif "Else if" b +else if ${1:condition} + ${0:# body...} +endsnippet + +snippet ifte "Ternary if" b +if ${1:condition} then ${2:value} else ${3:other} +endsnippet + +snippet unl "Unless" b +${1:action} unless ${2:condition} +endsnippet + +snippet fora "Array Comprehension" b +for ${1:name} in ${2:array} + ${0:# body...} +endsnippet + +snippet foro "Object Comprehension" b +for ${1:key}, ${2:value} of ${3:Object} + ${0:# body...} +endsnippet + +snippet forr "Range Comprehension (inclusive)" b +for ${1:name} in [${2:start}..${3:finish}]${4: by ${5:step}} + ${0:# body...} +endsnippet + +snippet forrex "Range Comprehension (exclusive)" b +for ${1:name} in [${2:start}...${3:finish}]${4: by ${5:step}} + ${0:# body...} +endsnippet + +snippet swi "Switch" b +switch ${1:object} + when ${2:value} + ${0:# body...} +endsnippet + +snippet cla "Class" b +class ${1:ClassName}${2: extends ${3:Ancestor}} + + ${4:constructor: (${5:args}) -> + ${6:# body...}} + $7 +endsnippet + +snippet try "Try .. Catch" b +try + $1 +catch ${2:error} + $3 +endsnippet + +snippet req "Require" b +${1/^'?(\w+)'?$/\L$1\E/} = require(${1:'${2:sys}'}) +endsnippet + +snippet # "Interpolated Code" +#{$1}$0 +endsnippet + +snippet log "Log" b +console.log ${1:"${2:msg}"} +endsnippet + diff --git a/vim/bundle/ultisnips/UltiSnips/coffee_jasmine.snippets b/vim/bundle/ultisnips/UltiSnips/coffee_jasmine.snippets new file mode 100644 index 0000000..47d1e6b --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/coffee_jasmine.snippets @@ -0,0 +1,163 @@ +# +# CoffeeScript versions -- adapted from the JS TextMate bundle + additions +# for some jasmine-jquery matchers +# +extends coffee + +snippet des "Describe (coffee)" b +describe '${1:description}', -> + $0 +endsnippet + +snippet it "it (coffee)" b +it '${1:description}', -> + $0 +endsnippet + +snippet bef "before each (coffee)" b +beforeEach -> + $0 +endsnippet + +snippet aft "after each (coffee)" b +afterEach -> + $0 +endsnippet + +snippet any "any (coffee)" b +jasmine.any($1) +endsnippet + +snippet ru "runs (coffee)" b +runs -> + $0 +endsnippet + +snippet wa "waits (coffee)" b +waits($1) +endsnippet + +snippet ex "expect (coffee)" b +expect(${1:target})$0 +endsnippet + +snippet ee "expect to equal (coffee)" b +expect(${1:target}).toEqual(${2:value}) +endsnippet + +snippet em "expect to match (coffee)" b +expect(${1:target}).toMatch(${2:pattern}) +endsnippet + +snippet eha "expect to have attribute (coffee)" b +expect(${1:target}).toHaveAttr('${2:attr}'${3:, '${4:value}'}) +endsnippet + +snippet et "expect to be truthy (coffee)" b +expect(${1:target}).toBeTruthy() +endsnippet + +snippet ef "expect to be falsy (coffee)" b +expect(${1:target}).toBeFalsy() +endsnippet + +snippet ed "expect to be defined (coffee)" b +expect(${1:target}).toBeDefined() +endsnippet + +snippet en "expect to be null (coffee)" b +expect(${1:target}).toBeNull() +endsnippet + +snippet ec "expect to contain (coffee)" b +expect(${1:target}).toContain(${2:value}) +endsnippet + +snippet ev "expect to be visible (coffee)" b +expect(${1:target}).toBeVisible() +endsnippet + +snippet eh "expect to be hidden (coffee)" b +expect(${1:target}).toBeHidden() +endsnippet + +snippet notx "expect not (coffee)" b +expect(${1:target}).not$0 +endsnippet + +snippet note "expect not to equal (coffee)" b +expect(${1:target}).not.toEqual(${2:value}) +endsnippet + +snippet notm "expect not to match (coffee)" b +expect(${1:target}).not.toMatch(${2:pattern}) +endsnippet + +snippet notha "expect to not have attribute (coffee)" b +expect(${1:target}).not.toHaveAttr('${2:attr}'${3:, '${4:value}'}) +endsnippet + +snippet nott "expect not to be truthy (coffee)" b +expect(${1:target}).not.toBeTruthy() +endsnippet + +snippet notf "expect not to be falsy (coffee)" b +expect(${1:target}).not.toBeFalsy() +endsnippet + +snippet notd "expect not to be defined (coffee)" b +expect(${1:target}).not.toBeDefined() +endsnippet + +snippet notn "expect not to be null (coffee)" b +expect(${1:target}).not.toBeNull() +endsnippet + +snippet notc "expect not to contain (coffee)" b +expect(${1:target}).not.toContain(${2:value}) +endsnippet + +snippet notv "expect not to be visible (coffee)" b +expect(${1:target}).not.toBeVisible() +endsnippet + +snippet noth "expect not to be hidden (coffee)" b +expect(${1:target}).not.toBeHidden() +endsnippet + +snippet s "spy on (coffee)" b +spyOn(${1:object}, "${2:method}")$0 +endsnippet + +snippet sr "spy on and return (coffee)" b +spyOn(${1:object}, "${2:method}").andReturn(${3:arguments}) +endsnippet + +snippet st "spy on and throw (coffee)" b +spyOn(${1:object}, "${2:method}").andThrow(${3:exception}) +endsnippet + +snippet sct "spy on and call through (coffee)" b +spyOn(${1:object}, "${2:method}").andCallThrough() +endsnippet + +snippet scf "spy on and call fake (coffee)" b +spyOn(${1:object}, "${2:method}").andCallFake(${3:function}) +endsnippet + +snippet esc "expect was called (coffee)" b +expect(${1:target}).wasCalled() +endsnippet + +snippet escw "expect was called with (coffee)" b +expect(${1:target}).wasCalledWith(${2:arguments}) +endsnippet + +snippet notsc "expect was not called (coffee)" b +expect(${1:target}).wasNotCalled() +endsnippet + +snippet noscw "expect was not called with (coffee)" b +expect(${1:target}).wasNotCalledWith(${2:arguments}) +endsnippet + diff --git a/vim/bundle/ultisnips/UltiSnips/django.snippets b/vim/bundle/ultisnips/UltiSnips/django.snippets new file mode 100644 index 0000000..59b77c5 --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/django.snippets @@ -0,0 +1,236 @@ +# Generic Tags +snippet % +{% ${1} %}${2} +endsnippet + +snippet %% +{% ${1:tag_name} %} + ${2} +{% end$1 %} +endsnippet + +snippet { +{{ ${1} }}${2} +endsnippet + +# Template Tags + +snippet autoescape +{% autoescape ${1:off} %} + ${2} +{% endautoescape %} +endsnippet + +snippet block +{% block ${1} %} + ${2} +{% endblock %} +endsnippet + +snippet # +{# ${1:comment} #} +endsnippet + +snippet comment +{% comment %} + ${1} +{% endcomment %} +endsnippet + +snippet cycle +{% cycle ${1:val1} ${2:val2} ${3:as ${4}} %} +endsnippet + +snippet debug +{% debug %} +endsnippet + +snippet extends +{% extends "${1:base.html}" %} +endsnippet + +snippet filter +{% filter ${1} %} + ${2} +{% endfilter %} +endsnippet + +snippet firstof +{% firstof ${1} %} +endsnippet + +snippet for +{% for ${1} in ${2} %} + ${3} +{% endfor %} +endsnippet + +snippet empty +{% empty %} + ${1} +endsnippet + +snippet if +{% if ${1} %} + ${2} +{% endif %} +endsnippet + +snippet else +{% else %} + ${1} +endsnippet + +snippet ifchanged +{% ifchanged %}${1}{% endifchanged %} +endsnippet + +snippet ifequal +{% ifequal ${1} ${2} %} + ${3} +{% endifequal %} +endsnippet + +snippet ifnotequal +{% ifnotequal ${1} ${2} %} + ${3} +{% endifnotequal %} +endsnippet + +snippet include +{% include "${1}" %} +endsnippet + +snippet load +{% load ${1} %} +endsnippet + +snippet now +{% now "${1:jS F Y H:i}" %} +endsnippet + +snippet regroup +{% regroup ${1} by ${2} as ${3} %} +endsnippet + +snippet spaceless +{% spaceless %}${1}{% endspaceless %} +endsnippet + +snippet ssi +{% ssi ${1} %} +endsnippet + +snippet trans +{% trans "${1:string}" %} +endsnippet + +snippet url +{% url ${1} as ${2} %} +endsnippet + +snippet widthratio +{% widthratio ${1:this_value} ${2:max_value} ${3:100} %} +endsnippet + +snippet with +{% with ${1} as ${2} %} +endsnippet + +# Template Filters + +# Note: Since SnipMate can't determine which template filter you are +# expanding without the "|" character, these do not add the "|" +# character. These save a few keystrokes still. + +# Note: Template tags that take no arguments are not implemented. + +snippet add +add:"${1}" +endsnippet + +snippet center +center:"${1}" +endsnippet + +snippet cut +cut:"${1}" +endsnippet + +snippet date +date:"${1}" +endsnippet + +snippet default +default:"${1}" +endsnippet + +snippet defaultifnone +default_if_none:"${1}" +endsnippet + +snippet dictsort +dictsort:"${1}" +endsnippet + +snippet dictsortrev +dictsortreversed:"${1}" +endsnippet + +snippet divisibleby +divisibleby:"${1}" +endsnippet + +snippet floatformat +floatformat:"${1}" +endsnippet + +snippet getdigit +get_digit:"${1}" +endsnippet + +snippet join +join:"${1}" +endsnippet + +snippet lengthis +length_is:"${1}" +endsnippet + +snippet pluralize +pluralize:"${1}" +endsnippet + +snippet removetags +removetags:"${1}" +endsnippet + +snippet slice +slice:"${1}" +endsnippet + +snippet stringformat +stringformat:"${1}" +endsnippet + +snippet time +time:"${1}" +endsnippet + +snippet truncatewords +truncatewords:${1} +endsnippet + +snippet truncatewordshtml +truncatewords_html:${1} +endsnippet + +snippet urlizetrunc +urlizetrunc:${1} +endsnippet + +snippet wordwrap +wordwrap:${1} +endsnippet + +# vim:ft=snippets: diff --git a/vim/bundle/ultisnips/UltiSnips/eruby.snippets b/vim/bundle/ultisnips/UltiSnips/eruby.snippets index 122fd11..1fdcfc1 100644 --- a/vim/bundle/ultisnips/UltiSnips/eruby.snippets +++ b/vim/bundle/ultisnips/UltiSnips/eruby.snippets @@ -256,7 +256,7 @@ render :partial => "${1:item}", :status => ${2:500} endsnippet snippet slt "stylesheet_link_tag" -`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`stylesheet_link_tag {1::all}${2:, :cache => ${3:true}}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`stylesheet_link_tag ${1::all}${2:, :cache => ${3:true}}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` endsnippet snippet st "submit_tag" diff --git a/vim/bundle/ultisnips/UltiSnips/go.snippets b/vim/bundle/ultisnips/UltiSnips/go.snippets index 3f0f85d..ea46931 100644 --- a/vim/bundle/ultisnips/UltiSnips/go.snippets +++ b/vim/bundle/ultisnips/UltiSnips/go.snippets @@ -5,7 +5,7 @@ # optional local name? snippet /^import/ "Import declaration" r import ( - "${1:package}" + "${1:package}" ) endsnippet @@ -17,7 +17,7 @@ endsnippet # Mostly converted from: https://github.com/AlanQuatermain/go-tmbundle snippet /^cons/ "Constants declaration" r const ( - ${1:constant}${2/(.+)/ /}${2:type} = ${0:value} + ${1:constant}${2/(.+)/ /}${2:type} = ${0:value} ) endsnippet @@ -27,26 +27,26 @@ endsnippet snippet iota "Iota constant generator" b const ( - ${1:constant}${2/(.+)/ /}${2:type} = iota + ${1:constant}${2/(.+)/ /}${2:type} = iota ) endsnippet # statements snippet for "For loop" !b for ${1:condition}${1/(.+)/ /}{ - ${0:// body} + ${0:${VISUAL}} } endsnippet snippet forr "For range loop" !b for ${2:name} := range ${1:collection} { - ${0:// body} + ${0:${VISUAL}} } endsnippet snippet if "If statement" !b if ${1:condition}${1/(.+)/ /}{ - ${0:// body} + ${0:${VISUAL}} } endsnippet @@ -58,30 +58,30 @@ endsnippet snippet case "Case clause" !b case ${1:condition}: - ${0://body} + ${0:${VISUAL}} endsnippet snippet default "Default clause" !b default: - ${0://body} + ${0:${VISUAL}} endsnippet # functions snippet /^main/ "Main function" r func main() { - ${0:// body} + ${0:${VISUAL}} } endsnippet snippet /^meth/ "Method" r func (${1:receiver} ${2:type}) ${3:name}(${4:params})${5/(.+)/ /}${5:type} { - ${0:// body} + ${0:${VISUAL}} } endsnippet -snippet /^func/ "Function" r +snippet func "Function" b func ${1:name}(${2:params})${3/(.+)/ /}${3:type} { - ${0:// body} + ${0:${VISUAL}} } endsnippet @@ -100,7 +100,7 @@ endsnippet snippet vars "Variables declaration" !b var ( - ${1:name}${2/(.+)/ /}${2:type}${3: = ${0:value} } + ${1:name}${2/(.+)/ /}${2:type}${3: = ${0:value} } ) endsnippet diff --git a/vim/bundle/ultisnips/UltiSnips/haskell.snippets b/vim/bundle/ultisnips/UltiSnips/haskell.snippets new file mode 100644 index 0000000..eb7b2c6 --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/haskell.snippets @@ -0,0 +1,61 @@ +snippet if "if ... then ... else ..." +if ${1:condition} + then ${2:expression} + else ${3:expression} +endsnippet + +snippet case "case ... of ..." +case ${1:expression} of + ${2:pattern} -> ${3:expression} + ${4:pattern} -> ${5:expression} +endsnippet + +snippet :: "Type signature" +${1:name} :: ${2:Type} -> ${3:Type} +endsnippet + +snippet => "Type constraint" +(${1:Class} ${2:Type var}) => ${3:$2} +endsnippet + +snippet def "Function definition" +${1:name} :: ${2:Type} -> ${3:Type} +endsnippet + +snippet def[] "Function definition for list patterns" +${1:name} :: [${2:Type}] -> ${3:Type} +$1 [] = ${4:undefined} +$1 ${5:(x:xs)} = ${6:undefined} +endsnippet + +snippet = "Function clause" +${1:name} ${2:pattern} = ${3:undefined} +endsnippet + +snippet 2= "Function clause" +${1:name} ${2:pattern} = ${3:undefined} +$1 ${4:pattern} = ${5:undefined} +endsnippet + +snippet 3= "Function clause" +${1:name} ${2:pattern} = ${3:undefined} +$1 ${4:pattern} = ${5:undefined} +$1 ${6:pattern} = ${7:undefined} +endsnippet + +snippet | "Guard" +| ${1:predicate} = ${2:undefined} +endsnippet + +snippet \ "Lambda expression" +\ ${1:pattern} -> ${2:expression} +endsnippet + +snippet [|] "List comprehension" +[${3:foo }$1 | ${1:x} <- ${2:xs} ] +endsnippet + +snippet let "let ... in ..." +let ${1:name} = ${2:expression} +in ${3:expression} +endsnippet diff --git a/vim/bundle/ultisnips/UltiSnips/html.snippets b/vim/bundle/ultisnips/UltiSnips/html.snippets index b6f23dc..1cb86b2 100644 --- a/vim/bundle/ultisnips/UltiSnips/html.snippets +++ b/vim/bundle/ultisnips/UltiSnips/html.snippets @@ -37,6 +37,10 @@ snippet doctype "HTML - 4.0 Transitional (doctype)" b endsnippet +snippet doctype "HTML - 5.0 (doctype)" b + + +endsnippet ############# # Shortcuts # diff --git a/vim/bundle/ultisnips/UltiSnips/htmldjango.snippets b/vim/bundle/ultisnips/UltiSnips/htmldjango.snippets index 59b77c5..9df5f78 100644 --- a/vim/bundle/ultisnips/UltiSnips/htmldjango.snippets +++ b/vim/bundle/ultisnips/UltiSnips/htmldjango.snippets @@ -1,236 +1 @@ -# Generic Tags -snippet % -{% ${1} %}${2} -endsnippet - -snippet %% -{% ${1:tag_name} %} - ${2} -{% end$1 %} -endsnippet - -snippet { -{{ ${1} }}${2} -endsnippet - -# Template Tags - -snippet autoescape -{% autoescape ${1:off} %} - ${2} -{% endautoescape %} -endsnippet - -snippet block -{% block ${1} %} - ${2} -{% endblock %} -endsnippet - -snippet # -{# ${1:comment} #} -endsnippet - -snippet comment -{% comment %} - ${1} -{% endcomment %} -endsnippet - -snippet cycle -{% cycle ${1:val1} ${2:val2} ${3:as ${4}} %} -endsnippet - -snippet debug -{% debug %} -endsnippet - -snippet extends -{% extends "${1:base.html}" %} -endsnippet - -snippet filter -{% filter ${1} %} - ${2} -{% endfilter %} -endsnippet - -snippet firstof -{% firstof ${1} %} -endsnippet - -snippet for -{% for ${1} in ${2} %} - ${3} -{% endfor %} -endsnippet - -snippet empty -{% empty %} - ${1} -endsnippet - -snippet if -{% if ${1} %} - ${2} -{% endif %} -endsnippet - -snippet else -{% else %} - ${1} -endsnippet - -snippet ifchanged -{% ifchanged %}${1}{% endifchanged %} -endsnippet - -snippet ifequal -{% ifequal ${1} ${2} %} - ${3} -{% endifequal %} -endsnippet - -snippet ifnotequal -{% ifnotequal ${1} ${2} %} - ${3} -{% endifnotequal %} -endsnippet - -snippet include -{% include "${1}" %} -endsnippet - -snippet load -{% load ${1} %} -endsnippet - -snippet now -{% now "${1:jS F Y H:i}" %} -endsnippet - -snippet regroup -{% regroup ${1} by ${2} as ${3} %} -endsnippet - -snippet spaceless -{% spaceless %}${1}{% endspaceless %} -endsnippet - -snippet ssi -{% ssi ${1} %} -endsnippet - -snippet trans -{% trans "${1:string}" %} -endsnippet - -snippet url -{% url ${1} as ${2} %} -endsnippet - -snippet widthratio -{% widthratio ${1:this_value} ${2:max_value} ${3:100} %} -endsnippet - -snippet with -{% with ${1} as ${2} %} -endsnippet - -# Template Filters - -# Note: Since SnipMate can't determine which template filter you are -# expanding without the "|" character, these do not add the "|" -# character. These save a few keystrokes still. - -# Note: Template tags that take no arguments are not implemented. - -snippet add -add:"${1}" -endsnippet - -snippet center -center:"${1}" -endsnippet - -snippet cut -cut:"${1}" -endsnippet - -snippet date -date:"${1}" -endsnippet - -snippet default -default:"${1}" -endsnippet - -snippet defaultifnone -default_if_none:"${1}" -endsnippet - -snippet dictsort -dictsort:"${1}" -endsnippet - -snippet dictsortrev -dictsortreversed:"${1}" -endsnippet - -snippet divisibleby -divisibleby:"${1}" -endsnippet - -snippet floatformat -floatformat:"${1}" -endsnippet - -snippet getdigit -get_digit:"${1}" -endsnippet - -snippet join -join:"${1}" -endsnippet - -snippet lengthis -length_is:"${1}" -endsnippet - -snippet pluralize -pluralize:"${1}" -endsnippet - -snippet removetags -removetags:"${1}" -endsnippet - -snippet slice -slice:"${1}" -endsnippet - -snippet stringformat -stringformat:"${1}" -endsnippet - -snippet time -time:"${1}" -endsnippet - -snippet truncatewords -truncatewords:${1} -endsnippet - -snippet truncatewordshtml -truncatewords_html:${1} -endsnippet - -snippet urlizetrunc -urlizetrunc:${1} -endsnippet - -snippet wordwrap -wordwrap:${1} -endsnippet - -# vim:ft=snippets: +extends html, django diff --git a/vim/bundle/ultisnips/UltiSnips/javascript_jasmine.snippets b/vim/bundle/ultisnips/UltiSnips/javascript_jasmine.snippets new file mode 100644 index 0000000..49e38a3 --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/javascript_jasmine.snippets @@ -0,0 +1,168 @@ +# +# JavaScript versions -- from the TextMate bundle + some additions +# for jasmine-jquery matchers +# +extends javascript + +snippet des "Describe (js)" b +describe('${1:description}', function() { + $0 +}); +endsnippet + +snippet it "it (js)" b +it('${1:description}', function() { + $0 +}); +endsnippet + +snippet bef "before each (js)" b +beforeEach(function() { + $0 +}); +endsnippet + +snippet aft "after each (js)" b +afterEach(function() { + $0 +}); +endsnippet + +snippet any "any (js)" b +jasmine.any($1) +endsnippet + +snippet ru "runs (js)" b +runs(function() { + $0 +}); +endsnippet + +snippet wa "waits (js)" b +waits($1); +endsnippet + +snippet ex "expect (js)" b +expect(${1:target})$0; +endsnippet + +snippet ee "expect to equal (js)" b +expect(${1:target}).toEqual(${2:value}); +endsnippet + +snippet em "expect to match (js)" b +expect(${1:target}).toMatch(${2:pattern}); +endsnippet + +snippet eha "expect to have attribute (js)" b +expect(${1:target}).toHaveAttr('${2:attr}'${3:, '${4:value}'}); +endsnippet + +snippet et "expect to be truthy (js)" b +expect(${1:target}).toBeTruthy(); +endsnippet + +snippet ef "expect to be falsy (js)" b +expect(${1:target}).toBeFalsy(); +endsnippet + +snippet ed "expect to be defined (js)" b +expect(${1:target}).toBeDefined(); +endsnippet + +snippet en "expect to be null (js)" b +expect(${1:target}).toBeNull(); +endsnippet + +snippet ec "expect to contain (js)" b +expect(${1:target}).toContain(${2:value}); +endsnippet + +snippet ev "expect to be visible (js)" b +expect(${1:target}).toBeVisible(); +endsnippet + +snippet eh "expect to be hidden (js)" b +expect(${1:target}).toBeHidden(); +endsnippet + +snippet notx "expect not (js)" b +expect(${1:target}).not$0; +endsnippet + +snippet note "expect not to equal (js)" b +expect(${1:target}).not.toEqual(${2:value}); +endsnippet + +snippet notm "expect not to match (js)" b +expect(${1:target}).not.toMatch(${2:pattern}); +endsnippet + +snippet notha "expect to not have attribute (js)" b +expect(${1:target}).not.toHaveAttr('${2:attr}'${3:, '${4:value}'}); +endsnippet + +snippet nott "expect not to be truthy (js)" b +expect(${1:target}).not.toBeTruthy(); +endsnippet + +snippet notf "expect not to be falsy (js)" b +expect(${1:target}).not.toBeFalsy(); +endsnippet + +snippet notd "expect not to be defined (js)" b +expect(${1:target}).not.toBeDefined(); +endsnippet + +snippet notn "expect not to be null (js)" b +expect(${1:target}).not.toBeNull(); +endsnippet + +snippet notc "expect not to contain (js)" b +expect(${1:target}).not.toContain(${2:value}); +endsnippet + +snippet notv "expect not to be visible (js)" b +expect(${1:target}).not.toBeVisible(); +endsnippet + +snippet noth "expect not to be hidden (js)" b +expect(${1:target}).not.toBeHidden(); +endsnippet + +snippet s "spy on (js)" b +spyOn(${1:object}, '${2:method}')$0; +endsnippet + +snippet sr "spy on and return (js)" b +spyOn(${1:object}, '${2:method}').andReturn(${3:arguments}); +endsnippet + +snippet st "spy on and throw (js)" b +spyOn(${1:object}, '${2:method}').andThrow(${3:exception}); +endsnippet + +snippet sct "spy on and call through (js)" b +spyOn(${1:object}, '${2:method}').andCallThrough(); +endsnippet + +snippet scf "spy on and call fake (js)" b +spyOn(${1:object}, '${2:method}').andCallFake(${3:function}); +endsnippet + +snippet esc "expect was called (js)" b +expect(${1:target}).wasCalled(); +endsnippet + +snippet escw "expect was called with (js)" b +expect(${1:target}).wasCalledWith(${2:arguments}); +endsnippet + +snippet notsc "expect was not called (js)" b +expect(${1:target}).wasNotCalled(); +endsnippet + +snippet noscw "expect was not called with (js)" b +expect(${1:target}).wasNotCalledWith(${2:arguments}); +endsnippet + diff --git a/vim/bundle/ultisnips/UltiSnips/json.snippets b/vim/bundle/ultisnips/UltiSnips/json.snippets new file mode 100644 index 0000000..81e6561 --- /dev/null +++ b/vim/bundle/ultisnips/UltiSnips/json.snippets @@ -0,0 +1,19 @@ +snippet s "String" b +"${1:key}": "${0:value}", +endsnippet + +snippet n "number" b +"${1:key}": ${0:value}, +endsnippet + +snippet a "Array" b +[ + ${VISUAL}$0 +], +endsnippet +snippet o "Object" b +{ + ${VISUAL}$0 +}, +endsnippet + diff --git a/vim/bundle/ultisnips/UltiSnips/mkd.snippets b/vim/bundle/ultisnips/UltiSnips/mkd.snippets index 3f100d2..eebab1a 100644 --- a/vim/bundle/ultisnips/UltiSnips/mkd.snippets +++ b/vim/bundle/ultisnips/UltiSnips/mkd.snippets @@ -34,7 +34,7 @@ endsnippet # Common stuff # ################ snippet link "Link to something" -[${1:Text}](${3:http://${2:www.url.com}})$0 +[${1:${VISUAL:Text}}](${3:http://${2:www.url.com}})$0 endsnippet snippet img "Link to something" diff --git a/vim/bundle/ultisnips/UltiSnips/python.snippets b/vim/bundle/ultisnips/UltiSnips/python.snippets index a53d758..462bf20 100644 --- a/vim/bundle/ultisnips/UltiSnips/python.snippets +++ b/vim/bundle/ultisnips/UltiSnips/python.snippets @@ -27,6 +27,7 @@ global !p NORMAL = 0x1 DOXYGEN = 0x2 +SPHINX = 0x3 def get_args(arglist): args = [arg.split('=')[0].strip() for arg in arglist.split(',') if arg] @@ -39,12 +40,15 @@ def get_style(snip): style = snip.opt("g:ultisnips_python_style", "normal") if style == "doxygen": return DOXYGEN + elif style == "sphinx": return SPHINX else: return NORMAL def format_arg(arg, style): if style == DOXYGEN: return "@param %s @todo" % arg + elif style == SPHINX: + return ":param %s: @todo" % arg elif style == NORMAL: return ":%s: @todo" % arg @@ -52,7 +56,7 @@ def format_arg(arg, style): def format_return(style): if style == DOXYGEN: return "@return: @todo" - elif style == NORMAL: + elif style in (NORMAL, SPHINX): return ":returns: @todo" @@ -61,7 +65,7 @@ def write_docstring_args(args, snip): snip.rv += ' """' return - snip += "" + snip.rv += '\n' + snip.mkline('', indent='') style = get_style(snip) @@ -77,7 +81,7 @@ def write_init_body(args, parents, snip): snip += p + ".__init__(self)" if parents: - snip += "" + snip.rv += '\n' + snip.mkline('', indent='') for arg in args: snip += "self._%s = %s" % (arg, arg) @@ -105,9 +109,10 @@ snip >> 2 args = get_args(t[4]) write_docstring_args(args, snip) -if args: snip += '"""' +if args: + snip.rv += '\n' + snip.mkline('', indent='') + snip += '"""' -snip += "" write_init_body(args, t[2], snip) ` $0 @@ -117,7 +122,7 @@ endsnippet snippet slotclass "class with slots and docstrings" b class ${1:MyClass}(${2:object}): """${3:Docstring for $1 }""" - `!p +`!p snip >> 1 args = get_args(t[4]) write_slots_args(args, snip) @@ -131,9 +136,10 @@ snip >> 2 args = get_args(t[4]) write_docstring_args(args, snip) -if args: snip += '"""' +if args: + snip.rv += '\n' + snip.mkline('', indent='') + snip += '"""' -snip += "" write_init_body(args, t[2], snip) ` $0 @@ -222,13 +228,13 @@ endsnippet snippet repr "methods implementing string representation" -def __repr__(self, other): +def __repr__(self): ${1:pass} -def __str__(self, other): +def __str__(self): ${2:pass} -def __unicode__(self, other): +def __unicode__(self): ${3:pass} endsnippet @@ -322,18 +328,21 @@ def __coerce__(self, other): endsnippet snippet def "function with docstrings" b -def ${1:function}(`!p if snip.indent: snip.rv = 'self, '`${2:arg1}): +def ${1:function}(`!p +if snip.indent: + snip.rv = 'self' + (", " if len(t[2]) else "")`${2:arg1}): """${4:@todo: Docstring for $1}`!p snip.rv = "" snip >> 1 args = get_args(t[2]) -write_docstring_args(args, snip) +if args: + write_docstring_args(args, snip) style = get_style(snip) snip += format_return(style) +snip.rv += '\n' + snip.mkline('', indent='') snip += '"""' ` - ${0:pass} endsnippet @@ -412,6 +421,10 @@ endsnippet # Assertions & Tests # ##################### +snippet pdb "Set PDB breakpoint" b +import pdb; pdb.set_trace() +endsnippet + snippet ae "Assert equal" b self.assertEqual(${1:first},${2:second}) endsnippet @@ -438,13 +451,13 @@ class Test${1:Class}(${2:unittest.TestCase}): """${3:Test case docstring}""" def setUp(self): - ${3:pass} + ${4:pass} def tearDown(self): - ${4:pass} + ${5:pass} - def test_${5:name}(self): - ${6:pass} + def test_${6:name}(self): + ${7:pass} endsnippet # vim:ft=snippets: diff --git a/vim/bundle/ultisnips/UltiSnips/rails.snippets b/vim/bundle/ultisnips/UltiSnips/rails.snippets index 9f36116..9e0e29f 100644 --- a/vim/bundle/ultisnips/UltiSnips/rails.snippets +++ b/vim/bundle/ultisnips/UltiSnips/rails.snippets @@ -3,7 +3,7 @@ ########################################################################### snippet anaf "accepts_nested_attributes_for" -accepts_nested_attributes_for :${1:association_name}${2:${3:, :allow_destroy => true}${4:, :reject_if => proc { |obj| ${5:obj.blank?} \}}} +accepts_nested_attributes_for :${1:association_name}${2:${3:, :allow_destroy => true}${4:, :reject_if => proc \{ |obj| ${5:obj.blank?} \}}} endsnippet diff --git a/vim/bundle/ultisnips/UltiSnips/rst.snippets b/vim/bundle/ultisnips/UltiSnips/rst.snippets index 39bbb6c..7174510 100644 --- a/vim/bundle/ultisnips/UltiSnips/rst.snippets +++ b/vim/bundle/ultisnips/UltiSnips/rst.snippets @@ -4,9 +4,9 @@ # General Stuff # ########################################################################### snippet part "Part" b -`!p snip.rv = len(t[1])*'*'` +`!p snip.rv = len(t[1])*'#'` ${1:Part name} -`!p snip.rv = len(t[1])*'*'` +`!p snip.rv = len(t[1])*'#'` $0 endsnippet @@ -32,6 +32,21 @@ ${1:Section name} $0 endsnippet +snippet chap "Chapter" b +`!p snip.rv = len(t[1])*'*'` +${1:Chapter name} +`!p snip.rv = len(t[1])*'*'` + +$0 +endsnippet + +snippet para "Paragraph" b +${1:Paragraph name} +`!p snip.rv = len(t[1])*'"'` + +$0 +endsnippet + ########################################################################### # More Specialized Stuff. # ########################################################################### diff --git a/vim/bundle/ultisnips/UltiSnips/ruby.snippets b/vim/bundle/ultisnips/UltiSnips/ruby.snippets index aaddac3..6336589 100644 --- a/vim/bundle/ultisnips/UltiSnips/ruby.snippets +++ b/vim/bundle/ultisnips/UltiSnips/ruby.snippets @@ -1,11 +1,10 @@ -snippet #! "#!/usr/bin/env ruby" +snippet "^#!" "#!/usr/bin/env ruby" r #!/usr/bin/env ruby $0 endsnippet - -snippet #utf8 "# encoding: UTF-8" +snippet "^# ?[uU][tT][fF]-?8" "# encoding: UTF-8" r # encoding: UTF-8 $0 endsnippet @@ -13,13 +12,13 @@ endsnippet snippet If " if " -${1:command} if ${2:expression$0} +${1:command} if ${0:expression} endsnippet snippet Unless " unless " -${1:command} unless ${2:expression$0} +${1:command} unless ${0:expression} endsnippet @@ -27,7 +26,7 @@ endsnippet snippet if "if ... end" if ${1:condition} ${2:# TODO} -end${3:$0} +end endsnippet @@ -37,7 +36,7 @@ if ${1:condition} ${2:# TODO} else ${3:# TODO} -end${4:$0} +end endsnippet @@ -48,16 +47,16 @@ if ${1:condition} elsif ${3:condition} ${4:# TODO} else - ${5:# TODO} -end${6:$0} + ${0:# TODO} +end endsnippet snippet unless "unless ... end" unless ${1:condition} - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet @@ -66,8 +65,8 @@ snippet unlesse "unless ... else ... end" unless ${1:condition} ${2:# TODO} else - ${3:# TODO} -end${4:$0} + ${0:# TODO} +end endsnippet @@ -78,15 +77,15 @@ unless ${1:condition} elsif ${3:condition} ${4:# TODO} else - ${5:# TODO} -end${6:$0} + ${0:# TODO} +end endsnippet -snippet "(de)?f" "def ..." r +snippet "\b(de)?f" "def ..." r def ${1:function_name}${2: ${3:*args}} - ${4:# TODO$0} + ${0:# TODO} end endsnippet @@ -94,7 +93,7 @@ endsnippet snippet defi "def initialize ..." def initialize${1: ${2:*args}} - ${3:# TODO$0} + ${0:# TODO} end endsnippet @@ -104,153 +103,168 @@ snippet defr "def ... rescue ..." def ${1:function_name}${2: ${3:*args}} ${4:# TODO} rescue - ${5:# TODO} + ${0:# TODO} end endsnippet snippet For "(..).each { || }" -(${1:from}..${2:to}).each { |${3:i}| ${4:# TODO} }${5:$0} +(${1:from}..${2:to}).each { |${3:i}| ${4:# TODO} } endsnippet snippet for "(..).each do || end" (${1:from}..${2:to}).each do |${3:i}| - ${4:# TODO} -end${5:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Merge!" ".merge!() { |,,| }" r -`!p snip.rv=match.group(1)`.merge!(${1:other_hash}) { |${2:key},${3:oldval},${4:newval}| ${5:block} }${6:$0} +snippet "(\S+)\.Merge!" ".merge!() { |,,| }" r +`!p snip.rv=match.group(1)`.merge!(${1:other_hash}) { |${2:key},${3:oldval},${4:newval}| ${5:block} } endsnippet -snippet "([^ \t]+)\.merge!" ".merge!() do |,,| end" r +snippet "(\S+)\.merge!" ".merge!() do |,,| end" r `!p snip.rv=match.group(1)`.merge!(${1:other_hash}) do |${2:key},${3:oldval},${4:newval}| - ${5:block} -end${6:$0} + ${0:block} +end endsnippet -snippet "([^ \t]+)\.Delete_?if" ".delete_if { |,| }" r -`!p snip.rv=match.group(1)`.delete_if { |${1:key},${2:value}| ${3:# TODO} }${4:$0} +snippet "(\S+)\.Del(ete)?_?if" ".delete_if { |,| }" r +`!p snip.rv=match.group(1)`.delete_if { |${1:key},${2:value}| ${3:# TODO} } endsnippet -snippet "([^ \t]+)\.delete_?if" ".delete_if do |,| end" r +snippet "(\S+)\.del(ete)?_?if" ".delete_if do |,| end" r `!p snip.rv=match.group(1)`.delete_if do |${1:key},${2:value}| - ${3:# TODO} -end${4:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Keep_?if" ".keep_if { |,| }" r -`!p snip.rv=match.group(1)`.keep_if { |${1:key},${2:value}| ${3:# TODO} }${4:$0} +snippet "(\S+)\.Keep_?if" ".keep_if { |,| }" r +`!p snip.rv=match.group(1)`.keep_if { |${1:key},${2:value}| ${3:# TODO} } endsnippet -snippet "([^ \t]+)\.keep_?if" ".keep_if do ,| end" r +snippet "(\S+)\.keep_?if" ".keep_if do ,| end" r `!p snip.rv=match.group(1)`.keep_if do |${1:key},${2:value}| - ${3:# TODO} -end${4:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Reject" ".reject { |,| }" r -`!p snip.rv=match.group(1)`.reject { |${1:key},${2:value}| ${3:# TODO} }${4:$0} +snippet "(\S+)\.Reject" ".reject { |,| }" r +`!p snip.rv=match.group(1)`.reject { |${1:key},${2:value}| ${3:# TODO} } endsnippet -snippet "([^ \t]+)\.reject" ".reject do ,| end" r +snippet "(\S+)\.reject" ".reject do ,| end" r `!p snip.rv=match.group(1)`.reject do |${1:key},${2:value}| - ${3:# TODO} -end${4:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Select" ".select { || }" r -`!p snip.rv=match.group(1)`.select { |${1:item}| ${2:block} }${3:$0} +snippet "(\S+)\.Select" ".select { || }" r +`!p snip.rv=match.group(1)`.select { |${1:item}| ${2:block} } endsnippet -snippet "([^ \t]+)\.select" ".select do || end" r +snippet "(\S+)\.select" ".select do || end" r `!p snip.rv=match.group(1)`.select do |${1:item}| - ${2:block} -end${3:$0} + ${0:block} +end endsnippet -snippet "([^ \t]+)\.Sort" ".sort { |,| }" i -`!p snip.rv=match.group(1)`.sort { |${1:a},${2,b}| ${3:# TODO} }${4:$0} +snippet "(\S+)\.Sort" ".sort { |,| }" r +`!p snip.rv=match.group(1)`.sort { |${1:a},${2:b}| ${3:# TODO} } endsnippet -snippet "([^ \t]+)\.sort" ".sort do |,| end" r -`!p snip.rv=match.group(1)`.sort do |${1:a},${2,b}| - ${3:# TODO} -end${4:$0} +snippet "(\S+)\.sort" ".sort do |,| end" r +`!p snip.rv=match.group(1)`.sort do |${1:a},${2:b}| + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Each_?key" ".each_key { || }" r -`!p snip.rv=match.group(1)`.each_key { |${1:key}| ${2:# TODO} }${3:$0} +snippet "(\S+)\.Each_?k(ey)?" ".each_key { || }" r +`!p snip.rv=match.group(1)`.each_key { |${1:key}| ${2:# TODO} } endsnippet -snippet "([^ \t]+)\.each_?key" ".each_key do |key| end" r +snippet "(\S+)\.each_?k(ey)?" ".each_key do |key| end" r `!p snip.rv=match.group(1)`.each_key do |${1:key}| - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Each_?value" ".each_value { || }" r -`!p snip.rv=match.group(1)`.each_value { |${1:value}| ${2:# TODO} }${3:$0} +snippet "(\S+)\.Each_?val(ue)?" ".each_value { || }" r +`!p snip.rv=match.group(1)`.each_value { |${1:value}| ${2:# TODO} } endsnippet -snippet "([^ \t]+)\.each_?value" ".each_value do || end" r +snippet "(\S+)\.each_?val(ue)?" ".each_value do || end" r `!p snip.rv=match.group(1)`.each_value do |${1:value}| - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet snippet Each ".each { || }" -${1:elements}.each { |${2:${1/s$//}}| ${3:# TODO} }${4:$0} +${1:elements}.each { |${2:${1/s$//}}| ${3:# TODO} } endsnippet snippet each ".each do || end" ${1:elements}.each do |${2:${1/s$//}}| - ${3:# TODO} -end${4:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Map" ".map { || }" r +snippet each_?s(lice)? ".each_slice(n) do |slice| end" +each_slice(${1:2}) do |${2:slice}| + ${0:# TODO} +end +endsnippet + + + +snippet Each_?s(lice)? ".each_slice(n) { |slice| }" +each_slice(${1:2}) { |${2:slice}| ${3:# TODO} } +endsnippet + + + + +snippet "(\S+)\.Map" ".map { || }" r `!p snip.rv=match.group(1)`.map { |${1:`!p element_name = match.group(1).lstrip('$@') ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) @@ -259,12 +273,12 @@ try: snip.rv = wmatch.group(1).lower() except: snip.rv = 'element' -`}| ${2:# TODO} }${3:$0} +`}| ${2:# TODO} } endsnippet -snippet "([^ \t]+)\.map" ".map do || end" r +snippet "(\S+)\.map" ".map do || end" r `!p snip.rv=match.group(1)`.map do |${1:`!p element_name = match.group(1).lstrip('$@') ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) @@ -274,13 +288,13 @@ try: except: snip.rv = 'element' `}| - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Reverse_?each" ".reverse_each { || }" r +snippet "(\S+)\.Rev(erse)?_?each" ".reverse_each { || }" r `!p snip.rv=match.group(1)`.reverse_each { |${1:`!p element_name = match.group(1).lstrip('$@') ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) @@ -289,12 +303,12 @@ try: snip.rv = wmatch.group(1).lower() except: snip.rv = 'element' -`}| ${2:# TODO} }${3:$0} +`}| ${2:# TODO} } endsnippet -snippet "([^ \t]+)\.reverse_?each" ".reverse_each do || end" r +snippet "(\S+)\.rev(erse)?_?each" ".reverse_each do || end" r `!p snip.rv=match.group(1)`.reverse_each do |${1:`!p element_name = match.group(1).lstrip('$@') ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) @@ -304,13 +318,13 @@ try: except: snip.rv = 'element' `}| - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Each" ".each { || }" r +snippet "(\S+)\.Each" ".each { || }" r `!p snip.rv=match.group(1)`.each { |${1:`!p element_name = match.group(1).lstrip('$@') ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) @@ -319,12 +333,12 @@ try: snip.rv = wmatch.group(1).lower() except: snip.rv = 'element' -`}| ${2:# TODO} }${3:$0} +`}| ${2:# TODO} } endsnippet -snippet "([^ \t]+)\.each" ".each do || end" r +snippet "(\S+)\.each" ".each do || end" r `!p snip.rv=match.group(1)`.each do |${1:`!p element_name = match.group(1).lstrip('$@') ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) @@ -334,55 +348,87 @@ try: except: snip.rv = 'element' `}| - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Each_?index" ".each_index { || }" r -`!p snip.rv=match.group(1)`.each_index { |${1:index}| ${2:# TODO} }${3:$0} + +snippet "(\S+)\.Each_w(ith)?_?i(ndex)?" ".each_with_index { |,| }" r +`!p snip.rv=match.group(1)`.each_with_index { |${1:`!p +element_name = match.group(1).lstrip('$@') +ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) +try: + wmatch = re.search("([A-Za-z][A-Za-z0-9_]+)$", ematch.group(1)) + snip.rv = wmatch.group(1).lower() +except: + snip.rv = 'element' +`},${2:i}| ${3:# TODO} }$0 endsnippet -snippet "([^ \t]+)\.each_?index" ".each_index do || end" r -`!p snip.rv=match.group(1)`.each_index do |${1:index}| - ${2:# TODO} -end${3:$0} +snippet "(\S+)\.each_?w(ith)?_?i(ndex)?" ".each_with_index do |,| end" r +`!p snip.rv=match.group(1)`.each_with_index do |${1:`!p +element_name = match.group(1).lstrip('$@') +ematch = re.search("([A-Za-z][A-Za-z0-9_]+?)s?[^A-Za-z0-9_]*?$", element_name) +try: + wmatch = re.search("([A-Za-z][A-Za-z0-9_]+)$", ematch.group(1)) + snip.rv = wmatch.group(1).lower() +except: + snip.rv = 'element' +`},${2:i}| + ${0:# TODO} +end endsnippet -snippet "([^ \t]+)\.Each_?pair" ".each_pair { |,| }" r -`!p snip.rv=match.group(1)`.each_pair { |${1:key},${2:value}| ${3:# TODO} }${4:$0} + +snippet "(\S+)\.Each_?p(air)?" ".each_pair { |,| }" r +`!p snip.rv=match.group(1)`.each_pair { |${1:key},${2:value}| ${3:# TODO} } endsnippet -snippet "([^ \t]+)\.each_?pair" ".each_pair do |,| end" r +snippet "(\S+)\.each_?p(air)?" ".each_pair do |,| end" r `!p snip.rv=match.group(1)`.each_pair do |${1:key},${2:value}| - ${3:# TODO} -end${4:$0} + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.sub" ".sub() { }" r +`!p snip.rv=match.group(1)`.sub(${1:expression}) { ${2:"replace_with"} } endsnippet -snippet "([^ \t]+)\.sub" ".sub() { }" r -`!p snip.rv=match.group(1)`.sub(${1:expression}) { ${2:"replace_with"} }${3:$0} +snippet "(\S+)\.gsub" ".gsub() { }" r +`!p snip.rv=match.group(1)`.gsub(${1:expression}) { ${2:"replace_with"} } endsnippet -snippet "([^ \t]+)\.gsub" ".gsub() { }" r -`!p snip.rv=match.group(1)`.gsub(${1:expression}) { ${2:"replace_with"} }${3:$0} +snippet "(\S+)\.index" ".index { |item| }" r +`!p snip.rv=match.group(1)`.index { |${1:item}| ${2:block} } +endsnippet + + + +snippet "(\S+)\.Index" ".index do |item| ... end" r +`!p snip.rv=match.group(1)`.index do |${1:item}| + ${0:block} +end endsnippet snippet do "do || ... end" i do ${1:|${2:key}|} - ${3:$0} + $0 end endsnippet @@ -390,76 +436,57 @@ endsnippet snippet Do "do ... end" i do - ${1:$0} + $0 end endsnippet snippet until "until ... end" until ${1:expression} - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet snippet Until "begin ... end until " begin - ${2:# TODO} -end until ${1:expression}${3:$0} + ${0:# TODO} +end until ${1:expression} endsnippet snippet while "while ... end" while ${1:expression} - ${2:# TODO} -end${3:$0} + ${0:# TODO} +end endsnippet snippet While "begin ... end while " begin - ${2:# TODO} -end while ${1:expression}${3:$0} -endsnippet - - - -snippet r "attr_reader :" -attr_reader :${1:attr_names} -endsnippet - - - -snippet w "attr_writer :" -attr_writer :${1:attr_names} -endsnippet - - - -snippet w "attr_accessor :" -snippet rw -attr_accessor :${1:attr_names} + ${0:# TODO} +end while ${1:expression} endsnippet -snippet attr "attr_reader :" -attr_reader :${1:attr_names} +snippet "\b(r|attr)" "attr_reader :" r +attr_reader :${0:attr_names} endsnippet -snippet attr "attr_writer :" -attr_writer :${1:attr_names} +snippet "\b(w|attr)" "attr_writer :" r +attr_writer :${0:attr_names} endsnippet -snippet attr "attr_accessor :" -attr_accessor :${1:attr_names} +snippet "\b(rw|attr)" "attr_accessor :" r +attr_accessor :${0:attr_names} endsnippet @@ -468,7 +495,7 @@ snippet begin "begin ... rescue ... end" begin ${1:# TODO} rescue - ${2:# TODO} + ${0:# TODO} end endsnippet @@ -484,7 +511,7 @@ rescue Exception => e else ${3:# other exception} ensure - ${4:# always excute} + ${0:# always excute} end endsnippet @@ -494,15 +521,15 @@ snippet rescue rescue Exception => e puts e.message puts e.backtrace.inspect - ${1:# Rescue} + ${0:# Rescue} endsnippet -snippet case "case when ... end" +snippet "\b(case|sw(itch)?)" "case when ... end" r case ${1:variable} when ${2:expression} -${3:$0} +$0 end endsnippet @@ -516,9 +543,26 @@ endsnippet snippet class "class def initialize ... end end" class ${1:class_name} - ${2:def initialize ${3:*args} - ${4} - end} + def initialize ${2:*args} + $0 + end +end +endsnippet + + + +snippet module "module" +module ${1:module_name} $0 end endsnippet + + + +snippet ### +=begin + $0 +=end +endsnippet + +# vim: set ts=2 sw=2 expandtab: diff --git a/vim/bundle/ultisnips/UltiSnips/snippets.snippets b/vim/bundle/ultisnips/UltiSnips/snippets.snippets index 95a644e..414f350 100644 --- a/vim/bundle/ultisnips/UltiSnips/snippets.snippets +++ b/vim/bundle/ultisnips/UltiSnips/snippets.snippets @@ -16,4 +16,8 @@ $0 `!p snip.rv = "endglobal"` endsnippet +snippet vis "${VISUAL}" i +\$\{VISUAL${1:${2:default}${3:/transform/}}\} +endsnippet + # vim:ft=snippets: diff --git a/vim/bundle/ultisnips/UltiSnips/tex.snippets b/vim/bundle/ultisnips/UltiSnips/tex.snippets index 74554af..d6e62fc 100644 --- a/vim/bundle/ultisnips/UltiSnips/tex.snippets +++ b/vim/bundle/ultisnips/UltiSnips/tex.snippets @@ -17,7 +17,7 @@ endsnippet ################# snippet "b(egin)?" "begin{} / end{}" br \begin{${1:something}} - $0 + ${0:${VISUAL}} \end{$1} endsnippet diff --git a/vim/bundle/ultisnips/UltiSnips/texmath.snippets b/vim/bundle/ultisnips/UltiSnips/texmath.snippets index efd06f4..03589f0 100644 --- a/vim/bundle/ultisnips/UltiSnips/texmath.snippets +++ b/vim/bundle/ultisnips/UltiSnips/texmath.snippets @@ -26,7 +26,7 @@ snippet eqann "Equation array without numbers" b endsnippet snippet frac "Fraction" w -\frac{${1:nom}}{${2:denom}} +\frac{${1:${VISUAL:nom}}}{${2:denom}} endsnippet snippet mat "Smart Matrix" @@ -36,11 +36,19 @@ snippet mat "Smart Matrix" endsnippet snippet lr( "left( right)" w -\left( $0 \right) +\left( ${1:${VISUAL}} \right) endsnippet snippet lr| "left| right|" w -\left| $0 \right| +\left| ${1:${VISUAL}} \right| +endsnippet + +snippet lr{ "left\{ right\}" w +\left\\{ ${1:${VISUAL}} \right\\} +endsnippet + +snippet lr[ "left[ right]" w +\left[ ${1:${VISUAL}} \right] endsnippet # vim:ft=snippets: diff --git a/vim/bundle/ultisnips/doc/UltiSnips.txt b/vim/bundle/ultisnips/doc/UltiSnips.txt index 197eb2a..e39964f 100644 --- a/vim/bundle/ultisnips/doc/UltiSnips.txt +++ b/vim/bundle/ultisnips/doc/UltiSnips.txt @@ -1,9 +1,13 @@ -*UltiSnips.txt* The Ultimate Plugin for snippets in Vim. +*UltiSnips.txt* For Vim version 7.0 or later. + + The Ultimate Plugin for Snippets in Vim~ UltiSnips *snippet* *snippets* *UltiSnips* 1. Description |UltiSnips-description| -2. Installation and Updating |UltiSnips-installnupgrade| + 1.1 Requirements |UltiSnips-requirements| + 1.2 Acknowledgments |UltiSnips-acknowledgments| +2. Installation and Updating |UltiSnips-installnupdate| 3. Settings & Commands |UltiSnips-settings| 3.1 Commands |UltiSnips-commands| 3.2 Triggers |UltiSnips-triggers| @@ -22,188 +26,268 @@ UltiSnips *snippet* *snippets* *UltiSnips* 4.4.2 VimScript |UltiSnips-vimscript| 4.4.3 Python |UltiSnips-python| 4.4.4 Global Snippets |UltiSnips-globals| - 4.5 Tab Stops and Placeholders |UltiSnips-tabstops| + 4.5 Tabstops and Placeholders |UltiSnips-tabstops| 4.6 Mirrors |UltiSnips-mirrors| 4.7 Transformations |UltiSnips-transformations| 4.7.1 Replacement String |UltiSnips-replacement-string| 4.7.2 Demos |UltiSnips-demos| 4.8 Clearing snippets |UltiSnips-clearing-snippets| -5. Helping out |UltiSnips-helping| -6. Contact |UltiSnips-contact| +5. Helping Out |UltiSnips-helping| +6. Contact |UltiSnips-contact| 7. Contributors |UltiSnips-contributors| 7.1 Patches & Coding |UltiSnips-contricoding| 7.2 Snippets |UltiSnips-contrisnippets| -For Vim version 7.0 or later. This plugin only works if 'compatible' is not set. {Vi does not have any of these features} +{only available when |+python| or |+python3| have been enabled at compile time} -This plugin needs Python support >= 2.6 compiled into Vim. -============================================================================= -DESCRIPTION *UltiSnips-description* +============================================================================== +1. Description *UltiSnips-description* -UltiSnips aims to provide a snippets solution that users came to expect from -editors. A Snippet is a short piece of text which is either typed very often -or which contains a lot of redundant text. Such snippets are very often -encountered in structured text like Source Code but I also use them for email -signatures and to insert the current date or time into the text while typing. +UltiSnips provides snippet management for the Vim editor. A snippet is a short +piece of text that is either re-used often or contains a lot of redundant +text. UltiSnips allows you to insert a snippet with only a few key strokes. +Snippets are common in structured text like source code but can also be used +for general editing like, for example, inserting a signature in an email or +inserting the current date in a text file. -UltiSnips is an implementation that is developed with in the philosophy of TDD -(Test driven development). This guarantees that features do not disappear and -bugs do not reappear after they have been fixed once. +UltiSnips was developed using the TDD (Test-driven development) philosophy. +This ensures that features do not disappear and bugs do not reappear after +they have been fixed. -You can learn what UltiSnips can do by watching some short screencasts and -reading the accompanying blog posts on my blog: +On my blog, http://www.sirver.net, I posted several short screencasts, which +make a great introduction to UltiSnips, illustrating its features and usage. http://www.sirver.net/blog/2011/12/30/first-episode-of-ultisnips-screencast/ http://www.sirver.net/blog/2012/01/08/second-episode-of-ultisnips-screencast/ +http://www.sirver.net/blog/2012/02/05/third-episode-of-ultisnips-screencast/ +http://www.sirver.net/blog/2012/03/31/fourth-episode-of-ultisnips-screencast/ - Acknowledgments: *UltiSnips-acknowledgments* +1.1 Requirements *UltiSnips-requirements* +---------------- -UltiSnips is inspired by the snippets solution implemented in TextMate -(http://macromates.com/). The idea of implementing snippets for vim is not new -and I want to thank Michael Sanders (Author of snipMate) for some -implementation details I stole from him and for the permission to use some of -his snippets. +This plugin works with Vim version 7.0 or later. It only works if the +'compatible' setting is not set. -============================================================================= -2. INSTALLATION AND UPDATING *UltiSnips-installnupdate* +This plugin requires python >= 2.6. It has been specifically tested using +python 2.7 and python 3.2 but should theoretically work on all versions of +python >= 2.6. + +The Python 2.x or Python 3.x interface must be available. In other words, Vim +must be compiled with either the |+python| feature or the |+python3| feature. +The following commands show how to test if you have python compiled in Vim. +They print '1' if the python version is compiled in, '0' if not. + +Test if Vim is compiled with python version 2.x: > + :echo has("python") -To use UltiSnips, you need a python enabled Vim 7. You have python if either - :echo has("python") or :echo has("python3") -yields '1'. Recent versions have been tested with python 2.7 and python 3.2, -theoretically, UltiSnips should work with all versions >= python 2.6. +Test if Vim is compiled with python version 3.x: > + :echo has("python3") + +UltiSnips attempts to autodetect which python version is compiled into Vim. +Unfortunately, in some versions of Vim this detection does not work. +In that case you have to explicitly tell UltiSnips which version to use using +the 'UltiSnipsUsePythonVersion' global variable. + +To use python version 2.x: > + let g:UltiSnipsUsePythonVersion = 2 + +To use python version 3.x: > + let g:UltiSnipsUsePythonVersion = 3 + + +1.2 Acknowledgments *UltiSnips-acknowledgments* +------------------- + +UltiSnips was inspired by the snippets feature of TextMate +(http://macromates.com/), the GUI text editor for Mac OS X. Managing snippets +in Vim is not new. I want to thank Michael Sanders, the author of snipMate, +for some implementation details I borrowed from his plugin and for the +permission to use his snippets. + + +============================================================================= +2. Installation and Updating *UltiSnips-installnupdate* Using Pathogen: *UltiSnips-using-pathogen* -If you are a Pathogen user, you can track the official mirror of UltiSnips on github: > +If you are a pathogen user, you can track the official mirror of UltiSnips on +github: > $ cd ~/.vim/ $ git submodule add https://github.com/sirver/ultisnips bundle/ultisnips -See the pathogen documentation how to update a bundle. +See the pathogen documentation for more details on how to update a bundle. + Using Bzr: *UltiSnips-using-bzr* To track the main repository on github, you will need bzr -(http://bazaar-vcs.org/). It is in all major linux distribution (either -package bzr or bazaar) and can be easily installed under Mac OS X: > +(http://bazaar-vcs.org/). bzr is available in all major Linux distributions +(packaged as bzr or bazaar) and can be easily installed under Mac OS X: > $ pip install bzr -To get UltiSnips, check it out into a directory of your choice. Then add this -directory to your Vim runtime path: > +Using bzr, checkout UltiSnips into a directory of your choice. > $ cd ~/.vim/ $ bzr get lp:ultisnips ultisnips_rep - $ vim ~/.vimrc -add the line: > +Then add this directory to your Vim runtime path by adding this line to your +vimrc file. > set runtimepath+=~/.vim/ultisnips_rep -Restart vim. UltiSnips should work now. To access the help, use > +Restart Vim and UltiSnips should work. To access the help, use > :helptags ~/.vim/ultisnips_rep/doc :help UltiSnips -To Update an installation, simply pull the latest revision: > +To update an installation, simply pull the latest revision: > $ cd ~/.vim/ultisnips_rep $ bzr pull Using a downloaded packet: *UltiSnips-using-a-downloaded-packet* -See UltiSnips-using-bzr. Just unpack into a directory of your choice and add -the path to runtimepath. +Download the packet and unpack into a directory of your choice. Add the path +to runtimepath. See |UltiSnips-using-bzr| for an example. ============================================================================= -3. SETTINGS *UltiSnips-settings* +3. Settings & Commands *UltiSnips-settings* 3.1 Commands *UltiSnips-commands* ------------ - *:UltiSnipsEdit* -UltiSnipsEdit opens or creates your private snippet definition file for the -current filetype. You can easily open them manually of course, this is just a -shortcut. There is also a variable called: > - g:UltiSnipsEditSplit -which can be set to "normal" (default), "horizontal" or "vertical" that -defines if a new window should be opened for the edit. There is also a -variable called: > - g:UltiSnipsSnippetsDir -that, when set to a directory like "~/.vim/mydir/UltiSnips", becomes the base -directory for the snippet file to open. For example, if it is set to -"~/.vim/mydir/UltiSnips" and the current 'filetype' is "cpp", then -:UltiSnipsEdit will open "~/.vim/mydir/UltiSnips/cpp.snippets". +The UltiSnipsEdit command opens the private snippet definition file for the +current filetype for editing. If a definition file does not exist a new file +is opened with the appropriate name. Snippet definition files are standard +text files and can be edited directly. UltiSnipsEdit makes it easier. + +There are several variables associated with the UltiSnipsEdit command. + + *g:UltiSnipsEditSplit* +g:UltiSnipsEditSplit Defines how the edit window is open. Possible + values: + |normal| Default. Opens in the current window. + |horizontal| Splits the window horizontally. + |vertical| Splits the window vertically. + + *g:UltiSnipsSnippetsDir* +g:UltiSnipsSnippetsDir + Defines the directory private snippet definition + files are stored in. For example, if the variable + is set to "~/.vim/mydir/UltiSnips" and the current + 'filetype' is "cpp", then :UltiSnipsEdit will open + "~/.vim/mydir/UltiSnips/cpp.snippets". + + *:UltiSnipsAddFiletypes* +The UltiSnipsAddFiletypes command allows for explicit merging of other snippet +filetypes for the current buffer. For example if you edit a .rst file, but +also want the Lua snippets to be available you can issue the command > + + :UltiSnipsAddFiletypes rst.lua + +using the dotted filetype syntax. Order is important, the first filetype in +this list will be the one used for UltiSnipsEdit and the list is +ordered by evaluation priority. Consequently, you might add this to your +ftplugin/rails.vim > + + :UltiSnipsAddFiletypes rails.ruby + +I mention rails first, because I want to edit rails snippet when using +UltiSnipsEdit and because rails snippet should overwrite equivalent ruby +snippets. The priority will now be rails -> ruby -> all. If you have some +special programming snippets that should have lower priority than your ruby +snippets you can call > + + :UltiSnipsAddFiletypes ruby.programming + +The priority will then be rails -> ruby -> programming -> all. 3.2 Triggers *UltiSnips-triggers* ------------ -You can freely define the keys used to expand a snippet and jump forward and -backwards in it. There is also a key to list all snippets available for the -current expand situation. The variables with the default values are: > +You can define the keys used to trigger UltiSnips actions by setting global +variables. Variables define the keys used to expand a snippet, jump forward +and jump backwards within a snippet, and list all available snippets in the +current expand context. The variables with their default values are: > g:UltiSnipsExpandTrigger g:UltiSnipsListSnippets g:UltiSnipsJumpForwardTrigger g:UltiSnipsJumpBackwardTrigger -It is possible to set the Expand and Forward trigger to the same value. You -can get a more TextMate like configuration by adding the next three lines to -your vimrc: > +The g:UltiSnipsExpandTrigger and g:UltiSnipsJumpForwardTrigger can be set to +the same value. To simulate TextMate behavior, add the following lines to your +vimrc file. > let g:UltiSnipsExpandTrigger="" let g:UltiSnipsJumpForwardTrigger="" let g:UltiSnipsJumpBackwardTrigger="" + 3.3 Snippet Search Path *UltiSnips-snippet-search-path* ----------------------- -UltiSnips lets you override the name of the directories that are searched -for snippets. You need to set the variable g:UltiSnipsSnippetDirectories, -which defaults to: > - g:UltiSnipsSnippetDirectories ["UltiSnips"] +UltiSnips snippet definition files are stored in one or more directories. +There are several variables used to indicate those directories and define how +UltiSnips loads snippets. -Snippet definition files are searched in 'runtimepath', but the 'runtimepath' -variable is traversed in reversed order (last item first). If you would like -to have UltiSnips traverse this in proper order, add these to your vimrc: > - let g:UltiSnipsDontReverseSearchPath="1" +Snippet definition files are stored in snippet directories. A snippet +directory must be a subdirectory of a directory defined in the 'runtimepath' +option. The variable g:UltiSnipsSnippetDirectories defines a list of names +used for snippet directories. The default is shown below. > + + g:UltiSnipsSnippetDirectories ["UltiSnips"] -In each directory, UltiSnips will search for the folder names in the order -they appear in g:UltiSnipsSnippetDirectories. If you keep your snippets in a -folder called "mycoolsnippets" in your .vim directory and you want the -snippets that ship with UltiSnips to be available as well, use > +UltiSnips will search each 'runtimepath' directory for the subdirectory names +defined in g:UltiSnipsSnippetDirectories in the order they are defined. For +example, if you keep your snippets in a .vim subdirectory called +"mycoolsnippets" and you want to make use of the default snippets that come +with UltiSnips, add the following to your vimrc file. > let g:UltiSnipsSnippetDirectories=["UltiSnips", "mycoolsnippets"] -If you do not want the shipped snippets to be available, only use -"mycoolsnippets". +If you do not want to use the snippets that come with UltiSnips, define the +variable accordingly. > + let g:UltiSnipsSnippetDirectories=["mycoolsnippets"] + +UltiSnips searches in 'runtimepath' for snippet directories but traverses +'runtimepath' in reverse order (last item first). If you would like to have +UltiSnips traverse 'runtimepath' in the standard order, add this to your vimrc +file: > + let g:UltiSnipsDontReverseSearchPath="1" -By default, UltiSnips will check for updates to .snippets files whenever -it is activated. This behavior can be disabled as follows: > +By default, whenever a snippet expand is triggered, UltiSnips will check for +modifications to the snippet file associated with the filetype and reload it +if necessary. This behavior can be disabled as follows: > let g:UltiSnipsDoHash=0 -See |UltiSnips-adding-snippet| for an introduction which files are parsed for -which file type. +|UltiSnips-adding-snippets| explains which files are parsed for a given filetype. + 3.4 Warning About Select Mode Mappings *UltiSnips-warning-smappings* -------------------------------------- -The help for vim's *mapmode-s* states: > +Vim's help document for |mapmode-s| states: > NOTE: Mapping a printable character in Select mode may confuse the user. It's better to explicitly use :xmap and :smap for printable characters. Or use :sunmap after defining the mapping. -But most vim plugins (even the ones shipped with vim) do not adhere to this. -As UltiSnips uses select mode to mark tabstops in snippets for overwriting -these wrong mappings get in the way. UltiSnips therefore defaults to -*:sunmap* all mappings for printable characters in select mode. It will not -touch any other mappings, especially not normal, insert or visual mode -mappings. +However, most Vim plugins, including some default Vim plugins, do not adhere +to this. UltiSnips uses Select mode to mark tabstops in snippets for +overwriting. Existing Visual+Select mode mappings will interfere. Therefore, +UltiSnips issues a |:sunmap| command to remove each Select mode mapping for +printable characters. No other mappings are touched. In particular, UltiSnips +does not change existing normal, insert or visual mode mappings. -If this behaviour is not desired, you can disable it via > +If this behavior is not desired, you can disable it by adding this line to +your vimrc file. > let g:UltiSnipsRemoveSelectModeMappings = 0 -If you want to keep certain mappings, you can modify the list of ignores for -this feature. For example > - let g:UltiSnipsMappingsToIgnore = [ "somePlugin", "otherPlugin" ] +If you want to disable this feature for specific mappings only, add them to +the list of mappings to be ignored. For example, the following lines in your +vimrc file will unmap all Select mode mappings except those mappings +containing either the string "somePlugin" or the string "otherPlugin" in its +complete definition as listed by the |:smap| command. > -will not unmap any mapping that contains the string "somePlugin" or -"otherPlugin" in its complete definition as listed by *:smap* . + let g:UltiSnipsRemoveSelectModeMappings = 1 + let g:UltiSnipsMappingsToIgnore = [ "somePlugin", "otherPlugin" ] 3.5 Functions *UltiSnips-functions* @@ -211,143 +295,215 @@ will not unmap any mapping that contains the string "somePlugin" or UltiSnips provides two functions for extending core functionality. + 3.5.1 UltiSnips_AddSnippet *UltiSnips_AddSnippet* The first function is UltiSnips_AddSnippet(trigger, value, description, -options, ...) which adds a new snippet to the current list of snippets with -the provided trigger, value, description, and options, see |UltiSnips-syntax| -for details on the meaning of those. All of the arguments are strings. You can -also specify the filetype for the new snippet with the final optional -argument. +options, ...). It adds a new snippet with the provided trigger, value, +description, and options to the current list of snippets. See +|UltiSnips-syntax| for details on the meaning of the function arguments. All +arguments are strings. An optional fifth argument can be used to specify the +filetype for the new snippet. + 3.5.2 UltiSnips_Anon *UltiSnips_Anon* -The second function is UltiSnips_Anon(value, ...), which expands an anonymous -Snippet. The snippet that gets expanded doesn't get added to the global list -of snippets, so it can't be expanded a second time unless the function is -called again. The value argument is the same as |UltiSnips_AddSnippet|. There -are also optional arguments, which are 1) the trigger, 2) the description of -the snippet, and 3) the options. All of the optional arguments are the same as -the |UltiSnips_AddSnippet| function. The description is unused right now, -whereas the trigger and options can change the way the snippet expands. +The second function is UltiSnips_Anon(value, ...). It expands an anonymous +snippet. Anonymous snippets are defined on the spot, expanded and immediately +discarded again. Anonymous snippets are not added to the global list of +snippets, so they cannot be expanded a second time unless the function is +called again. The function takes three optional arguments, in order: trigger, +description, options. Arguments coincide with the arguments of the +|UltiSnips_AddSnippet| function of the same name. The trigger and options +arguments can change the way the snippet expands. The description is unused at +this point. -This feature is frequently used in .vimrc. A typical use case from my -restructured text file looks like this: +An example use case might be this line from a reStructuredText plugin file: inoremap $$ $$=UltiSnips_Anon(':latex:\`$1\`', '$$') -This expands the snippet whenever I type two $ signs. Note that In the right -hand site of the mapping, I retype the '$$' trigger and also inform UltiSnips -about the trigger; if I do not do this or give an empty trigger, vim will -trick UltiSnips by unreliably claiming that there is already one or zero '$' -signs before the snippet is expanded. +This expands the snippet whenever two $ signs are typed. +Note: The right hand side of the mapping starts with an immediate retype of +the '$$' trigger and passes '$$' to the function as the trigger argument. +This is required in order for UltiSnips to have access to the characters +typed so it can determine if the trigger matches or not. + ============================================================================= -4. SYNTAX *UltiSnips-syntax* +4. Syntax *UltiSnips-syntax* + +This chapter describes how to write your own snippets and snippet definition +syntax. Examples are used to help illustrate. -This chapter describes where to add new snippets and how to write them. I'll -provide many examples to make things clearer. 4.1 Adding Snippets *UltiSnips-adding-snippets* ------------------- See |UltiSnips-snippet-search-path| for an explanation of where directories -with snippet definitions are expected. - -While iterating over the snippet definition directories found, files are -looked for called ft.snippets or *_ft.snippets where "ft" is the current -'filetype', and the "*" matches anything, for example: > - ruby.snippets - c.snippets - my_c.snippets - perl.snippets -These files contain the snippet definitions for the various file types. A -special file is > - all.snippets -which contains snippets that are always expanded, no matter what file type is -defined. For example, I keep mail signatures and date insertion snippets here. - -The dotted file type syntax of vim is supported. For example, for my cpp or -CUDA files, I keep the file type set to ":set ft=cpp.c" or ":set -ft=cuda.cpp.c". This activates all snippets for each file type in the order -specified. - -As an alternative, a snippet file may contain a line that looks like this: > +with snippet definitions should be located. + +Using a strategy similar to how Vim detects |ftplugins|, UltiSnips iterates +over the snippet definition directories looking for files with names of the +following patterns: ft.snippets, ft_*.snippets, or ft/*, where "ft" is the +'filetype' of the current document and "*" is a shell-like wildcard matching +any string including the empty string. The following table shows some typical +snippet filenames and their associated filetype. + + snippet filename filetype ~ + ruby.snippets ruby + perl.snippets perl + c.snippets c + c_my.snippets c + c/a c + c/b.snippets c + all.snippets *all + all/a.snippets *all + +* The 'all' filetype is unique. It represents snippets available for use when +editing any document regardless of the filetype. A date insertion snippet, for +example, would be fit well in the all.snippets file. + +UltiSnips supports Vim's dotted filetype syntax. To illustrate, the filetype +for a cpp file could be set as follows ":set ft=cpp.c". If there exists +c.snippets and cpp.c.snippets files in snippet directories snippets from both +files are activated. CUDA files could have filetypes set to 'cuda.cpp.c' +Snippets from all three, c.snippets, cpp.c.snippets and cuda.cpp.c.snippets +are activated for that filetype. + +The extends directive provides an alternative way of combining snippet files. +When the extends directive is included in a snippet file, it instructs +UltiSnips to include all snippets from the indicated filetypes. + +The syntax looks like this: > extends ft1, ft2, ft3 + For example, the first line in cpp.snippets looks like this: > extends c -This means, first check all triggers for c, then add the triggers from this -file. This is a convenient way to add more special cases to more general ones. -Multiple "extends" lines are permitted throughout the snippets file. +When UltiSnips activates snippets for a cpp file, it first looks for all c +snippets and activates them as well. This is a convenient way to create +specialized snippet files from more general ones. Multiple "extends" lines are +permitted in a snippet file, and they can be included anywhere in the file. + +The snippets file syntax is simple. All lines starting with a # character are +considered comments. Comments are ignored by UltiSnips. Use them to document +snippets. + +A line beginning with the keyword 'snippet' marks the beginning of snippet +definition and a line starting with the keyword 'endsnippet' marks the end. +The snippet definition is placed between the lines. Here is a snippet of an +'if' statement for the Unix shell (sh) filetype. + + snippet if "if ... then (if)" + if ${2:[[ ${1:condition} ]]}; then + ${0:#statements} + fi + endsnippet + +The start line takes the following form: > -The snippets file format is simple. A line starting with # is a comment, each -snippet starts with a line in the form of: > snippet tab_trigger [ "description" [ options ] ] -The following lines are the snippets definition; a line starting with > - endsnippet -marks the end of the snippet. The trailing newline is chopped from the -definition. In the starting line, the description and options are optional. -If you want to use a multi-word trigger, you can surround the trigger with any -single character on each side. e.g. > +The tab_trigger is required, but the description and options are optional. + +The 'tab_trigger' is the word or string sequence used to trigger the snippet. +Generally a single word is used but the tab_trigger can include spaces. If you +wish to include spaces, you must wrap the tab trigger in quotes. > + snippet "tab trigger" [ "description" [ options ] ] -or > + +The quotes are not part of the trigger. To activate the snippet type: tab trigger +followed by the snippet expand character. + +It is not technically necessary to use quotes to wrap a trigger with spaces. +Any matching characters will do. For example, this is a valid snippet starting +line. > + snippet !tab trigger! [ "description" [ options ] ] + +Quotes can be included as part of the trigger by wrapping the trigger in +another character. > snippet !"tab trigger"! [ "description" [ options ] ] -if you actually want to include the double-quote characters in the trigger. - -The description is only needed when more than one snippet is defined with the -same tab trigger. The user is then given a choice and the description is -displayed for the user as helper. - -The options is a word of characters, each turning a specific option for this -snippet on. The options currently supported are > - ! Overwrite - This snippet will overwrite all previously defined - snippets with this tab trigger. Default is to let the user choose at - expansion which snippet to expand. This option is useful to overwrite - bundled tab stops with user defined ones. - b Beginning of line - This snippet will only be expanded if you are at - the beginning of a line (that is if there are only whitespaces in front - of the cursor). Default is to expand snippets at every position, even - in the middle of a line. Most of my snippets have this option set, it - keeps UltiSnips out of the way. - i Inword expansion - Normally, triggers need whitespace before them to be - expanded. With this option, triggers are also expanded in the middle of - a word. - w Word boundary - Normally, triggers need whitespace before them to be - expanded. With this option, the trigger will be expanded at a "word" - boundary as well, where word characters are letters, digits, and the - underscore character ('_'). This enables expansion of a trigger that - adjoins punctuation (for example) without expanding suffixes of larger - words. - r Regular expression - This uses a python regular expression for the - 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 + +To activate this snippet one would type: "tab trigger" + +The 'description' is a string describing the trigger. It is helpful for +documenting the snippet and for distinguishing it from other snippets with the +same tab trigger. When a snippet is activated and more than one tab trigger +match, UltiSnips displays a list of the matching snippets with their +descriptions. The user then selects the snippet they want. + +The 'options' control the behavior of the snippet. Options are indicated by +single characters. The 'options' characters for a snippet are combined into +a word without spaces. + +The options currently supported are: > + ! Overwrite - A snippet with this option will overwrite all previously + defined snippets with an identical tab trigger. The default behavior + is to display list of snippets matching the tab trigger and let the + user pick the one they want. Use this option to overwrite bundled + snippets with user defined ones. + + b Beginning of line - A snippet with this option is expanded only if the + tab trigger is the first word on the line. In other words, if only + whitespace precedes the tab trigger, expand. The default is to expand + snippets at any position regardless of the preceding non-whitespace + characters. + + i In-word expansion - By default a snippet is expanded only if the tab + trigger is the first word on the line or is preceded by one or more + whitespace characters. A snippet with this option is expanded + regardless of the preceding character. In other words, the snippet can + be triggered in the middle of a word. + + w Word boundary - With this option, the snippet is expanded if + the tab trigger start matches a word boundary and the tab trigger end + matches a word boundary. In other words the tab trigger must be + preceded and followed by non-word characters. Word characters are + letters, digits and the underscore. Use this option, for example, to + permit expansion where the tab trigger follows punctuation without + expanding suffixes of larger words. + + r Regular expression - With this option, the tab trigger is expected to + be a python regular expression. The snippet is expanded if the recently + typed characters match the regular expression. Note: The regular + expression MUST be quoted (or surrounded with another character) like a + multi-word tab trigger (see above) whether it has spaces or not. A + resulting match is passed to any python code blocks in the snippet definition as the local variable "match". - t Don't expand tabs - By default, UltiSnips tries to expand leading tabs - in a snippet to match the results of automatic indentation. If this - option is set, UltiSnips will not try to do this expansion, and will - leave the tabs alone. This can be useful for snippets dealing with - tab delimited formats, etc. - f Do not turn 'formatoptions' off when expanding the snippet. Normally, - UltiSnips will disable the 'c' and the 't' option of 'formatoptions' - because otherwise, Vim might break a line without UltiSnips noticing - and this might mess up the snippet completely. This is useful for - snippets that need paragraphs in their tabstops. -< - - 4.1.1 Character Escaping: *UltiSnips-character-escaping* - -In the snippet descriptions, various characters have special meaning -(e.g. '`{$\). If you want to insert any one of these characters literally, -prepend them with a single backslash (\). + + t Do not expand tabs - If a snippet definition includes leading tab + characters, by default UltiSnips expands the tab characters honoring + the Vim 'shiftwidth', 'softtabstop', 'expandtab' and 'tabstop' + indentation settings. (For example, if 'expandtab' is set, the tab is + replaced with spaces.) If this option is set, UltiSnips will ignore the + Vim settings and insert the tab characters as is. This option is useful + for snippets involved with tab delimited formats, for example. + +The end line is the 'endsnippet' keyword on a line by itself. > + + endsnippet + +When parsing snippet files, UltiSnips chops the trailing newline character +from the 'endsnippet' end line. + + + 4.1.1 Character Escaping: *UltiSnips-character-escaping* + +In snippet definitions, the characters '`', '{', '$', '\' and "'" (single +quote) have special meaning. If you want to insert one of these characters +literally, escape them with a backslash, '\'. + 4.2 Plaintext Snippets *UltiSnips-plaintext-snippets* ---------------------- -Lets start with a simple example. Add this to your all snippets file: > +To illustrate plaintext snippets, let's begin with a simple example. You can +try the examples yourself. Simply edit a new file with Vim. Example snippets +will be added to the 'all.snippets' file, so you'll want to open it in Vim for +editing as well. > ~/.vim/UltiSnips/all.snippets +Add this snippet to 'all.snippets' and save the file. + ------------------- SNIP ------------------- snippet bye "My mail signature" Good bye, Sir. Hope to talk to you soon. @@ -355,42 +511,80 @@ Good bye, Sir. Hope to talk to you soon. endsnippet ------------------- SNAP ------------------- -UltiSnips will pick up that you added/changed this file automatically, so just -try it in insert mode: -bye --> +UltiSnips detects when you write changes to a snippets file and automatically +makes the changes active. So in the empty buffer, type the tab trigger 'bye' +and then press the key. + +bye --> Good bye, Sir. Hope to talk to you soon. - Arthur, King of Britain +The word 'bye' will be replaced with the text of the snippet definition. + + 4.3 Visual Placeholder *UltiSnips-visual-placeholder* ---------------------- -Snippets can contain a special placeholder called ${VISUAL}. When you select -some text in visual mode and press the key to expand a trigger -(see g:UltiSnipsExpandTrigger) the selected text will get deleted and you will -drop to insert mode. The next snippet you expand will have the selected text -in the place of the ${VISUAL}. As a small example, let's take this snippet: +Snippets can contain a special placeholder called ${VISUAL}. The ${VISUAL} +variable is expanded with the text selected just prior to expanding the +snippet. + +To see how a snippet with a ${VISUAL} placeholder works, define a snippet with +the placeholder, use Vim's Visual mode to select some text, and then press the +key you use to trigger expanding a snippet (see g:UltiSnipsExpandTrigger). The +selected text is deleted, and you are dropped into Insert mode. Now type the +snippet tab trigger and press the key to trigger expansion. As the snippet +expands, the previously selected text is printed in place of the ${VISUAL} +placeholder. + +The ${VISUAL} placeholder can contain default text to use when the snippet has +been triggered when not in Visual mode. The syntax is: > + ${VISUAL:default text} + +The ${VISUAL} placeholder can also define a transformation (see +|UltiSnips-transformations|). The syntax is: > + ${VISUAL:default/search/replace/option}. + +Here is a simple example illustrating a visual transformation. The snippet +will take selected text, replace every instance of "should" within it with +"is" , and wrap the result in tags. ------------------- SNIP ------------------- snippet t -${VISUAL} +${VISUAL:inside text/should/is/g} endsnippet ------------------- SNAP ------------------- -And starting with this line: > + +Start with this line of text: > this should be cool -position the cursor on the should, then press viw (visual mode -> select inner -word). Then press tab, type "t" and press tab again > - -> this should be cool + +Position the cursor on the word "should", then press the key sequence: viw +(visual mode -> select inner word). Then press , type "t" and press +again. The result is: > + -> this is be cool + +If you expand this snippet while not in Visual mode (e.g., in Insert mode type +t), you will get: > + inside text + 4.4 Interpolation *UltiSnips-interpolation* ----------------- - 4.4.1 Shellcode: *UltiSnips-shellcode* + 4.4.1 Shellcode: *UltiSnips-shellcode* + +Snippets can include shellcode. Put a shell command in a snippet and when the +snippet is expanded, the shell command is replaced by the output produced when +the command is executed. The syntax for shellcode is simple: wrap the code in +backticks, '`'. When a snippet is expanded, UltiSnips runs shellcode by first +writing it to a temporary script and then executing the script. The shellcode +is replaced by the standard output. Anything you can run as a script can be +used in shellcode. Include a shebang line, for example, #!/usr/bin/perl, and +your snippet has the ability to run scripts using other programs, perl, for +example. -You can enter shellcode in your snippets in nearly all places. Shell code is -written to a script and then executed. The output is inserted into the snippet -instead of the shell code itself. Since the code is executed as a shell -script, you can use #!/bin/ notation to feed the input of your code to every -program you like. Let's consider an example that inserts the current date. +Here are some examples. This snippet uses a shell command to insert the +current date. ------------------- SNIP ------------------- snippet today @@ -401,7 +595,9 @@ endsnippet today -> Today is the 15.07.09. -Another example doing the same using perl + +This example inserts the current date using perl. + ------------------- SNIP ------------------- snippet today Today is `#!/usr/bin/perl @@ -411,12 +607,13 @@ endsnippet today -> Today is 15.6.2009. - 4.4.2 VimScript: *UltiSnips-vimscript* -You can also use VimScript (also sometimes called VimL) in interpolation. This -works very much the same as interpolation of shellcode, expect that it must be -started by using `!v `. Let's consider a simple example, that counts the -indent of the current line: + 4.4.2 VimScript: *UltiSnips-vimscript* + +You can also use Vim scripts (sometimes called VimL) in interpolation. The +syntax is similar to shellcode. Wrap the code in backticks and to distinguish +it as a Vim script, start the code with '!v'. Here is an example that counts +the indent of the current line: ------------------- SNIP ------------------- snippet indent @@ -426,76 +623,95 @@ endsnippet (note the 4 spaces in front): indent -> (note the 4 spaces in front): Indent is: 4. - 4.4.3 Python: *UltiSnips-python* -By far the most powerful interpolation is by using python code. The syntax is -similar to the one for Vimscript, but in python code the value of the property -"rv" on the "snip" object is inserted at the position of the code. Also, the -code is inside a `!p ` block. Python code gets some special variables defined -which can be used: > + 4.4.3 Python: *UltiSnips-python* + +By far python interpolation is the most powerful. The syntax is similar to Vim +scripts except code is started with '!p'. Python scripts can be run using the +python shebang '#!/usr/bin/python', but using the '!p' format comes with some +predefined objects and variables, which can simplify and shorten code. For +example, a 'snip' object instance is implied in python code. Python code using +the '!p' indicator differs in another way. Generally when a snippet is +expanded the standard output of code replaces the code. With python code the +value of the 'rv' property of the 'snip' instance replaces the code. Standard +output is ignored. + +The variables automatically defined in python code are: > 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. + t - The values of the placeholders, t[1] is the text of ${1}, and so on + snip - UltiSnips.TextObjects.SnippetUtil object instance. Has methods that + simplify indentation handling. -The snip object provides the following methods: > +The 'snip' object provides the following 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. + current 'tabstop' and 'expandtab' variables. snip.shift(amount=1): Shifts the default indentation level used by mkline right by the - number of spaces defined by shiftwidth, 'amount' times. + number of spaces defined by 'shiftwidth', 'amount' times. snip.unshift(amount=1): Shifts the default indentation level used by mkline left by the - number of spaces defined by shiftwidth, 'amount' times. + number of spaces defined by 'shiftwidth', 'amount' times. snip.reset_indent(): Resets the indentation level to its initial value. snip.opt(var, default): - Checks if the vim variable "var" has been set, if so, it returns it, - otherwise it returns "default". + Checks if the Vim variable 'var' has been set. If so, it returns the + variable's value; otherwise, it returns the value of 'default'. -The snip object provides some properties as well: > +The 'snip' object provides some properties as well: > 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. + 'rv' is the return value, the text that will replace the python block + in the snippet definition. It is initialized to the empty string. This + deprecates the 'res' variable. snip.c: - the text currently in the python block's position in the snippet - in it. You can check if snip.c is != "" to make sure that the - interpolation is only done once. This deprecates the "cur" variable. + The text currently in the python block's position within the snippet. + It is set to empty string as soon as interpolation is completed. Thus + you can check if snip.c is != "" to make sure that the interpolation + is only done once. This deprecates the "cur" variable. + + snip.v: + Data related to the ${VISUAL} placeholder. The property has two + attributes: + snip.v.mode ('v', 'V', '^V', see *visual-mode* ) + snip.v.text The text that was selected. snip.fn: - the current filename. + The current filename. snip.basename: - the current filename without it's extension. + The current filename with the extension removed. snip.ft: - the current filetype. + The current filetype. -The snip object also provides some operators to make python snippets -easier: > +For your convenience, the 'snip' object also provides the following +operators: > snip >> amount: - is equivalent to snip.shift(amount) + Equivalent to snip.shift(amount) snip << amount: - is equivalent to snip.unshift(amount) + Equivalent to snip.unshift(amount) snip += line: - is equivalent to "snip.rv += '\n' + snip.mkline(line)" + Equivalent to "snip.rv += '\n' + snip.mkline(line)" + +Any variables defined in a python block can be used in other python blocks +that follow within the same snippet. Also, the python modules 'vim', 're', +'os', 'string' and 'random' are pre-imported within the scope of snippet code. +Other modules can be imported using the python 'import' command. -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 -uppercase and right aligned: +Python code allows for very flexible snippets. For example, the following +snippet mirrors the first tabstop value on the same line but right aligned and +in uppercase. ------------------- SNIP ------------------- snippet wow @@ -505,14 +721,47 @@ endsnippet wowHello World -> Hello World HELLO WORLD +The following snippet uses the regular expression option and illustrates +regular expression grouping using python's match object. It shows that the +expansion of a snippet can depend on the tab trigger used to define the +snippet, and that tab trigger itself can vary. + +------------------- SNIP ------------------- +snippet "be(gin)?( (\S+))?" "begin{} / end{}" br +\begin{${1:`!p +snip.rv = match.group(3) if match.group(2) is not None else "something"`}} + ${2:${VISUAL}} +\end{$1}$0 +endsnippet +------------------- SNAP ------------------- +becenter -> +\begin{center} + +\end{center} +------------------- SNAP ------------------- +be center -> +\begin{center} + +\end{center} + +The second form is a variation of the first, both produce the same result, +but it illustrates how regular expression grouping works. Using regular +expressions in this manner has some drawbacks: +1. If you use the key for both expanding snippets and completion then + if you typed "be form" expecting the completion "be formatted", you + would end up with the above SNAP instead, not what you want. +2. The snippet is harder to read. + + 4.4.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: +Global snippets provide a way to reuse common code in multiple snippets. +Currently, only python code is supported. The result of executing the contents +of a global snippet is put into the globals of each python block in the +snippet file. To create a global snippet, use the keyword 'global' in place of +'snippet', and for python code, you use '!p' for the trigger. For example, the +following snippet produces the same output as the last example . However, with +this syntax the 'upper_right' snippet can be reused by other snippets. ------------------- SNIP ------------------- global !p @@ -527,78 +776,169 @@ endsnippet wowHello World -> Hello World HELLO WORLD -Sometimes you want to have helper functions that are available in all your -snippet files. This is easily achieved using a global snippet and a python -module. First, add a search path to your python path by adding something along -this line to your vimrc: > +Python global functions can be stored in a python module and then imported. +This makes global functions easily accessible to all snippet files. + +First, add the directory modules are stored in to the python search path. For +example, add this line to your vimrc file. > py import sys; sys.path.append("/home/sirver/.vim/python") -Now use a global snippet in your snippet file to import modules from this -directory: > +Now, import modules from this directory using a global snippet in your snippet +file > global !p from my_snippet_helpers import * endglobals -4.5 Tab Stops and Placeholders *UltiSnips-tabstops* *UltiSnips-placeholders* ------------------------------- -Very often, it is convenient to quickly add some text snippet and jump on to -the next point of interest. This is were tabstops come in: +4.4 Tabstops and Placeholders *UltiSnips-tabstops* *UltiSnips-placeholders* +----------------------------- + +Snippets are used to quickly insert reused text into a document. Often the +text has a fixed structure with variable components. Tabstops are used to +simplify modifying the variable content. With tabstops you can easily place +the cursor at the point of the variable content, enter the content you want, +then jump to the next variable component, enter that content, and continue +until all the variable components are complete. + +The syntax for a tabstop is the dollar sign followed by a number, for example, +'$1'. Tabstops start at number 1 and are followed in sequential order. The +'$0' tabstop is a special tabstop. It is always the last tabstop in the +snippet no matter how many tabstops are defined. + +Here is a simple example. ------------------- SNIP ------------------- -snippet jump -I $1 I was a $2. +snippet letter +Dear $1, $0 +Yours sincerely, +$2 +endsnippet +------------------- SNAP ------------------- +letterBenPaulThanks for suggesting UltiSnips!-> +Dear Ben, +Thanks for suggesting UltiSnips! +Yours sincerely, +Paul + + +You can use to jump to the next tabstop, and to jump to the +previous. The key was not used for jumping forward because many people +(myself included) use for completion. See |UltiSnips-triggers| for +help on defining different keys for tabstops. + +Many times it is useful to have some default text for a tabstop. The default +text may be a value commonly used for the variable component, or it may be a +word or phrase that reminds you what is expected for the variable component. +To include default text, the syntax is '${1:value}'. + +The following example illustrates a snippet for the shell 'case' statement. +The tabstops use default values to remind the user of what value is expected. + +------------------- SNIP ------------------- +snippet case +case ${1:word} in + ${2:pattern} ) $0;; +esac endsnippet ------------------- SNAP ------------------- -jumpwishhuntermore text -> -I wish I was a hunter. -more text -You can use and to jump to the next tab or the previous. was -not used for jumping forward because many people (like myself) use also -for completion. $0 is a special tab: This is the last tab in the snippet, no -matter how many tabs were defined before. +case$option-vverbose=true +case $option in + -v ) verbose=true;; +esac + + +Sometimes it is useful to have a tabstop within a tabstop. To do this, simply +include the nested tabstop as part of the default text. Consider the following +example illustrating an HTML anchor snippet. -Most of the time it is more useful to have some default text for a tabstop and -sometimes it is also useful to have a tab stop in a tab stop. Consider the -next example which could be a real life scenario from a HTML snippet: ------------------- SNIP ------------------- snippet a - + $0 endsnippet ------------------- SNAP ------------------- -Here, $1 marks the first tabstop; it is assumed that you always want to add a -url as href. After entering it you jump to $2 which has the default text ' -class="link"'. Now, you can either hit backspace, because you do not want to -enter a class attribute for this tag or you hit to change the class name -(which is tab stop $3). When you are satisfied with the first line you hit - again to finish this snippet and continue inside the anchor. +When this snippet is expanded, the first tabstop has a default value of +'http://www.example.com'. If you want the 'http://' schema, jump to the next +tabstop. It has a default value of 'example.com'. This can be replaced by +typing whatever domain you want. -ahttp://www.google.comhi -> +agoogle.comGoogle -> - hi + Google -ahttp://www.google.comvisitedhi -> +If at the first tabstop you want a different url schema or want to replace the +default url with a named anchor, '#name', for example, just type the value you +want. + +a#topTop -> + + Top + + +In the last example, typing any text at the first tabstop replaces the default +value, including the second tabstop, with the typed text. So the second +tabstop is essentially deleted. When a tabstop jump is triggered, UltiSnips +moves to the next remaining tabstop '$0'. This feature can be used +intentionally as a handy way for providing optional tabstop values to the +user. Here is an example to illustrate. + +------------------- SNIP ------------------- +snippet a + + $0 + +endsnippet +------------------- SNAP ------------------- + +Here, '$1' marks the first tabstop. It is assumed you always want to add a +value for the 'href' attribute. After entering the url and pressing , the +snippet will jump to the second tabstop, '$2'. This tabstop is optional. The +default text is ' class="link"'. You can press to accept the tabstop, +and the snippet will jump to the third tabstop, '$3', and you can enter the +class attribute value, or, at the second tabstop you can press the backspace +key thereby replacing the second tabstop default with an empty string, +essentially removing it. In either case, continue by pressing and the +snippet will jump to the final tabstop inside the anchor. + +ahttp://www.google.comvisitedGoogle -> - hi + Google + + +ahttp://www.google.comGoogle -> + + Google -Default tab stop text can also contain mirrors, transformations or + +The default text of tabstops can also contain mirrors, transformations or interpolation. + 4.6 Mirrors *UltiSnips-mirrors* ----------- -Mirrors simply repeat the content of a tabstop. A classical example would be a -TeX Environment which needs a \begin{} and an \end{} tag: +Mirrors repeat the content of a tabstop. During snippet expansion when you +enter the value for a tabstop, all mirrors of that tabstop are replaced with +the same value. To mirror a tabstop simply insert the tabstop again using the +"dollar sign followed by a number" syntax, e.g., '$1'. + +A tabstop can be mirrored multiple times in one snippet, and more than one +tabstop can be mirrored in the same snippet. A mirrored tabstop can have a +default value defined. Only the first instance of the tabstop need have a +default value. Mirrored tabstop will take on the default value automatically. + +Mirrors are handy for start-end tags, for example, TeX 'begin' and 'end' tag +labels, XML and HTML tags, and C code #ifndef blocks. Here are some snippet +examples. ------------------- SNIP ------------------- snippet env @@ -612,7 +952,6 @@ envitemize -> \end{itemize} -Another typical example is #ifndef block in C code: ------------------- SNIP ------------------- snippet ifndef #ifndef ${1:SOME_DEFINE} @@ -627,43 +966,52 @@ ifndefWIN32 -> #endif /* WIN32 */ + 4.7 Transformations *UltiSnips-transformations* ------------------- -A complete description of the features follows, the chapter closes with some -demos, because this feature is rather mighty and hard to understand. +Note: Transformations are a bit difficult to grasp so this chapter is divided +into two sections. The first describes transformations and their syntax, and +the second illustrates transformations with demos. -Transformations are like mirrors. But instead of just verbatim copying text -from the original tab stop, a regular expression is matched to the content of -the referenced tab stop and a transformation is then applied to the matched -pattern. UltiSnips follows the syntax and features of TextMate very closely -here. +Transformations are like mirrors but instead of just copying text from the +original tabstop verbatim, a regular expression is matched to the content of +the referenced tabstop and a transformation is then applied to the matched +pattern. The syntax and functionality of transformations in UltiSnips follow +very closely to TextMate transformations. -A Transformation has the syntax > - ${ + ${ - tab stop no - The number of the tab stop to reference - regular expression - The regular expression to match to the value of the - tab stop - replacement - The replacement string, see below - options - options for the regular expression +The components are defined as follows: > + tab_stop_no - The number of the tabstop to reference + regular_expression - The regular expression the value of the referenced + tabstop is matched on + replacement - The replacement string, explained in detail below + options - Options for the regular expression The options can be any combination of > - g - global replace, replaces all matches of the regular expression, not - just the first + g - global replace + By default, only the first match of the regular expression is + replaced. With this option all matches are replaced. + i - case insensitive + By default, regular expression matching is case sensitive. With this + option, matching is done without regard to case. + +The syntax of regular expressions is beyond the scope of this document. Python +regular expressions are used internally, so the python 're' module can be used +as a guide. See http://docs.python.org/library/re.html. -Regular expressions are not handled here. Python regular expressions are used -internally, so the reference for matching is the re module of python: - http://docs.python.org/library/re.html +The syntax for the replacement string is unique. The next paragraph describes +it in detail. -The replacement string is using a own syntax and is handled in the next paragraph. - 4.7.1 Replacement String: *UltiSnips-replacement-string* + 4.7.1 Replacement String: *UltiSnips-replacement-string* -The replacement string can contain $no variables to reference matched groups -in the regular expression, $0 is special and yields the whole match. The -replacement string can also contain special escape sequences: > +The replacement string can contain $no variables, e.g., $1, which reference +matched groups in the regular expression. The $0 variable is special and +yields the whole match. The replacement string can also contain special escape +sequences: > \u - Uppercase next letter; \l - Lowercase next letter \U - Uppercase everything till the next \E @@ -672,21 +1020,21 @@ replacement string can also contain special escape sequences: > \n - A newline \t - A literal tab -Last, but not least the replacement string might contain conditional -replacements with the following syntax (?no:text:other text). This reads as -follows: if the group $no has matched, insert "text", otherwise insert "other -text". "other text" could be skipped and would default to "", that is the -empty string. This is a very powerful feature to add optional text into -snippets. +Finally, the replacement string can contain conditional replacements using the +syntax (?no:text:other text). This reads as follows: if the group $no has +matched, insert "text", otherwise insert "other text". "other text" is +optional and if not provided defaults to the empty string, "". This feature +is very powerful. It allows you to add optional text into snippets. + - 4.7.2 Demos: *UltiSnips-demos* + 4.7.2 Demos: *UltiSnips-demos* -The transformations are very powerful but yield often a convoluted snippet -syntax. Therefore I offer for each feature a simple example below. +Transformations are very powerful but often the syntax is convoluted. +Hopefully the demos below help illustrate transformation features. -This shows uppercasing one character +Demo: Uppercase one character ------------------- SNIP ------------------- -snippet title "Titelize in the Transformation" +snippet title "Title transformation" ${1:a text} ${1/\w+\s*/\u$0/} endsnippet @@ -696,9 +1044,9 @@ big small Big small -This shows uppercasing one character and global replace: +Demo: Uppercase one character and global replace ------------------- SNIP ------------------- -snippet title "Titelize in the Transformation" +snippet title "Titlelize in the Transformation" ${1:a text} ${1/\w+\s*/\u$0/g} endsnippet @@ -707,8 +1055,11 @@ titlethis is a title -> this is a title This Is A Title -This is a clever c-like printf snippet, the second tabstop is only shown -when there is a format (%) character in the first tab stop. + +Demo: Regular expression grouping + This is a clever c-like printf snippet, the second tabstop is only shown + when there is a format (%) character in the first tabstop. + ------------------- SNIP ------------------- snippet printf printf("${1:%s}\n"${1/([^%]|%%)*(%.)?.*/(?2:, :\);)/}$2${1/([^%]|%%)*(%.)?.*/(?2:\);)/} @@ -725,79 +1076,90 @@ printf("A is: %s\n", A); // End of line There are many more examples of what can be done with transformations in the bundled snippets. - 4.8 Clearing snippets *UltiSnips-clearing-snippets* -To remove snippets for the current file type, use the "clearsnippets" -directive: +4.8 Clearing snippets *UltiSnips-clearing-snippets* + +To remove snippets for the current file type, use the 'clearsnippets' +directive. + ------------------- SNIP ------------------- clearsnippets ------------------- SNAP ------------------- -Without arguments, "clearsnippets" removes all snippets defined so far for the -current file type. UltiSnips travels in reverse along the 'runtimepath', so -"clearsnippets" removes snippet definitions appearing later in the -'runtimepath' than the ".snippets" file in which it's encountered. +Without arguments, 'clearsnippets' removes all snippets defined up to that +point far for the current file type. Just a reminder, by default UltiSnips +traverses 'runtimepath' in reverse order, so 'clearsnippets' removes snippet +definitions appearing in files in 'runtimepath' after the '.snippets' file in +which it is encountered. + +To clear one or more specific snippet, provide the names of the snippets as +arguments to the 'clearsnippets' command. The following example will clear +the snippets 'trigger1' and 'trigger2'. -Instead of clearing all snippets for the current file type, one or more -individual snippets may be cleared by specifying a space-separated list of -their triggers, e.g.: ------------------- SNIP ------------------- clearsnippets trigger1 trigger2 ------------------- SNAP ------------------- -This is useful if you only want to override a few triggers or all triggers -that came with UltiSnips with your own definitions. Note that you can -overwrite individual triggers when redefining them using the '!' option -(see |UltiSnips-adding-snippets| for the options). +UltiSnips comes with a set of default snippets for many file types. If you +would rather not have some of them defined, you can use 'clearsnippets' in +your personal snippets files to remove them. Note: you do not need to remove +snippets if you wish to replace them. Simply use the '!' option. (See +|UltiSnips-adding-snippets| for the options). -============================================================================= -5. HELPING OUT *UltiSnips-helping* -UltiSnips needs the help of a vibrant vim community to make it more useful -tomorrow than it is today. Please consider joining this effort by providing -new snippets, new features or bug reports. +============================================================================= +5. Helping Out *UltiSnips-helping* -You can contribute by fixing or reporting bugs in our issue tracker: -https://bugs.launchpad.net/ultisnips +UltiSnips needs the help of the Vim community to make it better. Please +consider joining this effort by providing new snippets, new features or bug +reports. -You can contribute snippets or patches in various ways. Here are the -possibilities in order of convenience for me (please be as convenient as you -can be): +You can contribute snippets or patches in various ways. The methods are listed +below in order of convenience for me. Please be as convenient as you +can be :) * Clone the repository on launchpad (bzr clone lp:ultisnips), make fixes, push the branch and send a merge request on launchpad. * Clone the repository on GitHub (git clone git@github.com:SirVer/ultisnips.git), make your changes and send a pull request on GitHub. -* Make a patch, report a bug/feature request and attach the patch to it. -* Send me an Email with a patch. +* Make a patch, report a bug/feature request (see below) and attach the patch + to it. +* Send me an Email with a patch (see Contact section below). * Send me an Email with the changed files only. -If you like this plugin, please also vote for it on its vim script page. It is -life changing for me, maybe it is for you too. -You can find the page here: -http://www.vim.org/scripts/script.php?script_id=2715 +You can contribute by fixing or reporting bugs in our issue tracker: +https://bugs.launchpad.net/ultisnips + + +If you like this plugin, please vote for it on its Vim script page > + http://www.vim.org/scripts/script.php?script_id=2715 +It is life changing for me. Maybe it is for you too. + ============================================================================= -6. CONTACT *UltiSnips-contact* +6. Contact *UltiSnips-contact* -You can reach me at SirVer -AT- gmx -ADOT- de. You can find the launchpad -project for UltiSnips at https://launchpad.net/ultisnips/, there is also the -bug tracker. +You can reach me at SirVer -AT- gmx -ADOT- de. You can also contact me through +the UltiSnips launchpad project page at https://launchpad.net/ultisnips/. The +launchpad project has an 'Answers' page where you can ask me questions and a +bug tracker where you can report bugs and issues. This project aims to be the one-for-all solution for Snippets for Vim. If you miss a feature or find a bug, please contact me or file a support ticket. + ============================================================================= -7. CONTRIBUTORS *UltiSnips-contributors* +7. Contributors *UltiSnips-contributors* + +The primary developer of UltiSnips is SirVer (Holger Rapp). The following +individuals have contributed code and snippets to UltiSnips. -UltiSnips is mainly developed by SirVer (Holger Rapp). The following -individuals have contributed code to UltiSnips. In order of apperance. 7.1 Patches & Coding *UltiSnips-contricoding* -------------------- -Contributers are listed in chronological order: +Contributors listed in chronological order: JCEB - Jan Christoph Ebersbach Michael Henry @@ -814,13 +1176,19 @@ Contributers are listed in chronological order: pberndt - Phillip Berndt thanatermesis-elive - Thanatermesis rico-ambiescent - Rico Sta. Cruz - Cody Frazer + Cody Frazer suy - Alejandro Exojo + grota - Giuseppe Rota + iiijjjii - Jim Karsten + fgalassi - Federico Galassi + lucapette + Psycojoker - Laurent Peuch + 7.2 Snippets *UltiSnips-contrisnippets* ------------ -Contributers are listed in chronological order: +Contributors listed in chronological order: Alec Thomas Ryan Wooden @@ -830,6 +1198,17 @@ Contributers are listed in chronological order: Georgi Valkov (gvalkov) Miek Gieben (miek) Aldis Berjoza (graudeejs) + Jorge (skeept) + Martin Grenfell (scrooloose) + Laughedelic + Anthony Wilson (anthonywilson) + Nick Anderson (nickanderson) + Timothy Mellor (mellort) + Chris Lasher (gotgenes) + Chen Houwu (chenhouwu) + Harry Zhxu (harryzhxu) + Pavel (neoascetic) + +Thank you for your support. vim:tw=78:ts=8:ft=help:norl: - diff --git a/vim/bundle/ultisnips/ftdetect/UltiSnips.vim b/vim/bundle/ultisnips/ftdetect/UltiSnips.vim new file mode 100644 index 0000000..e307ff7 --- /dev/null +++ b/vim/bundle/ultisnips/ftdetect/UltiSnips.vim @@ -0,0 +1,6 @@ +" This has to be called before ftplugins are loaded. Therefore +" it is here in ftdetect though it maybe shouldn't +if has("autocmd") + autocmd FileType * call UltiSnips_FileTypeChanged() +endif + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips.vim b/vim/bundle/ultisnips/plugin/UltiSnips.vim index 49d7561..6603b48 100644 --- a/vim/bundle/ultisnips/plugin/UltiSnips.vim +++ b/vim/bundle/ultisnips/plugin/UltiSnips.vim @@ -1,7 +1,6 @@ " File: UltiSnips.vim " Author: Holger Rapp " Description: The Ultimate Snippets solution for Vim -" Last Modified: July 21, 2009 " " Testing Info: {{{ " See directions at the top of the test.py script located one @@ -12,10 +11,21 @@ if exists('did_UltiSnips_vim') || &cp || version < 700 finish endif -if !has("python3") - if !has("python") - echo "UltiSnips requires py >= 2.5 or any py3" - finish +if !exists("g:UltiSnipsUsePythonVersion") + let g:_uspy=":py3 " + if !has("python3") + if !has("python") + echo "UltiSnips requires py >= 2.6 or any py3" + finish + endif + let g:_uspy=":py " + endif + let g:UltiSnipsUsePythonVersion = "" +else + if g:UltiSnipsUsePythonVersion == 2 + let g:_uspy=":py " + else + let g:_uspy=":py3 " endif endif @@ -67,23 +77,14 @@ if !exists("g:UltiSnipsSnippetDirectories") endif " }}} -"" Global Commands {{{ +" Global Commands {{{ function! UltiSnipsEdit(...) if a:0 == 1 && a:1 != '' let type = a:1 else - if has("python3") - python3 vim.command("let type = '%s'" % UltiSnips_Manager.filetype) - else - python vim.command("let type = '%s'" % UltiSnips_Manager.filetype) - endif - endif - - if has("python3") - python3 vim.command("let file = '%s'" % UltiSnips_Manager.file_to_edit(vim.eval("type"))) - else - python vim.command("let file = '%s'" % UltiSnips_Manager.file_to_edit(vim.eval("type"))) + exec g:_uspy "vim.command(\"let type = '%s'\" % UltiSnips_Manager.primary_filetype)" endif + exec g:_uspy "vim.command(\"let file = '%s'\" % UltiSnips_Manager.file_to_edit(vim.eval(\"type\")))" let mode = 'e' if exists('g:UltiSnipsEditSplit') @@ -99,129 +100,89 @@ endfunction " edit snippets, default of current file type or the specified type command! -nargs=? UltiSnipsEdit :call UltiSnipsEdit() +" Global Commands {{{ +function! UltiSnipsAddFiletypes(filetypes) + exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . a:filetypes . ".all')" + return "" +endfunction +command! -nargs=1 UltiSnipsAddFiletypes :call UltiSnipsAddFiletypes() + "" }}} -"" FUNCTIONS {{{ +" FUNCTIONS {{{ function! CompensateForPUM() """ The CursorMovedI event is not triggered while the popup-menu is visible, """ and it's by this event that UltiSnips updates its vim-state. The fix is """ to explicitly check for the presence of the popup menu, and update """ the vim-state accordingly. if pumvisible() - if has("python3") - python3 UltiSnips_Manager.cursor_moved() - else - python UltiSnips_Manager.cursor_moved() - endif + exec g:_uspy "UltiSnips_Manager.cursor_moved()" endif endfunction - function! UltiSnips_ExpandSnippet() - if has("python3") - python3 UltiSnips_Manager.expand() - else - python UltiSnips_Manager.expand() - endif + exec g:_uspy "UltiSnips_Manager.expand()" return "" endfunction function! UltiSnips_ExpandSnippetOrJump() call CompensateForPUM() - if has("python3") - python3 UltiSnips_Manager.expand_or_jump() - else - python UltiSnips_Manager.expand_or_jump() - endif + exec g:_uspy "UltiSnips_Manager.expand_or_jump()" return "" endfunction function! UltiSnips_ListSnippets() - if has("python3") - python3 UltiSnips_Manager.list_snippets() - else - python UltiSnips_Manager.list_snippets() - endif + exec g:_uspy "UltiSnips_Manager.list_snippets()" return "" endfunction function! UltiSnips_SaveLastVisualSelection() - if has("python3") - python3 UltiSnips_Manager.save_last_visual_selection() - else - python UltiSnips_Manager.save_last_visual_selection() - endif + exec g:_uspy "UltiSnips_Manager.save_last_visual_selection()" return "" endfunction function! UltiSnips_JumpBackwards() call CompensateForPUM() - if has("python3") - python3 UltiSnips_Manager.jump_backwards() - else - python UltiSnips_Manager.jump_backwards() - endif + exec g:_uspy "UltiSnips_Manager.jump_backwards()" return "" endfunction function! UltiSnips_JumpForwards() call CompensateForPUM() - if has("python3") - python3 UltiSnips_Manager.jump_forwards() - else - python UltiSnips_Manager.jump_forwards() - endif + exec g:_uspy "UltiSnips_Manager.jump_forwards()" + return "" +endfunction + +function! UltiSnips_FileTypeChanged() + exec g:_uspy "UltiSnips_Manager.reset_buffer_filetypes()" + exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . &ft . "')" return "" endfunction function! UltiSnips_AddSnippet(trigger, value, descr, options, ...) " Takes the same arguments as SnippetManager.add_snippet: " (trigger, value, descr, options, ft = "all", globals = None) -if has("python3") -python3 << EOB -args = vim.eval("a:000") -trigger = vim.eval("a:trigger") -value = vim.eval("a:value") -descr = vim.eval("a:descr") -options = vim.eval("a:options") - -UltiSnips_Manager.add_snippet(trigger, value, descr, options, *args) -EOB -else -python << EOB -args = vim.eval("a:000") -trigger = vim.eval("a:trigger") -value = vim.eval("a:value") -descr = vim.eval("a:descr") -options = vim.eval("a:options") - -UltiSnips_Manager.add_snippet(trigger, value, descr, options, *args) -EOB -endif + exec g:_uspy "args = vim.eval(\"a:000\")" + exec g:_uspy "trigger = vim.eval(\"a:trigger\")" + exec g:_uspy "value = vim.eval(\"a:value\")" + exec g:_uspy "descr = vim.eval(\"a:descr\")" + exec g:_uspy "options = vim.eval(\"a:options\")" + exec g:_uspy "UltiSnips_Manager.add_snippet(trigger, value, descr, options, *args)" return "" endfunction function! UltiSnips_Anon(value, ...) " Takes the same arguments as SnippetManager.expand_anon: " (value, trigger="", descr="", options="", globals = None) -if has("python3") -python3 << EOB -args = vim.eval("a:000") -value = vim.eval("a:value") -UltiSnips_Manager.expand_anon(value, *args) -EOB -else -python << EOB -args = vim.eval("a:000") -value = vim.eval("a:value") -UltiSnips_Manager.expand_anon(value, *args) -EOB -endif + exec g:_uspy "args = vim.eval(\"a:000\")" + exec g:_uspy "value = vim.eval(\"a:value\")" + exec g:_uspy "UltiSnips_Manager.expand_anon(value, *args)" return "" endfunction function! UltiSnips_MapKeys() " Map the keys correctly if g:UltiSnipsExpandTrigger == g:UltiSnipsJumpForwardTrigger + exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips_ExpandSnippetOrJump()" exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips_ExpandSnippetOrJump()" else @@ -230,75 +191,40 @@ function! UltiSnips_MapKeys() exec "inoremap " . g:UltiSnipsJumpForwardTrigger . " =UltiSnips_JumpForwards()" exec "snoremap " . g:UltiSnipsJumpForwardTrigger . " :call UltiSnips_JumpForwards()" endif - exec 'xnoremap ' . g:UltiSnipsExpandTrigger. ' :call UltiSnips_SaveLastVisualSelection()gvs' + exec 'xnoremap ' . g:UltiSnipsExpandTrigger. ' :call UltiSnips_SaveLastVisualSelection()gvs' exec "inoremap " . g:UltiSnipsJumpBackwardTrigger . " =UltiSnips_JumpBackwards()" exec "snoremap " . g:UltiSnipsJumpBackwardTrigger . " :call UltiSnips_JumpBackwards()" exec "inoremap " . g:UltiSnipsListSnippets . " =UltiSnips_ListSnippets()" exec "snoremap " . g:UltiSnipsListSnippets . " :call UltiSnips_ListSnippets()" - " Do not remap this. - if has("python3") - snoremap :python3 UltiSnips_Manager.backspace_while_selected() - else - snoremap :python UltiSnips_Manager.backspace_while_selected() - endif + snoremap c endf function! UltiSnips_CursorMoved() - if has("python3") - python3 UltiSnips_Manager.cursor_moved() - else - python UltiSnips_Manager.cursor_moved() - endif + exec g:_uspy "UltiSnips_Manager.cursor_moved()" endf function! UltiSnips_EnteredInsertMode() - if has("python3") - python3 UltiSnips_Manager.entered_insert_mode() - else - python UltiSnips_Manager.entered_insert_mode() - endif + exec g:_uspy "UltiSnips_Manager.entered_insert_mode()" endf -function! UltiSnips_LeavingWindow() - if has("python3") - python3 UltiSnips_Manager.leaving_window() - else - python UltiSnips_Manager.leaving_window() - endif +function! UltiSnips_LeavingBuffer() + exec g:_uspy "UltiSnips_Manager.leaving_buffer()" endf " }}} "" STARTUP CODE {{{ " Expand our path -if has("python3") -python3 << EOF -import vim, os, sys - -new_path = vim.eval('expand(":h")') -sys.path.append(new_path) - -from UltiSnips import UltiSnips_Manager -UltiSnips_Manager.expand_trigger = vim.eval("g:UltiSnipsExpandTrigger") -UltiSnips_Manager.forward_trigger = vim.eval("g:UltiSnipsJumpForwardTrigger") -UltiSnips_Manager.backward_trigger = vim.eval("g:UltiSnipsJumpBackwardTrigger") -EOF -else -python << EOF -import vim, os, sys - -new_path = vim.eval('expand(":h")') -sys.path.append(new_path) - -from UltiSnips import UltiSnips_Manager -UltiSnips_Manager.expand_trigger = vim.eval("g:UltiSnipsExpandTrigger") -UltiSnips_Manager.forward_trigger = vim.eval("g:UltiSnipsJumpForwardTrigger") -UltiSnips_Manager.backward_trigger = vim.eval("g:UltiSnipsJumpBackwardTrigger") -EOF -endif +exec g:_uspy "import vim, os, sys" +exec g:_uspy "new_path = vim.eval('expand(\":h\")')" +exec g:_uspy "sys.path.append(new_path)" +exec g:_uspy "from UltiSnips import UltiSnips_Manager" +exec g:_uspy "UltiSnips_Manager.expand_trigger = vim.eval('g:UltiSnipsExpandTrigger')" +exec g:_uspy "UltiSnips_Manager.forward_trigger = vim.eval('g:UltiSnipsJumpForwardTrigger')" +exec g:_uspy "UltiSnips_Manager.backward_trigger = vim.eval('g:UltiSnipsJumpBackwardTrigger')" au CursorMovedI * call UltiSnips_CursorMoved() -au InsertEnter * call UltiSnips_EnteredInsertMode() -au WinLeave * call UltiSnips_LeavingWindow() +au CursorMoved * call UltiSnips_CursorMoved() +au BufLeave * call UltiSnips_LeavingBuffer() call UltiSnips_MapKeys() diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Buffer.py b/vim/bundle/ultisnips/plugin/UltiSnips/Buffer.py deleted file mode 100644 index 7634959..0000000 --- a/vim/bundle/ultisnips/plugin/UltiSnips/Buffer.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -import vim -from UltiSnips.Geometry import Position -from UltiSnips.Compatibility import make_suitable_for_vim, as_unicode - -__all__ = [ "TextBuffer", "VimBuffer" ] - -class Buffer(object): - def _replace(self, start, end, content, first_line, last_line): - text = content[:] - if len(text) == 1: - arr = [ first_line + text[0] + last_line ] - new_end = start + Position(0,len(text[0])) - else: - arr = [ first_line + text[0] ] + \ - text[1:-1] + \ - [ text[-1] + last_line ] - new_end = Position(start.line + len(text)-1, len(text[-1])) - - self[start.line:end.line+1] = arr - - return new_end - -class TextBuffer(Buffer): - def __init__(self, textblock): - # We do not use splitlines() here because it handles cases like 'text\n' - # differently than we want it here - self._lines = [ as_unicode(l) for l in textblock.replace('\r','').split('\n') ] - - def calc_end(self, start): - text = self._lines[:] - if len(text) == 1: - new_end = start + Position(0,len(text[0])) - else: - new_end = Position(start.line + len(text)-1, len(text[-1])) - return new_end - - def replace_text( self, start, end, content ): - first_line = self[start.line][:start.col] - last_line = self[end.line][end.col:] - return self._replace( start, end, content, first_line, last_line) - - def __getitem__(self, a): - return self._lines.__getitem__(a) - def __setitem__(self, a, b): - return self._lines.__setitem__(a,b) - def __repr__(self): - return repr('\n'.join(self._lines)) - def __str__(self): - return '\n'.join(self._lines) - -class VimBuffer(Buffer): - def __init__(self, before, after): - self._bf = before - self._af = after - def __getitem__(self, a): - if isinstance(a, slice): - return [ as_unicode(k) for k in vim.current.buffer[a] ] - return as_unicode(vim.current.buffer[a]) - - def __setitem__(self, a, b): - if isinstance(a,slice): - vim.current.buffer[a.start:a.stop] = make_suitable_for_vim(b) - else: - vim.current.buffer[a] = make_suitable_for_vim(b) - - # Open any folds this might have created - vim.current.window.cursor = a.start + 1, 0 - vim.command("normal zv") - - def __repr__(self): - return "VimBuffer()" - - def replace_lines( self, fline, eline, content ): - start = Position(fline,0 ) - end = Position(eline, 100000) - return self._replace( start, end, content, self._bf, self._af) - - diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Compatibility.py b/vim/bundle/ultisnips/plugin/UltiSnips/Compatibility.py deleted file mode 100644 index eeab008..0000000 --- a/vim/bundle/ultisnips/plugin/UltiSnips/Compatibility.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -""" -This file contains compatibility code to stay compatible with -as many python versions as possible. -""" - -import sys - -import vim - -__all__ = ['as_unicode', 'compatible_exec', 'CheapTotalOrdering', 'vim_cursor', 'set_vim_cursor'] - -if sys.version_info >= (3,0): - from UltiSnips.Compatibility_py3 import * - - def set_vim_cursor(line, col): - """Wrapper around vims access to window.cursor. It can't handle - multibyte chars, we therefore have to compensate""" - - pre_chars = vim.current.buffer[line-1][:col] - nbytes = len(pre_chars.encode("utf-8")) - - vim.current.window.cursor = line, nbytes - - def vim_cursor(): - """Returns the character position (not the byte position) of the - vim cursor""" - - line, nbyte = vim.current.window.cursor - - raw_bytes = vim.current.buffer[line-1].encode("utf-8")[:nbyte] - - col = len(raw_bytes.decode("utf-8")) - return line, col - class CheapTotalOrdering: - """Total ordering only appears in python 2.7. We try to stay compatible with - python 2.5 for now, so we define our own""" - - def __lt__(self, other): - return self.__cmp__(other) < 0 - - def __le__(self, other): - return self.__cmp__(other) <= 0 - - def __gt__(self, other): - return self.__cmp__(other) > 0 - - def __ge__(self, other): - return self.__cmp__(other) >= 0 - - def as_unicode(s): - if isinstance(s, bytes): - return s.decode("utf-8") - return str(s) - - def make_suitable_for_vim(s): - return s -else: - from UltiSnips.Compatibility_py2 import * - - def set_vim_cursor(line, col): - """Wrapper around vims access to window.cursor. It can't handle - multibyte chars, we therefore have to compensate""" - - pre_chars = vim.current.buffer[line-1].decode("utf-8")[:col] - nbytes = len(pre_chars.encode("utf-8")) - - vim.current.window.cursor = line, nbytes - - def vim_cursor(): - """Returns the character position (not the byte position) of the - vim cursor""" - - line, nbyte = vim.current.window.cursor - - raw_bytes = vim.current.buffer[line-1][:nbyte] - - col = len(raw_bytes.decode("utf-8")) - return line, col - - - class CheapTotalOrdering(object): - """Total ordering only appears in python 2.7. We try to stay compatible with - python 2.5 for now, so we define our own""" - - def __lt__(self, other): - return self.__cmp__(other) < 0 - - def __le__(self, other): - return self.__cmp__(other) <= 0 - - def __gt__(self, other): - return self.__cmp__(other) > 0 - - def __ge__(self, other): - return self.__cmp__(other) >= 0 - - def as_unicode(s): - if isinstance(s, str): - return s.decode("utf-8") - return unicode(s) - - def make_suitable_for_vim(s): - if isinstance(s, list): - return [ a.encode("utf-8") for a in s ] - return s.encode("utf-8") - diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Geometry.py b/vim/bundle/ultisnips/plugin/UltiSnips/Geometry.py deleted file mode 100644 index 1e12645..0000000 --- a/vim/bundle/ultisnips/plugin/UltiSnips/Geometry.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -from UltiSnips.Compatibility import CheapTotalOrdering - -__all__ = [ "Position", "Span" ] - -class Position(CheapTotalOrdering): - def __init__(self, line, col): - self.line = line - self.col = col - - def col(): - def fget(self): - return self._col - def fset(self, value): - self._col = value - return locals() - col = property(**col()) - - def line(): - doc = "Zero base line numbers" - def fget(self): - return self._line - def fset(self, value): - self._line = value - return locals() - line = property(**line()) - - def __add__(self,pos): - if not isinstance(pos,Position): - raise TypeError("unsupported operand type(s) for +: " \ - "'Position' and %s" % type(pos)) - - return Position(self.line + pos.line, self.col + pos.col) - - def __sub__(self,pos): - if not isinstance(pos,Position): - raise TypeError("unsupported operand type(s) for +: " \ - "'Position' and %s" % type(pos)) - - return Position(self.line - pos.line, self.col - pos.col) - - def __cmp__(self, other): - s = self._line, self._col - o = other._line, other._col - if s < o: return -1 - if s > o: return 1 - return 0 - - def __repr__(self): - return "(%i,%i)" % (self._line, self._col) - -class Span(object): - def __init__(self, start, end): - self._s = start - self._e = end - - def __contains__(self, pos): - return self._s <= pos < self._e - - def start(): - def fget(self): - return self._s - def fset(self, value): - self._s = value - return locals() - start = property(**start()) - - def end(): - def fget(self): - return self._e - def fset(self, value): - self._e = value - return locals() - end = property(**end()) - - def __repr__(self): - return "(%s -> %s)" % (self._s, self._e) - diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Langmap.py b/vim/bundle/ultisnips/plugin/UltiSnips/Langmap.py deleted file mode 100644 index 84c2bb2..0000000 --- a/vim/bundle/ultisnips/plugin/UltiSnips/Langmap.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -""" -This file contains object to care for the vim langmap option and basically -reverses the mappings. This was the only solution to get UltiSnips to work -nicely with langmap; other stuff I tried was using inoremap movement commands -and caching and restoring the langmap option. - -Note that this will not work if the langmap overwrites a character completely, -for example if 'j' is remapped, but nothing is mapped back to 'j', then moving -one line down is no longer possible and UltiSnips will fail. -""" - -import vim - -from UltiSnips.Compatibility import as_unicode - -class Real_LangMapTranslator(object): - """ - This is the object to deal with langmaps if this option is compiled - into vim. - """ - _maps = {} - - def _create_translation(self, langmap): - from_chars, to_chars = "", "" - for c in langmap.split(','): - if ";" in c: - a,b = c.split(';') - from_chars += a - to_chars += b - else: - from_chars += c[::2] - to_chars += c[1::2] - - self._maps[langmap] = (from_chars, to_chars) - - def translate(self, s): - langmap = as_unicode(vim.eval("&langmap").strip()) - if langmap == "": - return s - - if langmap not in self._maps: - self._create_translation(langmap) - - for f,t in zip(*self._maps[langmap]): - s = s.replace(f,t) - return s - -class Dummy_LangMapTranslator(object): - """ - If vim hasn't got the langmap compiled in, we never have to do anything. - Then this class is used. - """ - translate = lambda self, s: s - -LangMapTranslator = Real_LangMapTranslator -if not int(vim.eval('has("langmap")')): - LangMapTranslator = Dummy_LangMapTranslator - - - diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/TextObjects.py b/vim/bundle/ultisnips/plugin/UltiSnips/TextObjects.py deleted file mode 100644 index 31596a7..0000000 --- a/vim/bundle/ultisnips/plugin/UltiSnips/TextObjects.py +++ /dev/null @@ -1,812 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -import os -import re -import stat -import tempfile -import vim - -from UltiSnips.Buffer import TextBuffer -from UltiSnips.Compatibility import CheapTotalOrdering -from UltiSnips.Compatibility import compatible_exec, as_unicode -from UltiSnips.Geometry import Span, Position -from UltiSnips.Lexer import tokenize, EscapeCharToken, VisualToken, \ - TransformationToken, TabStopToken, MirrorToken, PythonCodeToken, \ - VimLCodeToken, ShellCodeToken -from UltiSnips.Util import IndentUtil - -__all__ = [ "Mirror", "Transformation", "SnippetInstance", "StartMarker" ] - -########################################################################### -# Helper class # -########################################################################### -class _CleverReplace(object): - """ - This class mimics TextMates replace syntax - """ - _DOLLAR = re.compile(r"\$(\d+)", re.DOTALL) - _SIMPLE_CASEFOLDINGS = re.compile(r"\\([ul].)", re.DOTALL) - _LONG_CASEFOLDINGS = re.compile(r"\\([UL].*?)\\E", re.DOTALL) - _CONDITIONAL = re.compile(r"\(\?(\d+):", re.DOTALL) - - _UNESCAPE = re.compile(r'\\[^ntrab]') - _SCHARS_ESCPAE = re.compile(r'\\[ntrab]') - - def __init__(self, s): - self._s = s - - def _scase_folding(self, m): - if m.group(1)[0] == 'u': - return m.group(1)[-1].upper() - else: - return m.group(1)[-1].lower() - def _lcase_folding(self, m): - if m.group(1)[0] == 'U': - return m.group(1)[1:].upper() - else: - return m.group(1)[1:].lower() - - def _replace_conditional(self, match, v): - def _find_closingbrace(v,start_pos): - bracks_open = 1 - for idx, c in enumerate(v[start_pos:]): - if c == '(': - if v[idx+start_pos-1] != '\\': - bracks_open += 1 - elif c == ')': - if v[idx+start_pos-1] != '\\': - bracks_open -= 1 - if not bracks_open: - return start_pos+idx+1 - m = self._CONDITIONAL.search(v) - - def _part_conditional(v): - bracks_open = 0 - args = [] - carg = "" - for idx, c in enumerate(v): - if c == '(': - if v[idx-1] != '\\': - bracks_open += 1 - elif c == ')': - if v[idx-1] != '\\': - bracks_open -= 1 - elif c == ':' and not bracks_open and not v[idx-1] == '\\': - args.append(carg) - carg = "" - continue - carg += c - args.append(carg) - return args - - while m: - start = m.start() - end = _find_closingbrace(v,start+4) - - args = _part_conditional(v[start+4:end-1]) - - rv = "" - if match.group(int(m.group(1))): - rv = self._unescape(self._replace_conditional(match,args[0])) - elif len(args) > 1: - rv = self._unescape(self._replace_conditional(match,args[1])) - - v = v[:start] + rv + v[end:] - - m = self._CONDITIONAL.search(v) - return v - - def _unescape(self, v): - return self._UNESCAPE.subn(lambda m: m.group(0)[-1], v)[0] - def _schar_escape(self, v): - return self._SCHARS_ESCPAE.subn(lambda m: eval(r"'\%s'" % m.group(0)[-1]), v)[0] - - def replace(self, match): - start, end = match.span() - - tv = self._s - - # Replace all $? with capture groups - tv = self._DOLLAR.subn(lambda m: match.group(int(m.group(1))), tv)[0] - - # Replace CaseFoldings - tv = self._SIMPLE_CASEFOLDINGS.subn(self._scase_folding, tv)[0] - tv = self._LONG_CASEFOLDINGS.subn(self._lcase_folding, tv)[0] - tv = self._replace_conditional(match, tv) - - return self._unescape(self._schar_escape(tv)) - -class _TOParser(object): - def __init__(self, parent_to, text, indent): - self._indent = indent - self._parent_to = parent_to - self._text = text - - def parse(self, add_ts_zero = False): - seen_ts = {} - all_tokens = [] - - self._do_parse(all_tokens, seen_ts) - - self._resolve_ambiguity(all_tokens, seen_ts) - self._create_objects_with_links_to_tabs(all_tokens, seen_ts) - - if add_ts_zero and 0 not in seen_ts: - mark = all_tokens[-1][1].end # Last token is always EndOfText - m1 = Position(mark.line, mark.col + 1) - self._parent_to._add_tabstop(TabStop(self._parent_to, 0, mark, m1)) - - ##################### - # Private Functions # - ##################### - def _resolve_ambiguity(self, all_tokens, seen_ts): - for parent, token in all_tokens: - if isinstance(token, MirrorToken): - if token.no not in seen_ts: - ts = TabStop(parent, token) - seen_ts[token.no] = ts - parent._add_tabstop(ts) - else: - Mirror(parent, seen_ts[token.no], token) - - def _create_objects_with_links_to_tabs(self, all_tokens, seen_ts): - for parent, token in all_tokens: - if isinstance(token, TransformationToken): - if token.no not in seen_ts: - raise RuntimeError("Tabstop %i is not known but is used by a Transformation" % token.no) - Transformation(parent, seen_ts[token.no], token) - - def _do_parse(self, all_tokens, seen_ts): - tokens = list(tokenize(self._text, self._indent)) - - for token in tokens: - all_tokens.append((self._parent_to, token)) - - if isinstance(token, TabStopToken): - ts = TabStop(self._parent_to, token) - seen_ts[token.no] = ts - self._parent_to._add_tabstop(ts) - - k = _TOParser(ts, ts.current_text, self._indent) - k._do_parse(all_tokens, seen_ts) - elif isinstance(token, EscapeCharToken): - EscapedChar(self._parent_to, token) - elif isinstance(token, VisualToken): - Visual(self._parent_to, token) - elif isinstance(token, ShellCodeToken): - ShellCode(self._parent_to, token) - elif isinstance(token, PythonCodeToken): - PythonCode(self._parent_to, token) - elif isinstance(token, VimLCodeToken): - VimLCode(self._parent_to, token) - -########################################################################### -# Public classes # -########################################################################### -class TextObject(CheapTotalOrdering): - """ - This base class represents any object in the text - that has a span in any ways - """ - def __init__(self, parent, token, end = None, initial_text = ""): - 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._tabstops = {} - - if parent is not None: - parent._add_child(self) - - self._cts = 0 - - def __cmp__(self, other): - return self._start.__cmp__(other._start) - - ############## - # PROPERTIES # - ############## - def current_text(): - def fget(self): - return as_unicode(self._current_text) - def fset(self, text): - self._current_text = TextBuffer(text) - - # All our childs are set to "" so they - # do no longer disturb anything that mirrors it - for c in self._childs: - c.current_text = "" - self._childs = [] - self._tabstops = {} - return locals() - current_text = property(**current_text()) - - @property - def current_tabstop(self): - if self._cts is None: - return None - return self._tabstops[self._cts] - - def abs_start(self): - if self._parent: - ps = self._parent.abs_start - if self._start.line == 0: - return ps + self._start - else: - return Position(ps.line + self._start.line, self._start.col) - return self._start - abs_start = property(abs_start) - - def abs_end(self): - if self._parent: - ps = self._parent.abs_start - if self._end.line == 0: - return ps + self._end - else: - return Position(ps.line + self._end.line, self._end.col) - - return self._end - abs_end = property(abs_end) - - def span(self): - return Span(self._start, self._end) - span = property(span) - - def start(self): - return self._start - start = property(start) - - def end(self): - return self._end - end = property(end) - - def abs_span(self): - return Span(self.abs_start, self.abs_end) - abs_span = property(abs_span) - - #################### - # Public functions # - #################### - def update(self): - def _update_childs(childs): - for idx,c in childs: - oldend = Position(c.end.line, c.end.col) - - new_end = c.update() - - moved_lines = new_end.line - oldend.line - moved_cols = new_end.col - oldend.col - - self._current_text.replace_text(c.start, oldend, c._current_text) - - self._move_textobjects_behind(c.start, oldend, moved_lines, - moved_cols, idx) - - _update_childs((idx, c) for idx, c in enumerate(self._childs) if isinstance(c, TabStop)) - _update_childs((idx, c) for idx, c in enumerate(self._childs) if not isinstance(c, TabStop)) - - self._do_update() - - new_end = self._current_text.calc_end(self._start) - - self._end = new_end - - return new_end - - def _get_next_tab(self, no): - if not len(self._tabstops.keys()): - return - tno_max = max(self._tabstops.keys()) - - possible_sol = [] - i = no + 1 - while i <= tno_max: - if i in self._tabstops: - possible_sol.append( (i, self._tabstops[i]) ) - break - i += 1 - - c = [ c._get_next_tab(no) for c in self._childs ] - c = filter(lambda i: i, c) - - possible_sol += c - - if not len(possible_sol): - return None - - return min(possible_sol) - - - def _get_prev_tab(self, no): - if not len(self._tabstops.keys()): - return - tno_min = min(self._tabstops.keys()) - - possible_sol = [] - i = no - 1 - while i >= tno_min and i > 0: - if i in self._tabstops: - possible_sol.append( (i, self._tabstops[i]) ) - break - i -= 1 - - c = [ c._get_prev_tab(no) for c in self._childs ] - c = filter(lambda i: i, c) - - possible_sol += c - - if not len(possible_sol): - return None - - return max(possible_sol) - - ############################### - # Private/Protected functions # - ############################### - def _do_update(self): - pass - - def _move_textobjects_behind(self, start, end, lines, cols, obj_idx): - if lines == 0 and cols == 0: - return - - for idx,m in enumerate(self._childs[obj_idx+1:]): - delta_lines = 0 - delta_cols_begin = 0 - delta_cols_end = 0 - - if m.start.line > end.line: - delta_lines = lines - elif m.start.line == end.line: - if m.start.col >= end.col: - if lines: - delta_lines = lines - delta_cols_begin = cols - if m.start.line == m.end.line: - delta_cols_end = cols - m.start.line += delta_lines - m.end.line += delta_lines - m.start.col += delta_cols_begin - m.end.col += delta_cols_end - - def _get_tabstop(self, requester, no): - if no in self._tabstops: - return self._tabstops[no] - for c in self._childs: - if c is requester: - continue - - rv = c._get_tabstop(self, no) - if rv is not None: - return rv - if self._parent and requester is not self._parent: - return self._parent._get_tabstop(self, no) - - def _add_child(self,c): - self._childs.append(c) - self._childs.sort() - - def _add_tabstop(self, ts): - self._tabstops[ts.no] = ts - -class EscapedChar(TextObject): - """ - This class is a escape char like \$. It is handled in a text object - to make sure that remaining children are correctly moved after - replacing the text. - - This is a base class without functionality just to mark it in the code. - """ - pass - -class StartMarker(TextObject): - """ - This class only remembers it's starting position. It is used to - transform relative values into absolute position values in the vim - buffer - """ - def __init__(self, start): - end = Position(start.line, start.col) - TextObject.__init__(self, None, start, end) - - -class Mirror(TextObject): - """ - A Mirror object mirrors a TabStop that is, text is repeated here - """ - def __init__(self, parent, ts, token): - TextObject.__init__(self, parent, token) - - self._ts = ts - - def _do_update(self): - self.current_text = self._ts.current_text - - def __repr__(self): - return "Mirror(%s -> %s)" % (self._start, self._end) - -class Visual(TextObject): - """ - A ${VISUAL} placeholder that will use the text that was last visually - selected and insert it here. If there was no text visually selected, - this will be the empty string - """ - def __init__(self, parent, token): - - # Find our containing snippet for visual_content - snippet = parent - while snippet and not isinstance(snippet, SnippetInstance): - snippet = snippet._parent - - text = "" - for idx, line in enumerate(snippet.visual_content.splitlines(True)): - text += token.leading_whitespace - text += line - - self._text = text - - TextObject.__init__(self, parent, token, initial_text = self._text) - - def _do_update(self): - self.current_text = self._text - - def __repr__(self): - return "Visual(%s -> %s)" % (self._start, self._end) - - -class Transformation(Mirror): - def __init__(self, parent, ts, token): - Mirror.__init__(self, parent, ts, token) - - flags = 0 - self._match_this_many = 1 - if token.options: - if "g" in token.options: - self._match_this_many = 0 - if "i" in token.options: - flags |= re.IGNORECASE - - self._find = re.compile(token.search, flags | re.DOTALL) - self._replace = _CleverReplace(token.replace) - - def _do_update(self): - t = self._ts.current_text - t = self._find.subn(self._replace.replace, t, self._match_this_many)[0] - self.current_text = t - - def __repr__(self): - return "Transformation(%s -> %s)" % (self._start, self._end) - -class ShellCode(TextObject): - def __init__(self, parent, token): - code = token.code.replace("\\`", "`") - - # Write the code to a temporary file - handle, path = tempfile.mkstemp(text=True) - os.write(handle, code.encode("utf-8")) - os.close(handle) - - os.chmod(path, stat.S_IRWXU) - - # Interpolate the shell code. We try to stay as compatible with Python - # 2.3, therefore, we do not use the subprocess module here - output = os.popen(path, "r").read() - if len(output) and output[-1] == '\n': - output = output[:-1] - if len(output) and output[-1] == '\r': - output = output[:-1] - - os.unlink(path) - - token.initial_text = output - TextObject.__init__(self, parent, token) - - def __repr__(self): - return "ShellCode(%s -> %s)" % (self._start, self._end) - -class VimLCode(TextObject): - def __init__(self, parent, token): - self._code = token.code.replace("\\`", "`").strip() - - TextObject.__init__(self, parent, token) - - def _do_update(self): - self.current_text = as_unicode(vim.eval(self._code)) - - def __repr__(self): - return "VimLCode(%s -> %s)" % (self._start, self._end) - -class _Tabs(object): - def __init__(self, to): - self._to = to - - def __getitem__(self, no): - ts = self._to._get_tabstop(self._to, int(no)) - if ts is None: - return "" - return ts.current_text - -class SnippetUtil(object): - """ Provides easy access to indentation, etc. - """ - - def __init__(self, initial_indent, cur=""): - self._ind = IndentUtil() - - self._initial_indent = self._ind.indent_to_spaces(initial_indent) - - self._reset(cur) - - def _reset(self, cur): - """ Gets the snippet ready for another update. - - :cur: the new value for c. - """ - self._ind.reset() - self._c = cur - self._rv = "" - self._changed = False - self.reset_indent() - - def shift(self, amount=1): - """ Shifts the indentation level. - Note that this uses the shiftwidth because thats what code - formatters use. - - :amount: the amount by which to shift. - """ - self.indent += " " * self._ind.sw * amount - - def unshift(self, amount=1): - """ Unshift the indentation level. - Note that this uses the shiftwidth because thats what code - formatters use. - - :amount: the amount by which to unshift. - """ - by = -self._ind.sw * amount - try: - self.indent = self.indent[:by] - except IndexError: - indent = "" - - def mkline(self, line="", indent=None): - """ Creates 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 - # this deals with the fact that the first line is - # already properly indented - if '\n' not in self._rv: - try: - indent = indent[len(self._initial_indent):] - except IndexError: - indent = "" - indent = self._ind.spaces_to_indent(indent) - - return indent + line - - def reset_indent(self): - """ Clears the indentation. """ - self.indent = self._initial_indent - - # Utility methods - @property - def fn(self): - """ The filename. """ - return vim.eval('expand("%:t")') or "" - - @property - def basename(self): - """ The filename without extension. """ - return vim.eval('expand("%:t:r")') or "" - - @property - def ft(self): - """ The filetype. """ - return self.opt("&filetype", "") - - # Necessary stuff - def rv(): - """ The return value. - This is a list of lines to insert at the - location of the placeholder. - - Deprecates res. - """ - def fget(self): - return self._rv - def fset(self, value): - self._changed = True - self._rv = value - return locals() - rv = property(**rv()) - - @property - def _rv_changed(self): - """ True if rv has changed. """ - return self._changed - - @property - def c(self): - """ The current text of the placeholder. - - Deprecates cur. - """ - return self._c - - def opt(self, option, default=None): - """ Gets a vim variable. """ - if vim.eval("exists('%s')" % option) == "1": - try: - return vim.eval(option) - except vim.error: - pass - return default - - # Syntatic sugar - def __add__(self, value): - """ Appends the given line to rv using mkline. """ - self.rv += '\n' # handles the first line properly - self.rv += self.mkline(value) - return self - - def __lshift__(self, other): - """ Same as unshift. """ - self.unshift(other) - - def __rshift__(self, other): - """ Same as shift. """ - self.shift(other) - - -class PythonCode(TextObject): - def __init__(self, parent, token): - - code = token.code.replace("\\`", "`") - - # Find our containing snippet for snippet local data - snippet = parent - while snippet and not isinstance(snippet, SnippetInstance): - try: - snippet = snippet._parent - except AttributeError: - snippet = None - self._snip = SnippetUtil(token.indent) - self._locals = snippet.locals - - self._globals = {} - globals = snippet.globals.get("!p", []) - compatible_exec("\n".join(globals).replace("\r\n", "\n"), self._globals) - - # Add Some convenience to the code - self._code = "import re, os, vim, string, random\n" + code - - TextObject.__init__(self, parent, token) - - - def _do_update(self): - path = vim.eval('expand("%")') - if path is None: - path = "" - fn = os.path.basename(path) - - ct = self.current_text - self._snip._reset(ct) - local_d = self._locals - - local_d.update({ - 't': _Tabs(self), - 'fn': fn, - 'path': path, - 'cur': ct, - 'res': ct, - 'snip' : self._snip, - }) - - self._code = self._code.replace("\r\n", "\n") - compatible_exec(self._code, self._globals, local_d) - - if self._snip._rv_changed: - self.current_text = self._snip.rv - else: - self.current_text = as_unicode(local_d["res"]) - - def __repr__(self): - return "PythonCode(%s -> %s)" % (self._start, self._end) - -class TabStop(TextObject): - """ - This is the most important TextObject. A TabStop is were the cursor - comes to rest when the user taps through the Snippet. - """ - def __init__(self, parent, token, start = None, end = None): - if start is not None: - self._no = token - TextObject.__init__(self, parent, start, end) - else: - TextObject.__init__(self, parent, token) - self._no = token.no - - def no(self): - return self._no - no = property(no) - - def __repr__(self): - return "TabStop(%s -> %s, %s)" % (self._start, self._end, - repr(self._current_text)) - -class SnippetInstance(TextObject): - """ - A Snippet instance is an instance of a Snippet Definition. That is, - when the user expands a snippet, a SnippetInstance is created to - keep track of the corresponding TextObjects. The Snippet itself is - also a TextObject because it has a start an end - """ - - def __init__(self, parent, indent, initial_text, start, end, visual_content, last_re, globals): - if start is None: - start = Position(0,0) - if end is None: - end = Position(0,0) - - self.locals = {"match" : last_re} - self.globals = globals - self.visual_content = visual_content - - TextObject.__init__(self, parent, start, end, initial_text) - - _TOParser(self, initial_text, indent).parse(True) - - if not isinstance(parent, TabStop): - self.update() - - def __repr__(self): - return "SnippetInstance(%s -> %s)" % (self._start, self._end) - - def _get_tabstop(self, requester, no): - # SnippetInstances are completely self contained, therefore, we do not - # need to ask our parent for Tabstops - p = self._parent - self._parent = None - rv = TextObject._get_tabstop(self, requester, no) - self._parent = p - - return rv - - def select_next_tab(self, backwards = False): - if self._cts is None: - return - - if backwards: - cts_bf = self._cts - - res = self._get_prev_tab(self._cts) - if res is None: - self._cts = cts_bf - return self._tabstops[self._cts] - self._cts, ts = res - return ts - else: - res = self._get_next_tab(self._cts) - if res is None: - self._cts = None - return self._tabstops[0] - else: - self._cts, ts = res - return ts - - return self._tabstops[self._cts] diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Util.py b/vim/bundle/ultisnips/plugin/UltiSnips/Util.py deleted file mode 100644 index 7beeb6c..0000000 --- a/vim/bundle/ultisnips/plugin/UltiSnips/Util.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -import os -import types -import vim - -from UltiSnips.Compatibility import as_unicode - -def vim_string(inp): - """ Creates a vim-friendly string from a group of - dicts, lists and strings. - """ - def conv(obj): - if isinstance(obj, list): - rv = as_unicode('[' + ','.join(conv(o) for o in obj) + ']') - elif isinstance(obj, dict): - rv = as_unicode('{' + ','.join([ - "%s:%s" % (conv(key), conv(value)) - for key, value in obj.iteritems()]) + '}') - else: - rv = as_unicode('"%s"') % as_unicode(obj).replace('"', '\\"') - return rv - return conv(inp) - -class IndentUtil(object): - """ Utility class for dealing properly with indentation. """ - - def __init__(self): - self.reset() - - def reset(self): - """ Gets the spacing properties from vim. """ - self.sw = int(vim.eval("&sw")) - self.sts = int(vim.eval("&sts")) - self.et = (vim.eval("&expandtab") == "1") - self.ts = int(vim.eval("&ts")) - - # The amount added when pressing tab in insert mode - self.ind_len = self.sts or self.ts - - def _strip_tabs(self, indent, ts): - new_ind = [] - for ch in indent: - if ch == '\t': - new_ind.append(" " * (ts - (len(new_ind) % ts))) - else: - new_ind.append(ch) - return "".join(new_ind) - - def ntabs_to_proper_indent(self, ntabs): - line_ind = ntabs * self.sw * " " - line_ind = self.indent_to_spaces(line_ind) - line_ind = self.spaces_to_indent(line_ind) - return line_ind - - def indent_to_spaces(self, indent): - """ Converts indentation to spaces respecting vim settings. """ - indent = self._strip_tabs(indent, self.ts) - right = (len(indent) - len(indent.rstrip(" "))) * " " - indent = indent.replace(" ", "") - indent = indent.replace('\t', " " * self.ts) - return indent + right - - def spaces_to_indent(self, indent): - """ Converts spaces to proper indentation respecting vim settings """ - if not self.et: - indent = indent.replace(" " * self.ts, '\t') - return indent diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/__init__.py b/vim/bundle/ultisnips/plugin/UltiSnips/__init__.py index ce7154e..34f6b9a 100644 --- a/vim/bundle/ultisnips/plugin/UltiSnips/__init__.py +++ b/vim/bundle/ultisnips/plugin/UltiSnips/__init__.py @@ -2,50 +2,25 @@ # encoding: utf-8 from functools import wraps +from collections import deque, defaultdict import glob import hashlib import os -import platform import re import traceback -import vim - -from UltiSnips.Geometry import Position -from UltiSnips.Compatibility import make_suitable_for_vim, set_vim_cursor, vim_cursor -from UltiSnips.TextObjects import * -from UltiSnips.Buffer import VimBuffer -from UltiSnips.Util import IndentUtil, vim_string, as_unicode -from UltiSnips.Langmap import LangMapTranslator - -# The following lines silence DeprecationWarnings. They are raised -# by python2.6 for vim.error (which is a string that is used as an exception, -# which is deprecated since 2.5 and will no longer work in 2.7. Let's hope -# vim gets this fixed before) -import sys -if (2,6) <= sys.version_info[:2] < (3,0): - import warnings - warnings.filterwarnings("ignore", category=DeprecationWarning) - -def _to_scratch_buffer(text): - """Create a new scratch buffer with the text given""" - vim.command("botright new") - vim.command("set ft=text") - vim.command("set buftype=nofile") - - vim.buffers[-1][:] = text.splitlines() - -def _dot_vim(): - """Under windows .vim is _vim""" - if platform.system() == "Windows": - return "_vim" - return ".vim" +from UltiSnips.compatibility import as_unicode, byte2col +from UltiSnips._diff import diff, guess_edit +from UltiSnips.geometry import Position +from UltiSnips.text_objects import SnippetInstance +from UltiSnips.util import IndentUtil +import UltiSnips._vim as _vim def err_to_scratch_buffer(f): @wraps(f) - def wrapper(*args, **kwds): + def wrapper(self, *args, **kwds): try: - return f(*args, **kwds) + return f(self, *args, **kwds) except: s = \ """An error occured. This is either a bug in UltiSnips or a bug in a @@ -55,17 +30,10 @@ def wrapper(*args, **kwds): Following is the full stack trace: """ s += traceback.format_exc() - _to_scratch_buffer(s) + self.leaving_buffer() # Vim sends no WinLeave msg here. + _vim.new_scratch_buffer(s) return wrapper -def feedkeys(s, mode='n'): - """Wrapper around vim's feedkeys function. Mainly for convenience.""" - vim.command(r'call feedkeys("%s", "%s")' % (s, mode)) - -def echom(mes, *args): - mes = mes % args - vim.command('echom %s' % vim_string(mes)) - class _SnippetDictionary(object): def __init__(self, *args, **kwargs): self._added = [] @@ -87,9 +55,9 @@ def get_matching_snippets(self, trigger, potentially): else: return [ s for s in self.snippets if s.could_match(trigger) ] + @property def snippets(self): return self._added + self._snippets - snippets = property(snippets) def clear_snippets(self, triggers=[]): """Remove all snippets that match each trigger in triggers. @@ -106,9 +74,9 @@ def clear_snippets(self, triggers=[]): self._snippets = [] self._added = [] + @property def files(self): return self._files - files = property(files) def reset(self): self._snippets = [] @@ -154,7 +122,7 @@ def __init__(self, ft, fn, snip_manager, file_data=None): self._idx = 0 def _error(self, msg): - fn = vim.eval("""fnamemodify(%s, ":~:.")""" % vim_string(self._fn)) + fn = _vim.eval("""fnamemodify(%s, ":~:.")""" % _vim.escape(self._fn)) self._sm._error("%s in %s(%d)" % (msg, fn, self._idx + 1)) def _line(self): @@ -328,7 +296,7 @@ def matches(self, trigger): self._matched = "" # Don't expand on whitespace - if trigger and trigger.rstrip() is not trigger: + if trigger and trigger.rstrip() != trigger: return False words = self._words_for_line(trigger) @@ -365,7 +333,9 @@ def matches(self, trigger): def could_match(self, trigger): self._matched = "" - # Don't expand on whitespace + # List all on whitespace. + if trigger and trigger[-1] in (" ", "\t"): + trigger = "" if trigger and trigger.rstrip() is not trigger: return False @@ -404,28 +374,24 @@ def could_match(self, trigger): return match - def keep_formatoptions_unchanged(self): - return "f" in self._opts - keep_formatoptions_unchanged = property(keep_formatoptions_unchanged) - + @property def overwrites_previous(self): return "!" in self._opts - overwrites_previous = property(overwrites_previous) + @property def description(self): return ("(%s) %s" % (self._t, self._d)).strip() - description = property(description) + @property def trigger(self): return self._t - trigger = property(trigger) + @property def matched(self): """ The last text that was matched. """ return self._matched - matched = property(matched) - def launch(self, text_before, visual_content, parent, start, end = None): + def launch(self, text_before, visual_content, parent, start, end): indent = self._INDENT.match(text_before).group(0) lines = (self._v + "\n").splitlines() ind_util = IndentUtil() @@ -444,222 +410,114 @@ def launch(self, text_before, visual_content, parent, start, end = None): line_ind = indent + line_ind v.append(line_ind + line[tabs:]) - v = os.linesep.join(v) + v = '\n'.join(v) if parent is None: - return SnippetInstance(StartMarker(start), indent, v, None, None, visual_content = visual_content, + si = SnippetInstance(None, indent, v, start, end, visual_content = visual_content, last_re = self._last_re, globals = self._globals) else: - return SnippetInstance(parent, indent, v, start, end, visual_content, + si = SnippetInstance(parent, indent, v, start, end, visual_content, last_re = self._last_re, globals = self._globals) -class VimState(object): + return si + +class VisualContentPreserver(object): def __init__(self): - self._abs_pos = None - self._moved = Position(0,0) - - self._lines = None - self._dlines = None - self._cols = None - self._dcols = None - self._cline = None - self._lline = None - self._text_changed = None - - def update(self): - line, col = vim_cursor() - line -= 1 - abs_pos = Position(line,col) - if self._abs_pos: - self._moved = abs_pos - self._abs_pos - self._abs_pos = abs_pos - - # Update buffer infos - cols = len(as_unicode(vim.current.buffer[line])) - if self._cols: - self._dcols = cols - self._cols - self._cols = cols - - lines = len(vim.current.buffer) - if self._lines: - self._dlines = lines - self._lines - self._lines = lines - - # Check if the buffer has changed in any ways - self._text_changed = False - # does it have more lines? - if self._dlines: - self._text_changed = True - # did we stay in the same line and it has more columns now? - elif not self.moved.line and self._dcols: - self._text_changed = True - # If the length didn't change but we moved a column, check if - # the char under the cursor has changed (might be one char tab). - elif self.moved.col == 1: - self._text_changed = self._cline != as_unicode(vim.current.buffer[line]) - self._lline = self._cline - self._cline = as_unicode(vim.current.buffer[line]) - - def select_span(self, r): - self._unmap_select_mode_mapping() - - delta = r.end - r.start - lineno, col = r.start.line, r.start.col - - set_vim_cursor(lineno + 1, col) - - if delta.line == delta.col == 0: - if col == 0 or vim.eval("mode()") != 'i' and \ - col < len(as_unicode(vim.current.buffer[lineno])): - feedkeys(r"\i") - else: - feedkeys(r"\a") + self.reset() + + def reset(self): + self._mode = "" + self._text = as_unicode("") + + def conserve(self): + sl, sbyte = map(int, (_vim.eval("""line("'<")"""), _vim.eval("""col("'<")"""))) + el, ebyte = map(int, (_vim.eval("""line("'>")"""), _vim.eval("""col("'>")"""))) + sc = byte2col(sl, sbyte - 1) + ec = byte2col(el, ebyte - 1) + self._mode = _vim.eval("visualmode()") + + def _vim_line_with_eol(ln): + return _vim.buf[ln] + '\n' + + if sl == el: + text = _vim_line_with_eol(sl-1)[sc:ec+1] else: - # If a tabstop immediately starts with a newline, the selection - # must start after the last character in the current line. But if - # we are in insert mode and out of it, we cannot go past the - # last character with move_one_right and therefore cannot - # visual-select this newline. We have to hack around this by adding - # an extra space which we can select. Note that this problem could - # be circumvent by selecting the tab backwards (that is starting - # at the end); one would not need to modify the line for this. - if col >= len(as_unicode(vim.current.buffer[lineno])): - vim.current.buffer[lineno] += " " - - if delta.line: - move_lines = "%ij" % delta.line - else: - move_lines = "" - # Depending on the current mode and position, we - # might need to move escape out of the mode and this - # will move our cursor one left - if col != 0 and vim.eval("mode()") == 'i': - move_one_right = "l" - else: - move_one_right = "" - - # After moving to the correct line, we go back to column 0 - # and select right from there. Note that the we have to select - # one column less since vim's visual selection is including the - # ending while Python slicing is excluding the ending. - if r.end.col == 0 and not len(as_unicode(vim.current.buffer[r.end.line])): - # Selecting should end on an empty line -> Select the previous - # line till its end - do_select = "k$" - elif r.end.col > 1: - do_select = "0%il" % (r.end.col-1) - else: - do_select = "0" + text = _vim_line_with_eol(sl-1)[sc:] + for cl in range(sl,el-1): + text += _vim_line_with_eol(cl) + text += _vim_line_with_eol(el-1)[:ec+1] - move_cmd = LangMapTranslator().translate( - r"\%sv%s%s\" % (move_one_right, move_lines, do_select) - ) + self._text = text - feedkeys(move_cmd) + @property + def text(self): + return self._text + @property + def mode(self): + return self._mode - def buf_changed(self): - return self._text_changed - buf_changed = property(buf_changed) +class _VimPosition(Position): + def __init__(self): + pos = _vim.buf.cursor + self._mode = _vim.eval("mode()") + self._visualmode = _vim.eval("visualmode()") + Position.__init__(self, pos.line, pos.col) - def pos(self): - return self._abs_pos - pos = property(pos) + @property + def mode(self): + return self._mode + @property + def visualmode(self): + return self._visualmode - def ppos(self): - if not self.has_moved: - return self.pos - return self.pos - self.moved - ppos = property(ppos) - - def moved(self): - return self._moved - moved = property(moved) - - def has_moved(self): - return bool(self._moved.line or self._moved.col) - has_moved = property(has_moved) - - def last_line(self): - return self._lline - last_line = property(last_line) - - ########################### - # Private functions below # - ########################### - def _unmap_select_mode_mapping(self): - """This function unmaps select mode mappings if so wished by the user. - Removes select mode mappings that can actually be typed by the user - (ie, ignores things like ). + +class VimState(object): + def __init__(self): """ - if int(vim.eval("g:UltiSnipsRemoveSelectModeMappings")): - ignores = vim.eval("g:UltiSnipsMappingsToIgnore") + ['UltiSnips'] - - for option in ("", ""): - # Put all smaps into a var, and then read the var - vim.command(r"redir => _tmp_smaps | silent smap %s " % option + - "| redir END") - - # Check if any mappings where found - all_maps = list(filter(len, vim.eval(r"_tmp_smaps").splitlines())) - if (len(all_maps) == 1 and all_maps[0][0] not in " sv"): - # "No maps found". String could be localized. Hopefully - # it doesn't start with any of these letters in any - # language - continue - - # Only keep mappings that should not be ignored - maps = [m for m in all_maps if - not any(i in m for i in ignores) and len(m.strip())] - - for m in maps: - # The first three chars are the modes, that might be listed. - # We are not interested in them here. - trig = m[3:].split()[0] - - # The bar separates commands - if trig[-1] == "|": - trig = trig[:-1] + "" - - # Special ones - if trig[0] == "<": - add = False - # Only allow these - for valid in ["Tab", "NL", "CR", "C-Tab", "BS"]: - if trig == "<%s>" % valid: - add = True - if not add: - continue - - # Actually unmap it - try: - cmd = ("silent! sunmap %s %s") % (option, trig) - vim.command(cmd) - except: - # Bug 908139: ignore unmaps that fail because of - # unprintable characters. This is not ideal because we - # will not be able to unmap lhs with any unprintable - # character. If the lhs stats with a printable - # character this will leak to the user when he tries to - # type this character as a first in a selected tabstop. - # This case should be rare enough to not bother us - # though. - pass + This class caches some state information from Vim to better + guess what editing tasks the user might have done in the last step + """ + self._poss = deque(maxlen=5) + self._lvb = None + + def remember_position(self): + self._poss.append(_VimPosition()) + + def remember_buffer(self, to): + self._lvb = _vim.buf[to.start.line:to.end.line+1] + self._lvb_len = len(_vim.buf) + self.remember_position() + + @property + def diff_in_buffer_length(self): + return len(_vim.buf) - self._lvb_len + + @property + def pos(self): + return self._poss[-1] + @property + def ppos(self): + return self._poss[-2] + @property + def remembered_buffer(self): + return self._lvb[:] + class SnippetManager(object): def __init__(self): - self._vstate = VimState() self._supertab_keys = None self._csnippets = [] - self._cached_offending_vim_options = {} self.reset() @err_to_scratch_buffer def reset(self, test_error=False): + self._vstate = VimState() self._test_error = test_error self._snippets = {} - self._visual_content = as_unicode("") + self._filetypes = defaultdict(lambda: ['all']) + self._visual_content = VisualContentPreserver() while len(self._csnippets): self._current_snippet_is_done() @@ -683,7 +541,7 @@ def expand(self): @err_to_scratch_buffer def list_snippets(self): - before, after = self._get_before_after() + before, after = _vim.buf.current_line_splitted snippets = self._snips(before, True) # Sort snippets alphabetically @@ -721,21 +579,7 @@ def save_last_visual_selection(self): Our job is to remember everything between '< and '> and pass it on to ${VISUAL} in case it will be needed. """ - sl, sc = map(int, (vim.eval("""line("'<")"""), vim.eval("""virtcol("'<")"""))) - el, ec = map(int, (vim.eval("""line("'>")"""), vim.eval("""virtcol("'>")"""))) - - def _vim_line_with_eol(ln): - return as_unicode(vim.current.buffer[ln] + '\n') - - if sl == el: - text = _vim_line_with_eol(sl-1)[sc-1:ec] - else: - text = _vim_line_with_eol(sl-1)[sc-1:] - for cl in range(sl,el-1): - text += _vim_line_with_eol(cl) - text += _vim_line_with_eol(el-1)[:ec] - - self._visual_content = text + self._visual_content.conserve() def snippet_dict(self, ft): if ft not in self._snippets: @@ -758,7 +602,7 @@ def expand_anon(self, value, trigger="", descr="", options="", globals=None): if globals is None: globals = {} - before, after = self._get_before_after() + before, after = _vim.buf.current_line_splitted snip = Snippet(trigger, value, descr, options, globals) if not trigger or snip.matches(before): @@ -781,102 +625,71 @@ def add_extending_info(self, ft, parents): sd.extends.append(p) - - @err_to_scratch_buffer - def backspace_while_selected(self): - """ - This is called when backspace was pressed while vim was in select - mode. For us this might mean that a TabStop was selected and it's - content should be deleted. - """ - if self._cs and (self._span_selected is not None): - # This only happens when a default value is delted using backspace. - # This does not change the buffer at all, only moves the cursor. - self._vstate.update() - feedkeys(r"i") - self._chars_entered('') - else: - # We can't just pass through, because we took vim - # out of SELECT mode, so instead we reselect and replace - feedkeys(r"gvc") - @err_to_scratch_buffer def cursor_moved(self): - self._vstate.update() - - if not self._vstate.buf_changed and not self._expect_move_wo_change: - self._check_if_still_inside_snippet() - - if not self._ctab: + self._vstate.remember_position() + if _vim.eval("mode()") not in 'in': return - if self._vstate.buf_changed and self._ctab: - # Detect a carriage return - if self._vstate.moved.col <= 0 and self._vstate.moved.line == 1: - # Multiple things might have happened: either the user entered - # a newline character or pasted some text which means we have - # to copy everything he entered on the last line and keep the - # indent vim chose for this line. - lline = as_unicode(vim.current.buffer[self._vstate.ppos.line]) - - # Another thing that might have happened is that a word - # wrapped, in this case the last line is shortened and we must - # delete what Vim deleted there - line_was_shortened = len(self._vstate.last_line) > len(lline) - - # Another thing that might have happened is that vim has - # adjusted the indent of the last line and therefore the line - # effectively got longer. This means a newline was entered and - # we quite definitively do not want the indent that vim added - line_was_lengthened = len(lline) > len(self._vstate.last_line) - - user_didnt_enter_newline = len(lline) != self._vstate.ppos.col - cline = as_unicode(vim.current.buffer[self._vstate.pos.line]) - if line_was_lengthened: - this_entered = vim.current.line[:self._vstate.pos.col] - self._chars_entered('\n' + cline + this_entered, 1) - if line_was_shortened and user_didnt_enter_newline: - nchars_deleted_in_lline = self._vstate.ppos.col - len(lline) - self._backspace(nchars_deleted_in_lline) - nchars_wrapped_from_lline_after_cursor = \ - len(self._vstate.last_line) - self._vstate.ppos.col - self._chars_entered('\n' + cline - [:len(cline)-nchars_wrapped_from_lline_after_cursor], 1) - else: - pentered = lline[self._vstate.ppos.col:] - this_entered = vim.current.line[:self._vstate.pos.col] - - self._chars_entered(pentered + '\n' + this_entered) - elif self._vstate.moved.line == 0 and self._vstate.moved.col<0: - # Some deleting was going on - self._backspace(-self._vstate.moved.col) - elif self._vstate.moved.line < 0: - # Backspace over line end - self._backspace(1) - else: - line = as_unicode(vim.current.line) - - chars = line[self._vstate.pos.col - self._vstate.moved.col: - self._vstate.pos.col] - self._chars_entered(chars) - - self._expect_move_wo_change = False - - @err_to_scratch_buffer - def entered_insert_mode(self): - self._vstate.update() - if self._cs and self._vstate.has_moved: - while len(self._csnippets): - self._current_snippet_is_done() - self._reinit() + if self._ignore_movements: + self._ignore_movements = False + return - @err_to_scratch_buffer - def leaving_window(self): + if self._csnippets: + cstart = self._csnippets[0].start.line + cend = self._csnippets[0].end.line + self._vstate.diff_in_buffer_length + ct = _vim.buf[cstart:cend + 1] + lt = self._vstate.remembered_buffer + pos = _vim.buf.cursor + + lt_span = [0, len(lt)] + ct_span = [0, len(ct)] + initial_line = cstart + + # Cut down on lines searched for changes. Start from behind and + # remove all equal lines. Then do the same from the front. + if lt and ct: + while (lt[lt_span[1]-1] == ct[ct_span[1]-1] and + self._vstate.ppos.line < initial_line + lt_span[1]-1 and pos.line < initial_line + ct_span[1]-1 and + (lt_span[0] < lt_span[1]) and + (ct_span[0] < ct_span[1])): + ct_span[1] -= 1 + lt_span[1] -= 1 + while (lt_span[0] < lt_span[1] and + ct_span[0] < ct_span[1] and + lt[lt_span[0]] == ct[ct_span[0]] and + self._vstate.ppos.line >= initial_line and pos.line >= initial_line): + ct_span[0] += 1 + lt_span[0] += 1 + initial_line += 1 + ct_span[0] = max(0, ct_span[0] - 1) + lt_span[0] = max(0, lt_span[0] - 1) + initial_line = max(cstart, initial_line - 1) + + lt = lt[lt_span[0]:lt_span[1]] + ct = ct[ct_span[0]:ct_span[1]] + + try: + rv, es = guess_edit(initial_line, lt, ct, self._vstate) + if not rv: + lt = '\n'.join(lt) + ct = '\n'.join(ct) + es = diff(lt, ct, initial_line) + self._csnippets[0].replay_user_edits(es) + except IndexError: + pass # Rather do nothing than throwing an error. It will be correct most of the time + + self._check_if_still_inside_snippet() + if self._csnippets: + self._csnippets[0].update_textobjects() + self._vstate.remember_buffer(self._csnippets[0]) + + + def leaving_buffer(self): """ - Called when the user switches tabs. It basically means that all - snippets must be properly terminated + Called when the user switches tabs/windows/buffers. It basically means + that all snippets must be properly terminated """ - self._vstate.update() while len(self._csnippets): self._current_snippet_is_done() self._reinit() @@ -886,61 +699,53 @@ def leaving_window(self): # Private/Protect Functions Below # ################################### def _error(self, msg): - msg = vim_string("UltiSnips: " + msg) + msg = _vim.escape("UltiSnips: " + msg) if self._test_error: msg = msg.replace('"', r'\"') msg = msg.replace('|', r'\|') - vim.command("let saved_pos=getpos('.')") - vim.command("$:put =%s" % msg) - vim.command("call setpos('.', saved_pos)") + _vim.command("let saved_pos=getpos('.')") + _vim.command("$:put =%s" % msg) + _vim.command("call setpos('.', saved_pos)") elif False: - vim.command("echohl WarningMsg") - vim.command("echomsg %s" % msg) - vim.command("echohl None") + _vim.command("echohl WarningMsg") + _vim.command("echomsg %s" % msg) + _vim.command("echohl None") else: - vim.command("echoerr %s" % msg) + _vim.command("echoerr %s" % msg) def _reinit(self): self._ctab = None - self._span_selected = None - self._expect_move_wo_change = False + self._ignore_movements = False def _check_if_still_inside_snippet(self): - # Cursor moved without input. - self._ctab = None - # Did we leave the snippet with this movement? - if self._cs and not (self._vstate.pos in self._cs.abs_span): + if self._cs and ( + not self._cs.start <= _vim.buf.cursor <= self._cs.end + ): self._current_snippet_is_done() - self._reinit() - self._check_if_still_inside_snippet() def _current_snippet_is_done(self): self._csnippets.pop() - if not len(self._csnippets): - self._reset_offending_vim_options() - def _jump(self, backwards = False): jumped = False if self._cs: - self._expect_move_wo_change = True self._ctab = self._cs.select_next_tab(backwards) if self._ctab: - self._vstate.select_span(self._ctab.abs_span) - self._span_selected = self._ctab.abs_span + _vim.select(self._ctab.start, self._ctab.end) jumped = True if self._ctab.no == 0: self._current_snippet_is_done() - self._vstate.update() else: # This really shouldn't happen, because a snippet should # have been popped when its final tabstop was used. # Cleanup by removing current snippet and recursing. self._current_snippet_is_done() jumped = self._jump(backwards) + if jumped: + self._vstate.remember_position() return jumped def _handle_failure(self, trigger): @@ -953,10 +758,10 @@ def _handle_failure(self, trigger): feedkey = None mode = "n" if not self._supertab_keys: - if vim.eval("exists('g:SuperTabMappingForward')") != "0": + if _vim.eval("exists('g:SuperTabMappingForward')") != "0": self._supertab_keys = ( - vim.eval("g:SuperTabMappingForward"), - vim.eval("g:SuperTabMappingBackward"), + _vim.eval("g:SuperTabMappingForward"), + _vim.eval("g:SuperTabMappingBackward"), ) else: self._supertab_keys = [ '', '' ] @@ -972,27 +777,15 @@ def _handle_failure(self, trigger): break if feedkey: - feedkeys(feedkey, mode) - - def _get_before_after(self): - """ Returns the text before and after the cursor as a - tuple. - """ - lineno, col = vim.current.window.cursor # Note: we want byte position here - - line = vim.current.line - - # Get the word to the left of the current edit position - before, after = as_unicode(line[:col]), as_unicode(line[col:]) - - return before, after + _vim.feedkeys(feedkey, mode) def _snips(self, before, possible): """ Returns all the snippets for the given text before the cursor. If possible is True, then get all possible matches. """ - filetypes = self._ensure_snippets_loaded() + self._ensure_all_loaded() + filetypes = self._filetypes[_vim.buf.nr][::-1] found_snippets = [] for ft in filetypes: @@ -1018,71 +811,51 @@ def _ask_snippets(self, snippets): want to use, and return it. """ # make a python list - display = [ "%i: %s" % (i+1,s.description) for i,s in enumerate(snippets)] + display = [ as_unicode("%i: %s") % (i+1,s.description) for i,s in enumerate(snippets)] try: - # let vim_string format it as a vim list - rv = vim.eval(make_suitable_for_vim(as_unicode("inputlist(%s)") % vim_string(display))) + rv = _vim.eval("inputlist(%s)" % _vim.escape(display)) if rv is None or rv == '0': return None rv = int(rv) if rv > len(snippets): rv = len(snippets) return snippets[rv-1] - except vim.error as e: - if str(e) == 'invalid expression': - return None - raise + except _vim.error as e: + # Likely "invalid expression", but might be translated. We have no way + # of knowing the exact error, therefore, we ignore all errors silently. + return None def _do_snippet(self, snippet, before, after): """ Expands the given snippet, and handles everything - that needs to be done with it. 'before' and 'after' should - come from _get_before_after. + that needs to be done with it. """ - lineno, col = vim_cursor() # Adjust before, maybe the trigger is not the complete word - text_before = before if snippet.matched: text_before = before[:-len(snippet.matched)] - self._unset_offending_vim_options(snippet) - - self._expect_move_wo_change = True if self._cs: - # Determine position - pos = self._vstate.pos - p_start = self._ctab.abs_start - - if pos.line == p_start.line: - end = Position(0, pos.col - p_start.col) - else: - end = Position(pos.line - p_start.line, pos.col) - start = Position(end.line, end.col - len(snippet.matched)) - - si = snippet.launch(text_before, self._visual_content, self._ctab, start, end) - self._visual_content = "" - - self._update_vim_buffer() + start = Position(_vim.buf.cursor.line, len(text_before)) + end = Position(_vim.buf.cursor.line, len(before)) - self._csnippets.append(si) - self._jump() + si = snippet.launch(text_before, self._visual_content, + self._cs.find_parent_for_new_to(start), start, end) else: - self._vb = VimBuffer(text_before, after) + start = Position(_vim.buf.cursor.line, len(text_before)) + end = Position(_vim.buf.cursor.line, len(before)) + si = snippet.launch(text_before, self._visual_content, None, start, end) - start = Position(lineno-1, len(text_before)) - self._csnippets.append(snippet.launch(text_before, self._visual_content, None, start)) - self._visual_content = "" + self._visual_content.reset() + self._csnippets.append(si) - self._vb.replace_lines(lineno-1, lineno-1, - self._cs._current_text) + self._ignore_movements = True + self._vstate.remember_buffer(self._csnippets[0]) - self._jump() + self._jump() def _try_expand(self): - self._expect_move_wo_change = False - - before, after = self._get_before_after() + before, after = _vim.buf.current_line_splitted if not before: return False snippets = self._snips(before, False) @@ -1101,77 +874,11 @@ def _try_expand(self): return True - # Handling of offending vim options - def _unset_offending_vim_options(self, snippet): - # Care for textwrapping - if not snippet.keep_formatoptions_unchanged: - self._cached_offending_vim_options["fo"] = ''.join( - c for c in vim.eval("&fo") if c in "cta" - ) - for c in "cta": vim.command("set fo-=%s" % c) - - def _reset_offending_vim_options(self): - # Textwrapping - for c in self._cached_offending_vim_options.pop("fo", []): - vim.command("set fo+=%s" % c) - - # Input Handling - def _chars_entered(self, chars, del_more_lines = 0): - if (self._span_selected is not None): - # No current tabstop, but there are snippets? That means we returned from a recursive - # tabstop and still have the tabstop zero selected. The current tabstop is therefore - # the one in the latest snippet, but do not overwrite the complete text of the snippet - if self._ctab is None and len(self._csnippets): - self._ctab = self._csnippets[-1].current_tabstop - self._ctab.current_text += chars - else: - self._ctab.current_text = chars - - moved = 0 - # If this edit changed the buffer in any ways we might have to - # delete more or less lines, according how the cursors has moved - if self._vstate.buf_changed: - moved = self._span_selected.start.line - \ - self._span_selected.end.line - self._span_selected = None - - self._update_vim_buffer(moved + del_more_lines) - else: - self._ctab.current_text += chars - self._update_vim_buffer(del_more_lines) - - - def _backspace(self, count): - self._ctab.current_text = self._ctab.current_text[:-count] - self._update_vim_buffer() - - def _update_vim_buffer(self, del_more_lines = 0): - if not len(self._csnippets): - return - - s = self._csnippets[0] - sline = s.abs_start.line - dlines = s.end.line - s.start.line - - s.update() - - # Replace - if self._vstate.buf_changed: - dlines += self._vstate.moved.line - dlines += del_more_lines - self._vb.replace_lines(sline, sline + dlines, - s._current_text) - ct_end = self._ctab.abs_end - - set_vim_cursor(ct_end.line + 1, ct_end.col) - - self._vstate.update() - + @property def _cs(self): if not len(self._csnippets): return None return self._csnippets[-1] - _cs = property(_cs) def _parse_snippets(self, ft, fn, file_data=None): self.add_snippet_file(ft, fn) @@ -1188,21 +895,21 @@ def base_snippet_files_for(self, ft, default=True): the filetype. """ - snippet_dirs = vim.eval("g:UltiSnipsSnippetDirectories") + snippet_dirs = _vim.eval("g:UltiSnipsSnippetDirectories") base_snippets = os.path.realpath(os.path.join(__file__, "../../../UltiSnips")) ret = [] - paths = vim.eval("&runtimepath").split(',') + paths = _vim.eval("&runtimepath").split(',') - if vim.eval("exists('g:UltiSnipsDontReverseSearchPath')") == "0" or \ - vim.eval("g:UltiSnipsDontReverseSearchPath") == "0": + if _vim.eval("exists('g:UltiSnipsDontReverseSearchPath')") == "0" or \ + _vim.eval("g:UltiSnipsDontReverseSearchPath") == "0": paths = paths[::-1] for rtp in paths: for snippet_dir in snippet_dirs: pth = os.path.realpath(os.path.expanduser(os.path.join(rtp, snippet_dir))) - patterns = ["%s.snippets", "*_%s.snippets"] + patterns = ["%s.snippets", "%s_*.snippets", os.path.join("%s","*")] if not default and pth == base_snippets: patterns.remove("%s.snippets") @@ -1213,46 +920,39 @@ def base_snippet_files_for(self, ft, default=True): return ret - def _filetypes(self, dotft=None): - if dotft is None: - dotft = vim.eval("&filetype") - - fts = dotft.split(".") + [ "all" ] - return [ft for ft in fts[::-1] if ft] - - def filetype(self): - """ Property for the current (undotted) filetype. """ - return self._filetypes()[-1] - filetype = property(filetype) + @property + def primary_filetype(self): + """ Property for the primary filetype. This filetype + will be edited when UltiSnipsEdit is called + without any arguments. + """ + return self._filetypes[_vim.buf.nr][0] - def file_to_edit(self, ft=None): + def file_to_edit(self, ft): """ Gets a file to edit based on the given filetype. - If no filetype is given, uses the current filetype from vim. + If no filetype is given, uses the current filetype from Vim. Checks 'g:UltiSnipsSnippetsDir' and uses it if it exists If a non-shipped file already exists, it uses it. Otherwise uses a file in ~/.vim/ or ~/vimfiles """ - if not ft: - ft = self.filetype - edit = None existing = self.base_snippet_files_for(ft, False) filename = ft + ".snippets" - if vim.eval("exists('g:UltiSnipsSnippetsDir')") == "1": - snipdir = vim.eval("g:UltiSnipsSnippetsDir") + if _vim.eval("exists('g:UltiSnipsSnippetsDir')") == "1": + snipdir = _vim.eval("g:UltiSnipsSnippetsDir") edit = os.path.join(snipdir, filename) elif existing: edit = existing[-1] # last sourced/highest priority else: - home = vim.eval("$HOME") - rtp = vim.eval("&rtp").split(",") - snippet_dirs = ["UltiSnips"] + vim.eval("g:UltiSnipsSnippetDirectories") + home = _vim.eval("$HOME") + rtp = [ os.path.realpath(os.path.expanduser(p)) for p in _vim.eval("&rtp").split(",") ] + snippet_dirs = ["UltiSnips"] + _vim.eval("g:UltiSnipsSnippetDirectories") us = snippet_dirs[-1] - path = os.path.join(home, _dot_vim(), us) - for dirname in [_dot_vim(), "vimfiles"]: + path = os.path.join(home, ".vim", us) + for dirname in [".vim", "vimfiles"]: pth = os.path.join(home, dirname) if pth in rtp: path = os.path.join(pth, us) @@ -1264,21 +964,6 @@ def file_to_edit(self, ft=None): return edit - - def base_snippet_files(self, dotft=None): - """ Returns a list of all snippet files for the given filetype. - If no filetype is given, uses furrent filetype. - If the filetype is dotted (e.g. 'cuda.cpp.c') then it is split and - each filetype is checked. - """ - ret = [] - filetypes = self._filetypes(dotft) - - for ft in filetypes: - ret += self.base_snippet_files_for(ft) - - return ret - # Loading def _load_snippets_for(self, ft): self.snippet_dict(ft).reset() @@ -1293,8 +978,8 @@ def _load_snippets_for(self, ft): def _needs_update(self, ft): - do_hash = vim.eval('exists("g:UltiSnipsDoHash")') == "0" \ - or vim.eval("g:UltiSnipsDoHash") != "0" + do_hash = _vim.eval('exists("g:UltiSnipsDoHash")') == "0" \ + or _vim.eval("g:UltiSnipsDoHash") != "0" if ft not in self._snippets: return True @@ -1325,16 +1010,30 @@ def _ensure_loaded(self, ft, checked=None): self._ensure_loaded(parent, checked) - def _ensure_snippets_loaded(self): + def _ensure_all_loaded(self): + for ft in self._filetypes[_vim.buf.nr]: + self._ensure_loaded(ft) + + def reset_buffer_filetypes(self): + if _vim.buf.nr in self._filetypes: + del self._filetypes[_vim.buf.nr] + + def add_buffer_filetypes(self, ft): """ Checks for changes in the list of snippet files or the contents of the snippet files and reloads them if necessary. """ - filetypes = self._filetypes() - - for ft in filetypes: - self._ensure_loaded(ft) - - return filetypes + buf_fts = self._filetypes[_vim.buf.nr] + idx = -1 + for ft in ft.split("."): + ft = ft.strip() + if not ft: continue + try: + idx = buf_fts.index(ft) + except ValueError: + self._filetypes[_vim.buf.nr].insert(idx + 1, ft) + idx += 1 + + self._ensure_all_loaded() def _find_snippets(self, ft, trigger, potentially = False, seen=None): """ @@ -1345,7 +1044,6 @@ def _find_snippets(self, ft, trigger, potentially = False, seen=None): potentially - also returns snippets that could potentially match; that is which triggers start with the current trigger """ - snips = self._snippets.get(ft,None) if not snips: return [] diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/_diff.py b/vim/bundle/ultisnips/plugin/UltiSnips/_diff.py new file mode 100644 index 0000000..5376d76 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/_diff.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from collections import defaultdict +import sys + +from UltiSnips import _vim +from UltiSnips.geometry import Position + +def is_complete_edit(initial_line, a, b, cmds): + buf = a[:] + for cmd in cmds: + ctype, line, col, char = cmd + line -= initial_line + if ctype == "D": + if char != '\n': + buf[line] = buf[line][:col] + buf[line][col+len(char):] + else: + if line + 1 < len(buf): + buf[line] = buf[line] + buf[line+1] + del buf[line+1] + else: + del buf[line] + elif ctype == "I": + buf[line] = buf[line][:col] + char + buf[line][col:] + buf = '\n'.join(buf).split('\n') + return len(buf) == len(b) and all(j==k for j,k in zip(buf, b)) + +def guess_edit(initial_line, lt, ct, vs): + """ + Try to guess what the user might have done by heuristically looking at cursor movement + number of changed lines and if they got longer or shorter. This will detect most simple + movements like insertion, deletion of a line or carriage return. + """ + if not len(lt) and not len(ct): return True, () + pos = vs.pos + ppos = vs.ppos + if len(lt) and (not ct or (len(ct) == 1 and not ct[0])): # All text deleted? + es = [] + if not ct: ct = [''] + for i in lt: + es.append(("D", initial_line, 0, i)) + es.append(("D", initial_line, 0, "\n")) + es.pop() # Remove final \n because it is not really removed + if is_complete_edit(initial_line, lt, ct, es): return True, es + if ppos.mode == 'v': # Maybe selectmode? + sv = list(map(int, _vim.eval("""getpos("'<")"""))); sv = Position(sv[1]-1,sv[2]-1) + ev = list(map(int, _vim.eval("""getpos("'>")"""))); ev = Position(ev[1]-1,ev[2]-1) + if "exclusive" in _vim.eval("&selection"): + ppos.col -= 1 # We want to be inclusive, sorry. + ev.col -= 1 + es = [] + if sv.line == ev.line: + es.append(("D", sv.line, sv.col, lt[sv.line - initial_line][sv.col:ev.col+1])) + if sv != pos and sv.line == pos.line: + es.append(("I", sv.line, sv.col, ct[sv.line - initial_line][sv.col:pos.col+1])) + if is_complete_edit(initial_line, lt, ct, es): return True, es + if pos.line == ppos.line: + if len(lt) == len(ct): # Movement only in one line + llen = len(lt[ppos.line - initial_line]) + clen = len(ct[pos.line - initial_line]) + if ppos < pos and clen > llen: # Likely that only characters have been added + es = ( + ("I", ppos.line, ppos.col, ct[ppos.line - initial_line][ppos.col:pos.col]), + ) + if is_complete_edit(initial_line, lt, ct, es): return True, es + if clen < llen: + if ppos == pos: # 'x' or DEL or dt or something + es = ( + ("D", pos.line, pos.col, lt[ppos.line - initial_line][ppos.col:ppos.col + (llen - clen)]), + ) + if is_complete_edit(initial_line, lt, ct, es): return True, es + if pos < ppos: # Backspacing or dT dF? + es = ( + ("D", pos.line, pos.col, lt[pos.line - initial_line][pos.col:pos.col + llen - clen]), + ) + if is_complete_edit(initial_line, lt, ct, es): return True, es + elif len(ct) < len(lt): # Maybe some lines were deleted? (dd or so) + es = [] + for i in range(len(lt)-len(ct)): + es.append( ("D", pos.line, 0, lt[pos.line - initial_line + i])) + es.append( ("D", pos.line, 0, '\n')) + if is_complete_edit(initial_line, lt, ct, es): return True, es + else: # Movement in more than one line + if ppos.line + 1 == pos.line and pos.col == 0: # Carriage return? + es = (("I", ppos.line, ppos.col, "\n"),) + if is_complete_edit(initial_line, lt, ct, es): return True, es + return False, None + +def diff(a, b, sline = 0): + """ + Return a list of deletions and insertions that will turn a into b. This is + done by traversing an implicit edit graph and searching for the shortest + route. The basic idea is as follows: + + - Matching a character is free as long as there was no deletion/insertion + before. Then, matching will be seen as delete + insert [1]. + - Deleting one character has the same cost everywhere. Each additional + character costs only have of the first deletion. + - Insertion is cheaper the earlier it happes. The first character is more + expensive that any later [2]. + + [1] This is that world -> aolsa will be "D" world + "I" aolsa instead of + "D" w , "D" rld, "I" a, "I" lsa + [2] This is that "hello\n\n" -> "hello\n\n\n" will insert a newline after hello + and not after \n + """ + d = defaultdict(list) + seen = defaultdict(lambda: sys.maxsize) + + d[0] = [ (0,0,sline, 0, ()) ] + + cost = 0 + D_COST = len(a)+len(b) + I_COST = len(a)+len(b) + while True: + while len(d[cost]): + x, y, line, col, what = d[cost].pop() + + if a[x:] == b[y:]: + return what + + if x < len(a) and y < len(b) and a[x] == b[y]: + ncol = col + 1 + nline = line + if a[x] == '\n': + ncol = 0 + nline +=1 + lcost = cost + 1 + if (what and what[-1][0] == "D" and what[-1][1] == line and + what[-1][2] == col and a[x] != '\n'): + # Matching directly after a deletion should be as costly as + # DELETE + INSERT + a bit + lcost = (D_COST + I_COST)*1.5 + if seen[x+1,y+1] > lcost: + d[lcost].append((x+1,y+1, nline, ncol, what)) + seen[x+1,y+1] = lcost + + if y < len(b): # INSERT + ncol = col + 1 + nline = line + if b[y] == '\n': + ncol = 0 + nline += 1 + if (what and what[-1][0] == "I" and what[-1][1] == nline and + what[-1][2]+len(what[-1][-1]) == col and b[y] != '\n' and + seen[x,y+1] > cost + (I_COST + ncol) // 2 + ): + seen[x,y+1] = cost + (I_COST + ncol) // 2 + d[cost + (I_COST + ncol) // 2].append( + (x,y+1, line, ncol, what[:-1] + ( + ("I", what[-1][1], what[-1][2], what[-1][-1] + b[y]),) ) + ) + elif seen[x,y+1] > cost + I_COST + ncol: + seen[x,y+1] = cost + I_COST + ncol + d[cost + ncol + I_COST].append((x,y+1, nline, ncol, + what + (("I", line, col,b[y]),)) + ) + if x < len(a): # DELETE + if (what and what[-1][0] == "D" and what[-1][1] == line and + what[-1][2] == col and a[x] != '\n' and what[-1][-1] != '\n' and + seen[x+1,y] > cost + D_COST // 2 + ): + seen[x+1,y] = cost + D_COST // 2 + d[cost + D_COST // 2].append((x+1,y, line, col, what[:-1] + + (("D",line, col, what[-1][-1] + a[x]),) ) + ) + elif seen[x+1,y] > cost + D_COST: + seen[x+1,y] = cost + D_COST + d[cost + D_COST].append((x+1,y, line, col, what + + (("D",line, col, a[x]),) ) + ) + cost += 1 + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/_vim.py b/vim/bundle/ultisnips/plugin/UltiSnips/_vim.py new file mode 100755 index 0000000..18be1df --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/_vim.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python +# encoding: utf-8 + +""" +Wrapper functionality around the functions we need from Vim +""" +import vim +from vim import error + +from UltiSnips.geometry import Position +from UltiSnips.compatibility import col2byte, byte2col, \ + as_unicode, as_vimencoding + +class VimBuffer(object): + def __getitem__(self, idx): + if isinstance(idx, slice): # Py3 + return self.__getslice__(idx.start, idx.stop) + rv = vim.current.buffer[idx] + return as_unicode(rv) + def __getslice__(self, i, j): + rv = vim.current.buffer[i:j] + return [ as_unicode(l) for l in rv ] + + def __setitem__(self, idx, text): + if isinstance(idx, slice): # Py3 + return self.__setslice__(idx.start, idx.stop, text) + vim.current.buffer[idx] = as_vimencoding(text) + def __setslice__(self, i, j, text): + vim.current.buffer[i:j] = [ as_vimencoding(l) for l in text ] + + def __len__(self): + return len(vim.current.buffer) + + @property + def current_line_splitted(self): + """Returns the text before and after the cursor as a tuple.""" + # Note: we want byte position here + lineno, col = vim.current.window.cursor + + line = vim.current.line + before, after = as_unicode(line[:col]), as_unicode(line[col:]) + return before, after + + @property + def nr(self): + return int(eval("bufnr('%')")) + + def cursor(): + """ + The current windows cursor. Note that this is 0 based in col and 0 + based in line which is different from Vim's cursor. + """ + def fget(self): + line, nbyte = vim.current.window.cursor + col = byte2col(line, nbyte) + return Position(line - 1, col) + def fset(self, pos): + nbyte = col2byte(pos.line + 1, pos.col) + vim.current.window.cursor = pos.line + 1, nbyte + return locals() + cursor = property(**cursor()) +buf = VimBuffer() + +def text_to_vim(start, end, text): + lines = text.split('\n') + + # Open any folds this might have created + buf.cursor = start + vim.command("normal zv") + + new_end = _calc_end(lines, start) + + before = buf[start.line][:start.col] + after = buf[end.line][end.col:] + + new_lines = [] + if len(lines): + new_lines.append(before + lines[0]) + new_lines.extend(lines[1:]) + new_lines[-1] += after + buf[start.line:end.line + 1] = new_lines + + return new_end + +def escape(inp): + """ Creates a vim-friendly string from a group of + dicts, lists and strings. + """ + def conv(obj): + if isinstance(obj, list): + rv = as_unicode('[' + ','.join(conv(o) for o in obj) + ']') + elif isinstance(obj, dict): + rv = as_unicode('{' + ','.join([ + "%s:%s" % (conv(key), conv(value)) + for key, value in obj.iteritems()]) + '}') + else: + rv = as_unicode('"%s"') % as_unicode(obj).replace('"', '\\"') + return rv + return conv(inp) + +def command(s): + return as_unicode(vim.command(as_vimencoding(s))) + +def eval(s): + rv = vim.eval(as_vimencoding(s)) + if not isinstance(rv, (dict, list)): + return as_unicode(rv) + return rv + +def feedkeys(s, mode='n'): + """Wrapper around vim's feedkeys function. Mainly for convenience.""" + command(as_unicode(r'call feedkeys("%s", "%s")') % (s, mode)) + +def new_scratch_buffer(text): + """Create a new scratch buffer with the text given""" + command("botright new") + command("set ft=text") + command("set buftype=nofile") + + vim.buffers[-1][:] = text.splitlines() + +def select(start, end): + """Select the span in Select mode""" + + _unmap_select_mode_mapping() + + delta = end - start + lineno, col = start.line, start.col + + col = col2byte(lineno + 1, col) + vim.current.window.cursor = lineno + 1, col + + move_cmd = "" + if eval("mode()") != 'n': + move_cmd += r"\" + + # Case 1: Zero Length Tabstops + if delta.line == delta.col == 0: + if col == 0 or eval("mode()") not in 'i' and \ + col < len(buf[lineno]): + move_cmd += "i" + else: + move_cmd += "a" + else: + # Case 2a: Non zero length + # If a tabstop immediately starts with a newline, the selection + # must start after the last character in the current line. But if + # we are in insert mode and out of it, we cannot go past the + # last character with move_one_right and therefore cannot + # visual-select this newline. We have to hack around this by adding + # an extra space which we can select. Note that this problem could + # be circumvent by selecting the tab backwards (that is starting + # at the end); one would not need to modify the line for this. This creates other + # trouble though + if col >= len(buf[lineno]): + buf[lineno] += " " + + if delta.line: + move_lines = "%ij" % delta.line + else: + move_lines = "" + # Depending on the current mode and position, we + # might need to move escape out of the mode and this + # will move our cursor one left + if col != 0 and eval("mode()") == 'i': + move_one_right = "l" + else: + move_one_right = "" + + # After moving to the correct line, we go back to column 0 + # and select right from there. Note that the we have to select + # one column less since Vim's visual selection is including the + # ending while Python slicing is excluding the ending. + inclusive = "inclusive" in eval("&selection") + if end.col == 0: + # Selecting should end at beginning of line -> Select the + # previous line till its end + do_select = "k$" + if not inclusive: + do_select += "j0" + elif end.col > 1: + do_select = "0%il" % (end.col-1 if inclusive else end.col) + else: + do_select = "0" if inclusive else "0l" + + move_cmd += _LangMapTranslator().translate( + r"%sv%s%s\" % (move_one_right, move_lines, do_select) + ) + + feedkeys(move_cmd) + +# Helper functions {{{ +def _calc_end(lines, start): + if len(lines) == 1: + new_end = start + Position(0,len(lines[0])) + else: + new_end = Position(start.line + len(lines)-1, len(lines[-1])) + return new_end + +def _unmap_select_mode_mapping(): + """This function unmaps select mode mappings if so wished by the user. + Removes select mode mappings that can actually be typed by the user + (ie, ignores things like ). + """ + if int(eval("g:UltiSnipsRemoveSelectModeMappings")): + ignores = eval("g:UltiSnipsMappingsToIgnore") + ['UltiSnips'] + + for option in ("", ""): + # Put all smaps into a var, and then read the var + command(r"redir => _tmp_smaps | silent smap %s " % option + + "| redir END") + + # Check if any mappings where found + all_maps = list(filter(len, eval(r"_tmp_smaps").splitlines())) + if (len(all_maps) == 1 and all_maps[0][0] not in " sv"): + # "No maps found". String could be localized. Hopefully + # it doesn't start with any of these letters in any + # language + continue + + # Only keep mappings that should not be ignored + maps = [m for m in all_maps if + not any(i in m for i in ignores) and len(m.strip())] + + for m in maps: + # The first three chars are the modes, that might be listed. + # We are not interested in them here. + trig = m[3:].split()[0] if len(m[3:].split()) != 0 else None + + if trig is None: + continue + + # The bar separates commands + if trig[-1] == "|": + trig = trig[:-1] + "" + + # Special ones + if trig[0] == "<": + add = False + # Only allow these + for valid in ["Tab", "NL", "CR", "C-Tab", "BS"]: + if trig == "<%s>" % valid: + add = True + if not add: + continue + + # UltiSnips remaps . Keep this around. + if trig == "": + continue + + # Actually unmap it + try: + command("silent! sunmap %s %s" % (option, trig)) + except: + # Bug 908139: ignore unmaps that fail because of + # unprintable characters. This is not ideal because we + # will not be able to unmap lhs with any unprintable + # character. If the lhs stats with a printable + # character this will leak to the user when he tries to + # type this character as a first in a selected tabstop. + # This case should be rare enough to not bother us + # though. + pass +# End: Helper functions }}} +# Helper classes {{{ +class _Real_LangMapTranslator(object): + """ + This carse for the Vim langmap option and basically reverses the mappings. This + was the only solution to get UltiSnips to work nicely with langmap; other stuff + I tried was using inoremap movement commands and caching and restoring the + langmap option. + + Note that this will not work if the langmap overwrites a character completely, + for example if 'j' is remapped, but nothing is mapped back to 'j', then moving + one line down is no longer possible and UltiSnips will fail. + """ + _maps = {} + + def _create_translation(self, langmap): + from_chars, to_chars = "", "" + for c in langmap.split(','): + if ";" in c: + a,b = c.split(';') + from_chars += a + to_chars += b + else: + from_chars += c[::2] + to_chars += c[1::2] + self._maps[langmap] = (from_chars, to_chars) + + def translate(self, s): + langmap = eval("&langmap").strip() + if langmap == "": + return s + + s = as_unicode(s) + if langmap not in self._maps: + self._create_translation(langmap) + + for f,t in zip(*self._maps[langmap]): + s = s.replace(f,t) + return s + +class _Dummy_LangMapTranslator(object): + """ + If vim hasn't got the langmap compiled in, we never have to do anything. + Then this class is used. + """ + translate = lambda self, s: s + +_LangMapTranslator = _Real_LangMapTranslator +if not int(eval('has("langmap")')): + _LangMapTranslator = _Dummy_LangMapTranslator +# End: Helper classes }}} diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/compatibility.py b/vim/bundle/ultisnips/plugin/UltiSnips/compatibility.py new file mode 100644 index 0000000..d4b15dc --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/compatibility.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# encoding: utf-8 + +""" +This file contains compatibility code to stay compatible with +as many python versions as possible. +""" + +import sys + +import vim + +__all__ = ['as_unicode', 'compatible_exec', 'vim_cursor', 'set_vim_cursor'] + +if sys.version_info >= (3,0): + from UltiSnips.compatibility_py3 import * + + def col2byte(line, col): + """ + Convert a valid column index into a byte index inside + of vims buffer. + """ + pre_chars = vim.current.buffer[line-1][:col] + return len(pre_chars.encode(vim.eval("&encoding"))) + + def byte2col(line, nbyte): + """ + Convert a column into a byteidx suitable for a mark or cursor + position inside of vim + """ + line = vim.current.buffer[line-1] + vc = vim.eval("&encoding") + raw_bytes = line.encode(vc)[:nbyte] + return len(raw_bytes.decode(vc)) + + def as_unicode(s): + if isinstance(s, bytes): + vc = vim.eval("&encoding") + return s.decode(vc) + return str(s) + + def as_vimencoding(s): + return s +else: + from UltiSnips.compatibility_py2 import * + + import warnings + warnings.filterwarnings("ignore", category=DeprecationWarning) + + def col2byte(line, col): + """ + Convert a valid column index into a byte index inside + of vims buffer. + """ + vc = vim.eval("&encoding") + pre_chars = vim.current.buffer[line-1].decode(vc)[:col] + return len(pre_chars.encode(vc)) + + def byte2col(line, nbyte): + """ + Convert a column into a byteidx suitable for a mark or cursor + position inside of vim + """ + line = vim.current.buffer[line-1] + if nbyte >= len(line): # This is beyond end of line + return nbyte + return len(line[:nbyte].decode(vim.eval("&encoding"))) + + def as_unicode(s): + if isinstance(s, str): + vc = vim.eval("&encoding") + return s.decode(vc) + return unicode(s) + + def as_vimencoding(s): + vc = vim.eval("&encoding") + return s.encode(vc) + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Compatibility_py2.py b/vim/bundle/ultisnips/plugin/UltiSnips/compatibility_py2.py old mode 100755 new mode 100644 similarity index 100% rename from vim/bundle/ultisnips/plugin/UltiSnips/Compatibility_py2.py rename to vim/bundle/ultisnips/plugin/UltiSnips/compatibility_py2.py diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Compatibility_py3.py b/vim/bundle/ultisnips/plugin/UltiSnips/compatibility_py3.py similarity index 100% rename from vim/bundle/ultisnips/plugin/UltiSnips/Compatibility_py3.py rename to vim/bundle/ultisnips/plugin/UltiSnips/compatibility_py3.py diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/debug.py b/vim/bundle/ultisnips/plugin/UltiSnips/debug.py index ba562d1..e508773 100644 --- a/vim/bundle/ultisnips/plugin/UltiSnips/debug.py +++ b/vim/bundle/ultisnips/plugin/UltiSnips/debug.py @@ -3,13 +3,30 @@ __all__ = [ "debug" ] -import types +import sys -from UltiSnips.Compatibility import as_unicode +from UltiSnips.compatibility import as_unicode + +def echo_to_hierarchy(to): + par = to + while par._parent: par = par._parent + + def _do_print(to, indent=""): + debug(indent + as_unicode(to)) + + try: + for c in to._childs: + _do_print(c, indent=indent + " ") + except AttributeError: + pass + + _do_print(par) def debug(s): s = as_unicode(s) - f = open("/tmp/file.txt","ab") + fn = "/tmp/file.txt" if not sys.platform.lower().startswith("win") \ + else "C:/windows/temp/ultisnips.txt" + f = open(fn,"ab") f.write((s + '\n').encode("utf-8")) f.close() diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/geometry.py b/vim/bundle/ultisnips/plugin/UltiSnips/geometry.py new file mode 100644 index 0000000..bfbef74 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/geometry.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# encoding: utf-8 + +__all__ = [ "Position" ] + +class Position(object): + def __init__(self, line, col): + self.line = line + self.col = col + + def col(): + def fget(self): + return self._col + def fset(self, value): + self._col = value + return locals() + col = property(**col()) + + def line(): + doc = "Zero base line numbers" + def fget(self): + return self._line + def fset(self, value): + self._line = value + return locals() + line = property(**line()) + + def move(self, pivot, diff): + """pivot is the position of the first changed + character, diff is how text after it moved""" + if self < pivot: return + if diff.line == 0: + if self.line == pivot.line: + self.col += diff.col + elif diff.line > 0: + if self.line == pivot.line: + self.col += diff.col - pivot.col + self.line += diff.line + else: + self.line += diff.line + if self.line == pivot.line: + self.col += - diff.col + pivot.col + + + def __add__(self,pos): + if not isinstance(pos,Position): + raise TypeError("unsupported operand type(s) for +: " \ + "'Position' and %s" % type(pos)) + + return Position(self.line + pos.line, self.col + pos.col) + + def __sub__(self,pos): + if not isinstance(pos,Position): + raise TypeError("unsupported operand type(s) for +: " \ + "'Position' and %s" % type(pos)) + return Position(self.line - pos.line, self.col - pos.col) + + def diff(self,pos): + if not isinstance(pos,Position): + raise TypeError("unsupported operand type(s) for +: " \ + "'Position' and %s" % type(pos)) + if self.line == pos.line: + return Position(0, self.col - pos.col) + else: + if self > pos: + return Position(self.line - pos.line, self.col) + else: + return Position(self.line - pos.line, pos.col) + return Position(self.line - pos.line, self.col - pos.col) + + def __eq__(self, other): + return (self._line, self._col) == (other._line, other._col) + def __ne__(self, other): + return (self._line, self._col) != (other._line, other._col) + def __lt__(self, other): + return (self._line, self._col) < (other._line, other._col) + def __le__(self, other): + return (self._line, self._col) <= (other._line, other._col) + + def __repr__(self): + return "(%i,%i)" % (self._line, self._col) + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/tests/test_diff.py b/vim/bundle/ultisnips/plugin/UltiSnips/tests/test_diff.py new file mode 100644 index 0000000..719ab91 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/tests/test_diff.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import unittest + +import os.path as p, sys; sys.path.append(p.join(p.dirname(__file__), "..")) + +from _diff import diff, guess_edit +from geometry import Position + + +def transform(a, cmds): + buf = a.split("\n") + + for cmd in cmds: + ctype, line, col, char = cmd + if ctype == "D": + if char != '\n': + buf[line] = buf[line][:col] + buf[line][col+len(char):] + else: + buf[line] = buf[line] + buf[line+1] + del buf[line+1] + elif ctype == "I": + buf[line] = buf[line][:col] + char + buf[line][col:] + buf = '\n'.join(buf).split('\n') + return '\n'.join(buf) + + +import unittest + +# Test Guessing {{{ +class _BaseGuessing(object): + def runTest(self): + rv, es = guess_edit(self.initial_line, self.a, self.b, Position(*self.ppos), Position(*self.pos)) + self.assertEqual(rv, True) + self.assertEqual(self.wanted, es) + +class TestGuessing_Noop0(_BaseGuessing, unittest.TestCase): + a, b = [], [] + initial_line = 0 + ppos, pos = (0, 6), (0, 7) + wanted = () + +class TestGuessing_InsertOneChar(_BaseGuessing, unittest.TestCase): + a, b = ["Hello World"], ["Hello World"] + initial_line = 0 + ppos, pos = (0, 6), (0, 7) + wanted = ( + ("I", 0, 6, " "), + ) +class TestGuessing_InsertOneChar1(_BaseGuessing, unittest.TestCase): + a, b = ["Hello World"], ["Hello World"] + initial_line = 0 + ppos, pos = (0, 7), (0, 8) + wanted = ( + ("I", 0, 7, " "), + ) +class TestGuessing_BackspaceOneChar(_BaseGuessing, unittest.TestCase): + a, b = ["Hello World"], ["Hello World"] + initial_line = 0 + ppos, pos = (0, 7), (0, 6) + wanted = ( + ("D", 0, 6, " "), + ) +class TestGuessing_DeleteOneChar(_BaseGuessing, unittest.TestCase): + a, b = ["Hello World"], ["Hello World"] + initial_line = 0 + ppos, pos = (0, 5), (0, 5) + wanted = ( + ("D", 0, 5, " "), + ) + +# End: Test Guessing }}} + +class _Base(object): + def runTest(self): + es = diff(self.a, self.b) + tr = transform(self.a, es) + self.assertEqual(self.b, tr) + self.assertEqual(self.wanted, es) + +class TestEmptyString(_Base, unittest.TestCase): + a, b = "", "" + wanted = () + +class TestAllMatch(_Base, unittest.TestCase): + a, b = "abcdef", "abcdef" + wanted = () + +class TestLotsaNewlines(_Base, unittest.TestCase): + a, b = "Hello", "Hello\nWorld\nWorld\nWorld" + wanted = ( + ("I", 0, 5, "\n"), + ("I", 1, 0, "World"), + ("I", 1, 5, "\n"), + ("I", 2, 0, "World"), + ("I", 2, 5, "\n"), + ("I", 3, 0, "World"), + ) + +class TestCrash(_Base, unittest.TestCase): + a = 'hallo Blah mitte=sdfdsfsd\nhallo kjsdhfjksdhfkjhsdfkh mittekjshdkfhkhsdfdsf' + b = 'hallo Blah mitte=sdfdsfsd\nhallo b mittekjshdkfhkhsdfdsf' + wanted = ( + ("D", 1, 6, "kjsdhfjksdhfkjhsdfkh"), + ("I", 1, 6, "b"), + ) + +class TestRealLife(_Base, unittest.TestCase): + a = 'hallo End Beginning' + b = 'hallo End t' + wanted = ( + ("D", 0, 10, "Beginning"), + ("I", 0, 10, "t"), + ) + +class TestRealLife1(_Base, unittest.TestCase): + a = 'Vorne hallo Hinten' + b = 'Vorne hallo Hinten' + wanted = ( + ("I", 0, 11, " "), + ) + +class TestWithNewline(_Base, unittest.TestCase): + a = 'First Line\nSecond Line' + b = 'n' + wanted = ( + ("D", 0, 0, "First Line"), + ("D", 0, 0, "\n"), + ("D", 0, 0, "Second Line"), + ("I", 0, 0, "n"), + ) + + +class TestCheapDelete(_Base, unittest.TestCase): + a = 'Vorne hallo Hinten' + b = 'Vorne Hinten' + wanted = ( + ("D", 0, 5, " hallo"), + ) + +class TestNoSubstring(_Base, unittest.TestCase): + a,b = "abc", "def" + wanted = ( + ("D", 0, 0, "abc"), + ("I", 0, 0, "def"), + ) + +class TestCommonCharacters(_Base, unittest.TestCase): + a,b = "hasomelongertextbl", "hol" + wanted = ( + ("D", 0, 1, "asomelongertextb"), + ("I", 0, 1, "o"), + ) + +class TestUltiSnipsProblem(_Base, unittest.TestCase): + a = "this is it this is it this is it" + b = "this is it a this is it" + wanted = ( + ("D", 0, 11, "this is it"), + ("I", 0, 11, "a"), + ) + +class MatchIsTooCheap(_Base, unittest.TestCase): + a = "stdin.h" + b = "s" + wanted = ( + ("D", 0, 1, "tdin.h"), + ) + +class MultiLine(_Base, unittest.TestCase): + a = "hi first line\nsecond line first line\nsecond line world" + b = "hi first line\nsecond line k world" + + wanted = ( + ("D", 1, 12, "first line"), + ("D", 1, 12, "\n"), + ("D", 1, 12, "second line"), + ("I", 1, 12, "k"), + ) + + +if __name__ == '__main__': + unittest.main() + # k = TestEditScript() + # unittest.TextTestRunner().run(k) + + + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/tests/test_geometry.py b/vim/bundle/ultisnips/plugin/UltiSnips/tests/test_geometry.py new file mode 100644 index 0000000..71d0249 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/tests/test_geometry.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import unittest +import os.path as p, sys; sys.path.append(p.join(p.dirname(__file__), "..")) + +from geometry import Position + +class _MPBase(object): + def runTest(self): + obj = Position(*self.obj) + for pivot, diff, wanted in self.steps: + obj.move(Position(*pivot), Position(*diff)) + self.assertEqual(Position(*wanted), obj) + +class MovePosition_DelSameLine(_MPBase, unittest.TestCase): + # hello wor*ld -> h*ld -> hl*ld + obj = (0, 9) + steps = ( + ((0, 1), (0, -8), (0, 1)), + ((0, 1), (0, 1), (0, 2)), + ) +class MovePosition_DelSameLine1(_MPBase, unittest.TestCase): + # hel*lo world -> hel*world -> hel*worl + obj = (0,3) + steps = ( + ((0, 4), (0, -3), (0,3)), + ((0, 8), (0, -1), (0,3)), + ) +class MovePosition_InsSameLine1(_MPBase, unittest.TestCase): + # hel*lo world -> hel*woresld + obj = (0, 3) + steps = ( + ((0, 4), (0, -3), (0, 3)), + ((0, 6), (0, 2), (0, 3)), + ((0, 8), (0, -1), (0, 3)) + ) +class MovePosition_InsSameLine2(_MPBase, unittest.TestCase): + # hello wor*ld -> helesdlo wor*ld + obj = (0, 9) + steps = ( + ((0, 3), (0, 3), (0, 12)), + ) + +class MovePosition_DelSecondLine(_MPBase, unittest.TestCase): + # hello world. sup hello world.*a, was + # *a, was ach nix + # ach nix + obj = (1, 0) + steps = ( + ((0, 12), (0, -4), (1, 0)), + ((0, 12), (-1, 0), (0, 12)), + ) +class MovePosition_DelSecondLine1(_MPBase, unittest.TestCase): + # hello world. sup + # a, *was + # ach nix + # hello world.a*was + # ach nix + obj = (1, 3) + steps = ( + ((0, 12), (0, -4), (1, 3)), + ((0, 12), (-1, 0), (0, 15)), + ((0, 12), (0, -3), (0, 12)), + ((0, 12), (0, 1), (0, 13)), + ) + +if __name__ == '__main__': + unittest.main() diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/__init__.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/__init__.py new file mode 100644 index 0000000..27e87f9 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from ._snippet_instance import SnippetInstance + +__all__ = [ "SnippetInstance" ] + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_base.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_base.py new file mode 100755 index 0000000..d3f046a --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_base.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import vim + +import UltiSnips._vim as _vim +from UltiSnips.geometry import Position + +__all__ = ["TextObject", "EditableTextObject", "NoneditableTextObject"] + +class TextObject(object): + """ + This base class represents any object in the text + that has a span in any ways + """ + def __init__(self, parent, token, end = None, initial_text = "", tiebreaker = None): + self._parent = parent + + ct = None + if end is not None: # Took 4 arguments + self._start = token + self._end = end + self._initial_text = initial_text + else: # Initialize from token + self._start = token.start + self._end = token.end + self._initial_text = token.initial_text + self._tiebreaker = tiebreaker or Position(self._start.line, self._end.line) + + if parent is not None: + parent._add_child(self) + + def overwrite(self, gtext = None): + """ + Overwrite the text of this object in the Vim Buffer and update its + length information + """ + # We explicitly do not want to move our childs around here as we + # either have non or we are replacing text initially which means we do + # not want to mess with their positions + if self.current_text == gtext: return + old_end = self._end + self._end = _vim.text_to_vim( + self._start, self._end, gtext or self._initial_text) + if self._parent: + self._parent._child_has_moved( + self._parent._childs.index(self), min(old_end, self._end), + self._end.diff(old_end) + ) + + def __lt__(self, other): + me = (self._start.line, self._start.col, + self._tiebreaker.line, self._tiebreaker.col) + o = (other._start.line, other._start.col, + other._tiebreaker.line, other._tiebreaker.col) + return me < o + def __le__(self, other): + me = (self._start.line, self._start.col, + self._tiebreaker.line, self._tiebreaker.col) + o = (other._start.line, other._start.col, + other._tiebreaker.line, other._tiebreaker.col) + return me <= o + + def __repr__(self): + ct = "" + try: + ct = self.current_text + except IndexError: + ct = "" + + return "%s(%r->%r,%r)" % (self.__class__.__name__, + self._start, self._end, ct) + + ############## + # PROPERTIES # + ############## + @property + def current_text(self): + if self._start.line == self._end.line: + return _vim.buf[self._start.line][self._start.col:self._end.col] + else: + lines = [_vim.buf[self._start.line][self._start.col:]] + lines.extend(_vim.buf[self._start.line+1:self._end.line]) + lines.append(_vim.buf[self._end.line][:self._end.col]) + return '\n'.join(lines) + + def start(self): + return self._start + start = property(start) + + def end(self): + return self._end + end = property(end) + + #################### + # Public functions # + #################### + def _move(self, pivot, diff): + self._start.move(pivot, diff) + self._end.move(pivot, diff) + +class EditableTextObject(TextObject): + """ + This base class represents any object in the text + that can be changed by the user + """ + def __init__(self, *args, **kwargs): + TextObject.__init__(self, *args, **kwargs) + + self._childs = [] + self._tabstops = {} + + ############## + # Properties # + ############## + @property + def _editable_childs(self): + return [ c for c in self._childs if isinstance(c, EditableTextObject) ] + + #################### + # Public Functions # + #################### + def find_parent_for_new_to(self, pos): + for c in self._editable_childs: + if (c._start <= pos < c._end): + return c.find_parent_for_new_to(pos) + return self + + ############################### + # Private/Protected functions # + ############################### + def _do_edit(self, cmd): + ctype, line, col, text = cmd + assert( ('\n' not in text) or (text == "\n")) + pos = Position(line, col) + + to_kill = set() + new_cmds = [] + for c in self._childs: + if ctype == "I": # Insertion + if c._start < pos < Position(c._end.line, c._end.col) and isinstance(c, NoneditableTextObject): + to_kill.add(c) + new_cmds.append(cmd) + break + elif (c._start <= pos <= c._end) and isinstance(c, EditableTextObject): + c._do_edit(cmd) + return + else: # Deletion + delend = pos + Position(0, len(text)) if text != "\n" \ + else Position(line + 1, 0) + if (c._start <= pos < c._end) and (c._start < delend <= c._end): + # this edit command is completely for the child + if isinstance(c, NoneditableTextObject): + to_kill.add(c) + new_cmds.append(cmd) + break + else: + c._do_edit(cmd) + return + elif (pos < c._start and c._end <= delend) or (pos <= c._start and c._end < delend): + # Case: this deletion removes the child + to_kill.add(c) + new_cmds.append(cmd) + break + elif (pos < c._start and (c._start < delend <= c._end)): + # Case: partially for us, partially for the child + my_text = text[:(c._start-pos).col] + c_text = text[(c._start-pos).col:] + new_cmds.append((ctype, line, col, my_text)) + new_cmds.append((ctype, line, col, c_text)) + break + elif (delend >= c._end and (c._start <= pos < c._end)): + # Case: partially for us, partially for the child + c_text = text[(c._end-pos).col:] + my_text = text[:(c._end-pos).col] + new_cmds.append((ctype, line, col, c_text)) + new_cmds.append((ctype, line, col, my_text)) + break + + for c in to_kill: + self._del_child(c) + if len(new_cmds): + for c in new_cmds: + self._do_edit(c) + return + + # We have to handle this ourselves + delta = Position(1, 0) if text == "\n" else Position(0, len(text)) + if ctype == "D": + if self._start == self._end: # Makes no sense to delete in empty textobject + return + delta.line *= -1 + delta.col *= -1 + pivot = Position(line, col) + idx = -1 + for cidx, c in enumerate(self._childs): + if c._start < pivot <= c._end: + idx = cidx + self._child_has_moved(idx, pivot, delta) + + def _move(self, pivot, diff): + TextObject._move(self, pivot, diff) + + for c in self._childs: + c._move(pivot, diff) + + def _child_has_moved(self, idx, pivot, diff): + self._end.move(pivot, diff) + + for c in self._childs[idx+1:]: + c._move(pivot, diff) + + if self._parent: + self._parent._child_has_moved( + self._parent._childs.index(self), pivot, diff + ) + + def _get_next_tab(self, no): + if not len(self._tabstops.keys()): + return + tno_max = max(self._tabstops.keys()) + + possible_sol = [] + i = no + 1 + while i <= tno_max: + if i in self._tabstops: + possible_sol.append( (i, self._tabstops[i]) ) + break + i += 1 + + c = [ c._get_next_tab(no) for c in self._editable_childs ] + c = filter(lambda i: i, c) + + possible_sol += c + + if not len(possible_sol): + return None + + return min(possible_sol) + + + def _get_prev_tab(self, no): + if not len(self._tabstops.keys()): + return + tno_min = min(self._tabstops.keys()) + + possible_sol = [] + i = no - 1 + while i >= tno_min and i > 0: + if i in self._tabstops: + possible_sol.append( (i, self._tabstops[i]) ) + break + i -= 1 + + c = [ c._get_prev_tab(no) for c in self._editable_childs ] + c = filter(lambda i: i, c) + + possible_sol += c + + if not len(possible_sol): + return None + + return max(possible_sol) + + def _get_tabstop(self, requester, no): + if no in self._tabstops: + return self._tabstops[no] + for c in self._editable_childs: + if c is requester: + continue + + rv = c._get_tabstop(self, no) + if rv is not None: + return rv + if self._parent and requester is not self._parent: + return self._parent._get_tabstop(self, no) + + def _update(self, done, not_done): + """ + Update this object inside the Vim Buffer. + + Return False if you want to be called again + for this edit cycle. Otherwise return True. + """ + if all((c in done) for c in self._childs): + assert(self not in done) + + done.add(self) + return True + + def _add_child(self,c): + self._childs.append(c) + self._childs.sort() + + def _del_child(self,c): + c._parent = None + self._childs.remove(c) + + # If this is a tabstop, delete it + try: + del self._tabstops[c.no] + except AttributeError: + pass + +class NoneditableTextObject(TextObject): + """ + All passive text objects that the user can't edit by hand + """ + + def _update(self, done, not_done): + return True + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_escaped_char.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_escaped_char.py new file mode 100755 index 0000000..57158c9 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_escaped_char.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from UltiSnips.text_objects._base import NoneditableTextObject + +class EscapedChar(NoneditableTextObject): + """ + This class is a escape char like \$. It is handled in a text object to make + sure that siblings are correctly moved after replacing the text. + + This is a base class without functionality just to mark it in the code. + """ + pass + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/Lexer.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_lexer.py similarity index 76% rename from vim/bundle/ultisnips/plugin/UltiSnips/Lexer.py rename to vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_lexer.py index dc30e6a..5ea1d6e 100644 --- a/vim/bundle/ultisnips/plugin/UltiSnips/Lexer.py +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_lexer.py @@ -9,7 +9,8 @@ import string import re -from UltiSnips.Geometry import Position +from UltiSnips.geometry import Position +from UltiSnips.compatibility import as_unicode __all__ = [ "tokenize", "EscapeCharToken", "VisualToken", "TransformationToken", "TabStopToken", @@ -18,10 +19,10 @@ # Helper Classes {{{ class _TextIterator(object): - def __init__(self, text): - self._text = text - self._line = 0 - self._col = 0 + def __init__(self, text, offset): + self._text = as_unicode(text) + self._line = offset.line + self._col = offset.col self._idx = 0 @@ -53,6 +54,19 @@ def peek(self, count = 1): @property def pos(self): return Position(self._line, self._col) + +def unescape(s): + rv = "" + i = 0 + while i < len(s): + if i+1 < len(s) and s[i] == '\\': + rv += s[i+1] + i += 1 + else: + rv += s[i] + i += 1 + return rv + # End: Helper Classes }}} # Helper functions {{{ def _parse_number(stream): @@ -86,27 +100,31 @@ def _parse_till_closing_brace(stream): rv += c return rv -def _parse_till_unescaped_char(stream, char): +def _parse_till_unescaped_char(stream, chars): """ - Returns all chars till a non-escaped `char` is found. + Returns all chars till a non-escaped char is found. - Will also consume the closing `char`, but not return it + Will also consume the closing char, but and return it as second + return value """ rv = "" while True: - if EscapeCharToken.starts_here(stream, char): - rv += stream.next() + stream.next() - else: + escaped = False + for c in chars: + if EscapeCharToken.starts_here(stream, c): + rv += stream.next() + stream.next() + escaped = True + if not escaped: c = stream.next() - if c == char: break + if c in chars: break rv += c - return rv + return rv, c # End: Helper functions }}} # Tokens {{{ class Token(object): def __init__(self, gen, indent): - self.initial_text = "" + self.initial_text = as_unicode("") self.start = gen.pos self._parse(gen, indent) self.end = gen.pos @@ -134,28 +152,32 @@ def __repr__(self): ) class VisualToken(Token): - TOKEN = "${VISUAL}" - CHECK = re.compile(r"^[ \t]*\${VISUAL}") + CHECK = re.compile(r"^\${VISUAL[:}/]") @classmethod def starts_here(klass, stream): - return klass.CHECK.match(stream.peek(10000)) is not None + return klass.CHECK.match(stream.peek(10)) is not None def _parse(self, stream, indent): - self.leading_whitespace = "" - while stream.peek() != self.TOKEN[0]: - self.leading_whitespace += stream.next() - - for i in range(len(self.TOKEN)): + for i in range(8): # ${VISUAL stream.next() - # Make sure that a ${VISUAL} at the end of a line behaves like a block - # of text and does not introduce another line break. - while 1: - nc = stream.peek() - if nc is None or nc not in '\r\n': - break + if stream.peek() == ":": stream.next() + self.alternative_text, c = _parse_till_unescaped_char(stream, '/}') + self.alternative_text = unescape(self.alternative_text) + + if c == '/': # Transformation going on + try: + self.search = _parse_till_unescaped_char(stream, '/')[0] + self.replace = _parse_till_unescaped_char(stream, '/')[0] + self.options = _parse_till_closing_brace(stream) + except StopIteration: + raise RuntimeError("Invalid ${VISUAL} transformation! Forgot to escape a '/'?") + else: + self.search = None + self.replace = None + self.options = None def __repr__(self): return "VisualToken(%r,%r)" % ( @@ -177,8 +199,8 @@ def _parse(self, stream, indent): stream.next() # / - self.search = _parse_till_unescaped_char(stream, '/') - self.replace = _parse_till_unescaped_char(stream, '/') + self.search = _parse_till_unescaped_char(stream, '/')[0] + self.replace = _parse_till_unescaped_char(stream, '/')[0] self.options = _parse_till_closing_brace(stream) def __repr__(self): @@ -225,7 +247,7 @@ def starts_here(klass, stream): def _parse(self, stream, indent): stream.next() # ` - self.code = _parse_till_unescaped_char(stream, '`') + self.code = _parse_till_unescaped_char(stream, '`')[0] def __repr__(self): return "ShellCodeToken(%r,%r,%r)" % ( @@ -245,7 +267,7 @@ def _parse(self, stream, indent): if stream.peek() in '\t ': stream.next() - code = _parse_till_unescaped_char(stream, '`') + code = _parse_till_unescaped_char(stream, '`')[0] # Strip the indent if any if len(indent): @@ -272,7 +294,7 @@ def starts_here(klass, stream): def _parse(self, stream, indent): for i in range(4): stream.next() # `!v - self.code = _parse_till_unescaped_char(stream, '`') + self.code = _parse_till_unescaped_char(stream, '`')[0] def __repr__(self): return "VimLCodeToken(%r,%r,%r)" % ( @@ -291,8 +313,8 @@ def __repr__(self): EscapeCharToken, VisualToken, TransformationToken, TabStopToken, MirrorToken, PythonCodeToken, VimLCodeToken, ShellCodeToken ] -def tokenize(text, indent): - stream = _TextIterator(text) +def tokenize(text, indent, offset): + stream = _TextIterator(text, offset) try: while True: diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_mirror.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_mirror.py new file mode 100755 index 0000000..a78caab --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_mirror.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from UltiSnips.text_objects._base import NoneditableTextObject + +class Mirror(NoneditableTextObject): + """ + A Mirror object mirrors a TabStop that is, text is repeated here + """ + def __init__(self, parent, tabstop, token): + NoneditableTextObject.__init__(self, parent, token) + + self._ts = tabstop + + def _update(self, done, not_done): + if self._ts.is_killed: + self.overwrite("") + self._parent._del_child(self) + return True + + if self._ts not in done: + return False + + self.overwrite(self._get_text()) + return True + + def _get_text(self): + return self._ts.current_text + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_parser.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_parser.py new file mode 100755 index 0000000..6fa5437 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_parser.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from UltiSnips.geometry import Position +from UltiSnips.text_objects._lexer import tokenize, EscapeCharToken, VisualToken, \ + TransformationToken, TabStopToken, MirrorToken, PythonCodeToken, \ + VimLCodeToken, ShellCodeToken +from UltiSnips.text_objects._escaped_char import EscapedChar +from UltiSnips.text_objects._mirror import Mirror +from UltiSnips.text_objects._python_code import PythonCode +from UltiSnips.text_objects._shell_code import ShellCode +from UltiSnips.text_objects._tabstop import TabStop +from UltiSnips.text_objects._transformation import Transformation +from UltiSnips.text_objects._viml_code import VimLCode +from UltiSnips.text_objects._visual import Visual + +__all__ = ["TOParser"] + +class TOParser(object): + TOKEN2TO = { + EscapeCharToken: EscapedChar, + VisualToken: Visual, + ShellCodeToken: ShellCode, + PythonCodeToken: PythonCode, + VimLCodeToken: VimLCode, + } + + def __init__(self, parent_to, text, indent): + """ + The parser is responsible for turning tokens into Real TextObjects + """ + self._indent = indent + self._parent_to = parent_to + self._text = text + + def parse(self, add_ts_zero = False): + seen_ts = {} + all_tokens = [] + + self._do_parse(all_tokens, seen_ts) + + self._resolve_ambiguity(all_tokens, seen_ts) + self._create_objects_with_links_to_tabs(all_tokens, seen_ts) + + if add_ts_zero and 0 not in seen_ts: + mark = all_tokens[-1][1].end # Last token is always EndOfText + m1 = Position(mark.line, mark.col) + TabStop(self._parent_to, 0, mark, m1) + + self._parent_to.replace_initital_text() + + ##################### + # Private Functions # + ##################### + def _resolve_ambiguity(self, all_tokens, seen_ts): + for parent, token in all_tokens: + if isinstance(token, MirrorToken): + if token.no not in seen_ts: + seen_ts[token.no] = TabStop(parent, token) + else: + Mirror(parent, seen_ts[token.no], token) + + def _create_objects_with_links_to_tabs(self, all_tokens, seen_ts): + for parent, token in all_tokens: + if isinstance(token, TransformationToken): + if token.no not in seen_ts: + raise RuntimeError("Tabstop %i is not known but is used by a Transformation" % token.no) + Transformation(parent, seen_ts[token.no], token) + + def _do_parse(self, all_tokens, seen_ts): + tokens = list(tokenize(self._text, self._indent, self._parent_to.start)) + + for token in tokens: + all_tokens.append((self._parent_to, token)) + + if isinstance(token, TabStopToken): + ts = TabStop(self._parent_to, token) + seen_ts[token.no] = ts + + k = TOParser(ts, token.initial_text, self._indent) + k._do_parse(all_tokens, seen_ts) + else: + klass = self.TOKEN2TO.get(token.__class__, None) + if klass is not None: + klass(self._parent_to, token) + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_python_code.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_python_code.py new file mode 100755 index 0000000..7df1e96 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_python_code.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import os +import re +from collections import namedtuple + +import UltiSnips._vim as _vim +from UltiSnips.compatibility import compatible_exec, as_unicode +from UltiSnips.util import IndentUtil + +from UltiSnips.text_objects._base import NoneditableTextObject + +class _Tabs(object): + def __init__(self, to): + self._to = to + + def __getitem__(self, no): + ts = self._to._get_tabstop(self._to, int(no)) + if ts is None: + return "" + return ts.current_text + +_VisualContent = namedtuple('_VisualContent', ['mode', 'text']) +class SnippetUtil(object): + """ Provides easy access to indentation, etc. + """ + + def __init__(self, initial_indent, vmode, vtext): + self._ind = IndentUtil() + self._visual = _VisualContent(vmode, vtext) + + self._initial_indent = self._ind.indent_to_spaces(initial_indent) + + self._reset("") + + def _reset(self, cur): + """ Gets the snippet ready for another update. + + :cur: the new value for c. + """ + self._ind.reset() + self._c = cur + self._rv = "" + self._changed = False + self.reset_indent() + + def shift(self, amount=1): + """ Shifts the indentation level. + Note that this uses the shiftwidth because thats what code + formatters use. + + :amount: the amount by which to shift. + """ + self.indent += " " * self._ind.sw * amount + + def unshift(self, amount=1): + """ Unshift the indentation level. + Note that this uses the shiftwidth because thats what code + formatters use. + + :amount: the amount by which to unshift. + """ + by = -self._ind.sw * amount + try: + self.indent = self.indent[:by] + except IndexError: + indent = "" + + def mkline(self, line="", indent=None): + """ Creates 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 + # this deals with the fact that the first line is + # already properly indented + if '\n' not in self._rv: + try: + indent = indent[len(self._initial_indent):] + except IndexError: + indent = "" + indent = self._ind.spaces_to_indent(indent) + + return indent + line + + def reset_indent(self): + """ Clears the indentation. """ + self.indent = self._initial_indent + + # Utility methods + @property + def fn(self): + """ The filename. """ + return _vim.eval('expand("%:t")') or "" + + @property + def basename(self): + """ The filename without extension. """ + return _vim.eval('expand("%:t:r")') or "" + + @property + def ft(self): + """ The filetype. """ + return self.opt("&filetype", "") + + # Necessary stuff + def rv(): + """ The return value. + This is a list of lines to insert at the + location of the placeholder. + + Deprecates res. + """ + def fget(self): + return self._rv + def fset(self, value): + self._changed = True + self._rv = value + return locals() + rv = property(**rv()) + + @property + def _rv_changed(self): + """ True if rv has changed. """ + return self._changed + + @property + def c(self): + """ The current text of the placeholder. + + Deprecates cur. + """ + return self._c + + @property + def v(self): + """Content of visual expansions""" + return self._visual + + def opt(self, option, default=None): + """ Gets a Vim variable. """ + if _vim.eval("exists('%s')" % option) == "1": + try: + return _vim.eval(option) + except _vim.error: + pass + return default + + # Syntatic sugar + def __add__(self, value): + """ Appends the given line to rv using mkline. """ + self.rv += '\n' # handles the first line properly + self.rv += self.mkline(value) + return self + + def __lshift__(self, other): + """ Same as unshift. """ + self.unshift(other) + + def __rshift__(self, other): + """ Same as shift. """ + self.shift(other) + + +class PythonCode(NoneditableTextObject): + def __init__(self, parent, token): + code = token.code.replace("\\`", "`") + + # Find our containing snippet for snippet local data + snippet = parent + while snippet: + try: + self._locals = snippet.locals + t = snippet.visual_content.text + m = snippet.visual_content.mode + break + except AttributeError: + snippet = snippet._parent + self._snip = SnippetUtil(token.indent, m, t) + + self._globals = {} + globals = snippet.globals.get("!p", []) + compatible_exec("\n".join(globals).replace("\r\n", "\n"), self._globals) + + # Add Some convenience to the code + self._code = "import re, os, vim, string, random\n" + code + + NoneditableTextObject.__init__(self, parent, token) + + def _update(self, done, not_done): + path = _vim.eval('expand("%")') + if path is None: + path = "" + fn = os.path.basename(path) + + ct = self.current_text + self._snip._reset(ct) + local_d = self._locals + + local_d.update({ + 't': _Tabs(self._parent), + 'fn': fn, + 'path': path, + 'cur': ct, + 'res': ct, + 'snip' : self._snip, + }) + + compatible_exec(self._code, self._globals, local_d) + + rv = as_unicode(self._snip.rv if self._snip._rv_changed + else as_unicode(local_d['res'])) + + if ct != rv: + self.overwrite(rv) + return False + return True + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_shell_code.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_shell_code.py new file mode 100755 index 0000000..22d57bc --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_shell_code.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import os +import subprocess +import stat +import tempfile + +from UltiSnips.compatibility import as_unicode +from UltiSnips.text_objects._base import NoneditableTextObject + +class ShellCode(NoneditableTextObject): + def __init__(self, parent, token): + NoneditableTextObject.__init__(self, parent, token) + + self._code = token.code.replace("\\`", "`") + + def _update(self, done, not_done): + # Write the code to a temporary file + handle, path = tempfile.mkstemp(text=True) + os.write(handle, self._code.encode("utf-8")) + os.close(handle) + os.chmod(path, stat.S_IRWXU) + + # Execute the file and read stdout + proc = subprocess.Popen(path, shell=True, stdout=subprocess.PIPE) + proc.wait() + output = as_unicode(proc.stdout.read()) + + if len(output) and output[-1] == '\n': + output = output[:-1] + if len(output) and output[-1] == '\r': + output = output[:-1] + + os.unlink(path) + + self.overwrite(output) + self._parent._del_child(self) + + return True + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_snippet_instance.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_snippet_instance.py new file mode 100755 index 0000000..8b5bfc4 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_snippet_instance.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from UltiSnips.geometry import Position +import UltiSnips._vim as _vim + +from UltiSnips.text_objects._base import EditableTextObject, NoneditableTextObject +from UltiSnips.text_objects._parser import TOParser + +class SnippetInstance(EditableTextObject): + """ + A Snippet instance is an instance of a Snippet Definition. That is, + when the user expands a snippet, a SnippetInstance is created to + keep track of the corresponding TextObjects. The Snippet itself is + also a TextObject because it has a start an end + """ + + def __init__(self, parent, indent, initial_text, start, end, visual_content, last_re, globals): + if start is None: + start = Position(0,0) + if end is None: + end = Position(0,0) + + self._cts = 0 + + self.locals = {"match" : last_re} + self.globals = globals + self.visual_content = visual_content + + EditableTextObject.__init__(self, parent, start, end, initial_text) + + TOParser(self, initial_text, indent).parse(True) + + self.update_textobjects() + + def replace_initital_text(self): + def _place_initial_text(obj): + obj.overwrite() + + if isinstance(obj, EditableTextObject): + for c in obj._childs: + _place_initial_text(c) + + _place_initial_text(self) + + def replay_user_edits(self, cmds): + """Replay the edits the user has done to keep endings of our + Text objects in sync with reality""" + for cmd in cmds: + self._do_edit(cmd) + + def update_textobjects(self): + """Update the text objects that should change automagically after + the users edits have been replayed. This might also move the Cursor + """ + vc = _VimCursor(self) + + done = set() + not_done = set() + def _find_recursive(obj): + if isinstance(obj, EditableTextObject): + for c in obj._childs: + _find_recursive(c) + not_done.add(obj) + _find_recursive(self) + + counter = 10 + while (done != not_done) and counter: + for obj in sorted(not_done - done): # Order matters for python locals! + if obj._update(done, not_done): + done.add(obj) + counter -= 1 + if counter == 0: + raise RuntimeError("Cyclic dependency in Snippet definition!") + + vc.to_vim() + self._del_child(vc) + + def select_next_tab(self, backwards = False): + if self._cts is None: + return + + if backwards: + cts_bf = self._cts + + res = self._get_prev_tab(self._cts) + if res is None: + self._cts = cts_bf + return self._tabstops.get(self._cts, None) + self._cts, ts = res + return ts + else: + res = self._get_next_tab(self._cts) + if res is None: + self._cts = None + return self._tabstops.get(0, None) + else: + self._cts, ts = res + return ts + + return self._tabstops[self._cts] + + def _get_tabstop(self, requester, no): + # SnippetInstances are completely self contained, therefore, we do not + # need to ask our parent for Tabstops + p = self._parent + self._parent = None + rv = EditableTextObject._get_tabstop(self, requester, no) + self._parent = p + + return rv + + +class _VimCursor(NoneditableTextObject): + """Helper class to keep track of the Vim Cursor""" + + def __init__(self, parent): + NoneditableTextObject.__init__( + self, parent, _vim.buf.cursor, _vim.buf.cursor, tiebreaker = Position(0,0), + ) + + def to_vim(self): + assert(self._start == self._end) + _vim.buf.cursor = self._start + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_tabstop.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_tabstop.py new file mode 100755 index 0000000..c6ed97e --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_tabstop.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from UltiSnips.text_objects._base import EditableTextObject + +__all__ = ['EditableTextObject'] + +class TabStop(EditableTextObject): + """ + This is the most important TextObject. A TabStop is were the cursor + comes to rest when the user taps through the Snippet. + """ + def __init__(self, parent, token, start = None, end = None): + if start is not None: + self._no = token + EditableTextObject.__init__(self, parent, start, end) + else: + self._no = token.no + EditableTextObject.__init__(self, parent, token) + parent._tabstops[self._no] = self + + @property + def no(self): + return self._no + + @property + def is_killed(self): + return self._parent is None + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_transformation.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_transformation.py new file mode 100755 index 0000000..db77236 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_transformation.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import re + +from UltiSnips.text_objects._mirror import Mirror + +class _CleverReplace(object): + """ + This class mimics TextMates replace syntax + """ + _DOLLAR = re.compile(r"\$(\d+)", re.DOTALL) + _SIMPLE_CASEFOLDINGS = re.compile(r"\\([ul].)", re.DOTALL) + _LONG_CASEFOLDINGS = re.compile(r"\\([UL].*?)\\E", re.DOTALL) + _CONDITIONAL = re.compile(r"\(\?(\d+):", re.DOTALL) + + _UNESCAPE = re.compile(r'\\[^ntrab]') + _SCHARS_ESCPAE = re.compile(r'\\[ntrab]') + + def __init__(self, s): + self._s = s + + def _scase_folding(self, m): + if m.group(1)[0] == 'u': + return m.group(1)[-1].upper() + else: + return m.group(1)[-1].lower() + def _lcase_folding(self, m): + if m.group(1)[0] == 'U': + return m.group(1)[1:].upper() + else: + return m.group(1)[1:].lower() + + def _replace_conditional(self, match, v): + def _find_closingbrace(v,start_pos): + bracks_open = 1 + for idx, c in enumerate(v[start_pos:]): + if c == '(': + if v[idx+start_pos-1] != '\\': + bracks_open += 1 + elif c == ')': + if v[idx+start_pos-1] != '\\': + bracks_open -= 1 + if not bracks_open: + return start_pos+idx+1 + m = self._CONDITIONAL.search(v) + + def _part_conditional(v): + bracks_open = 0 + args = [] + carg = "" + for idx, c in enumerate(v): + if c == '(': + if v[idx-1] != '\\': + bracks_open += 1 + elif c == ')': + if v[idx-1] != '\\': + bracks_open -= 1 + elif c == ':' and not bracks_open and not v[idx-1] == '\\': + args.append(carg) + carg = "" + continue + carg += c + args.append(carg) + return args + + while m: + start = m.start() + end = _find_closingbrace(v,start+4) + args = _part_conditional(v[start+4:end-1]) + + rv = "" + if match.group(int(m.group(1))): + rv = self._unescape(self._replace_conditional(match,args[0])) + elif len(args) > 1: + rv = self._unescape(self._replace_conditional(match,args[1])) + + v = v[:start] + rv + v[end:] + + m = self._CONDITIONAL.search(v) + return v + + def _unescape(self, v): + return self._UNESCAPE.subn(lambda m: m.group(0)[-1], v)[0] + def _schar_escape(self, v): + return self._SCHARS_ESCPAE.subn(lambda m: eval(r"'\%s'" % m.group(0)[-1]), v)[0] + + def replace(self, match): + start, end = match.span() + + tv = self._s + + # Replace all $? with capture groups + tv = self._DOLLAR.subn(lambda m: match.group(int(m.group(1))), tv)[0] + + # Replace CaseFoldings + tv = self._SIMPLE_CASEFOLDINGS.subn(self._scase_folding, tv)[0] + tv = self._LONG_CASEFOLDINGS.subn(self._lcase_folding, tv)[0] + tv = self._replace_conditional(match, tv) + + return self._unescape(self._schar_escape(tv)) + +class TextObjectTransformation(object): + def __init__(self, token): + self._find = None + if token.search is None: + return + + flags = 0 + self._match_this_many = 1 + if token.options: + if "g" in token.options: + self._match_this_many = 0 + if "i" in token.options: + flags |= re.IGNORECASE + + self._find = re.compile(token.search, flags | re.DOTALL) + self._replace = _CleverReplace(token.replace) + + def _transform(self, text): + if self._find is None: + return text + return self._find.subn(self._replace.replace, text, self._match_this_many)[0] + +class Transformation(Mirror, TextObjectTransformation): + def __init__(self, parent, ts, token): + Mirror.__init__(self, parent, ts, token) + TextObjectTransformation.__init__(self, token) + + def _get_text(self): + return self._transform(self._ts.current_text) + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_viml_code.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_viml_code.py new file mode 100755 index 0000000..682b0b7 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_viml_code.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +import UltiSnips._vim as _vim +from UltiSnips.text_objects._base import NoneditableTextObject + +class VimLCode(NoneditableTextObject): + def __init__(self, parent, token): + self._code = token.code.replace("\\`", "`").strip() + + NoneditableTextObject.__init__(self, parent, token) + + def _update(self, done, not_done): + self.overwrite(_vim.eval(self._code)) + return True + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_visual.py b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_visual.py new file mode 100755 index 0000000..6133664 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/text_objects/_visual.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import re + +import UltiSnips._vim as _vim +from UltiSnips.util import IndentUtil +from UltiSnips.text_objects._transformation import TextObjectTransformation +from UltiSnips.text_objects._base import NoneditableTextObject + +class Visual(NoneditableTextObject,TextObjectTransformation): + """ + A ${VISUAL} placeholder that will use the text that was last visually + selected and insert it here. If there was no text visually selected, + this will be the empty string + """ + __REPLACE_NON_WS = re.compile(r"[^ \t]") + + def __init__(self, parent, token): + # Find our containing snippet for visual_content + snippet = parent + while snippet: + try: + self._text = snippet.visual_content.text + self._mode = snippet.visual_content.mode + break + except AttributeError: + snippet = snippet._parent + if not self._text: + self._text = token.alternative_text + self._mode = "v" + + NoneditableTextObject.__init__(self, parent, token) + TextObjectTransformation.__init__(self, token) + + def _update(self, done, not_done): + if self._mode != "v": + # Keep the indent for Line/Block Selection + text_before = _vim.buf[self.start.line][:self.start.col] + indent = self.__REPLACE_NON_WS.sub(" ", text_before) + iu = IndentUtil() + indent = iu.indent_to_spaces(indent) + indent = iu.spaces_to_indent(indent) + text = "" + for idx, line in enumerate(self._text.splitlines(True)): + if idx != 0: + text += indent + text += line + text = text[:-1] # Strip final '\n' + else: + text = self._text + + text = self._transform(text) + self.overwrite(text) + self._parent._del_child(self) + + return True + + diff --git a/vim/bundle/ultisnips/plugin/UltiSnips/util.py b/vim/bundle/ultisnips/plugin/UltiSnips/util.py new file mode 100644 index 0000000..bb1bef2 --- /dev/null +++ b/vim/bundle/ultisnips/plugin/UltiSnips/util.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import os +import types + +import UltiSnips._vim as _vim + +class IndentUtil(object): + """ Utility class for dealing properly with indentation. """ + + def __init__(self): + self.reset() + + def reset(self): + """ Gets the spacing properties from Vim. """ + self.sw = int(_vim.eval("&sw")) + self.sts = int(_vim.eval("&sts")) + self.et = (_vim.eval("&expandtab") == "1") + self.ts = int(_vim.eval("&ts")) + + def ntabs_to_proper_indent(self, ntabs): + line_ind = ntabs * self.sw * " " + line_ind = self.indent_to_spaces(line_ind) + line_ind = self.spaces_to_indent(line_ind) + return line_ind + + def indent_to_spaces(self, indent): + """ Converts indentation to spaces respecting Vim settings. """ + indent = indent.expandtabs(self.ts) + right = (len(indent) - len(indent.rstrip(" "))) * " " + indent = indent.replace(" ", "") + indent = indent.replace('\t', " " * self.ts) + return indent + right + + def spaces_to_indent(self, indent): + """ Converts spaces to proper indentation respecting Vim settings """ + if not self.et: + indent = indent.replace(" " * self.ts, '\t') + return indent diff --git a/vim/bundle/ultisnips/syntax/snippets.vim b/vim/bundle/ultisnips/syntax/snippets.vim index d5b31dc..e04a04d 100644 --- a/vim/bundle/ultisnips/syntax/snippets.vim +++ b/vim/bundle/ultisnips/syntax/snippets.vim @@ -6,6 +6,7 @@ if exists("b:current_syntax") endif syntax include @Python syntax/python.vim +syntax include @Viml syntax/vim.vim " global matches syn match snipComment "^#.*" contains=snipTODO @@ -22,11 +23,13 @@ syn match snipExtends "^extends.*" contains=snipKeyword " snippet definitions syn match snipStart "^snippet.*" contained contains=snipKeyword,snipString syn match snipEnd "^endsnippet" contained contains=snipKeyword -syn region snipCommand contained keepend start="`" end="`" contains=snipPythonCommand +syn region snipCommand contained keepend start="`" end="`" contains=snipPythonCommand,snipVimLCommand syn region snipPythonCommand contained keepend start="`!p" end="`" contained contains=@Python +syn region snipVimLCommand contained keepend start="`!v" end="`" contained contains=@Viml syn match snipVar "\$\d" contained +syn region snipVisual matchgroup=Define start="\${VISUAL" end="}" contained syn region snipVarExpansion matchgroup=Define start="\${\d" end="}" contained contains=snipVar,snipVarExpansion,snipCommand -syn region snippet fold keepend start="^snippet" end="^endsnippet" contains=snipStart,snipEnd,snipTabsOnly,snipCommand,snipVarExpansion,snipVar +syn region snippet fold keepend start="^snippet" end="^endsnippet" contains=snipStart,snipEnd,snipTabsOnly,snipCommand,snipVarExpansion,snipVar,snipVisual " global definitions syn match snipGlobalStart "^global.*" contained contains=snipKeyword,snipString @@ -48,6 +51,7 @@ hi link snipEnd Statement hi link snipCommand Special hi link snipVar StorageClass hi link snipVarExpansion Normal +hi link snipVisual Normal hi link snippet Normal hi link snipGlobalStart Statement diff --git a/vim/bundle/ultisnips/test.py b/vim/bundle/ultisnips/test.py index b4f4e06..fcb4aeb 100755 --- a/vim/bundle/ultisnips/test.py +++ b/vim/bundle/ultisnips/test.py @@ -24,6 +24,10 @@ # The testsuite will use ``screen`` to inject commands into the Vim under test, # and will compare the resulting output to expected results. # +# Under windows, COM's SendKeys is used to send keystrokes to the gvim window. +# Note that Gvim must use english keyboard input (choose in windows registry) +# for this to work properly as SendKeys is a piece of chunk. (i.e. it sends +# when you send a | symbol while using german key mappings) import os import tempfile @@ -33,10 +37,10 @@ import platform import sys -WIN = platform.system() == "Windows" - from textwrap import dedent +WIN = platform.system() == "Windows" + # Some constants for better reading BS = '\x7f' ESC = '\x1b' @@ -192,6 +196,7 @@ def check_output(self): if self.output != wanted: # Redo this, but slower self.sleeptime += 0.02 + self.send(ESC) self.setUp() self.assertEqual(self.output, wanted) @@ -216,8 +221,6 @@ def setUp(self): if self.skip_on_mac and system == "Darwin": return self._skip("Running on Darwin/Mac") - self.send(ESC) - # Close all scratch buffers self.send(":silent! close\n") @@ -257,8 +260,6 @@ def setUp(self): self.send(self.text_before + '\n\n') self.send('\n\n' + self.text_after) - self.send(ESC) - # Go to the middle of the buffer self.send(ESC + "ggjj") @@ -277,7 +278,7 @@ def setUp(self): os.close(handle) os.unlink(fn) - self.send(ESC + ":w! %s\n" % fn) + self.send(":w! %s\n" % fn) # Read the output, chop the trailing newline tries = 50 @@ -288,9 +289,222 @@ def setUp(self): time.sleep(.05) tries -= 1 -################## -# Simple Expands # -################## +########################################################################### +# BEGINNING OF TEST # +########################################################################### +# Snippet Definition Parsing {{{# +class _PS_Base(_VimTest): + def _options_on(self): + self.send(":let UltiSnipsDoHash=0\n") + def _options_off(self): + self.send(":unlet UltiSnipsDoHash\n") + +class ParseSnippets_SimpleSnippet(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet testsnip "Test Snippet" b! + This is a test snippet! + endsnippet + """) + keys = "testsnip" + EX + wanted = "This is a test snippet!" + +class ParseSnippets_MissingEndSnippet(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet testsnip "Test Snippet" b! + This is a test snippet! + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = dedent(""" + UltiSnips: Missing 'endsnippet' for 'testsnip' in test_file(5) + """).strip() + +class ParseSnippets_UnknownDirective(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + unknown directive + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = dedent(""" + UltiSnips: Invalid line 'unknown directive' in test_file(2) + """).strip() + +class ParseSnippets_ExtendsWithoutFiletype(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + extends + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = dedent(""" + UltiSnips: 'extends' without file types in test_file(2) + """).strip() + +class ParseSnippets_ClearAll(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet testsnip "Test snippet" + This is a test. + endsnippet + + clearsnippets + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + +class ParseSnippets_ClearOne(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet testsnip "Test snippet" + This is a test. + endsnippet + + snippet toclear "Snippet to clear" + Do not expand. + endsnippet + + clearsnippets toclear + """) + keys = "toclear" + EX + "\n" + "testsnip" + EX + wanted = "toclear" + EX + "\n" + "This is a test." + +class ParseSnippets_ClearTwo(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet testsnip "Test snippet" + This is a test. + endsnippet + + snippet toclear "Snippet to clear" + Do not expand. + endsnippet + + clearsnippets testsnip toclear + """) + keys = "toclear" + EX + "\n" + "testsnip" + EX + wanted = "toclear" + EX + "\n" + "testsnip" + EX + + +class _ParseSnippets_MultiWord(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet /test snip/ + This is a test. + endsnippet + + snippet !snip test! "Another snippet" + This is another test. + endsnippet + + snippet "snippet test" "Another snippet" b + This is yet another test. + endsnippet + """) +class ParseSnippets_MultiWord_Simple(_ParseSnippets_MultiWord): + keys = "test snip" + EX + wanted = "This is a test." +class ParseSnippets_MultiWord_Description(_ParseSnippets_MultiWord): + keys = "snip test" + EX + wanted = "This is another test." +class ParseSnippets_MultiWord_Description_Option(_ParseSnippets_MultiWord): + keys = "snippet test" + EX + wanted = "This is yet another test." + +class _ParseSnippets_MultiWord_RE(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet /[d-f]+/ "" r + az test + endsnippet + + snippet !^(foo|bar)$! "" r + foo-bar test + endsnippet + + snippet "(test ?)+" "" r + re-test + endsnippet + """) +class ParseSnippets_MultiWord_RE1(_ParseSnippets_MultiWord_RE): + keys = "abc def" + EX + wanted = "abc az test" +class ParseSnippets_MultiWord_RE2(_ParseSnippets_MultiWord_RE): + keys = "foo" + EX + " bar" + EX + "\nbar" + EX + wanted = "foo-bar test bar\t\nfoo-bar test" +class ParseSnippets_MultiWord_RE3(_ParseSnippets_MultiWord_RE): + keys = "test test test" + EX + wanted = "re-test" + +class ParseSnippets_MultiWord_Quotes(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet "test snip" + This is a test. + endsnippet + """) + keys = "test snip" + EX + wanted = "This is a test." +class ParseSnippets_MultiWord_WithQuotes(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet !"test snip"! + This is a test. + endsnippet + """) + keys = '"test snip"' + EX + wanted = "This is a test." + +class ParseSnippets_MultiWord_NoContainer(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet test snip + This is a test. + endsnippet + """) + keys = "test snip" + EX + wanted = keys + expected_error = dedent(""" + UltiSnips: Invalid multiword trigger: 'test snip' in test_file(2) + """).strip() + +class ParseSnippets_MultiWord_UnmatchedContainer(_PS_Base): + snippets_test_file = ("all", "test_file", r""" + snippet !inv snip/ + This is a test. + endsnippet + """) + keys = "inv snip" + EX + wanted = keys + expected_error = dedent(""" + UltiSnips: Invalid multiword trigger: '!inv snip/' in test_file(2) + """).strip() + +class ParseSnippets_Global_Python(_PS_Base): + 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(_PS_Base): + 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: Snippet Definition Parsing #}}} + +# Simple Expands {{{# class _SimpleExpands(_VimTest): snippets = ("hallo", "Hallo Welt!") @@ -337,105 +551,39 @@ class MultilineExpandTestTyping_ExceptCorrectResult(_VimTest): snippets = ("hallo", "Hallo Welt!\nUnd Wie gehts") wanted = "Wie Hallo Welt!\nUnd Wie gehtsHuiui! gehts" keys = "Wie hallo gehts" + ESC + "bhi" + EX + "Huiui!" +class SimpleExpandEndingWithNewline_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "Hallo Welt\n") + keys = "hallo" + EX + "\nAnd more" + wanted = "Hallo Welt\n\nAnd more" -######################## -# Format options tests # -######################## -class _FormatoptionsBase(_VimTest): - def _options_on(self): - self.send(":set tw=20\n") - def _options_off(self): - self.send(":set tw=0\n") - -class FOSimple_WithoutBreak_ExceptCorrectResult(_FormatoptionsBase): - snippets = ("test", "${1:longer expand}\n$0") - keys = "test" + EX + "This is a longer text that should not wrap as formatoptions are disabled" - wanted = "This is a longer text that should not wrap as formatoptions are disabled\n" - -class FO_WithoutBreakEnableAfterSnippet_ExceptCorrectResult(_FormatoptionsBase): - snippets = ("test", "${1:longer expand}\n") - keys = "test" + EX + "This is a longer text that should not wrap as formatoptions are disabled" \ - + JF + "This is a longer text that should wrap" - wanted = "This is a longer text that should not wrap as formatoptions are disabled\n" + \ - "This is a longer\ntext that should\nwrap" +# End: Simple Expands #}}} +# TabStop Tests {{{# +class TabStopSimpleReplace_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo ${0:End} ${1:Beginning}") + keys = "hallo" + EX + "na" + JF + "Du Nase" + wanted = "hallo Du Nase na" +class TabStopSimpleReplaceReversed_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo ${1:End} ${0:Beginning}") + keys = "hallo" + EX + "na" + JF + "Du Nase" + wanted = "hallo na Du Nase" +class TabStopSimpleReplaceSurrounded_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo ${0:End} a small feed") + keys = "hallo" + EX + "Nase" + wanted = "hallo Nase a small feed" +class TabStopSimpleReplaceSurrounded1_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo $0 a small feed") + keys = "hallo" + EX + "Nase" + wanted = "hallo Nase a small feed" +class TabStop_Exit_ExceptCorrectResult(_VimTest): + snippets = ("echo", "$0 run") + keys = "echo" + EX + "test" + wanted = "test run" -class FOSimple_WithBreak_ExceptCorrectResult(_FormatoptionsBase): - snippets = ("test", "${1:longer expand}\n$0", "", "f") - keys = "test" + EX + "This is a longer text that should wrap" - wanted = "This is a longer\ntext that should\nwrap\n" - -class FOTextBeforeAndAfter_ExceptCorrectResult(_FormatoptionsBase): - snippets = ("test", "Before${1:longer expand}After\nstart$1end", "", "f") - keys = "test" + EX + "This is a longer text that should wrap" - wanted = \ -"""BeforeThis is a -longer text that -should wrapAfter -startThis is a -longer text that -should wrapend""" - - -class FOTextAfter_ExceptCorrectResult(_FormatoptionsBase): - """Testcase for lp:719998""" - snippets = ("test", "${1:longer expand}after\nstart$1end", "", "f") - keys = ("test" + EX + "This is a longer snippet that should wrap properly " - "and the mirror below should work as well") - wanted = \ -"""This is a longer -snippet that should -wrap properly and -the mirror below -should work as wellafter -startThis is a longer -snippet that should -wrap properly and -the mirror below -should work as wellend""" - -class FOWrapOnLongWord_ExceptCorrectResult(_FormatoptionsBase): - """Testcase for lp:719998""" - snippets = ("test", "${1:longer expand}after\nstart$1end", "", "f") - keys = ("test" + EX + "This is a longersnippet that should wrap properly") - wanted = \ -"""This is a -longersnippet that -should wrap properlyafter -startThis is a -longersnippet that -should wrap properlyend""" - -############ -# TabStops # -############ -class TabStopSimpleReplace_ExceptCorrectResult(_VimTest): - snippets = ("hallo", "hallo ${0:End} ${1:Beginning}") - keys = "hallo" + EX + "na" + JF + "Du Nase" - wanted = "hallo Du Nase na" -class TabStopSimpleReplaceSurrounded_ExceptCorrectResult(_VimTest): - snippets = ("hallo", "hallo ${0:End} a small feed") - keys = "hallo" + EX + "Nase" - wanted = "hallo Nase a small feed" -class TabStopSimpleReplaceSurrounded1_ExceptCorrectResult(_VimTest): - snippets = ("hallo", "hallo $0 a small feed") - keys = "hallo" + EX + "Nase" - wanted = "hallo Nase a small feed" -class TabStopSimpleReplaceEndingWithNewline_ExceptCorrectResult(_VimTest): - snippets = ("hallo", "Hallo Welt\n") - keys = "hallo" + EX + "\nAnd more" - wanted = "Hallo Welt\n\nAnd more" - - -class ExitTabStop_ExceptCorrectResult(_VimTest): - snippets = ("echo", "$0 run") - keys = "echo" + EX + "test" - wanted = "test run" - -class TabStopNoReplace_ExceptCorrectResult(_VimTest): - snippets = ("echo", "echo ${1:Hallo}") - keys = "echo" + EX - wanted = "echo Hallo" +class TabStopNoReplace_ExceptCorrectResult(_VimTest): + snippets = ("echo", "echo ${1:Hallo}") + keys = "echo" + EX + wanted = "echo Hallo" class TabStop_EscapingCharsBackticks(_VimTest): snippets = ("test", r"snip \` literal") @@ -492,26 +640,6 @@ class TabStopEscapingWhenSelectedNoCharTS_ECR(_VimTest): keys = "test" + EX + ESC + "0ihi" wanted = "hisnip " -class TabStopUsingBackspaceToDeleteDefaultValue_ECR(_VimTest): - snippets = ("test", "snip ${1/.+/(?0:matched)/} ${1:default}") - keys = "test" + EX + BS - wanted = "snip " -class TabStopUsingBackspaceToDeleteDefaultValueInFirstTab_ECR(_VimTest): - sleeptime = 0.09 # Do this very slowly - snippets = ("test", "snip ${1/.+/(?0:m1)/} ${2/.+/(?0:m2)/} " - "${1:default} ${2:def}") - keys = "test" + EX + BS + JF + "hi" - wanted = "snip m2 hi" -class TabStopUsingBackspaceToDeleteDefaultValueInSecondTab_ECR(_VimTest): - snippets = ("test", "snip ${1/.+/(?0:m1)/} ${2/.+/(?0:m2)/} " - "${1:default} ${2:def}") - keys = "test" + EX + "hi" + JF + BS - wanted = "snip m1 hi " -class TabStopUsingBackspaceToDeleteDefaultValueTypeSomethingThen_ECR(_VimTest): - snippets = ("test", "snip ${1/.+/(?0:matched)/} ${1:default}") - keys = "test" + EX + BS + "hallo" - wanted = "snip matched hallo" - class TabStopWithOneChar_ExceptCorrectResult(_VimTest): snippets = ("hallo", "nothing ${1:i} hups") keys = "hallo" + EX + "ship" @@ -530,7 +658,7 @@ class TabStopTestJumpingRLExampleWithZeroTab_ExceptCorrectResult(_VimTest): keys = "test" + EX + JF + "Blah" wanted = "each_byte { |byte| Blah }" -class TestJumpingDontJumpToEndIfThereIsTabZero_ExceptCorrectResult(_VimTest): +class TabStopTestJumpingDontJumpToEndIfThereIsTabZero_ExceptCorrectResult(_VimTest): snippets = ("hallo", "hallo $0 $1") keys = "hallo" + EX + "Test" + JF + "Hi" + JF + JF + "du" wanted = "hallo Hidu Test" @@ -557,7 +685,7 @@ class TabStop_TSInDefaultTextRLExample_OverwriteNone_ECR(_VimTest): snippets = ("test", """\n $0\n""") keys = "test" + EX wanted = """
\n \n
""" -class TabStop_TSInDefaultTextRLExample_OverwriteFirst(_VimTest): +class TabStop_TSInDefaultTextRLExample_OverwriteFirst_NoJumpBack(_VimTest): snippets = ("test", """\n $0\n""") keys = "test" + EX + " blah" + JF + "Hallo" wanted = """
\n Hallo\n
""" @@ -585,6 +713,27 @@ class TabStop_TSInDefaultTextRLExample_OverwriteSecondTabBackTwice(_VimTest): " allaway" + JF + "Third" + JF + "Last" wanted = """
\n Third Last\n
""" +class TabStop_TSInDefaultText_ZeroLengthNested_OverwriteSecond(_VimTest): + snippets = ("test", """h${1:a$2b}l""") + keys = "test" + EX + JF + "ups" + JF + "End" + wanted = """haupsblEnd""" +class TabStop_TSInDefaultText_ZeroLengthNested_OverwriteFirst(_VimTest): + snippets = ("test", """h${1:a$2b}l""") + keys = "test" + EX + "ups" + JF + "End" + wanted = """hupslEnd""" +class TabStop_TSInDefaultText_ZeroLengthNested_OverwriteSecondJumpBackOverwrite(_VimTest): + snippets = ("test", """h${1:a$2b}l""") + keys = "test" + EX + JF + "longertext" + JB + "overwrite" + JF + "End" + wanted = """hoverwritelEnd""" +class TabStop_TSInDefaultText_ZeroLengthNested_OverwriteSecondJumpBackAndForward0(_VimTest): + snippets = ("test", """h${1:a$2b}l""") + keys = "test" + EX + JF + "longertext" + JB + JF + "overwrite" + JF + "End" + wanted = """haoverwriteblEnd""" +class TabStop_TSInDefaultText_ZeroLengthNested_OverwriteSecondJumpBackAndForward1(_VimTest): + snippets = ("test", """h${1:a$2b}l""") + keys = "test" + EX + JF + "longertext" + JB + JF + JF + "End" + wanted = """halongertextblEnd""" + class TabStop_TSInDefaultNested_OverwriteOneJumpBackToOther(_VimTest): snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") keys = "test" + EX + JF + "Hallo" + JF + "Ende" @@ -606,7 +755,7 @@ class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond(_VimTest): snippets = ("test", "hi ${1:this ${2:second}} $2") keys = "test" + EX + JF + "Hallo" wanted = "hi this Hallo Hallo" -class TabStop_TSInDefault_MirrorsOutside_Overwrite(_VimTest): +class TabStop_TSInDefault_MirrorsOutside_Overwrite0(_VimTest): snippets = ("test", "hi ${1:this ${2:second}} $2") keys = "test" + EX + "Hallo" wanted = "hi Hallo " @@ -652,9 +801,12 @@ class TabStop_Multiline_DelFirstOverwriteSecond_Overwrite(_VimTest): keys = "test" + EX + BS + JF + "Nothing" wanted = "hi Nothing Nothing world" -########################### -# ShellCode Interpolation # -########################### +class TabStopNavigatingInInsertModeSimple_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "Hallo ${1:WELT} ups") + keys = "hallo" + EX + "haselnut" + 2*ARR_L + "hips" + JF + "end" + wanted = "Hallo haselnhipsut upsend" +# End: TabStop Tests #}}} +# ShellCode Interpolation {{{# class TabStop_Shell_SimpleExample(_VimTest): skip_on_windows = True snippets = ("test", "hi `echo hallo` you!") @@ -667,7 +819,6 @@ class TabStop_Shell_TextInNextLine(_VimTest): wanted = "hi hallo\nWeiterand more" class TabStop_Shell_InDefValue_Leave(_VimTest): skip_on_windows = True - sleeptime = 0.09 # Do this very slowly snippets = ("test", "Hallo ${1:now `echo fromecho`} end") keys = "test" + EX + JF + "and more" wanted = "Hallo now fromecho endand more" @@ -689,18 +840,20 @@ class TabStop_Shell_TestEscapedCharsAndShellVars_Overwrite(_VimTest): class TabStop_Shell_ShebangPython(_VimTest): skip_on_windows = True - sleeptime = 0.09 # Do this very slowly snippets = ("test", """Hallo ${1:now `#!/usr/bin/env python print "Hallo Welt" `} end""") keys = "test" + EX + JF + "and more" wanted = "Hallo now Hallo Welt endand more" - -############################ -# PythonCode Interpolation # -############################ - -#### Deprecated way ########## +# End: ShellCode Interpolation #}}} +# VimScript Interpolation {{{# +class TabStop_VimScriptInterpolation_SimpleExample(_VimTest): + snippets = ("test", """hi `!v indent(".")` End""") + keys = " test" + EX + wanted = " hi 4 End" +# End: VimScript Interpolation #}}} +# PythonCode Interpolation {{{# +# Deprecated Implementation {{{# class PythonCodeOld_SimpleExample(_VimTest): snippets = ("test", """hi `!p res = "Hallo"` End""") keys = "test" + EX @@ -727,9 +880,8 @@ class PythonCodeOld_IndentedMultiline(_VimTest): res = "a isbigger b"` end""") keys = " test" + EX wanted = " start b isbigger a end" - -#### New way ########## - +# End: Deprecated Implementation #}}} +# New Implementation {{{# class PythonCode_UseNewOverOld(_VimTest): snippets = ("test", """hi `!p res = "Old" snip.rv = "New"` End""") @@ -741,7 +893,6 @@ class PythonCode_SimpleExample(_VimTest): keys = "test" + EX wanted = "hi Hallo End" - class PythonCode_SimpleExample_ReturnValueIsEmptyString(_VimTest): snippets = ("test", """hi`!p snip.rv = ""`End""") keys = "test" + EX @@ -756,13 +907,11 @@ class PythonCode_ReferencePlaceholderBefore(_VimTest): snippets = ("test", """`!p snip.rv = len(t[1])*"#"`\n${1:some text}""") keys = "test" + EX + "Hallo Welt" wanted = "##########\nHallo Welt" - class PythonCode_TransformedBeforeMultiLine(_VimTest): snippets = ("test", """${1/.+/egal/m} ${1:`!p snip.rv = "Hallo"`} End""") keys = "test" + EX wanted = "egal Hallo End" - class PythonCode_MultilineIndented(_VimTest): snippets = ("test", """start `!p a = 1 b = 2 @@ -786,13 +935,6 @@ class PythonCode_MultiAppend(_VimTest): keys = "test" + EX wanted = "hi Hallo1\nHallo2\nHallo3 End" -class PythonCode_MultiAppend(_VimTest): - snippets = ("test", """hi `!p snip.rv = "Hallo1" -snip += "Hallo2" -snip += "Hallo3"` End""") - keys = "test" + EX - wanted = "hi Hallo1\nHallo2\nHallo3 End" - class PythonCode_MultiAppendSimpleIndent(_VimTest): snippets = ("test", """hi `!p snip.rv="Hallo1" @@ -989,6 +1131,10 @@ class PythonCode_IndentProblem(_VimTest): keys = " " * 8 + "test" + EX # < 8 works. wanted = """ hi World End""" +class PythonCode_TrickyReferences(_VimTest): + snippets = ("test", r"""${2:${1/.+/egal/}} ${1:$3} ${3:`!p snip.rv = "hi"`}""") + keys = "ups test" + EX + wanted = "ups egal hi hi" # locals class PythonCode_Locals(_VimTest): snippets = ("test", r"""hi `!p a = "test" @@ -997,67 +1143,525 @@ class PythonCode_Locals(_VimTest): keys = """test""" + EX wanted = """hi nothing test End""" +class PythonCode_LongerTextThanSource_Chars(_VimTest): + snippets = ("test", r"""hi`!p snip.rv = "a" * 100`end""") + keys = """test""" + EX + JF + "ups" + wanted = "hi" + 100*"a" + "endups" + +class PythonCode_LongerTextThanSource_MultiLine(_VimTest): + snippets = ("test", r"""hi`!p snip.rv = "a" * 100 + '\n'*100 + "a"*100`end""") + keys = """test""" + EX + JF + "ups" + wanted = "hi" + 100*"a" + 100*"\n" + 100*"a" + "endups" + +class PythonCode_AccessKilledTabstop_OverwriteSecond(_VimTest): + snippets = ("test", r"`!p snip.rv = t[2].upper()`${1:h${2:welt}o}`!p snip.rv = t[2].upper()`") + keys = "test" + EX + JF + "okay" + wanted = "OKAYhokayoOKAY" +class PythonCode_AccessKilledTabstop_OverwriteFirst(_VimTest): + snippets = ("test", r"`!p snip.rv = t[2].upper()`${1:h${2:welt}o}`!p snip.rv = t[2].upper()`") + keys = "test" + EX + "aaa" + wanted = "aaa" + +class PythonVisual_NoVisualSelection_Ignore(_VimTest): + snippets = ("test", "h`!p snip.rv = snip.v.mode + snip.v.text`b") + keys = "test" + EX + "abc" + wanted = "hbabc" +class PythonVisual_SelectOneWord(_VimTest): + snippets = ("test", "h`!p snip.rv = snip.v.mode + snip.v.text`b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + wanted = "hvblablubb" +class PythonVisual_LineSelect_Simple(_VimTest): + snippets = ("test", "h`!p snip.rv = snip.v.mode + snip.v.text`b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + wanted = "hVhello\nnice\nworld\nb" +# End: New Implementation #}}} +# End: PythonCode Interpolation #}}} +# Mirrors {{{# +class TextTabStopTextAfterTab_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 Hinten\n$1") + keys = "test" + EX + "hallo" + wanted = "hallo Hinten\nhallo" +class TextTabStopTextBeforeTab_ExceptCorrectResult(_VimTest): + snippets = ("test", "Vorne $1\n$1") + keys = "test" + EX + "hallo" + wanted = "Vorne hallo\nhallo" +class TextTabStopTextSurroundedTab_ExceptCorrectResult(_VimTest): + snippets = ("test", "Vorne $1 Hinten\n$1") + keys = "test" + EX + "hallo test" + wanted = "Vorne hallo test Hinten\nhallo test" +class TextTabStopTextBeforeMirror_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\nVorne $1") + keys = "test" + EX + "hallo" + wanted = "hallo\nVorne hallo" +class TextTabStopAfterMirror_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n$1 Hinten") + keys = "test" + EX + "hallo" + wanted = "hallo\nhallo Hinten" +class TextTabStopSurroundMirror_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\nVorne $1 Hinten") + keys = "test" + EX + "hallo welt" + wanted = "hallo welt\nVorne hallo welt Hinten" +class TextTabStopAllSurrounded_ExceptCorrectResult(_VimTest): + snippets = ("test", "ObenVorne $1 ObenHinten\nVorne $1 Hinten") + keys = "test" + EX + "hallo welt" + wanted = "ObenVorne hallo welt ObenHinten\nVorne hallo welt Hinten" +class MirrorBeforeTabstopLeave_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1:this is it} $1") + keys = "test" + EX + wanted = "this is it this is it this is it" +class MirrorBeforeTabstopOverwrite_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1:this is it} $1") + keys = "test" + EX + "a" + wanted = "a a a" -########################### -# VimScript Interpolation # -########################### -class TabStop_VimScriptInterpolation_SimpleExample(_VimTest): - snippets = ("test", """hi `!v indent(".")` End""") - keys = " test" + EX - wanted = " hi 4 End" - -############# -# EXPANDTAB # -############# -class _ExpandTabs(_VimTest): - def _options_on(self): - self.send(":set sw=3\n") - self.send(":set expandtab\n") - def _options_off(self): - self.send(":set sw=8\n") - self.send(":set noexpandtab\n") +class TextTabStopSimpleMirrorMultiline_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n$1") + keys = "test" + EX + "hallo" + wanted = "hallo\nhallo" +class SimpleMirrorMultilineMany_ExceptCorrectResult(_VimTest): + snippets = ("test", " $1\n$1\na$1b\n$1\ntest $1 mich") + keys = "test" + EX + "hallo" + wanted = " hallo\nhallo\nahallob\nhallo\ntest hallo mich" +class MultilineTabStopSimpleMirrorMultiline_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n\n$1\n\n$1") + keys = "test" + EX + "hallo Du\nHi" + wanted = "hallo Du\nHi\n\nhallo Du\nHi\n\nhallo Du\nHi" +class MultilineTabStopSimpleMirrorMultiline1_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n$1\n$1") + keys = "test" + EX + "hallo Du\nHi" + wanted = "hallo Du\nHi\nhallo Du\nHi\nhallo Du\nHi" +class MultilineTabStopSimpleMirrorDeleteInLine_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n$1\n$1") + keys = "test" + EX + "hallo Du\nHi\b\bAch Blah" + wanted = "hallo Du\nAch Blah\nhallo Du\nAch Blah\nhallo Du\nAch Blah" +class TextTabStopSimpleMirrorMultilineMirrorInFront_ECR(_VimTest): + snippets = ("test", "$1\n${1:sometext}") + keys = "test" + EX + "hallo\nagain" + wanted = "hallo\nagain\nhallo\nagain" -class RecTabStopsWithExpandtab_SimpleExample_ECR(_ExpandTabs): - snippets = ("m", "\tBlaahblah \t\t ") - keys = "m" + EX - wanted = " Blaahblah \t\t " +class SimpleMirrorDelete_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n$1") + keys = "test" + EX + "hallo\b\b" + wanted = "hal\nhal" -class RecTabStopsWithExpandtab_SpecialIndentProblem_ECR(_ExpandTabs): - # Windows indents the Something line after pressing return, though it - # shouldn't because it contains a manual indent. All other vim versions do - # not do this. Windows vim does not interpret the changes made by :py as - # changes made 'manually', while the other vim version seem to do so. Since - # the fault is not with UltiSnips, we simply skip this test on windows - # completely. - skip_on_windows = True - snippets = ( - ("m1", "Something"), - ("m", "\t$0"), - ) - keys = "m" + EX + "m1" + EX + '\nHallo' - wanted = " Something\n Hallo" - def _options_on(self): - _ExpandTabs._options_on(self) - self.send(":set indentkeys=o,O,*,<>>,{,}\n") - self.send(":set indentexpr=8\n") - def _options_off(self): - _ExpandTabs._options_off(self) - self.send(":set indentkeys=\n") - self.send(":set indentexpr=\n") +class SimpleMirrorSameLine_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 $1") + keys = "test" + EX + "hallo" + wanted = "hallo hallo" +class SimpleMirrorSameLine_InText_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 $1") + keys = "ups test blah" + ESC + "02f i" + EX + "hallo" + wanted = "ups hallo hallo blah" +class SimpleMirrorSameLineBeforeTabDefVal_ECR(_VimTest): + snippets = ("test", "$1 ${1:replace me}") + keys = "test" + EX + "hallo foo" + wanted = "hallo foo hallo foo" +class SimpleMirrorSameLineBeforeTabDefVal_DelB4Typing_ECR(_VimTest): + snippets = ("test", "$1 ${1:replace me}") + keys = "test" + EX + BS + "hallo foo" + wanted = "hallo foo hallo foo" +class SimpleMirrorSameLineMany_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 $1 $1 $1") + keys = "test" + EX + "hallo du" + wanted = "hallo du hallo du hallo du hallo du" +class SimpleMirrorSameLineManyMultiline_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 $1 $1 $1") + keys = "test" + EX + "hallo du\nwie gehts" + wanted = "hallo du\nwie gehts hallo du\nwie gehts hallo du\nwie gehts" \ + " hallo du\nwie gehts" +class SimpleMirrorDeleteSomeEnterSome_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1\n$1") + keys = "test" + EX + "hallo\b\bhups" + wanted = "halhups\nhalhups" +class SimpleTabstopWithDefaultSimpelType_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha ${1:defa}\n$1") + keys = "test" + EX + "world" + wanted = "ha world\nworld" +class SimpleTabstopWithDefaultComplexType_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha ${1:default value} $1\nanother: $1 mirror") + keys = "test" + EX + "world" + wanted = "ha world world\nanother: world mirror" +class SimpleTabstopWithDefaultSimpelKeep_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha ${1:defa}\n$1") + keys = "test" + EX + wanted = "ha defa\ndefa" +class SimpleTabstopWithDefaultComplexKeep_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha ${1:default value} $1\nanother: $1 mirror") + keys = "test" + EX + wanted = "ha default value default value\nanother: default value mirror" +class TabstopWithMirrorManyFromAll_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $5 ${1:blub} $4 $0 ${2:$1.h} $1 $3 ${4:More}") + keys = "test" + EX + "hi" + JF + "hu" + JF + "hub" + JF + "hulla" + \ + JF + "blah" + JF + "end" + wanted = "ha blah hi hulla end hu hi hub hulla" +class TabstopWithMirrorInDefaultNoType_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha ${1:blub} ${2:$1.h}") + keys = "test" + EX + wanted = "ha blub blub.h" +class TabstopWithMirrorInDefaultNoType1_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha ${1:blub} ${2:$1}") + keys = "test" + EX + wanted = "ha blub blub" +class TabstopWithMirrorInDefaultTwiceAndExtra_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $1 ${2:$1.h $1.c}\ntest $1") + keys = "test" + EX + "stdin" + wanted = "ha stdin stdin.h stdin.c\ntest stdin" +class TabstopWithMirrorInDefaultMultipleLeave_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $1 ${2:snip} ${3:$1.h $2}") + keys = "test" + EX + "stdin" + wanted = "ha stdin snip stdin.h snip" +class TabstopWithMirrorInDefaultMultipleOverwrite_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $1 ${2:snip} ${3:$1.h $2}") + keys = "test" + EX + "stdin" + JF + "do snap" + wanted = "ha stdin do snap stdin.h do snap" +class TabstopWithMirrorInDefaultOverwrite_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $1 ${2:$1.h}") + keys = "test" + EX + "stdin" + JF + "overwritten" + wanted = "ha stdin overwritten" +class TabstopWithMirrorInDefaultOverwrite1_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $1 ${2:$1}") + keys = "test" + EX + "stdin" + JF + "overwritten" + wanted = "ha stdin overwritten" +class TabstopWithMirrorInDefaultNoOverwrite1_ExceptCorrectResult(_VimTest): + snippets = ("test", "ha $1 ${2:$1}") + keys = "test" + EX + "stdin" + JF + JF + "end" + wanted = "ha stdin stdinend" -############################### -# Recursive (Nested) Snippets # -############################### -class RecTabStops_SimpleCase_ExceptCorrectResult(_VimTest): - snippets = ("m", "[ ${1:first} ${2:sec} ]") - keys = "m" + EX + "m" + EX + "hello" + JF + "world" + JF + "ups" + JF + "end" - wanted = "[ [ hello world ]ups end ]" -class RecTabStops_SimpleCaseLeaveSecondSecond_ExceptCorrectResult(_VimTest): +class MirrorRealLifeExample_ExceptCorrectResult(_VimTest): + snippets = ( + ("for", "for(size_t ${2:i} = 0; $2 < ${1:count}; ${3:++$2})" \ + "\n{\n\t${0:/* code */}\n}"), + ) + keys ="for" + EX + "100" + JF + "avar\b\b\b\ba_variable" + JF + \ + "a_variable *= 2" + JF + "// do nothing" + wanted = """for(size_t a_variable = 0; a_variable < 100; a_variable *= 2) +{ +\t// do nothing +}""" + +class Mirror_TestKill_InsertBefore_NoKill(_VimTest): + snippets = "test", "$1 $1_" + keys = "hallo test" + EX + "auch" + ESC + "wihi" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noauch hinoauch_end" +class Mirror_TestKill_InsertAfter_NoKill(_VimTest): + snippets = "test", "$1 $1_" + keys = "hallo test" + EX + "auch" + ESC + "eiab" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noauch noauchab_end" +class Mirror_TestKill_InsertBeginning_Kill(_VimTest): + snippets = "test", "$1 $1_" + keys = "hallo test" + EX + "auch" + ESC + "wahi" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noauch ahiuch_end" +class Mirror_TestKill_InsertEnd_Kill(_VimTest): + snippets = "test", "$1 $1_" + keys = "hallo test" + EX + "auch" + ESC + "ehihi" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noauch auchih_end" +class Mirror_TestKillTabstop_Kill(_VimTest): + snippets = "test", "welt${1:welt${2:welt}welt} $2" + keys = "hallo test" + EX + "elt" + wanted = "hallo weltelt " + +# End: Mirrors #}}} +# Transformations {{{# +class Transformation_SimpleCase_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/foo/batzl/}") + keys = "test" + EX + "hallo foo boy" + wanted = "hallo foo boy hallo batzl boy" +class Transformation_SimpleCaseNoTransform_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/foo/batzl/}") + keys = "test" + EX + "hallo" + wanted = "hallo hallo" +class Transformation_SimpleCaseTransformInFront_ExceptCorrectResult(_VimTest): + snippets = ("test", "${1/foo/batzl/} $1") + keys = "test" + EX + "hallo foo" + wanted = "hallo batzl hallo foo" +class Transformation_SimpleCaseTransformInFrontDefVal_ECR(_VimTest): + snippets = ("test", "${1/foo/batzl/} ${1:replace me}") + keys = "test" + EX + "hallo foo" + wanted = "hallo batzl hallo foo" +class Transformation_MultipleTransformations_ECR(_VimTest): + snippets = ("test", "${1:Some Text}${1/.+/\\U$0\E/}\n${1/.+/\L$0\E/}") + keys = "test" + EX + "SomE tExt " + wanted = "SomE tExt SOME TEXT \nsome text " +class Transformation_TabIsAtEndAndDeleted_ECR(_VimTest): + snippets = ("test", "${1/.+/is something/}${1:some}") + keys = "hallo test" + EX + "some\b\b\b\b\b" + wanted = "hallo " +class Transformation_TabIsAtEndAndDeleted1_ECR(_VimTest): + snippets = ("test", "${1/.+/is something/}${1:some}") + keys = "hallo test" + EX + "some\b\b\b\bmore" + wanted = "hallo is somethingmore" +class Transformation_TabIsAtEndNoTextLeave_ECR(_VimTest): + snippets = ("test", "${1/.+/is something/}${1}") + keys = "hallo test" + EX + wanted = "hallo " +class Transformation_TabIsAtEndNoTextType_ECR(_VimTest): + snippets = ("test", "${1/.+/is something/}${1}") + keys = "hallo test" + EX + "b" + wanted = "hallo is somethingb" +class Transformation_InsideTabLeaveAtDefault_ECR(_VimTest): + snippets = ("test", r"$1 ${2:${1/.+/(?0:defined $0)/}}") + keys = "test" + EX + "sometext" + JF + wanted = "sometext defined sometext" +class Transformation_InsideTabOvertype_ECR(_VimTest): + snippets = ("test", r"$1 ${2:${1/.+/(?0:defined $0)/}}") + keys = "test" + EX + "sometext" + JF + "overwrite" + wanted = "sometext overwrite" + + +class Transformation_Backreference_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/([ab])oo/$1ull/}") + keys = "test" + EX + "foo boo aoo" + wanted = "foo boo aoo foo bull aoo" +class Transformation_BackreferenceTwice_ExceptCorrectResult(_VimTest): + snippets = ("test", r"$1 ${1/(dead) (par[^ ]*)/this $2 is a bit $1/}") + keys = "test" + EX + "dead parrot" + wanted = "dead parrot this parrot is a bit dead" + +class Transformation_CleverTransformUpercaseChar_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(.)/\\u$1/}") + keys = "test" + EX + "hallo" + wanted = "hallo Hallo" +class Transformation_CleverTransformLowercaseChar_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(.*)/\l$1/}") + keys = "test" + EX + "Hallo" + wanted = "Hallo hallo" +class Transformation_CleverTransformLongUpper_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(.*)/\\U$1\E/}") + keys = "test" + EX + "hallo" + wanted = "hallo HALLO" +class Transformation_CleverTransformLongLower_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(.*)/\L$1\E/}") + keys = "test" + EX + "HALLO" + wanted = "HALLO hallo" + +class Transformation_ConditionalInsertionSimple_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(^a).*/(?0:began with an a)/}") + keys = "test" + EX + "a some more text" + wanted = "a some more text began with an a" +class Transformation_CIBothDefinedNegative_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(?:(^a)|(^b)).*/(?1:yes:no)/}") + keys = "test" + EX + "b some" + wanted = "b some no" +class Transformation_CIBothDefinedPositive_ExceptCorrectResult(_VimTest): + snippets = ("test", "$1 ${1/(?:(^a)|(^b)).*/(?1:yes:no)/}") + keys = "test" + EX + "a some" + wanted = "a some yes" +class Transformation_ConditionalInsertRWEllipsis_ECR(_VimTest): + snippets = ("test", r"$1 ${1/(\w+(?:\W+\w+){,7})\W*(.+)?/$1(?2:...)/}") + keys = "test" + EX + "a b c d e f ghhh h oha" + wanted = "a b c d e f ghhh h oha a b c d e f ghhh h..." +class Transformation_ConditionalInConditional_ECR(_VimTest): + snippets = ("test", r"$1 ${1/^.*?(-)?(>)?$/(?2::(?1:>:.))/}") + keys = "test" + EX + "hallo" + ESC + "$a\n" + \ + "test" + EX + "hallo-" + ESC + "$a\n" + \ + "test" + EX + "hallo->" + wanted = "hallo .\nhallo- >\nhallo-> " + +class Transformation_CINewlines_ECR(_VimTest): + snippets = ("test", r"$1 ${1/, */\n/}") + keys = "test" + EX + "test, hallo" + wanted = "test, hallo test\nhallo" +class Transformation_CITabstop_ECR(_VimTest): + snippets = ("test", r"$1 ${1/, */\t/}") + keys = "test" + EX + "test, hallo" + wanted = "test, hallo test\thallo" +class Transformation_CIEscapedParensinReplace_ECR(_VimTest): + snippets = ("test", r"$1 ${1/hal((?:lo)|(?:ul))/(?1:ha\($1\))/}") + keys = "test" + EX + "test, halul" + wanted = "test, halul test, ha(ul)" + +class Transformation_OptionIgnoreCase_ECR(_VimTest): + snippets = ("test", r"$1 ${1/test/blah/i}") + keys = "test" + EX + "TEST" + wanted = "TEST blah" +class Transformation_OptionReplaceGlobal_ECR(_VimTest): + snippets = ("test", r"$1 ${1/, */-/g}") + keys = "test" + EX + "a, nice, building" + wanted = "a, nice, building a-nice-building" +class Transformation_OptionReplaceGlobalMatchInReplace_ECR(_VimTest): + snippets = ("test", r"$1 ${1/, */, /g}") + keys = "test" + EX + "a, nice, building" + wanted = "a, nice, building a, nice, building" +class TransformationUsingBackspaceToDeleteDefaultValueInFirstTab_ECR(_VimTest): + snippets = ("test", "snip ${1/.+/(?0:m1)/} ${2/.+/(?0:m2)/} " + "${1:default} ${2:def}") + keys = "test" + EX + BS + JF + "hi" + wanted = "snip m2 hi" +class TransformationUsingBackspaceToDeleteDefaultValueInSecondTab_ECR(_VimTest): + snippets = ("test", "snip ${1/.+/(?0:m1)/} ${2/.+/(?0:m2)/} " + "${1:default} ${2:def}") + keys = "test" + EX + "hi" + JF + BS + wanted = "snip m1 hi " +class TransformationUsingBackspaceToDeleteDefaultValueTypeSomethingThen_ECR(_VimTest): + snippets = ("test", "snip ${1/.+/(?0:matched)/} ${1:default}") + keys = "test" + EX + BS + "hallo" + wanted = "snip matched hallo" +class TransformationUsingBackspaceToDeleteDefaultValue_ECR(_VimTest): + snippets = ("test", "snip ${1/.+/(?0:matched)/} ${1:default}") + keys = "test" + EX + BS + wanted = "snip " +class Transformation_TestKill_InsertBefore_NoKill(_VimTest): + snippets = "test", r"$1 ${1/.*/\L$0$0\E/}_" + keys = "hallo test" + EX + "AUCH" + ESC + "wihi" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noAUCH hinoauchnoauch_end" +class Transformation_TestKill_InsertAfter_NoKill(_VimTest): + snippets = "test", r"$1 ${1/.*/\L$0$0\E/}_" + keys = "hallo test" + EX + "AUCH" + ESC + "eiab" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noAUCH noauchnoauchab_end" +class Transformation_TestKill_InsertBeginning_Kill(_VimTest): + snippets = "test", r"$1 ${1/.*/\L$0$0\E/}_" + keys = "hallo test" + EX + "AUCH" + ESC + "wahi" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noAUCH ahiuchauch_end" +class Transformation_TestKill_InsertEnd_Kill(_VimTest): + snippets = "test", r"$1 ${1/.*/\L$0$0\E/}_" + keys = "hallo test" + EX + "AUCH" + ESC + "ehihi" + ESC + "bb" + "ino" + JF + "end" + wanted = "hallo noAUCH auchauchih_end" +# End: Transformations #}}} +# ${VISUAL} {{{# +class Visual_NoVisualSelection_Ignore(_VimTest): + snippets = ("test", "h${VISUAL}b") + keys = "test" + EX + "abc" + wanted = "hbabc" +class Visual_SelectOneWord(_VimTest): + snippets = ("test", "h${VISUAL}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + wanted = "hblablubb" +class Visual_SelectOneWord_ProblemAfterTab(_VimTest): + snippets = ("test", "h${VISUAL}b", "", "i") + keys = "\tblablub" + ESC + "5hv3l" + EX + "test" + EX + wanted = "\tbhlablbub" +class VisualWithDefault_ExpandWithoutVisual(_VimTest): + snippets = ("test", "h${VISUAL:world}b") + keys = "test" + EX + "hi" + wanted = "hworldbhi" +class VisualWithDefaultWithSlashes_ExpandWithoutVisual(_VimTest): + snippets = ("test", r"h${VISUAL:\/\/ body}b") + keys = "test" + EX + "hi" + wanted = "h// bodybhi" +class VisualWithDefault_ExpandWithVisual(_VimTest): + snippets = ("test", "h${VISUAL:world}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + wanted = "hblablubb" + +class Visual_ExpandTwice(_VimTest): + snippets = ("test", "h${VISUAL}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + "\ntest" + EX + wanted = "hblablubb\nhb" + +class Visual_SelectOneWord_TwiceVisual(_VimTest): + snippets = ("test", "h${VISUAL}b${VISUAL}a") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + wanted = "hblablubbblabluba" +class Visual_SelectOneWord_Inword(_VimTest): + snippets = ("test", "h${VISUAL}b", "Description", "i") + keys = "blablub" + ESC + "0lv4l" + EX + "test" + EX + wanted = "bhlablubb" +class Visual_SelectOneWord_TillEndOfLine(_VimTest): + snippets = ("test", "h${VISUAL}b", "Description", "i") + keys = "blablub" + ESC + "0v$" + EX + "test" + EX + ESC + "o" + wanted = "hblablub\nb" +class Visual_SelectOneWordWithTabstop_TillEndOfLine(_VimTest): + snippets = ("test", "h${2:ahh}${VISUAL}${1:ups}b", "Description", "i") + keys = "blablub" + ESC + "0v$" + EX + "test" + EX + "mmm" + JF + "n" + JF + "done" + ESC + "o" + wanted = "hnblablub\nmmmbdone" +class Visual_InDefaultText_SelectOneWord_NoOverwrite(_VimTest): + snippets = ("test", "h${1:${VISUAL}}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + JF + "hello" + wanted = "hblablubbhello" +class Visual_InDefaultText_SelectOneWord(_VimTest): + snippets = ("test", "h${1:${VISUAL}}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + "hello" + wanted = "hhellob" + +class Visual_CrossOneLine(_VimTest): + snippets = ("test", "h${VISUAL}b") + keys = "bla blub\n helloi" + ESC + "0k4lvjll" + EX + "test" + EX + wanted = "bla hblub\n hellobi" + +class Visual_LineSelect_Simple(_VimTest): + snippets = ("test", "h${VISUAL}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + wanted = "hhello\n nice\n worldb" +class Visual_InDefaultText_LineSelect_NoOverwrite(_VimTest): + snippets = ("test", "h${1:bef${VISUAL}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi" + wanted = "hbefhello\n nice\n worldaftbhi" +class Visual_InDefaultText_LineSelect_Overwrite(_VimTest): + snippets = ("test", "h${1:bef${VISUAL}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "jup" + JF + "hi" + wanted = "hjupbhi" +class Visual_LineSelect_CheckIndentSimple(_VimTest): + snippets = ("test", "beg\n\t${VISUAL}\nend") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + wanted = "beg\n\thello\n\tnice\n\tworld\nend" +class Visual_LineSelect_CheckIndentTwice(_VimTest): + snippets = ("test", "beg\n\t${VISUAL}\nend") + keys = " hello\n nice\n\tworld" + ESC + "Vkk" + EX + "test" + EX + wanted = "beg\n\t hello\n\t nice\n\t\tworld\nend" +class Visual_InDefaultText_IndentSpacesToTabstop_NoOverwrite(_VimTest): + snippets = ("test", "h${1:beforea${VISUAL}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi" + wanted = "hbeforeahello\n\tnice\n\tworldaftbhi" +class Visual_InDefaultText_IndentSpacesToTabstop_Overwrite(_VimTest): + snippets = ("test", "h${1:beforea${VISUAL}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "ups" + JF + "hi" + wanted = "hupsbhi" +class Visual_InDefaultText_IndentSpacesToTabstop_NoOverwrite1(_VimTest): + snippets = ("test", "h${1:beforeaaa${VISUAL}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi" + wanted = "hbeforeaaahello\n\t nice\n\t worldaftbhi" +class Visual_InDefaultText_IndentBeforeTabstop_NoOverwrite(_VimTest): + snippets = ("test", "hello\n\t ${1:${VISUAL}}\nend") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi" + wanted = "hello\n\t hello\n\t nice\n\t world\nendhi" + +class Visual_LineSelect_WithTabStop(_VimTest): + snippets = ("test", "beg\n\t${VISUAL}\n\t${1:here_we_go}\nend") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "super" + JF + "done" + wanted = "beg\n\thello\n\tnice\n\tworld\n\tsuper\nenddone" +class Visual_LineSelect_CheckIndentWithTS_NoOverwrite(_VimTest): + snippets = ("test", "beg\n\t${0:${VISUAL}}\nend") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + wanted = "beg\n\thello\n\tnice\n\tworld\nend" + +class VisualTransformation_SelectOneWord(_VimTest): + snippets = ("test", r"h${VISUAL/./\U$0\E/g}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + wanted = "hBLABLUBb" +class VisualTransformationWithDefault_ExpandWithoutVisual(_VimTest): + snippets = ("test", r"h${VISUAL:world/./\U$0\E/g}b") + keys = "test" + EX + "hi" + wanted = "hWORLDbhi" +class VisualTransformationWithDefault_ExpandWithVisual(_VimTest): + snippets = ("test", r"h${VISUAL:world/./\U$0\E/g}b") + keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + wanted = "hBLABLUBb" +class VisualTransformation_LineSelect_Simple(_VimTest): + snippets = ("test", r"h${VISUAL/./\U$0\E/g}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + wanted = "hHELLO\n NICE\n WORLDb" +class VisualTransformation_InDefaultText_LineSelect_NoOverwrite(_VimTest): + snippets = ("test", r"h${1:bef${VISUAL/./\U$0\E/g}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi" + wanted = "hbefHELLO\n NICE\n WORLDaftbhi" +class VisualTransformation_InDefaultText_LineSelect_Overwrite(_VimTest): + snippets = ("test", r"h${1:bef${VISUAL/./\U$0\E/g}aft}b") + keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "jup" + JF + "hi" + wanted = "hjupbhi" + +# End: ${VISUAL} #}}} + +# Recursive (Nested) Snippets {{{# +class RecTabStops_SimpleCase_ExceptCorrectResult(_VimTest): + snippets = ("m", "[ ${1:first} ${2:sec} ]") + keys = "m" + EX + "m" + EX + "hello" + JF + "world" + JF + "ups" + JF + "end" + wanted = "[ [ hello world ]ups end ]" +class RecTabStops_SimpleCaseLeaveSecondSecond_ExceptCorrectResult(_VimTest): snippets = ("m", "[ ${1:first} ${2:sec} ]") keys = "m" + EX + "m" + EX + "hello" + JF + "world" + JF + JF + JF + "end" wanted = "[ [ hello world ] sec ]end" @@ -1237,390 +1841,90 @@ class RecTabStops_MirroredZeroTS_ECR(_VimTest): keys = "m" + EX + "m1" + EX + "one" + JF + "two" + \ JF + "three" + JF + "four" + JF + "end" wanted = "[ [ one three three two ] four ]end" +# End: Recursive (Nested) Snippets #}}} +# List Snippets {{{# +class _ListAllSnippets(_VimTest): + snippets = ( ("testblah", "BLAAH", "Say BLAH"), + ("test", "TEST ONE", "Say tst one"), + ("aloha", "OHEEEE", "Say OHEE"), + ) -########### -# MIRRORS # -########### -class TextTabStopTextAfterTab_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 Hinten\n$1") - keys = "test" + EX + "hallo" - wanted = "hallo Hinten\nhallo" -class TextTabStopTextBeforeTab_ExceptCorrectResult(_VimTest): - snippets = ("test", "Vorne $1\n$1") - keys = "test" + EX + "hallo" - wanted = "Vorne hallo\nhallo" -class TextTabStopTextSurroundedTab_ExceptCorrectResult(_VimTest): - snippets = ("test", "Vorne $1 Hinten\n$1") - keys = "test" + EX + "hallo test" - wanted = "Vorne hallo test Hinten\nhallo test" +class ListAllAvailable_NothingTyped_ExceptCorrectResult(_ListAllSnippets): + keys = "" + LS + "3\n" + wanted = "BLAAH" +class ListAllAvailable_SpaceInFront_ExceptCorrectResult(_ListAllSnippets): + keys = " " + LS + "3\n" + wanted = " BLAAH" +class ListAllAvailable_BraceInFront_ExceptCorrectResult(_ListAllSnippets): + keys = "} " + LS + "3\n" + wanted = "} BLAAH" +class ListAllAvailable_testtyped_ExceptCorrectResult(_ListAllSnippets): + keys = "hallo test" + LS + "2\n" + wanted = "hallo BLAAH" +class ListAllAvailable_testtypedSecondOpt_ExceptCorrectResult(_ListAllSnippets): + keys = "hallo test" + LS + "1\n" + wanted = "hallo TEST ONE" -class TextTabStopTextBeforeMirror_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\nVorne $1") - keys = "test" + EX + "hallo" - wanted = "hallo\nVorne hallo" -class TextTabStopAfterMirror_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n$1 Hinten") - keys = "test" + EX + "hallo" - wanted = "hallo\nhallo Hinten" -class TextTabStopSurroundMirror_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\nVorne $1 Hinten") - keys = "test" + EX + "hallo welt" - wanted = "hallo welt\nVorne hallo welt Hinten" -class TextTabStopAllSurrounded_ExceptCorrectResult(_VimTest): - snippets = ("test", "ObenVorne $1 ObenHinten\nVorne $1 Hinten") - keys = "test" + EX + "hallo welt" - wanted = "ObenVorne hallo welt ObenHinten\nVorne hallo welt Hinten" - -class MirrorBeforeTabstopLeave_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1:this is it} $1") - keys = "test" + EX - wanted = "this is it this is it this is it" -class MirrorBeforeTabstopOverwrite_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1:this is it} $1") - keys = "test" + EX + "a" - wanted = "a a a" - -class TextTabStopSimpleMirrorMultiline_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n$1") - keys = "test" + EX + "hallo" - wanted = "hallo\nhallo" -class SimpleMirrorMultilineMany_ExceptCorrectResult(_VimTest): - snippets = ("test", " $1\n$1\na$1b\n$1\ntest $1 mich") - keys = "test" + EX + "hallo" - wanted = " hallo\nhallo\nahallob\nhallo\ntest hallo mich" -class MultilineTabStopSimpleMirrorMultiline_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n\n$1\n\n$1") - keys = "test" + EX + "hallo Du\nHi" - wanted = "hallo Du\nHi\n\nhallo Du\nHi\n\nhallo Du\nHi" -class MultilineTabStopSimpleMirrorMultiline1_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n$1\n$1") - keys = "test" + EX + "hallo Du\nHi" - wanted = "hallo Du\nHi\nhallo Du\nHi\nhallo Du\nHi" -class MultilineTabStopSimpleMirrorDeleteInLine_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n$1\n$1") - keys = "test" + EX + "hallo Du\nHi\b\bAch Blah" - wanted = "hallo Du\nAch Blah\nhallo Du\nAch Blah\nhallo Du\nAch Blah" -class TextTabStopSimpleMirrorMultilineMirrorInFront_ECR(_VimTest): - snippets = ("test", "$1\n${1:sometext}") - keys = "test" + EX + "hallo\nagain" - wanted = "hallo\nagain\nhallo\nagain" - -class SimpleMirrorDelete_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n$1") - keys = "test" + EX + "hallo\b\b" - wanted = "hal\nhal" - -class SimpleMirrorSameLine_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 $1") - keys = "test" + EX + "hallo" - wanted = "hallo hallo" -class Transformation_SimpleMirrorSameLineBeforeTabDefVal_ECR(_VimTest): - snippets = ("test", "$1 ${1:replace me}") - keys = "test" + EX + "hallo foo" - wanted = "hallo foo hallo foo" -class SimpleMirrorSameLineMany_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 $1 $1 $1") - keys = "test" + EX + "hallo du" - wanted = "hallo du hallo du hallo du hallo du" -class SimpleMirrorSameLineManyMultiline_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 $1 $1 $1") - keys = "test" + EX + "hallo du\nwie gehts" - wanted = "hallo du\nwie gehts hallo du\nwie gehts hallo du\nwie gehts" \ - " hallo du\nwie gehts" -class SimpleMirrorDeleteSomeEnterSome_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1\n$1") - keys = "test" + EX + "hallo\b\bhups" - wanted = "halhups\nhalhups" - - -class SimpleTabstopWithDefaultSimpelType_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha ${1:defa}\n$1") - keys = "test" + EX + "world" - wanted = "ha world\nworld" -class SimpleTabstopWithDefaultComplexType_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha ${1:default value} $1\nanother: $1 mirror") - keys = "test" + EX + "world" - wanted = "ha world world\nanother: world mirror" -class SimpleTabstopWithDefaultSimpelKeep_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha ${1:defa}\n$1") - keys = "test" + EX - wanted = "ha defa\ndefa" -class SimpleTabstopWithDefaultComplexKeep_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha ${1:default value} $1\nanother: $1 mirror") - keys = "test" + EX - wanted = "ha default value default value\nanother: default value mirror" - -class TabstopWithMirrorManyFromAll_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha $5 ${1:blub} $4 $0 ${2:$1.h} $1 $3 ${4:More}") - keys = "test" + EX + "hi" + JF + "hu" + JF + "hub" + JF + "hulla" + \ - JF + "blah" + JF + "end" - wanted = "ha blah hi hulla end hu hi hub hulla" -class TabstopWithMirrorInDefaultNoType_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha ${1:blub} ${2:$1.h}") - keys = "test" + EX - wanted = "ha blub blub.h" -class TabstopWithMirrorInDefaultTwiceAndExtra_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha $1 ${2:$1.h $1.c}\ntest $1") - keys = "test" + EX + "stdin" - wanted = "ha stdin stdin.h stdin.c\ntest stdin" -class TabstopWithMirrorInDefaultMultipleLeave_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha $1 ${2:snip} ${3:$1.h $2}") - keys = "test" + EX + "stdin" - wanted = "ha stdin snip stdin.h snip" -class TabstopWithMirrorInDefaultMultipleOverwrite_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha $1 ${2:snip} ${3:$1.h $2}") - keys = "test" + EX + "stdin" + JF + "do snap" - wanted = "ha stdin do snap stdin.h do snap" -class TabstopWithMirrorInDefaultOverwrite_ExceptCorrectResult(_VimTest): - snippets = ("test", "ha $1 ${2:$1.h}") - keys = "test" + EX + "stdin" + JF + "overwritten" - wanted = "ha stdin overwritten" - -class MirrorRealLifeExample_ExceptCorrectResult(_VimTest): +class ListAllAvailable_NonDefined_NoExceptionShouldBeRaised(_ListAllSnippets): + keys = "hallo qualle" + LS + "Hi" + wanted = "hallo qualleHi" +# End: List Snippets #}}} +# Selecting Between Same Triggers {{{# +class _MultipleMatches(_VimTest): + snippets = ( ("test", "Case1", "This is Case 1"), + ("test", "Case2", "This is Case 2") ) +class Multiple_SimpleCaseSelectFirst_ECR(_MultipleMatches): + keys = "test" + EX + "1\n" + wanted = "Case1" +class Multiple_SimpleCaseSelectSecond_ECR(_MultipleMatches): + keys = "test" + EX + "2\n" + wanted = "Case2" +class Multiple_SimpleCaseSelectTooHigh_ESelectLast(_MultipleMatches): + keys = "test" + EX + "5\n" + wanted = "Case2" +class Multiple_SimpleCaseSelectZero_EEscape(_MultipleMatches): + keys = "test" + EX + "0\n" + "hi" + wanted = "testhi" +class Multiple_SimpleCaseEscapeOut_ECR(_MultipleMatches): + keys = "test" + EX + ESC + "hi" + wanted = "testhi" +class Multiple_ManySnippetsOneTrigger_ECR(_VimTest): + # Snippet definition {{{# snippets = ( - ("for", "for(size_t ${2:i} = 0; $2 < ${1:count}; ${3:++$2})" \ - "\n{\n\t${0:/* code */}\n}"), - ) - keys ="for" + EX + "100" + JF + "avar\b\b\b\ba_variable" + JF + \ - "a_variable *= 2" + JF + "// do nothing" - wanted = """for(size_t a_variable = 0; a_variable < 100; a_variable *= 2) -{ -\t// do nothing -}""" - - -################### -# TRANSFORMATIONS # -################### -class Transformation_SimpleCase_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/foo/batzl/}") - keys = "test" + EX + "hallo foo boy" - wanted = "hallo foo boy hallo batzl boy" -class Transformation_SimpleCaseNoTransform_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/foo/batzl/}") - keys = "test" + EX + "hallo" - wanted = "hallo hallo" -class Transformation_SimpleCaseTransformInFront_ExceptCorrectResult(_VimTest): - snippets = ("test", "${1/foo/batzl/} $1") - keys = "test" + EX + "hallo foo" - wanted = "hallo batzl hallo foo" -class Transformation_SimpleCaseTransformInFrontDefVal_ECR(_VimTest): - snippets = ("test", "${1/foo/batzl/} ${1:replace me}") - keys = "test" + EX + "hallo foo" - wanted = "hallo batzl hallo foo" -class Transformation_MultipleTransformations_ECR(_VimTest): - snippets = ("test", "${1:Some Text}${1/.+/\\U$0\E/}\n${1/.+/\L$0\E/}") - keys = "test" + EX + "SomE tExt " - wanted = "SomE tExt SOME TEXT \nsome text " -class Transformation_TabIsAtEndAndDeleted_ECR(_VimTest): - snippets = ("test", "${1/.+/is something/}${1:some}") - keys = "hallo test" + EX + "some\b\b\b\b\b" - wanted = "hallo " -class Transformation_TabIsAtEndAndDeleted1_ECR(_VimTest): - snippets = ("test", "${1/.+/is something/}${1:some}") - keys = "hallo test" + EX + "some\b\b\b\bmore" - wanted = "hallo is somethingmore" -class Transformation_TabIsAtEndNoTextLeave_ECR(_VimTest): - snippets = ("test", "${1/.+/is something/}${1}") - keys = "hallo test" + EX - wanted = "hallo " -class Transformation_TabIsAtEndNoTextType_ECR(_VimTest): - snippets = ("test", "${1/.+/is something/}${1}") - keys = "hallo test" + EX + "b" - wanted = "hallo is somethingb" -class Transformation_InsideTabLeaveAtDefault_ECR(_VimTest): - snippets = ("test", r"$1 ${2:${1/.+/(?0:defined $0)/}}") - keys = "test" + EX + "sometext" + JF - wanted = "sometext defined sometext" -class Transformation_InsideTabOvertype_ECR(_VimTest): - snippets = ("test", r"$1 ${2:${1/.+/(?0:defined $0)/}}") - keys = "test" + EX + "sometext" + JF + "overwrite" - wanted = "sometext overwrite" - - -class Transformation_Backreference_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/([ab])oo/$1ull/}") - keys = "test" + EX + "foo boo aoo" - wanted = "foo boo aoo foo bull aoo" -class Transformation_BackreferenceTwice_ExceptCorrectResult(_VimTest): - snippets = ("test", r"$1 ${1/(dead) (par[^ ]*)/this $2 is a bit $1/}") - keys = "test" + EX + "dead parrot" - wanted = "dead parrot this parrot is a bit dead" - -class Transformation_CleverTransformUpercaseChar_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(.)/\\u$1/}") - keys = "test" + EX + "hallo" - wanted = "hallo Hallo" -class Transformation_CleverTransformLowercaseChar_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(.*)/\l$1/}") - keys = "test" + EX + "Hallo" - wanted = "Hallo hallo" -class Transformation_CleverTransformLongUpper_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(.*)/\\U$1\E/}") - keys = "test" + EX + "hallo" - wanted = "hallo HALLO" -class Transformation_CleverTransformLongLower_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(.*)/\L$1\E/}") - keys = "test" + EX + "HALLO" - wanted = "HALLO hallo" - -class Transformation_ConditionalInsertionSimple_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(^a).*/(?0:began with an a)/}") - keys = "test" + EX + "a some more text" - wanted = "a some more text began with an a" -class Transformation_CIBothDefinedNegative_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(?:(^a)|(^b)).*/(?1:yes:no)/}") - keys = "test" + EX + "b some" - wanted = "b some no" -class Transformation_CIBothDefinedPositive_ExceptCorrectResult(_VimTest): - snippets = ("test", "$1 ${1/(?:(^a)|(^b)).*/(?1:yes:no)/}") - keys = "test" + EX + "a some" - wanted = "a some yes" -class Transformation_ConditionalInsertRWEllipsis_ECR(_VimTest): - snippets = ("test", r"$1 ${1/(\w+(?:\W+\w+){,7})\W*(.+)?/$1(?2:...)/}") - keys = "test" + EX + "a b c d e f ghhh h oha" - wanted = "a b c d e f ghhh h oha a b c d e f ghhh h..." -class Transformation_ConditionalInConditional_ECR(_VimTest): - snippets = ("test", r"$1 ${1/^.*?(-)?(>)?$/(?2::(?1:>:.))/}") - keys = "test" + EX + "hallo" + ESC + "$a\n" + \ - "test" + EX + "hallo-" + ESC + "$a\n" + \ - "test" + EX + "hallo->" - wanted = "hallo .\nhallo- >\nhallo-> " - -class Transformation_CINewlines_ECR(_VimTest): - snippets = ("test", r"$1 ${1/, */\n/}") - keys = "test" + EX + "test, hallo" - wanted = "test, hallo test\nhallo" -class Transformation_CITabstop_ECR(_VimTest): - snippets = ("test", r"$1 ${1/, */\t/}") - keys = "test" + EX + "test, hallo" - wanted = "test, hallo test\thallo" -class Transformation_CIEscapedParensinReplace_ECR(_VimTest): - snippets = ("test", r"$1 ${1/hal((?:lo)|(?:ul))/(?1:ha\($1\))/}") - keys = "test" + EX + "test, halul" - wanted = "test, halul test, ha(ul)" - -class Transformation_OptionIgnoreCase_ECR(_VimTest): - snippets = ("test", r"$1 ${1/test/blah/i}") - keys = "test" + EX + "TEST" - wanted = "TEST blah" -class Transformation_OptionReplaceGlobal_ECR(_VimTest): - snippets = ("test", r"$1 ${1/, */-/g}") - keys = "test" + EX + "a, nice, building" - wanted = "a, nice, building a-nice-building" -class Transformation_OptionReplaceGlobalMatchInReplace_ECR(_VimTest): - snippets = ("test", r"$1 ${1/, */, /g}") - keys = "test" + EX + "a, nice, building" - wanted = "a, nice, building a, nice, building" - -################### -# CURSOR MOVEMENT # -################### -class CursorMovement_Multiline_ECR(_VimTest): - snippets = ("test", r"$1 ${1:a tab}") - keys = "test" + EX + "this is something\nvery nice\nnot" + JF + "more text" - wanted = "this is something\nvery nice\nnot " \ - "this is something\nvery nice\nnotmore text" - - -###################### -# INSERT MODE MOVING # -###################### -class IMMoving_CursorsKeys_ECR(_VimTest): - snippets = ("test", "${1:Some}") - keys = "test" + EX + "text" + 3*ARR_U + 6*ARR_D - wanted = "text" -class IMMoving_DoNotAcceptInputWhenMoved_ECR(_VimTest): - snippets = ("test", r"$1 ${1:a tab}") - keys = "test" + EX + "this" + ARR_L + "hallo" - wanted = "this thihallos" -class IMMoving_NoExiting_ECR(_VimTest): - snippets = ("test", r"$1 ${2:a tab} ${1:Tab}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + 7*ARR_L + \ - JF + "hallo" - wanted = "hello tab hallo tab this" -class IMMoving_NoExitingEventAtEnd_ECR(_VimTest): - snippets = ("test", r"$1 ${2:a tab} ${1:Tab}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + JF + "hallo" - wanted = "hello tab hallo tab this" -class IMMoving_ExitWhenOutsideRight_ECR(_VimTest): - snippets = ("test", r"$1 ${2:blub} ${1:Tab}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + ARR_R + JF + "hallo" - wanted = "hello tab blub tab hallothis" -class IMMoving_NotExitingWhenBarelyOutsideLeft_ECR(_VimTest): - snippets = ("test", r"${1:Hi} ${2:blub}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + 3*ARR_L + \ - JF + "hallo" - wanted = "hello tab hallo this" -class IMMoving_ExitWhenOutsideLeft_ECR(_VimTest): - snippets = ("test", r"${1:Hi} ${2:blub}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + 4*ARR_L + \ - JF + "hallo" - wanted = "hellohallo tab blub this" -class IMMoving_ExitWhenOutsideAbove_ECR(_VimTest): - snippets = ("test", "${1:Hi}\n${2:blub}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + 1*ARR_U + JF + \ - "\nhallo" - wanted = "hallo\nhello tab\nblub this" -class IMMoving_ExitWhenOutsideBelow_ECR(_VimTest): - snippets = ("test", "${1:Hi}\n${2:blub}") - keys = "hello test this" + ESC + "02f i" + EX + "tab" + 2*ARR_D + JF + \ - "testhallo\n" - wanted = "hello tab\nblub this\ntesthallo" - - -#################### -# PROPER INDENTING # -#################### -class ProperIndenting_SimpleCase_ECR(_VimTest): - snippets = ("test", "for\n blah") - keys = " test" + EX + "Hui" - wanted = " for\n blahHui" -class ProperIndenting_SingleLineNoReindenting_ECR(_VimTest): - snippets = ("test", "hui") - keys = " test" + EX + "blah" - wanted = " huiblah" -class ProperIndenting_AutoIndentAndNewline_ECR(_VimTest): - snippets = ("test", "hui") - keys = " test" + EX + "\n"+ "blah" - wanted = " hui\n blah" - def _options_on(self): - self.send(":set autoindent\n") - def _options_off(self): - self.send(":set noautoindent\n") - -#################### -# COMPLETION TESTS # -#################### -class Completion_SimpleExample_ECR(_VimTest): - snippets = ("test", "$1 ${1:blah}") - keys = "superkallifragilistik\ntest" + EX + "sup" + COMPL_KW + \ - COMPL_ACCEPT + " some more" - wanted = "superkallifragilistik\nsuperkallifragilistik some more " \ - "superkallifragilistik some more" - -# We need >2 different words with identical starts to create the -# popup-menu: -COMPLETION_OPTIONS = "completion1\ncompletion2\n" - -class Completion_ForwardsJumpWithoutCOMPL_ACCEPT(_VimTest): - # completions should not be truncated when JF is activated without having - # pressed COMPL_ACCEPT (Bug #598903) - snippets = ("test", "$1 $2") - keys = COMPLETION_OPTIONS + "test" + EX + "com" + COMPL_KW + JF + "foo" - wanted = COMPLETION_OPTIONS + "completion1 foo" - -class Completion_BackwardsJumpWithoutCOMPL_ACCEPT(_VimTest): - # completions should not be truncated when JB is activated without having - # pressed COMPL_ACCEPT (Bug #598903) - snippets = ("test", "$1 $2") - keys = COMPLETION_OPTIONS + "test" + EX + "foo" + JF + "com" + COMPL_KW + \ - JB + "foo" - wanted = COMPLETION_OPTIONS + "foo completion1" - -################### -# SNIPPET OPTIONS # -################### + ("test", "Case1", "This is Case 1"), + ("test", "Case2", "This is Case 2"), + ("test", "Case3", "This is Case 3"), + ("test", "Case4", "This is Case 4"), + ("test", "Case5", "This is Case 5"), + ("test", "Case6", "This is Case 6"), + ("test", "Case7", "This is Case 7"), + ("test", "Case8", "This is Case 8"), + ("test", "Case9", "This is Case 9"), + ("test", "Case10", "This is Case 10"), + ("test", "Case11", "This is Case 11"), + ("test", "Case12", "This is Case 12"), + ("test", "Case13", "This is Case 13"), + ("test", "Case14", "This is Case 14"), + ("test", "Case15", "This is Case 15"), + ("test", "Case16", "This is Case 16"), + ("test", "Case17", "This is Case 17"), + ("test", "Case18", "This is Case 18"), + ("test", "Case19", "This is Case 19"), + ("test", "Case20", "This is Case 20"), + ("test", "Case21", "This is Case 21"), + ("test", "Case22", "This is Case 22"), + ("test", "Case23", "This is Case 23"), + ("test", "Case24", "This is Case 24"), + ("test", "Case25", "This is Case 25"), + ("test", "Case26", "This is Case 26"), + ("test", "Case27", "This is Case 27"), + ("test", "Case28", "This is Case 28"), + ("test", "Case29", "This is Case 29"), + ) #}}} + keys = "test" + EX + " " + ESC + ESC + "ahi" + wanted = "testhi" +# End: Selecting Between Same Triggers #}}} +# Snippet Options {{{# class SnippetOptions_OverwriteExisting_ECR(_VimTest): snippets = ( ("test", "${1:Hallo}", "Types Hallo"), @@ -1692,6 +1996,7 @@ class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand2(_VimTest): keys = "-test" + EX wanted = "-Expand me!" class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand3(_VimTest): + skip_on_windows = True # SendKeys can't send UTF characters snippets = (("test", "Expand me!", "", "i"), ) keys = "ßßtest" + EX wanted = "ßßExpand me!" @@ -1719,24 +2024,17 @@ class SnippetOptions_ExpandWordSnippets_ExpandSuffix3( keys = "[[test" + EX wanted = "[[Expand me!" -#################### -# NO TAB EXPANSION # -#################### class _No_Tab_Expand(_VimTest): snippets = ("test", "\t\tExpand\tme!\t", "", "t") - class No_Tab_Expand_Simple(_No_Tab_Expand): keys = "test" + EX wanted = "\t\tExpand\tme!\t" - class No_Tab_Expand_Leading_Spaces(_No_Tab_Expand): keys = " test" + EX wanted = " \t\tExpand\tme!\t" - class No_Tab_Expand_Leading_Tabs(_No_Tab_Expand): keys = "\ttest" + EX wanted = "\t\t\tExpand\tme!\t" - class No_Tab_Expand_No_TS(_No_Tab_Expand): def _options_on(self): self.send(":set sw=3\n") @@ -1746,7 +2044,6 @@ def _options_off(self): self.send(":set sts=0\n") keys = "test" + EX wanted = "\t\tExpand\tme!\t" - class No_Tab_Expand_ET(_No_Tab_Expand): def _options_on(self): self.send(":set sw=3\n") @@ -1756,7 +2053,6 @@ def _options_off(self): self.send(":set noexpandtab\n") keys = "test" + EX wanted = "\t\tExpand\tme!\t" - class No_Tab_Expand_ET_Leading_Spaces(_No_Tab_Expand): def _options_on(self): self.send(":set sw=3\n") @@ -1766,7 +2062,6 @@ def _options_off(self): self.send(":set noexpandtab\n") keys = " test" + EX wanted = " \t\tExpand\tme!\t" - class No_Tab_Expand_ET_SW(_No_Tab_Expand): def _options_on(self): self.send(":set sw=8\n") @@ -1776,7 +2071,6 @@ def _options_off(self): self.send(":set noexpandtab\n") keys = "test" + EX wanted = "\t\tExpand\tme!\t" - class No_Tab_Expand_ET_SW_TS(_No_Tab_Expand): def _options_on(self): self.send(":set sw=3\n") @@ -1791,10 +2085,36 @@ def _options_off(self): keys = "test" + EX wanted = "\t\tExpand\tme!\t" +class _TabExpand_RealWorld(object): + snippets = ("hi", +r"""hi +`!p snip.rv="i1\n" +snip.rv += snip.mkline("i1\n") +snip.shift(1) +snip.rv += snip.mkline("i2\n") +snip.unshift(2) +snip.rv += snip.mkline("i0\n") +snip.shift(3) +snip.rv += snip.mkline("i3")` +snip.rv = repr(snip.rv) +End""") + +class No_Tab_Expand_RealWorld(_TabExpand_RealWorld,_VimTest): + def _options_on(self): + self.send(":set noexpandtab\n") + def _options_off(self): + self.send(":set noexpandtab\n") + keys = "\t\thi" + EX + wanted = """\t\thi +\t\ti1 +\t\ti1 +\t\t\ti2 +\ti0 +\t\t\t\ti3 +\t\tsnip.rv = repr(snip.rv) +\t\tEnd""" + -################# -# REGEX MATCHES # -################# class SnippetOptions_Regex_Expand(_VimTest): snippets = ("(test)", "Expand me!", "", "r") keys = "test" + EX @@ -1805,7 +2125,7 @@ class SnippetOptions_Regex_Multiple(_VimTest): wanted = "Expand me!" class _Regex_Self(_VimTest): - snippets = (r"((?<=\W)|^)(\.)", "self.", "", "r") + snippets = ("((?<=\W)|^)(\.)", "self.", "", "r") class SnippetOptions_Regex_Self_Start(_Regex_Self): keys = "." + EX wanted = "self." @@ -1818,7 +2138,6 @@ class SnippetOptions_Regex_Self_TextAfter(_Regex_Self): class SnippetOptions_Regex_Self_TextBefore(_Regex_Self): keys = "a." + EX wanted = "a." + EX - class SnippetOptions_Regex_PythonBlockMatch(_VimTest): snippets = (r"([abc]+)([def]+)", r"""`!p m = match snip.rv += m.group(2) @@ -1830,252 +2149,86 @@ class SnippetOptions_Regex_PythonBlockNoMatch(_VimTest): snippets = (r"cabfed", r"""`!p snip.rv = match or "No match"`""") keys = "test cabfed" + EX wanted = "test No match" - # Tests for Bug #691575 class SnippetOptions_Regex_SameLine_Long_End(_VimTest): snippets = ("(test.*)", "Expand me!", "", "r") keys = "test test abc" + EX wanted = "Expand me!" +class SnippetOptions_Regex_SameLine_Long_Start(_VimTest): + snippets = ("(.*test)", "Expand me!", "", "r") + keys = "abc test test" + EX + wanted = "Expand me!" +class SnippetOptions_Regex_SameLine_Simple(_VimTest): + snippets = ("(test)", "Expand me!", "", "r") + keys = "abc test test" + EX + wanted = "abc test Expand me!" -class SnippetOptions_Regex_SameLine_Long_Start(_VimTest): - snippets = ("(.*test)", "Expand me!", "", "r") - keys = "abc test test" + EX - wanted = "Expand me!" - -class SnippetOptions_Regex_SameLine_Simple(_VimTest): - snippets = ("(test)", "Expand me!", "", "r") - keys = "abc test test" + EX - wanted = "abc test Expand me!" - -####################### -# MULTI-WORD SNIPPETS # -####################### - -class MultiWordSnippet_Simple(_VimTest): - snippets = ("test me", "Expand me!") - keys = "test me" + EX - wanted = "Expand me!" - -class MultiWord_SnippetOptions_OverwriteExisting_ECR(_VimTest): - snippets = ( - ("test me", "${1:Hallo}", "Types Hallo"), - ("test me", "${1:World}", "Types World"), - ("test me", "We overwrite", "Overwrite the two", "!"), - ) - keys = "test me" + EX - wanted = "We overwrite" -class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_Expand(_VimTest): - snippets = ("test it", "Expand me!", "", "b") - keys = "test it" + EX - wanted = "Expand me!" -class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_Expand2(_VimTest): - snippets = ("test it", "Expand me!", "", "b") - keys = " test it" + EX - wanted = " Expand me!" -class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_DontExpand(_VimTest): - snippets = ("test it", "Expand me!", "", "b") - keys = "a test it" + EX - wanted = "a test it" + EX -class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_OneWithOneWO(_VimTest): - snippets = ( - ("test it", "Expand me!", "", "b"), - ("test it", "not at beginning", "", ""), - ) - keys = "a test it" + EX - wanted = "a not at beginning" -class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_OneWithOneWOChoose(_VimTest): - snippets = ( - ("test it", "Expand me!", "", "b"), - ("test it", "not at beginning", "", ""), - ) - keys = " test it" + EX + "1\n" - wanted = " Expand me!" - - -class MultiWord_SnippetOptions_ExpandInwordSnippets_SimpleExpand(_VimTest): - snippets = (("test it", "Expand me!", "", "i"), ) - keys = "atest it" + EX - wanted = "aExpand me!" -class MultiWord_SnippetOptions_ExpandInwordSnippets_ExpandSingle(_VimTest): - snippets = (("test it", "Expand me!", "", "i"), ) - keys = "test it" + EX - wanted = "Expand me!" - -class _MultiWord_SnippetOptions_ExpandWordSnippets(_VimTest): - snippets = (("test it", "Expand me!", "", "w"), ) -class MultiWord_SnippetOptions_ExpandWordSnippets_NormalExpand( - _MultiWord_SnippetOptions_ExpandWordSnippets): - keys = "test it" + EX - wanted = "Expand me!" -class MultiWord_SnippetOptions_ExpandWordSnippets_NoExpand( - _MultiWord_SnippetOptions_ExpandWordSnippets): - keys = "atest it" + EX - wanted = "atest it" + EX -class MultiWord_SnippetOptions_ExpandWordSnippets_ExpandSuffix( - _MultiWord_SnippetOptions_ExpandWordSnippets): - keys = "a-test it" + EX - wanted = "a-Expand me!" - -# Test for Bug #774917 -def _snip_quote(qt): - return ( - ("te" + qt + "st", "Expand me" + qt + "!", "test: "+qt), - ("te", "Bad", ""), - ) - -class Snippet_With_SingleQuote(_VimTest): - snippets = _snip_quote("'") - keys = "te'st" + EX - wanted = "Expand me'!" - -class Snippet_With_SingleQuote_List(_VimTest): - snippets = _snip_quote("'") - keys = "te" + LS + "2\n" - wanted = "Expand me'!" - -class Snippet_With_DoubleQuote(_VimTest): - snippets = _snip_quote('"') - keys = 'te"st' + EX - wanted = "Expand me\"!" - -class Snippet_With_Umlauts_List(_VimTest): - snippets = _snip_quote('ü') - keys = 'te' + LS + "2\n" - wanted = "Expand meü!" - -class Snippet_With_Umlauts(_VimTest): - snippets = _snip_quote('ü') - keys = 'teüst' + EX - wanted = "Expand meü!" - -class Snippet_With_Umlauts_TypeOn(_VimTest): - snippets = ('ül', 'üüüüüßßßß') - keys = 'te ül' + EX + "more text" - wanted = "te üüüüüßßßßmore text" -class Snippet_With_Umlauts_OverwriteFirst(_VimTest): - snippets = ('ül', 'üü ${1:world} üü ${2:hello}ßß\nüüüü') - keys = 'te ül' + EX + "more text" + JF + JF + "end" - wanted = "te üü more text üü helloßß\nüüüüend" -class Snippet_With_Umlauts_OverwriteSecond(_VimTest): - snippets = ('ül', 'üü ${1:world} üü ${2:hello}ßß\nüüüü') - keys = 'te ül' + EX + JF + "more text" + JF + "end" - wanted = "te üü world üü more textßß\nüüüüend" -class Snippet_With_Umlauts_OverwriteNone(_VimTest): - snippets = ('ül', 'üü ${1:world} üü ${2:hello}ßß\nüüüü') - keys = 'te ül' + EX + JF + JF + "end" - wanted = "te üü world üü helloßß\nüüüüend" -class Snippet_With_Umlauts_Mirrors(_VimTest): - snippets = ('ül', 'üü ${1:world} üü $1') - keys = 'te ül' + EX + "hello" - wanted = "te üü hello üü hello" -class Snippet_With_Umlauts_Python(_VimTest): - snippets = ('ül', 'üü ${1:world} üü `!p snip.rv = len(t[1])*"a"`') - keys = 'te ül' + EX + "hüüll" - wanted = "te üü hüüll üü aaaaa" - -class Snippet_With_DoubleQuote_List(_VimTest): - snippets = _snip_quote('"') - keys = "te" + LS + "2\n" - wanted = "Expand me\"!" - -# Test for Bug #774917 -class Backspace_TabStop_Zero(_VimTest): - snippets = ("test", "A${1:C} ${0:DDD}", "This is Case 1") - keys = "test" + EX + "A" + JF + BS + "BBB" - wanted = "AA BBB" - -class Backspace_TabStop_NotZero(_VimTest): - snippets = ("test", "A${1:C} ${2:DDD}", "This is Case 1") - keys = "test" + EX + "A" + JF + BS + "BBB" - wanted = "AA BBB" - -###################### -# SELECTING MULTIPLE # -###################### -class _MultipleMatches(_VimTest): - snippets = ( ("test", "Case1", "This is Case 1"), - ("test", "Case2", "This is Case 2") ) -class Multiple_SimpleCaseSelectFirst_ECR(_MultipleMatches): - keys = "test" + EX + "1\n" - wanted = "Case1" -class Multiple_SimpleCaseSelectSecond_ECR(_MultipleMatches): - keys = "test" + EX + "2\n" - wanted = "Case2" -class Multiple_SimpleCaseSelectTooHigh_ESelectLast(_MultipleMatches): - keys = "test" + EX + "5\n" - wanted = "Case2" -class Multiple_SimpleCaseSelectZero_EEscape(_MultipleMatches): - keys = "test" + EX + "0\n" + "hi" - wanted = "testhi" -class Multiple_SimpleCaseEscapeOut_ECR(_MultipleMatches): - keys = "test" + EX + ESC + "hi" - wanted = "testhi" -class Multiple_ManySnippetsOneTrigger_ECR(_VimTest): - # Snippet definition {{{ - snippets = ( - ("test", "Case1", "This is Case 1"), - ("test", "Case2", "This is Case 2"), - ("test", "Case3", "This is Case 3"), - ("test", "Case4", "This is Case 4"), - ("test", "Case5", "This is Case 5"), - ("test", "Case6", "This is Case 6"), - ("test", "Case7", "This is Case 7"), - ("test", "Case8", "This is Case 8"), - ("test", "Case9", "This is Case 9"), - ("test", "Case10", "This is Case 10"), - ("test", "Case11", "This is Case 11"), - ("test", "Case12", "This is Case 12"), - ("test", "Case13", "This is Case 13"), - ("test", "Case14", "This is Case 14"), - ("test", "Case15", "This is Case 15"), - ("test", "Case16", "This is Case 16"), - ("test", "Case17", "This is Case 17"), - ("test", "Case18", "This is Case 18"), - ("test", "Case19", "This is Case 19"), - ("test", "Case20", "This is Case 20"), - ("test", "Case21", "This is Case 21"), - ("test", "Case22", "This is Case 22"), - ("test", "Case23", "This is Case 23"), - ("test", "Case24", "This is Case 24"), - ("test", "Case25", "This is Case 25"), - ("test", "Case26", "This is Case 26"), - ("test", "Case27", "This is Case 27"), - ("test", "Case28", "This is Case 28"), - ("test", "Case29", "This is Case 29"), - ) # }}} - sleeptime = 0.09 # Do this very slowly - keys = "test" + EX + " " + ESC + ESC + "ahi" - wanted = "testhi" - - -################################## -# LIST OF ALL AVAILABLE SNIPPETS # -################################## -class _ListAllSnippets(_VimTest): - snippets = ( ("testblah", "BLAAH", "Say BLAH"), - ("test", "TEST ONE", "Say tst one"), - ("aloha", "OHEEEE", "Say OHEE"), - ) - -class ListAllAvailable_NothingTyped_ExceptCorrectResult(_ListAllSnippets): - keys = "" + LS + "3\n" - wanted = "BLAAH" -class ListAllAvailable_testtyped_ExceptCorrectResult(_ListAllSnippets): - keys = "hallo test" + LS + "2\n" - wanted = "hallo BLAAH" -class ListAllAvailable_testtypedSecondOpt_ExceptCorrectResult(_ListAllSnippets): - keys = "hallo test" + LS + "1\n" - wanted = "hallo TEST ONE" -class ListAllAvailable_NonDefined_NoExceptionShouldBeRaised(_ListAllSnippets): - keys = "hallo qualle" + LS + "Hi" - wanted = "hallo qualleHi" +class MultiWordSnippet_Simple(_VimTest): + snippets = ("test me", "Expand me!") + keys = "test me" + EX + wanted = "Expand me!" +class MultiWord_SnippetOptions_OverwriteExisting_ECR(_VimTest): + snippets = ( + ("test me", "${1:Hallo}", "Types Hallo"), + ("test me", "${1:World}", "Types World"), + ("test me", "We overwrite", "Overwrite the two", "!"), + ) + keys = "test me" + EX + wanted = "We overwrite" +class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_Expand(_VimTest): + snippets = ("test it", "Expand me!", "", "b") + keys = "test it" + EX + wanted = "Expand me!" +class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_Expand2(_VimTest): + snippets = ("test it", "Expand me!", "", "b") + keys = " test it" + EX + wanted = " Expand me!" +class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_DontExpand(_VimTest): + snippets = ("test it", "Expand me!", "", "b") + keys = "a test it" + EX + wanted = "a test it" + EX +class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_OneWithOneWO(_VimTest): + snippets = ( + ("test it", "Expand me!", "", "b"), + ("test it", "not at beginning", "", ""), + ) + keys = "a test it" + EX + wanted = "a not at beginning" +class MultiWord_SnippetOptions_OnlyExpandWhenWSInFront_OneWithOneWOChoose(_VimTest): + snippets = ( + ("test it", "Expand me!", "", "b"), + ("test it", "not at beginning", "", ""), + ) + keys = " test it" + EX + "1\n" + wanted = " Expand me!" +class MultiWord_SnippetOptions_ExpandInwordSnippets_SimpleExpand(_VimTest): + snippets = (("test it", "Expand me!", "", "i"), ) + keys = "atest it" + EX + wanted = "aExpand me!" +class MultiWord_SnippetOptions_ExpandInwordSnippets_ExpandSingle(_VimTest): + snippets = (("test it", "Expand me!", "", "i"), ) + keys = "test it" + EX + wanted = "Expand me!" -####################### -# ANONYMOUS EXPANSION # -####################### +class _MultiWord_SnippetOptions_ExpandWordSnippets(_VimTest): + snippets = (("test it", "Expand me!", "", "w"), ) +class MultiWord_SnippetOptions_ExpandWordSnippets_NormalExpand( + _MultiWord_SnippetOptions_ExpandWordSnippets): + keys = "test it" + EX + wanted = "Expand me!" +class MultiWord_SnippetOptions_ExpandWordSnippets_NoExpand( + _MultiWord_SnippetOptions_ExpandWordSnippets): + keys = "atest it" + EX + wanted = "atest it" + EX +class MultiWord_SnippetOptions_ExpandWordSnippets_ExpandSuffix( + _MultiWord_SnippetOptions_ExpandWordSnippets): + keys = "a-test it" + EX + wanted = "a-Expand me!" +# Snippet Options #}}} +# Anonymous Expansion {{{# class _AnonBase(_VimTest): args = "" def _options_on(self): @@ -2127,12 +2280,8 @@ class Anon_Trigger_Opts(_AnonBase): args = '"simple expand", ".*abc", "desc", "r"' keys = "blah blah abc" + EA wanted = "simple expand" - - -######################## -# ADD SNIPPET FUNCTION # -######################## - +# End: Anonymous Expansion #}}} +# AddSnippet Function {{{# class _AddFuncBase(_VimTest): args = "" def _options_on(self): @@ -2142,232 +2291,128 @@ def _options_on(self): class AddFunc_Simple(_AddFuncBase): args = '"test", "simple expand", "desc", ""' keys = "abc test" + EX - wanted = "abc simple expand" - -class AddFunc_Opt(_AddFuncBase): - args = '".*test", "simple expand", "desc", "r"' - keys = "abc test" + EX - wanted = "simple expand" - - -######################### -# SNIPPETS FILE PARSING # -######################### - -class _PS_Base(_VimTest): - def _options_on(self): - self.send(":let UltiSnipsDoHash=0\n") - def _options_off(self): - self.send(":unlet UltiSnipsDoHash\n") - -class ParseSnippets_SimpleSnippet(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet testsnip "Test Snippet" b! - This is a test snippet! - endsnippet - """) - keys = "testsnip" + EX - wanted = "This is a test snippet!" - -class ParseSnippets_MissingEndSnippet(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet testsnip "Test Snippet" b! - This is a test snippet! - """) - keys = "testsnip" + EX - wanted = "testsnip" + EX - expected_error = dedent(""" - UltiSnips: Missing 'endsnippet' for 'testsnip' in test_file(5) - """).strip() - -class ParseSnippets_UnknownDirective(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - unknown directive - """) - keys = "testsnip" + EX - wanted = "testsnip" + EX - expected_error = dedent(""" - UltiSnips: Invalid line 'unknown directive' in test_file(2) - """).strip() - -class ParseSnippets_ExtendsWithoutFiletype(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - extends - """) - keys = "testsnip" + EX - wanted = "testsnip" + EX - expected_error = dedent(""" - UltiSnips: 'extends' without file types in test_file(2) - """).strip() - -class ParseSnippets_ClearAll(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet testsnip "Test snippet" - This is a test. - endsnippet - - clearsnippets - """) - keys = "testsnip" + EX - wanted = "testsnip" + EX - -class ParseSnippets_ClearOne(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet testsnip "Test snippet" - This is a test. - endsnippet - - snippet toclear "Snippet to clear" - Do not expand. - endsnippet - - clearsnippets toclear - """) - keys = "toclear" + EX + "\n" + "testsnip" + EX - wanted = "toclear" + EX + "\n" + "This is a test." - -class ParseSnippets_ClearTwo(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet testsnip "Test snippet" - This is a test. - endsnippet - - snippet toclear "Snippet to clear" - Do not expand. - endsnippet - - clearsnippets testsnip toclear - """) - keys = "toclear" + EX + "\n" + "testsnip" + EX - wanted = "toclear" + EX + "\n" + "testsnip" + EX - - -class _ParseSnippets_MultiWord(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet /test snip/ - This is a test. - endsnippet - - snippet !snip test! "Another snippet" - This is another test. - endsnippet - - snippet "snippet test" "Another snippet" b - This is yet another test. - endsnippet - """) -class ParseSnippets_MultiWord_Simple(_ParseSnippets_MultiWord): - keys = "test snip" + EX - wanted = "This is a test." -class ParseSnippets_MultiWord_Description(_ParseSnippets_MultiWord): - keys = "snip test" + EX - wanted = "This is another test." -class ParseSnippets_MultiWord_Description_Option(_ParseSnippets_MultiWord): - keys = "snippet test" + EX - wanted = "This is yet another test." - -class _ParseSnippets_MultiWord_RE(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet /[d-f]+/ "" r - az test - endsnippet - - snippet !^(foo|bar)$! "" r - foo-bar test - endsnippet - - snippet "(test ?)+" "" r - re-test - endsnippet - """) -class ParseSnippets_MultiWord_RE1(_ParseSnippets_MultiWord_RE): - keys = "abc def" + EX - wanted = "abc az test" -class ParseSnippets_MultiWord_RE2(_ParseSnippets_MultiWord_RE): - keys = "foo" + EX + " bar" + EX + "\nbar" + EX - wanted = "foo-bar test bar\t\nfoo-bar test" -class ParseSnippets_MultiWord_RE3(_ParseSnippets_MultiWord_RE): - keys = "test test test" + EX - wanted = "re-test" - -class ParseSnippets_MultiWord_Quotes(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet "test snip" - This is a test. - endsnippet - """) - keys = "test snip" + EX - wanted = "This is a test." -class ParseSnippets_MultiWord_WithQuotes(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet !"test snip"! - This is a test. - endsnippet - """) - keys = '"test snip"' + EX - wanted = "This is a test." - -class ParseSnippets_MultiWord_NoContainer(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet test snip - This is a test. - endsnippet - """) - keys = "test snip" + EX - wanted = keys - expected_error = dedent(""" - UltiSnips: Invalid multiword trigger: 'test snip' in test_file(2) - """).strip() + wanted = "abc simple expand" -class ParseSnippets_MultiWord_UnmatchedContainer(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - snippet !inv snip/ - This is a test. - endsnippet - """) - keys = "inv snip" + EX - wanted = keys - expected_error = dedent(""" - UltiSnips: Invalid multiword trigger: '!inv snip/' in test_file(2) - """).strip() +class AddFunc_Opt(_AddFuncBase): + args = '".*test", "simple expand", "desc", "r"' + keys = "abc test" + EX + wanted = "simple expand" +# End: AddSnippet Function #}}} -class ParseSnippets_Global_Python(_PS_Base): - snippets_test_file = ("all", "test_file", r""" - global !p - def tex(ins): - return "a " + ins + " b" - endglobal +# ExpandTab {{{# +class _ExpandTabs(_VimTest): + def _options_on(self): + self.send(":set sw=3\n") + self.send(":set expandtab\n") + def _options_off(self): + self.send(":set sw=8\n") + self.send(":set noexpandtab\n") - snippet ab - x `!p snip.rv = tex("bob")` y - endsnippet +class RecTabStopsWithExpandtab_SimpleExample_ECR(_ExpandTabs): + snippets = ("m", "\tBlaahblah \t\t ") + keys = "m" + EX + wanted = " Blaahblah \t\t " - 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 RecTabStopsWithExpandtab_SpecialIndentProblem_ECR(_ExpandTabs): + # Windows indents the Something line after pressing return, though it + # shouldn't because it contains a manual indent. All other vim versions do + # not do this. Windows vim does not interpret the changes made by :py as + # changes made 'manually', while the other vim version seem to do so. Since + # the fault is not with UltiSnips, we simply skip this test on windows + # completely. + skip_on_windows = True + snippets = ( + ("m1", "Something"), + ("m", "\t$0"), + ) + keys = "m" + EX + "m1" + EX + '\nHallo' + wanted = " Something\n Hallo" + def _options_on(self): + _ExpandTabs._options_on(self) + self.send(":set indentkeys=o,O,*,<>>,{,}\n") + self.send(":set indentexpr=8\n") + def _options_off(self): + _ExpandTabs._options_off(self) + self.send(":set indentkeys=\n") + self.send(":set indentexpr=\n") +# End: ExpandTab #}}} +# Proper Indenting {{{# +class ProperIndenting_SimpleCase_ECR(_VimTest): + snippets = ("test", "for\n blah") + keys = " test" + EX + "Hui" + wanted = " for\n blahHui" +class ProperIndenting_SingleLineNoReindenting_ECR(_VimTest): + snippets = ("test", "hui") + keys = " test" + EX + "blah" + wanted = " huiblah" +class ProperIndenting_AutoIndentAndNewline_ECR(_VimTest): + snippets = ("test", "hui") + keys = " test" + EX + "\n"+ "blah" + wanted = " hui\n blah" + def _options_on(self): + self.send(":set autoindent\n") + def _options_off(self): + self.send(":set noautoindent\n") +# End: Proper Indenting #}}} +# Format options tests {{{# +class _FormatoptionsBase(_VimTest): + def _options_on(self): + self.send(":set tw=20\n") + self.send(":set fo=lrqntc\n") + def _options_off(self): + self.send(":set tw=0\n") + self.send(":set fo=tcq\n") -class ParseSnippets_Global_Local_Python(_PS_Base): - snippets_test_file = ("all", "test_file", r""" -global !p -def tex(ins): - return "a " + ins + " b" -endglobal +class FOSimple_Break_ExceptCorrectResult(_FormatoptionsBase): + snippets = ("test", "${1:longer expand}\n$1\n$0", "", "f") + keys = "test" + EX + "This is a longer text that should wrap as formatoptions are enabled" + JF + "end" + wanted = "This is a longer\ntext that should\nwrap as\nformatoptions are\nenabled\n" + \ + "This is a longer\ntext that should\nwrap as\nformatoptions are\nenabled\n" + "end" -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" +class FOTextBeforeAndAfter_ExceptCorrectResult(_FormatoptionsBase): + snippets = ("test", "Before${1:longer expand}After\nstart$1end") + keys = "test" + EX + "This is a longer text that should wrap" + wanted = \ +"""BeforeThis is a +longer text that +should wrapAfter +startThis is a +longer text that +should wrapend""" + + +class FOTextAfter_ExceptCorrectResult(_FormatoptionsBase): + """Testcase for lp:719998""" + snippets = ("test", "${1:longer expand}after\nstart$1end") + keys = ("test" + EX + "This is a longer snippet that should wrap properly " + "and the mirror below should work as well") + wanted = \ +"""This is a longer +snippet that should +wrap properly and +the mirror below +should work as wellafter +startThis is a longer +snippet that should +wrap properly and +the mirror below +should work as wellend""" -####################### +class FOWrapOnLongWord_ExceptCorrectResult(_FormatoptionsBase): + """Testcase for lp:719998""" + snippets = ("test", "${1:longer expand}after\nstart$1end") + keys = ("test" + EX + "This is a longersnippet that should wrap properly") + wanted = \ +"""This is a +longersnippet that +should wrap properlyafter +startThis is a +longersnippet that +should wrap properlyend""" +# End: Format options tests #}}} +# Langmap Handling {{{# # Test for bug 501727 # -####################### class TestNonEmptyLangmap_ExceptCorrectResult(_VimTest): snippets = ("testme", """my snipped ${1:some_default} @@ -2385,30 +2430,248 @@ def _options_on(self): def _options_off(self): self.send(":set langmap=\n") -####################### -# Test for bug 871357 # -####################### -class TestLangmapWithUtf8_ExceptCorrectResult(_VimTest): - snippets = ("testme", -"""my snipped ${1:some_default} -and a mirror: $1 -$2...$3 -$0""") - keys = "testme" + EX + "hi1" + JF + "hi2" + JF + "hi3" + JF + "hi4" - wanted ="""my snipped hi1 -and a mirror: hi1 -hi2...hi3 -hi4""" +# Test for bug 871357 # +class TestLangmapWithUtf8_ExceptCorrectResult(_VimTest): + skip_on_windows = True # SendKeys can't send UTF characters + snippets = ("testme", +"""my snipped ${1:some_default} +and a mirror: $1 +$2...$3 +$0""") + keys = "testme" + EX + "hi1" + JF + "hi2" + JF + "hi3" + JF + "hi4" + wanted ="""my snipped hi1 +and a mirror: hi1 +hi2...hi3 +hi4""" + + def _options_on(self): + self.send(":set langmap=йq,цw,уe,кr,еt,нy,гu,шi,щo,зp,х[,ъ],фa,ыs,вd,аf,пg,рh,оj,лk,дl,ж\\;,э',яz,чx,сc,мv,иb,тn,ьm,ю.,ё',ЙQ,ЦW,УE,КR,ЕT,НY,ГU,ШI,ЩO,ЗP,Х\{,Ъ\},ФA,ЫS,ВD,АF,ПG,РH,ОJ,ЛK,ДL,Ж\:,Э\",ЯZ,ЧX,СC,МV,ИB,ТN,ЬM,Б\<,Ю\>\n") + + def _options_off(self): + self.send(":set langmap=\n") +# End: Langmap Handling #}}} +# Unmap SelectMode Mappings {{{# +# Test for bug 427298 # +class _SelectModeMappings(_VimTest): + snippets = ("test", "${1:World}") + keys = "test" + EX + "Hello" + wanted = "Hello" + maps = ("", "") + buffer_maps = ("", "") + do_unmapping = True + ignores = [] + + def _options_on(self): + self.send(":let g:UltiSnipsRemoveSelectModeMappings=%i\n" % + int(self.do_unmapping)) + self.send(":let g:UltiSnipsMappingsToIgnore=%s\n" % + repr(self.ignores)) + + if not isinstance(self.maps[0], tuple): + self.maps = (self.maps,) + if not isinstance(self.buffer_maps[0], tuple): + self.buffer_maps = (self.buffer_maps,) + + for key, m in self.maps: + if not len(key): continue + self.send(":smap %s %s\n" % (key,m)) + for key, m in self.buffer_maps: + if not len(key): continue + self.send(":smap %s %s\n" % (key,m)) + + def _options_off(self): + for key, m in self.maps: + if not len(key): continue + self.send(":silent! sunmap %s\n" % key) + for key, m in self.buffer_maps: + if not len(key): continue + self.send(":silent! sunmap %s\n" % key) + + self.send(":let g:UltiSnipsRemoveSelectModeMappings=1\n") + self.send(":let g:UltiSnipsMappingsToIgnore= []\n") + +class SelectModeMappings_RemoveBeforeSelecting_ECR(_SelectModeMappings): + maps = ("H", "x") + wanted = "Hello" +class SelectModeMappings_DisableRemoveBeforeSelecting_ECR(_SelectModeMappings): + do_unmapping = False + maps = ("H", "x") + wanted = "xello" +class SelectModeMappings_IgnoreMappings_ECR(_SelectModeMappings): + ignores = ["e"] + maps = ("H", "x"), ("e", "l") + wanted = "Hello" +class SelectModeMappings_IgnoreMappings1_ECR(_SelectModeMappings): + ignores = ["H"] + maps = ("H", "x"), ("e", "l") + wanted = "xello" +class SelectModeMappings_IgnoreMappings2_ECR(_SelectModeMappings): + ignores = ["e", "H"] + maps = ("e", "l"), ("H", "x") + wanted = "xello" +class SelectModeMappings_BufferLocalMappings_ECR(_SelectModeMappings): + buffer_maps = ("H", "blah") + wanted = "Hello" + +# End: Unmap SelectMode Mappings #}}} +# Folding Interaction {{{# +class FoldingEnabled_SnippetWithFold_ExpectNoFolding(_VimTest): + def _options_on(self): + self.send(":set foldlevel=0\n") + self.send(":set foldmethod=marker\n") + def _options_off(self): + self.send(":set foldlevel=0\n") + self.send(":set foldmethod=manual\n") + + snippets = ("test", r"""Hello {{{ +${1:Welt} }}}""") + keys = "test" + EX + "Ball" + wanted = """Hello {{{ +Ball }}}""" +class FoldOverwrite_Simple_ECR(_VimTest): + snippets = ("fold", +"""# ${1:Description} `!p snip.rv = vim.eval("&foldmarker").split(",")[0]` + +# End: $1 `!p snip.rv = vim.eval("&foldmarker").split(",")[1]`""") + keys = "fold" + EX + "hi" + wanted = "# hi {{{\n\n# End: hi }}}" +class Fold_DeleteMiddleLine_ECR(_VimTest): + snippets = ("fold", +"""# ${1:Description} `!p snip.rv = vim.eval("&foldmarker").split(",")[0]` + + +# End: $1 `!p snip.rv = vim.eval("&foldmarker").split(",")[1]`""") + keys = "fold" + EX + "hi" + ESC + "jdd" + wanted = "# hi {{{\n\n# End: hi }}}" +# End: Folding Interaction #}}} + +# Cursor Movement {{{# +class CursorMovement_Multiline_ECR(_VimTest): + snippets = ("test", r"$1 ${1:a tab}") + keys = "test" + EX + "this is something\nvery nice\nnot" + JF + "more text" + wanted = "this is something\nvery nice\nnot " \ + "this is something\nvery nice\nnotmore text" +class CursorMovement_BS_InEditMode(_VimTest): + def _options_on(self): + self.send(":set backspace=eol,indent,start\n") + + def _options_off(self): + self.send(":set backspace=\n") + snippets = ("\n\t$1\n\t$2\n\n$3") + keys = "2 different words with identical starts to create the +# popup-menu: +COMPLETION_OPTIONS = "completion1\ncompletion2\n" - def _options_on(self): - self.send(":set langmap=йq,цw,уe,кr,еt,нy,гu,шi,щo,зp,х[,ъ],фa,ыs,вd,аf,пg,рh,оj,лk,дl,ж\\;,э',яz,чx,сc,мv,иb,тn,ьm,ю.,ё',ЙQ,ЦW,УE,КR,ЕT,НY,ГU,ШI,ЩO,ЗP,Х\{,Ъ\},ФA,ЫS,ВD,АF,ПG,РH,ОJ,ЛK,ДL,Ж\:,Э\",ЯZ,ЧX,СC,МV,ИB,ТN,ЬM,Б\<,Ю\>\n") +class Completion_ForwardsJumpWithoutCOMPL_ACCEPT(_VimTest): + # completions should not be truncated when JF is activated without having + # pressed COMPL_ACCEPT (Bug #598903) + snippets = ("test", "$1 $2") + keys = COMPLETION_OPTIONS + "test" + EX + "com" + COMPL_KW + JF + "foo" + wanted = COMPLETION_OPTIONS + "completion1 foo" - def _options_off(self): - self.send(":set langmap=\n") +class Completion_BackwardsJumpWithoutCOMPL_ACCEPT(_VimTest): + # completions should not be truncated when JB is activated without having + # pressed COMPL_ACCEPT (Bug #598903) + snippets = ("test", "$1 $2") + keys = COMPLETION_OPTIONS + "test" + EX + "foo" + JF + "com" + COMPL_KW + \ + JB + "foo" + wanted = COMPLETION_OPTIONS + "foo completion1" +# End: Tab Completion of Words #}}} +# Pressing BS in TabStop {{{# +# Test for Bug #774917 +class Backspace_TabStop_Zero(_VimTest): + snippets = ("test", "A${1:C} ${0:DDD}", "This is Case 1") + keys = "test" + EX + "A" + JF + BS + "BBB" + wanted = "AA BBB" -######################## +class Backspace_TabStop_NotZero(_VimTest): + snippets = ("test", "A${1:C} ${2:DDD}", "This is Case 1") + keys = "test" + EX + "A" + JF + BS + "BBB" + wanted = "AA BBB" +# End: Pressing BS in TabStop #}}} +# Newline in default text {{{# # Tests for bug 616315 # -######################## class TrailingNewline_TabStop_NLInsideStuffBehind(_VimTest): snippets = ("test", r""" x${1: @@ -2515,165 +2778,123 @@ class MultiLineDefault_BS(_MultiLineDefault): x y""" -####################### -# Test for bug 427298 # -####################### -class _SelectModeMappings(_VimTest): - snippets = ("test", "${1:World}") - keys = "test" + EX + "Hello" - wanted = "Hello" - maps = ("", "") - buffer_maps = ("", "") - do_unmapping = True - ignores = [] - - def _options_on(self): - self.send(":let g:UltiSnipsRemoveSelectModeMappings=%i\n" % - int(self.do_unmapping)) - self.send(":let g:UltiSnipsMappingsToIgnore=%s\n" % - repr(self.ignores)) - - if not isinstance(self.maps[0], tuple): - self.maps = (self.maps,) - if not isinstance(self.buffer_maps[0], tuple): - self.buffer_maps = (self.buffer_maps,) - - for key, m in self.maps: - if not len(key): continue - self.send(":smap %s %s\n" % (key,m)) - for key, m in self.buffer_maps: - if not len(key): continue - self.send(":smap %s %s\n" % (key,m)) - - def _options_off(self): - for key, m in self.maps: - if not len(key): continue - self.send(":silent! sunmap %s\n" % key) - for key, m in self.buffer_maps: - if not len(key): continue - self.send(":silent! sunmap %s\n" % key) - - self.send(":let g:UltiSnipsRemoveSelectModeMappings=1\n") - self.send(":let g:UltiSnipsMappingsToIgnore= []\n") - -class SelectModeMappings_RemoveBeforeSelecting_ECR(_SelectModeMappings): - maps = ("H", "x") - wanted = "Hello" -class SelectModeMappings_DisableRemoveBeforeSelecting_ECR(_SelectModeMappings): - do_unmapping = False - maps = ("H", "x") - wanted = "xello" -class SelectModeMappings_IgnoreMappings_ECR(_SelectModeMappings): - ignores = ["e"] - maps = ("H", "x"), ("e", "l") - wanted = "Hello" -class SelectModeMappings_IgnoreMappings1_ECR(_SelectModeMappings): - ignores = ["H"] - maps = ("H", "x"), ("e", "l") - wanted = "xello" -class SelectModeMappings_IgnoreMappings2_ECR(_SelectModeMappings): - ignores = ["e", "H"] - maps = ("e", "l"), ("H", "x") - wanted = "xello" -class SelectModeMappings_BufferLocalMappings_ECR(_SelectModeMappings): - buffer_maps = ("H", "blah") - wanted = "Hello" - -#################### -# Folding problems # -#################### -class FoldingEnabled_SnippetWithFold_ExpectNoFolding(_VimTest): - def _options_on(self): - self.send(":set foldlevel=0\n") - self.send(":set foldmethod=marker\n") - def _options_off(self): - self.send(":set foldlevel=0\n") - self.send(":set foldmethod=manual\n") - - snippets = ("test", r"""Hello {{{ -${1:Welt} }}}""") - keys = "test" + EX + "Ball" - wanted = """Hello {{{ -Ball }}}""" -################### -# ${VISUAL} tests # -################### -class Visual_NoVisualSelection_Ignore(_VimTest): - snippets = ("test", "h${VISUAL}b") - keys = "test" + EX + "abc" - wanted = "hbabc" -class Visual_SelectOneWord(_VimTest): - snippets = ("test", "h${VISUAL}b") - keys = "blablub" + ESC + "0v6l" + EX + "test" + EX - wanted = "hblablubb" +# End: Newline in default text #}}} +# Quotes in Snippets {{{# +# Test for Bug #774917 +def _snip_quote(qt): + return ( + ("te" + qt + "st", "Expand me" + qt + "!", "test: "+qt), + ("te", "Bad", ""), + ) -class Visual_ExpandTwice(_VimTest): - snippets = ("test", "h${VISUAL}b") - keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + "\ntest" + EX - wanted = "hblablubb\nhb" +class Snippet_With_SingleQuote(_VimTest): + snippets = _snip_quote("'") + keys = "te'st" + EX + wanted = "Expand me'!" -class Visual_SelectOneWord_TwiceVisual(_VimTest): - snippets = ("test", "h${VISUAL}b${VISUAL}a") - keys = "blablub" + ESC + "0v6l" + EX + "test" + EX - wanted = "hblablubbblabluba" -class Visual_SelectOneWord_Inword(_VimTest): - snippets = ("test", "h${VISUAL}b", "Description", "i") - keys = "blablub" + ESC + "0lv4l" + EX + "test" + EX - wanted = "bhlablubb" -class Visual_SelectOneWord_TillEndOfLine(_VimTest): - snippets = ("test", "h${VISUAL}b", "Description", "i") - keys = "blablub" + ESC + "0v$" + EX + "test" + EX + ESC + "o" - wanted = "hblablub\nb" -class Visual_SelectOneWordWithTabstop_TillEndOfLine(_VimTest): - snippets = ("test", "h${2:ahh}${VISUAL}${1:ups}b", "Description", "i") - keys = "blablub" + ESC + "0v$" + EX + "test" + EX + "mmm" + JF + "n" + JF + "done" + ESC + "o" - wanted = "hnblablub\nmmmbdone" -class Visual_InDefaultText_SelectOneWord_NoOverwrite(_VimTest): - snippets = ("test", "h${1:${VISUAL}}b") - keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + JF + "hello" - wanted = "hblablubbhello" -class Visual_InDefaultText_SelectOneWord(_VimTest): - snippets = ("test", "h${1:${VISUAL}}b") - keys = "blablub" + ESC + "0v6l" + EX + "test" + EX + "hello" - wanted = "hhellob" +class Snippet_With_SingleQuote_List(_VimTest): + snippets = _snip_quote("'") + keys = "te" + LS + "2\n" + wanted = "Expand me'!" -class Visual_CrossOneLine(_VimTest): - snippets = ("test", "h${VISUAL}b") - keys = "bla blub\n helloi" + ESC + "0k4lvjll" + EX + "test" + EX - wanted = "bla hblub\n hellobi" +class Snippet_With_DoubleQuote(_VimTest): + snippets = _snip_quote('"') + keys = 'te"st' + EX + wanted = "Expand me\"!" -class Visual_LineSelect(_VimTest): - snippets = ("test", "h${VISUAL}b") - keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX - wanted = "hhello\nnice\nworld\nb" -class Visual_InDefaultText_LineSelect_NoOverwrite(_VimTest): - snippets = ("test", "h${1:bef${VISUAL}aft}b") - keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + JF + "hi" - wanted = "hbefhello\nnice\nworld\naftbhi" -class Visual_InDefaultText_LineSelect_Overwrite(_VimTest): - snippets = ("test", "h${1:bef${VISUAL}aft}b") - keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "jup" + JF + "hi" - wanted = "hjupbhi" -class Visual_LineSelect_CheckIndent(_VimTest): - snippets = ("test", "beg\n\t${VISUAL}\nend") - keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX - wanted = "beg\n\thello\n\tnice\n\tworld\nend" +class Snippet_With_DoubleQuote_List(_VimTest): + snippets = _snip_quote('"') + keys = "te" + LS + "2\n" + wanted = "Expand me\"!" +# End: Quotes in Snippets #}}} +# Umlauts and Special Chars {{{# +class _UmlautsBase(_VimTest): + skip_on_windows = True # SendKeys can't send UTF characters -class Visual_LineSelect_CheckIndentTwice(_VimTest): - snippets = ("test", "beg\n\t${VISUAL}\nend") - keys = " hello\n nice\n\tworld" + ESC + "Vkk" + EX + "test" + EX - wanted = "beg\n\t hello\n\t nice\n\t\tworld\nend" +class Snippet_With_Umlauts_List(_UmlautsBase): + snippets = _snip_quote('ü') + keys = 'te' + LS + "2\n" + wanted = "Expand meü!" -class Visual_LineSelect_WithTabStop(_VimTest): - snippets = ("test", "beg\n\t${VISUAL}\n\t${1:here_we_go}\nend") - keys = "hello\nnice\nworld" + ESC + "Vkk" + EX + "test" + EX + "super" + JF + "done" - wanted = "beg\n\thello\n\tnice\n\tworld\n\tsuper\nenddone" +class Snippet_With_Umlauts(_UmlautsBase): + snippets = _snip_quote('ü') + keys = 'teüst' + EX + wanted = "Expand meü!" +class Snippet_With_Umlauts_TypeOn(_UmlautsBase): + snippets = ('ül', 'üüüüüßßßß') + keys = 'te ül' + EX + "more text" + wanted = "te üüüüüßßßßmore text" +class Snippet_With_Umlauts_OverwriteFirst(_UmlautsBase): + snippets = ('ül', 'üü ${1:world} üü ${2:hello}ßß\nüüüü') + keys = 'te ül' + EX + "more text" + JF + JF + "end" + wanted = "te üü more text üü helloßß\nüüüüend" +class Snippet_With_Umlauts_OverwriteSecond(_UmlautsBase): + snippets = ('ül', 'üü ${1:world} üü ${2:hello}ßß\nüüüü') + keys = 'te ül' + EX + JF + "more text" + JF + "end" + wanted = "te üü world üü more textßß\nüüüüend" +class Snippet_With_Umlauts_OverwriteNone(_UmlautsBase): + snippets = ('ül', 'üü ${1:world} üü ${2:hello}ßß\nüüüü') + keys = 'te ül' + EX + JF + JF + "end" + wanted = "te üü world üü helloßß\nüüüüend" +class Snippet_With_Umlauts_Mirrors(_UmlautsBase): + snippets = ('ül', 'üü ${1:world} üü $1') + keys = 'te ül' + EX + "hello" + wanted = "te üü hello üü hello" +class Snippet_With_Umlauts_Python(_UmlautsBase): + snippets = ('ül', 'üü ${1:world} üü `!p snip.rv = len(t[1])*"a"`') + keys = 'te ül' + EX + "hüüll" + wanted = "te üü hüüll üü aaaaa" +# End: Umlauts and Special Chars #}}} +# Exclusive Selection {{{# +class _ES_Base(_VimTest): + def _options_on(self): + self.send(":set selection=exclusive\n") + def _options_off(self): + self.send(":set selection=inclusive\n") + +class ExclusiveSelection_SimpleTabstop_Test(_ES_Base): + snippets = ("test", "h${1:blah}w $1") + keys = "test" + EX + "ui" + JF + wanted = "huiw ui" + +class ExclusiveSelection_RealWorldCase_Test(_ES_Base): + snippets = ("for", +"""for ($${1:i} = ${2:0}; $$1 < ${3:count}; $$1${4:++}) { + ${5:// code} +}""") + keys = "for" + EX + "k" + JF + wanted = """for ($k = 0; $k < count; $k++) { + // code +}""" +# End: Exclusive Selection #}}} +# Normal mode editing {{{# +# Test for bug #927844 +class DeleteLastTwoLinesInSnippet(_VimTest): + snippets = ("test", "$1hello\nnice\nworld") + keys = "test" + EX + ESC + "j2dd" + wanted = "hello" +class DeleteCurrentTabStop1_JumpBack(_VimTest): + snippets = ("test", "${1:hi}\nend") + keys = "test" + EX + ESC + "ddi" + JB + wanted = "end" +class DeleteCurrentTabStop2_JumpBack(_VimTest): + snippets = ("test", "${1:hi}\n${2:world}\nend") + keys = "test" + EX + JF + ESC + "ddi" + JB + "hello" + wanted = "hello\nend" +class DeleteCurrentTabStop3_JumpAround(_VimTest): + snippets = ("test", "${1:hi}\n${2:world}\nend") + keys = "test" + EX + JF + ESC + "ddkji" + JB + "hello" + JF + "world" + wanted = "hello\nendworld" + +# End: Normal mode editing #}}} ########################################################################### # END OF TEST # ########################################################################### + + if __name__ == '__main__': import sys import optparse @@ -2748,4 +2969,4 @@ def parse_args(): v = 1 res = unittest.TextTestRunner(verbosity=v).run(suite) -# vim:fileencoding=utf-8: +# vim:fileencoding=utf-8:foldmarker={{{#,#}}}: diff --git a/vim/bundle/ultisnips/utils/convert_snipmate_snippets.py b/vim/bundle/ultisnips/utils/convert_snipmate_snippets.py index 2fdef8b..689f58f 100755 --- a/vim/bundle/ultisnips/utils/convert_snipmate_snippets.py +++ b/vim/bundle/ultisnips/utils/convert_snipmate_snippets.py @@ -48,7 +48,15 @@ def convert_snippet_file(source): # 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 + # Copy-paste the section from state=0 so that we don't skip every other snippet + 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 = "" else: snippet += line[len(whitespace):] if state == 2: diff --git a/vim/bundle/vim-fugitive/plugin/fugitive.vim b/vim/bundle/vim-fugitive/plugin/fugitive.vim index 5853526..fa33917 100644 --- a/vim/bundle/vim-fugitive/plugin/fugitive.vim +++ b/vim/bundle/vim-fugitive/plugin/fugitive.vim @@ -100,7 +100,7 @@ let s:abstract_prototype = {} " Initialization {{{1 function! fugitive#is_git_dir(path) abort - let path = a:path . '/' + let path = s:sub(a:path, '[\/]$', '') . '/' return isdirectory(path.'objects') && isdirectory(path.'refs') && getfsize(path.'HEAD') > 10 endfunction diff --git a/vim/update_bundles.rb b/vim/update_bundles.rb index f47a3df..a1f8d8e 100755 --- a/vim/update_bundles.rb +++ b/vim/update_bundles.rb @@ -27,7 +27,7 @@ "https://github.com/nelstrom/vim-textobj-rubyblock.git", "https://github.com/kana/vim-textobj-user.git", "https://github.com/fholgado/minibufexpl.vim.git", - "https://github.com/rygwdn/ultisnips.git", + "https://github.com/SirVer/ultisnips.git", "https://github.com/MarcWeber/vim-addon-mw-utils.git", "https://github.com/tomtom/tlib_vim.git", "https://github.com/majutsushi/tagbar.git", diff --git a/vimrc b/vimrc index 7c331e5..28e25fb 100644 --- a/vimrc +++ b/vimrc @@ -123,14 +123,18 @@ if has("autocmd") augroup vimrc autocmd! au FileType eruby,ruby setlocal nocindent - au FileType eruby,ruby set omnifunc=rubycomplete#Complete + au FileType eruby,ruby setlocal omnifunc=rubycomplete#Complete au FileType eruby,ruby let g:rubycomplete_buffer_loading = 1 au FileType eruby,ruby let g:rubycomplete_classes_in_global = 1 au FileType eruby,ruby let g:rubycomplete_rails = 1 + au FileType ruby setlocal foldmethod=syntax + au FileType ruby normal zR au FileType java setlocal omnifunc=javacomplete#Complete au FileType java setlocal completefunc=javacomplete#CompleteParamsInfo au BufReadCmd *.epub call zip#Browse(expand("")) au BufRead,BufNewFile pom.xml set filetype=xml.maven + + " Configure omnicomplete to use syntax completion if no other omnifunc exists au FileType * \ if &omnifunc == "" | @@ -249,7 +253,7 @@ inoremap u inoremap u " AutoComplPop Configuration -let g:acp_enableAtStartup = 0 +let g:acp_enableAtStartup = 1 inoremap pumvisible() \|\| &omnifunc == '' ? \ "\C-n>" : @@ -258,6 +262,9 @@ inoremap pumvisible() \|\| &omnifunc == '' ? \ "\" \\bs>\\C-n>\"\" imap +nnoremap @=(foldlevel('.')?'za':"\") +vnoremap zf + " Abbreviations " Change colorscheme from default to vilight