From 88649519d4f1e8df9a9906c4be565f96c95beab8 Mon Sep 17 00:00:00 2001 From: Buddy Sandidge Date: Wed, 19 Feb 2014 21:55:17 -0800 Subject: [PATCH] Squashed 'vim/bundle/ultisnips/' content from commit cecc7aad8 git-subtree-dir: vim/bundle/ultisnips git-subtree-split: cecc7aad882b56550ae52e3feea8b690ed330ab3 --- .bzrignore | 2 + .gitignore | 3 + COPYING.txt | 674 ++++ ChangeLog | 101 + README.rst | 22 + UltiSnips/README | 21 + UltiSnips/all.snippets | 120 + UltiSnips/bib.snippets | 52 + UltiSnips/bindzone.snippets | 29 + UltiSnips/c.snippets | 155 + UltiSnips/coffee.snippets | 91 + UltiSnips/coffee_jasmine.snippets | 166 + UltiSnips/cpp.snippets | 57 + UltiSnips/cs.snippets | 328 ++ UltiSnips/css.snippets | 407 ++ UltiSnips/d.snippets | 584 +++ UltiSnips/django.snippets | 238 ++ UltiSnips/erlang.snippets | 100 + UltiSnips/eruby.snippets | 280 ++ UltiSnips/go.snippets | 131 + UltiSnips/haskell.snippets | 63 + UltiSnips/help.snippets | 32 + UltiSnips/html.snippets | 302 ++ UltiSnips/htmldjango.snippets | 3 + UltiSnips/htmljinja.snippets | 3 + UltiSnips/java.snippets | 431 +++ UltiSnips/javascript.snippets | 162 + UltiSnips/javascript_jasmine.snippets | 169 + UltiSnips/javascript_jsdoc.snippets | 51 + UltiSnips/jinja2.snippets | 209 ++ UltiSnips/json.snippets | 20 + UltiSnips/ledger.snippets | 8 + UltiSnips/lhaskell.snippets | 3 + UltiSnips/lua.snippets | 39 + UltiSnips/mako.snippets | 92 + UltiSnips/markdown.snippets | 42 + UltiSnips/objc.snippets | 272 ++ UltiSnips/ocaml.snippets | 174 + UltiSnips/perl.snippets | 132 + UltiSnips/php.snippets | 264 ++ UltiSnips/puppet.snippets | 232 ++ UltiSnips/python.snippets | 533 +++ UltiSnips/rails.snippets | 904 +++++ UltiSnips/rst.snippets | 61 + UltiSnips/ruby.snippets | 570 +++ UltiSnips/scss.snippets | 55 + UltiSnips/sh.snippets | 92 + UltiSnips/snippets.snippets | 21 + UltiSnips/tcl.snippets | 52 + UltiSnips/tex.snippets | 110 + UltiSnips/texmath.snippets | 56 + UltiSnips/vim.snippets | 60 + UltiSnips/xhtml.snippets | 3 + UltiSnips/xml.snippets | 16 + UltiSnips/zsh.snippets | 17 + after/plugin/UltiSnips_after.vim | 13 + autoload/UltiSnips.vim | 188 + autoload/UltiSnips/map_keys.vim | 38 + autoload/UltiSnips/variables.vim | 48 + doc/UltiSnips.txt | 1417 +++++++ ftdetect/UltiSnips.vim | 5 + ftdetect/snippets.vim | 4 + ftplugin/snippets.vim | 16 + plugin/UltiSnips.vim | 69 + plugin/snipMate_compatibility.vim | 28 + pylintrc | 268 ++ pythonx/UltiSnips/__init__.py | 13 + pythonx/UltiSnips/_diff.py | 219 ++ pythonx/UltiSnips/_vim.py | 294 ++ pythonx/UltiSnips/compatibility.py | 85 + pythonx/UltiSnips/debug.py | 43 + pythonx/UltiSnips/escaping.py | 26 + pythonx/UltiSnips/indent_util.py | 39 + pythonx/UltiSnips/position.py | 65 + pythonx/UltiSnips/providers/__init__.py | 10 + pythonx/UltiSnips/providers/_base.py | 43 + .../providers/_snippet_dictionary.py | 80 + .../providers/added_snippets_provider.py | 13 + pythonx/UltiSnips/providers/snippet_file.py | 152 + pythonx/UltiSnips/providers/ultisnips_file.py | 125 + pythonx/UltiSnips/snippet_definition.py | 214 ++ pythonx/UltiSnips/snippet_manager.py | 526 +++ pythonx/UltiSnips/test_diff.py | 186 + pythonx/UltiSnips/test_position.py | 70 + pythonx/UltiSnips/text_objects/__init__.py | 6 + pythonx/UltiSnips/text_objects/_base.py | 362 ++ .../UltiSnips/text_objects/_escaped_char.py | 15 + pythonx/UltiSnips/text_objects/_lexer.py | 349 ++ pythonx/UltiSnips/text_objects/_mirror.py | 30 + pythonx/UltiSnips/text_objects/_parser.py | 76 + .../UltiSnips/text_objects/_python_code.py | 209 ++ pythonx/UltiSnips/text_objects/_shell_code.py | 71 + .../text_objects/_snippet_instance.py | 131 + pythonx/UltiSnips/text_objects/_tabstop.py | 30 + .../UltiSnips/text_objects/_transformation.py | 149 + pythonx/UltiSnips/text_objects/_viml_code.py | 18 + pythonx/UltiSnips/text_objects/_visual.py | 58 + pythonx/UltiSnips/vim_state.py | 129 + syntax/snippets.vim | 72 + test.py | 3300 +++++++++++++++++ utils/convert_snipmate_snippets.py | 108 + utils/get_tm_snippets.py | 148 + 102 files changed, 18372 insertions(+) create mode 100644 .bzrignore create mode 100644 .gitignore create mode 100644 COPYING.txt create mode 100644 ChangeLog create mode 100644 README.rst create mode 100644 UltiSnips/README create mode 100644 UltiSnips/all.snippets create mode 100644 UltiSnips/bib.snippets create mode 100644 UltiSnips/bindzone.snippets create mode 100644 UltiSnips/c.snippets create mode 100644 UltiSnips/coffee.snippets create mode 100644 UltiSnips/coffee_jasmine.snippets create mode 100644 UltiSnips/cpp.snippets create mode 100644 UltiSnips/cs.snippets create mode 100644 UltiSnips/css.snippets create mode 100644 UltiSnips/d.snippets create mode 100644 UltiSnips/django.snippets create mode 100644 UltiSnips/erlang.snippets create mode 100644 UltiSnips/eruby.snippets create mode 100644 UltiSnips/go.snippets create mode 100644 UltiSnips/haskell.snippets create mode 100644 UltiSnips/help.snippets create mode 100644 UltiSnips/html.snippets create mode 100644 UltiSnips/htmldjango.snippets create mode 100644 UltiSnips/htmljinja.snippets create mode 100644 UltiSnips/java.snippets create mode 100644 UltiSnips/javascript.snippets create mode 100644 UltiSnips/javascript_jasmine.snippets create mode 100644 UltiSnips/javascript_jsdoc.snippets create mode 100644 UltiSnips/jinja2.snippets create mode 100644 UltiSnips/json.snippets create mode 100644 UltiSnips/ledger.snippets create mode 100644 UltiSnips/lhaskell.snippets create mode 100644 UltiSnips/lua.snippets create mode 100644 UltiSnips/mako.snippets create mode 100644 UltiSnips/markdown.snippets create mode 100644 UltiSnips/objc.snippets create mode 100644 UltiSnips/ocaml.snippets create mode 100644 UltiSnips/perl.snippets create mode 100644 UltiSnips/php.snippets create mode 100644 UltiSnips/puppet.snippets create mode 100644 UltiSnips/python.snippets create mode 100644 UltiSnips/rails.snippets create mode 100644 UltiSnips/rst.snippets create mode 100644 UltiSnips/ruby.snippets create mode 100644 UltiSnips/scss.snippets create mode 100644 UltiSnips/sh.snippets create mode 100644 UltiSnips/snippets.snippets create mode 100644 UltiSnips/tcl.snippets create mode 100644 UltiSnips/tex.snippets create mode 100644 UltiSnips/texmath.snippets create mode 100644 UltiSnips/vim.snippets create mode 100644 UltiSnips/xhtml.snippets create mode 100644 UltiSnips/xml.snippets create mode 100644 UltiSnips/zsh.snippets create mode 100644 after/plugin/UltiSnips_after.vim create mode 100644 autoload/UltiSnips.vim create mode 100644 autoload/UltiSnips/map_keys.vim create mode 100644 autoload/UltiSnips/variables.vim create mode 100644 doc/UltiSnips.txt create mode 100644 ftdetect/UltiSnips.vim create mode 100644 ftdetect/snippets.vim create mode 100644 ftplugin/snippets.vim create mode 100644 plugin/UltiSnips.vim create mode 100644 plugin/snipMate_compatibility.vim create mode 100644 pylintrc create mode 100644 pythonx/UltiSnips/__init__.py create mode 100644 pythonx/UltiSnips/_diff.py create mode 100644 pythonx/UltiSnips/_vim.py create mode 100644 pythonx/UltiSnips/compatibility.py create mode 100644 pythonx/UltiSnips/debug.py create mode 100644 pythonx/UltiSnips/escaping.py create mode 100644 pythonx/UltiSnips/indent_util.py create mode 100644 pythonx/UltiSnips/position.py create mode 100644 pythonx/UltiSnips/providers/__init__.py create mode 100644 pythonx/UltiSnips/providers/_base.py create mode 100644 pythonx/UltiSnips/providers/_snippet_dictionary.py create mode 100644 pythonx/UltiSnips/providers/added_snippets_provider.py create mode 100644 pythonx/UltiSnips/providers/snippet_file.py create mode 100644 pythonx/UltiSnips/providers/ultisnips_file.py create mode 100644 pythonx/UltiSnips/snippet_definition.py create mode 100644 pythonx/UltiSnips/snippet_manager.py create mode 100644 pythonx/UltiSnips/test_diff.py create mode 100644 pythonx/UltiSnips/test_position.py create mode 100644 pythonx/UltiSnips/text_objects/__init__.py create mode 100644 pythonx/UltiSnips/text_objects/_base.py create mode 100644 pythonx/UltiSnips/text_objects/_escaped_char.py create mode 100644 pythonx/UltiSnips/text_objects/_lexer.py create mode 100644 pythonx/UltiSnips/text_objects/_mirror.py create mode 100644 pythonx/UltiSnips/text_objects/_parser.py create mode 100644 pythonx/UltiSnips/text_objects/_python_code.py create mode 100644 pythonx/UltiSnips/text_objects/_shell_code.py create mode 100644 pythonx/UltiSnips/text_objects/_snippet_instance.py create mode 100644 pythonx/UltiSnips/text_objects/_tabstop.py create mode 100644 pythonx/UltiSnips/text_objects/_transformation.py create mode 100644 pythonx/UltiSnips/text_objects/_viml_code.py create mode 100644 pythonx/UltiSnips/text_objects/_visual.py create mode 100644 pythonx/UltiSnips/vim_state.py create mode 100644 syntax/snippets.vim create mode 100755 test.py create mode 100755 utils/convert_snipmate_snippets.py create mode 100755 utils/get_tm_snippets.py diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..a64bfd0 --- /dev/null +++ b/.bzrignore @@ -0,0 +1,2 @@ +doc/tags +.bzr-repo diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb169b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +*.swp +doc/tags diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..2665648 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,101 @@ +version 2.2: + - Support to silence Python-not-found warnings. *UltiSnips-python-warning* + - Matchit support for snippet files. + - Improvements to syntax file. + - Various smaller bug fixes. + - New command to manually add a filetype to the list for the current + buffer. *:UltiSnipsAddFiletypes* + - New or improved snippets: all, snippets, haskell, bindzone, python, golang, + json, html, coffee, coffee_jasmine, javascript_jasmine, ruby, php, + markdown. + +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 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 + +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. + +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'. + +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) + +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 + +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* ) + diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..a5c261f --- /dev/null +++ b/README.rst @@ -0,0 +1,22 @@ +UltiSnips +========= + +This is the official repository for UltiSnips. Send Pull request to +SirVer/ultisnips, not the automatic clone from vim-scripts or any +other fork of this project. + +Screencasts +----------- + +The blog posts of the screencasts contain more advanced examples of the things +discussed in the videos. + +* `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/UltiSnips/README b/UltiSnips/README new file mode 100644 index 0000000..eafd086 --- /dev/null +++ b/UltiSnips/README @@ -0,0 +1,21 @@ +This directory contains the main scripts that come bundled with UltiSnips. + +Standing On The Shoulders of Giants +=================================== + +The snippets have been collected from various other project which I want to +express my gratitude for. My main source for inspiration where the following +two projects: + + TextMate: http://svn.textmate.org/trunk/Bundles/ + SnipMate: http://code.google.com/p/snipmate/ + +All snippets from those sources were copied and cleaned up, so that they are + - not using shell script, only python (so they are cross platform compatible) + - not using any feature that UltiSnips doesn't offer + +UltiSnips has seen contributions by various individuals. Those contributions +have been merged into this collection seamlessly and without further comments. + +-- vim:ft=rst:nospell: + diff --git a/UltiSnips/all.snippets b/UltiSnips/all.snippets new file mode 100644 index 0000000..085440a --- /dev/null +++ b/UltiSnips/all.snippets @@ -0,0 +1,120 @@ +# This file contains snippets that are always defined. I personally +# have snippets for signatures and often needed texts + +priority -50 + +############## +# NICE BOXES # +############## +global !p +import string, vim + +""" Maps a filetype to comment format used for boxes. +Automatically filled during usage""" +_commentDict = { } + +def _parse_comments(s): + """ Parses vim's comments option to extract comment format """ + i = iter(s.split(",")) + + rv = [] + try: + while True: + # get the flags and text of a comment part + flags, text = next(i).split(':', 1) + + if len(flags) == 0: + rv.append((text, text, text, "")) + # parse 3-part comment, but ignore those with O flag + elif flags[0] == 's' and 'O' not in flags: + ctriple = [] + indent = "" + + if flags[-1] in string.digits: + indent = " " * int(flags[-1]) + ctriple.append(text) + + flags,text = next(i).split(':', 1) + assert(flags[0] == 'm') + ctriple.append(text) + + flags,text = next(i).split(':', 1) + assert(flags[0] == 'e') + ctriple.append(text) + ctriple.append(indent) + + rv.append(ctriple) + elif flags[0] == 'b': + if len(text) == 1: + rv.insert(0, (text,text,text, "")) + except StopIteration: + return rv + +def _get_comment_format(): + """ Returns a 4-element tuple representing the comment format for + the current file. """ + return _parse_comments(vim.eval("&comments"))[0] + + +def make_box(twidth, bwidth=None): + b, m, e, i = _get_comment_format() + bwidth_inner = bwidth - 3 - max(len(b), len(i + e)) if bwidth else twidth + 2 + sline = b + m + bwidth_inner * m[0] + 2 * m[0] + nspaces = (bwidth_inner - twidth) // 2 + mlines = i + m + " " + " " * nspaces + mlinee = " " + " "*(bwidth_inner - twidth - nspaces) + m + eline = i + m + bwidth_inner * m[0] + 2 * m[0] + e + return sline, mlines, mlinee, eline + +def foldmarker(): + "Return a tuple of (open fold marker, close fold marker)" + return vim.eval("&foldmarker").split(",") + +endglobal + +snippet box "A nice box with the current comment symbol" b +`!p +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 +width = int(vim.eval("&textwidth")) or 71 +box = make_box(len(t[1]), width) +snip.rv = box[0] + '\n' + box[1] +`${1:content}`!p +box = make_box(len(t[1]), width) +snip.rv = box[2] + '\n' + box[3]` +$0 +endsnippet + +snippet fold "Insert a vim fold marker" b +`!p snip.rv = _get_comment_format()[0]` ${1:Fold description} `!p snip.rv = foldmarker()[0]`${2:1} `!p snip.rv = _get_comment_format()[2]` +endsnippet + +snippet foldc "Insert a vim fold close marker" b +`!p snip.rv = _get_comment_format()[0]` ${2:1}`!p snip.rv = foldmarker()[1]` `!p snip.rv = _get_comment_format()[2]` +endsnippet + +snippet foldp "Insert a vim fold marker pair" b +`!p snip.rv = _get_comment_format()[0]` ${1:Fold description} `!p snip.rv = foldmarker()[0]` `!p snip.rv = _get_comment_format()[2]` +${2:${VISUAL:Content}} +`!p snip.rv = _get_comment_format()[0]` `!p snip.rv = foldmarker()[1]` $1 `!p snip.rv = _get_comment_format()[2]` +endsnippet + +########################## +# LOREM IPSUM GENERATORS # +########################## +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/UltiSnips/bib.snippets b/UltiSnips/bib.snippets new file mode 100644 index 0000000..c9b8df5 --- /dev/null +++ b/UltiSnips/bib.snippets @@ -0,0 +1,52 @@ +priority -50 + +snippet online "Online resource" b +@online{${1:name}, + author={${2:author}}, + title={${3:title}}, + date={${4:date}}, + url={${5:url}} +} +$0 +endsnippet + +snippet article "Article reference" b +@article{${1:name}, + author={${2:author}}, + title={${3:title}}, + journaltitle={${4:journal}}, + volume={${5:NN}}, + number={${6:NN}}, + year={${7:YYYY}}, + pages={${8:NN}--${9:NN}} +} +$0 +endsnippet + +snippet book "Book reference" b +@book{${1:name}, + author={${2:author}}, + title={${3:title}}, + subtitle={${4:subtitle}}, + year={${5:YYYY}}, + location={${6:somewhere}}, + publisher={${7:publisher}}, + pages={${8:NN}--${9:NN}} +} +$0 +endsnippet + +snippet inb "In Book reference" b +@inbook{${1:name}, + author={${2:author}}, + title={${3:title}}, + subtitle={${4:subtitle}}, + booktitle={${5:book}}, + editor={${6:editor}}, + year={${7:YYYY}}, + location={${8:somewhere}}, + publisher={${9:publisher}}, + pages={${10:NN}--${11:NN}} +} +$0 +endsnippet diff --git a/UltiSnips/bindzone.snippets b/UltiSnips/bindzone.snippets new file mode 100644 index 0000000..b8ab0df --- /dev/null +++ b/UltiSnips/bindzone.snippets @@ -0,0 +1,29 @@ +priority -50 + +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/UltiSnips/c.snippets b/UltiSnips/c.snippets new file mode 100644 index 0000000..5b8eae8 --- /dev/null +++ b/UltiSnips/c.snippets @@ -0,0 +1,155 @@ +########################################################################### +# TextMate Snippets # +########################################################################### + +priority -50 + +snippet def "#define ..." +#define ${1} +endsnippet + +snippet ifndef "#ifndef ... #define ... #endif" +#ifndef ${1/([A-Za-z0-9_]+).*/$1/} +#define ${1:SYMBOL} ${2:value} +#endif +endsnippet + +snippet #if "#if #endif" b +#if ${1:0} +${VISUAL}${0:${VISUAL/(.*)/(?1::code)/}} +#endif +endsnippet + +snippet inc "#include local header (inc)" +#include "${1:`!p snip.rv = snip.basename + '.h'`}" +endsnippet + +snippet Inc "#include <> (Inc)" +#include <${1:.h}> +endsnippet + +snippet mark "#pragma mark (mark)" +#if 0 +${1:#pragma mark - +}#pragma mark $2 +#endif + +$0 +endsnippet + +snippet main "main() (main)" +int main(int argc, char *argv[]) +{ + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} + return 0; +} +endsnippet + +snippet for "for loop (for)" +for (${2:i} = 0; $2 < ${1:count}; ${3:++$2}) +{ + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet fori "for int loop (fori)" +for (${4:int} ${2:i} = 0; $2 < ${1:count}; ${3:++$2}) +{ + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet enum "Enumeration" +enum ${1:name} { $0 }; +endsnippet + +snippet once "Include header once only guard" +#ifndef ${1:`!p +if not snip.c: + import random, string + name = re.sub(r'[^A-Za-z0-9]+','_', snip.fn).upper() + rand = ''.join(random.sample(string.ascii_letters+string.digits, 8)) + snip.rv = ('%s_%s' % (name,rand)).upper() +else: + snip.rv = snip.c`} +#define $1 + +${0} + +#endif /* end of include guard: $1 */ + +endsnippet + +snippet td "Typedef" +typedef ${1:int} ${2:MyCustomType}; +endsnippet + +snippet wh "while loop" +while(${1:/* condition */}) { + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet do "do...while loop (do)" +do { + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} while(${1:/* condition */}); +endsnippet + +snippet fprintf "fprintf ..." +fprintf(${1:stderr}, "${2:%s}\n"${2/([^%]|%%)*(%.)?.*/(?2:, :\);)/}$3${2/([^%]|%%)*(%.)?.*/(?2:\);)/} +endsnippet + +snippet if "if .. (if)" +if (${1:/* condition */}) +{ + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet el "else .. (else)" +else { + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet eli "else if .. (eli)" +else if (${1:/* condition */}) { + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet ife "if .. else (ife)" +if (${1:/* condition */}) +{ + ${2:/* code */} +} +else +{ + ${3:/* else */} +} +endsnippet + +snippet printf "printf .. (printf)" +printf("${1:%s}\n"${1/([^%]|%%)*(%.)?.*/(?2:, :\);)/}$2${1/([^%]|%%)*(%.)?.*/(?2:\);)/} +endsnippet + +snippet st "struct" +struct ${1:`!p snip.rv = (snip.basename or "name") + "_t"`} +{ + ${0:/* data */} +}; +endsnippet + +snippet fun "function" b +${1:void} ${2:function_name}(${3}) +{ + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +} +endsnippet + +snippet fund "function declaration" b +${1:void} ${2:function_name}(${3}); +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/coffee.snippets b/UltiSnips/coffee.snippets new file mode 100644 index 0000000..68fe31c --- /dev/null +++ b/UltiSnips/coffee.snippets @@ -0,0 +1,91 @@ +# From the TextMate bundle + +priority -50 + +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/UltiSnips/coffee_jasmine.snippets b/UltiSnips/coffee_jasmine.snippets new file mode 100644 index 0000000..0dd35cd --- /dev/null +++ b/UltiSnips/coffee_jasmine.snippets @@ -0,0 +1,166 @@ +# +# CoffeeScript versions -- adapted from the JS TextMate bundle + additions +# for some jasmine-jquery matchers +# +priority -50 + +extends coffee + +priority -49 + +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/UltiSnips/cpp.snippets b/UltiSnips/cpp.snippets new file mode 100644 index 0000000..3d79a64 --- /dev/null +++ b/UltiSnips/cpp.snippets @@ -0,0 +1,57 @@ +priority -50 + +extends c + +# We want to overwrite everything in parent ft. +priority -49 + +########################################################################### +# TextMate Snippets # +########################################################################### +snippet beginend "$1.begin(), $1.end() (beginend)" +${1:v}${1/^.*?(-)?(>)?$/(?2::(?1:>:.))/}begin(), $1${1/^.*?(-)?(>)?$/(?2::(?1:>:.))/}end() +endsnippet + +snippet cl "class .. (class)" +class ${1:`!p snip.rv = snip.basename or "name"`} +{ +public: + ${1/(\w+).*/$1/} (${2:arguments}); + virtual ~${1/(\w+).*/$1/} (); + +private: + ${0:/* data */} +}; +endsnippet + +snippet ns "namespace .. (namespace)" +namespace${1/.+/ /m}${1:`!p snip.rv = snip.basename or "name"`} +{ + ${VISUAL}${0:${VISUAL/(.*)/(?1::\/* code *\/)/}} +}${1/.+/ \/* /m}$1${1/.+/ *\/ /m} +endsnippet + +snippet readfile "read file (readF)" +std::vector v; +if (FILE *fp = fopen(${1:"filename"}, "r")) +{ + char buf[1024]; + while(size_t len = fread(buf, 1, sizeof(buf), fp)) + v.insert(v.end(), buf, buf + len); + fclose(fp); +} +endsnippet + +snippet map "std::map (map)" +std::map<${1:key}, ${2:value}> map$0; +endsnippet + +snippet vector "std::vector (v)" +std::vector<${1:char}> v$0; +endsnippet + +snippet tp "template (template)" +template +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/cs.snippets b/UltiSnips/cs.snippets new file mode 100644 index 0000000..aca245e --- /dev/null +++ b/UltiSnips/cs.snippets @@ -0,0 +1,328 @@ +####################################################################### +# C# Snippets for UltiSnips # +####################################################################### + +priority -50 + +######################### +# classes and structs # +######################### + +snippet namespace "namespace" b +namespace ${1:MyNamespace} +{ + ${VISUAL}$0 +} +endsnippet + +snippet class "class" w +class ${1:MyClass} +{ + $0 +} +endsnippet + +snippet struct "struct" w +struct ${1:MyStruct} +{ + $0 +} +endsnippet + +snippet interface "interface" w +interface I${1:Interface} +{ + $0 +} +endsnippet + +snippet enum "enumeration" b +enum ${1:MyEnum} { ${2:Item} }; +endsnippet + + +############ +# Main() # +############ + +snippet sim "static int main" b +static int Main(string[] args) +{ + $0 +} +endsnippet + +snippet svm "static void main" b +static void Main(string[] args) +{ + $0 +} +endsnippet + + +################ +# properties # +################ + +snippet prop "Simple property declaration" b +public ${1:int} ${2:MyProperty} { get; set; } +endsnippet + +snippet propfull "Full property declaration" b +private ${1:int} ${2:_myProperty}; + +public $1 ${3:MyProperty} +{ + get { return $2; } + set { $2 = value; } +} +endsnippet + +snippet propg "Property with a private setter" b +public ${1:int} ${2:MyProperty} { get; private set; } +endsnippet + + +############ +# blocks # +############ + +snippet #if "#if #endif" b +#if ${1:DEBUG} +${VISUAL}$0 +#endif +endsnippet + +snippet #region "#region #endregion" b +#region ${1:Region} +${VISUAL}$0 +#endregion +endsnippet + + +########### +# loops # +########### + +snippet for "for loop" b +for (int ${1:i} = 0; $1 < ${2:10}; $1++) +{ + ${VISUAL}$0 +} +endsnippet + +snippet forr "for loop (reverse)" b +for (int ${1:i} = ${2:10}; $1 >= 0; $1--) +{ + ${VISUAL}$0 +} +endsnippet + +snippet foreach "foreach loop" b +foreach (${3:var} ${2:item} in ${1:items}) +{ + ${VISUAL}$0 +} +endsnippet + +snippet while "while loop" b +while (${1:true}) +{ + ${VISUAL}$0 +} +endsnippet + +snippet do "do loop" b +do +{ + ${VISUAL}$0 +} while (${1:true}); +endsnippet + + +############### +# branching # +############### + +snippet if "if statement" b +if ($1) +{ + ${VISUAL}$0 +} +endsnippet + +snippet ife "if else statement" b +if ($1) +{ + ${VISUAL}$0 +} +else +{ +} +endsnippet + +snippet elif "else if" b +else if ($1) +{ + $0 +} +endsnippet + +snippet elseif "else if" b +else if ($1) +{ + $0 +} +endsnippet + +snippet ifnn "if not null" b +if ($1 != null) +{ + ${VISUAL}$0 +} +endsnippet + +snippet switch "switch statement" b +switch (${1:statement}) +{ + case ${2:value}: + break; + + default: + $0break; +} +endsnippet + +snippet case "case" b +case ${1:value}: + $2 + break; +endsnippet + + +############## +# wrappers # +############## + +snippet using "using statement" b +using (${1:resource}) +{ + ${VISUAL}$0 +} +endsnippet + +snippet unchecked "unchecked block" b +unchecked +{ + ${VISUAL}$0 +} +endsnippet + +snippet checked "checked block" b +checked +{ + ${VISUAL}$0 +} +endsnippet + +snippet unsafe "unsafe" b +unsafe +{ + ${VISUAL}$0 +} +endsnippet + + +######################## +# exception handling # +######################## + +snippet try "try catch block" b +try +{ + ${VISUAL}$0 +} +catch (${1:Exception} ${2:e}) +{ + throw; +} +endsnippet + +snippet tryf "try finally block" b +try +{ + ${VISUAL}$0 +} +finally +{ +} +endsnippet + +snippet throw "throw" +throw new ${1}Exception("${2}"); +endsnippet + + +########## +# LINQ # +########## + +snippet from "LINQ syntax" b +var ${1:seq} = + from ${2:item1} in ${3:items1} + join ${4:item2} in ${5:items2} on $2.${6:prop1} equals $4.${7:prop2} + select ${8:$2.prop3} + where ${9:clause} +endsnippet + + +############################ +# feedback and debugging # +############################ + +snippet da "Debug.Assert" b +Debug.Assert(${1:true}); +endsnippet + +snippet cw "Console.WriteLine" b +Console.WriteLine("$1"); +endsnippet + +# as you first type comma-separated parameters on the right, {n} values appear in the format string +snippet cwp "Console.WriteLine with parameters" b +Console.WriteLine("${2:`!p +snip.rv = ' '.join(['{' + str(i) + '}' for i in range(t[1].count(','))]) +`}"${1:, something}); +endsnippet + +snippet mbox "Message box" b +MessageBox.Show("${1:message}"); +endsnippet + + +################## +# full methods # +################## + +snippet equals "Equals method" b +public override bool Equals(object obj) +{ + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + $0 + return base.Equals(obj); +} +endsnippet + + +############## +# comments # +############## + +snippet /// "XML comment" b +/// +/// $1 +/// +endsnippet diff --git a/UltiSnips/css.snippets b/UltiSnips/css.snippets new file mode 100644 index 0000000..32c3f21 --- /dev/null +++ b/UltiSnips/css.snippets @@ -0,0 +1,407 @@ +########################################################################### +# Most of these came from TextMate # +########################################################################### + +priority -50 + +snippet ! "!important CSS (!)" +${1:!important} +endsnippet + +snippet fixed "Fixed Position Bottom 100% wide IE6" +${2:bottom: auto;}top: expression(eval(document.documentElement.scrollTop+document.documentElement.clientHeight-${1:THE HEIGHT OF THIS THING IN PIXELS})); +${3:left: expression(eval(document.documentElement.scrollLeft)); +}${4:width: expression(eval(document.documentElement.clientWidth));}$0 +endsnippet + +snippet background "background-attachment: scroll:fixed (background)" +background-attachment: ${1:scroll/fixed};$0 +endsnippet + +snippet background "background-color: color-hex (background)" +background-color: #${1:DDD};$0 +endsnippet + +snippet background "background-color: color-name (background)" +background-color: ${1:red};$0 +endsnippet + +snippet background "background-color: color-rgb (background)" +background-color: rgb(${1:255},${2:255},${3:255});$0 +endsnippet + +snippet background "background-color: transparent (background)" +background-color: transparent;$0 +endsnippet + +snippet background "background-image: none (background)" +background-image: none;$0 +endsnippet + +snippet background "background-image: url (background)" +background-image: url($1);$0 +endsnippet + +snippet background "background-position: position (background)" +background-position: ${1:top left/top center/top right/center left/center center/center right/bottom left/bottom center/bottom right/x-% y-%/x-pos y-pos};$0 +endsnippet + +snippet background "background-repeat: r:r-x:r-y:n-r (background)" +background-repeat: ${1:repeat/repeat-x/repeat-y/no-repeat};$0 +endsnippet + +snippet background "background: color image repeat attachment position (background)" +background:${6: #${1:DDD}} url($2) ${3:repeat/repeat-x/repeat-y/no-repeat} ${4:scroll/fixed} ${5:top left/top center/top right/center left/center center/center right/bottom left/bottom center/bottom right/x-% y-%/x-pos y-pos};$0 +endsnippet + +snippet border "border-bottom-color: size style color (border)" +border-bottom-color: #${1:999};$0 +endsnippet + +snippet border "border-bottom-style: size style color (border)" +border-bottom-style: ${1:none/hidden/dotted/dashed/solid/double/groove/ridge/inset/outset};$0 +endsnippet + +snippet border "border-bottom-width: size style color (border)" +border-bottom-width: ${1:1}px ${2:solid} #${3:999};$0 +endsnippet + +snippet border "border-bottom: size style color (border)" +border-bottom: ${1:1}px ${2:solid} #${3:999};$0 +endsnippet + +snippet border "border-color: color (border)" +border-color: ${1:999};$0 +endsnippet + +snippet border "border-left-color: color (border)" +border-right-color: #${1:999};$0 +endsnippet + +snippet border "border-left-style: style (border)" +border-left-style: ${1:none/hidden/dotted/dashed/solid/double/groove/ridge/inset/outset};$0 +endsnippet + +snippet border "border-left-width: size (border)" +border-left-width: ${1:1}px +endsnippet + +snippet border "border-left: size style color (border)" +border-left: ${1:1}px ${2:solid} #${3:999};$0 +endsnippet + +snippet border "border-right-color: color (border)" +border-right-color: #${1:999};$0 +endsnippet + +snippet border "border-right-style: style (border)" +border-right-style: ${1:none/hidden/dotted/dashed/solid/double/groove/ridge/inset/outset};$0 +endsnippet + +snippet border "border-right-width: size (border)" +border-right-width: ${1:1}px +endsnippet + +snippet border "border-right: size style color (border)" +border-right: ${1:1}px ${2:solid} #${3:999};$0 +endsnippet + +snippet border "border-style: style (border)" +border-style: ${1:none/hidden/dotted/dashed/solid/double/groove/ridge/inset/outset};$0 +endsnippet + +snippet border "border-top-color: color (border)" +border-top-color: #${1:999};$0 +endsnippet + +snippet border "border-top-style: style (border)" +border-top-style: ${1:none/hidden/dotted/dashed/solid/double/groove/ridge/inset/outset};$0 +endsnippet + +snippet border "border-top-width: size (border)" +border-top-width: ${1:1}px +endsnippet + +snippet border "border-top: size style color (border)" +border-top: ${1:1}px ${2:solid} #${3:999};$0 +endsnippet + +snippet border "border-width: width (border)" +border-width: ${1:1px};$0 +endsnippet + +snippet border "border: size style color (border)" +border: ${1:1px} ${2:solid} #${3:999};$0 +endsnippet + +snippet clear "clear: value (clear)" +clear: ${1:left/right/both/none};$0 +endsnippet + +snippet color "color: color-hex (color)" +color: #${1:DDD};$0 +endsnippet + +snippet color "color: color-name (color)" +color: ${1:red};$0 +endsnippet + +snippet color "color: color-rgb (color)" +color: rgb(${1:255},${2:255},${3:255});$0 +endsnippet + +snippet cursor "cursor: type (cursor)" +cursor: ${1:default/auto/crosshair/pointer/move/*-resize/text/wait/help};$0 +endsnippet + +snippet cursor "cursor: url (cursor)" +cursor: url($1);$0 +endsnippet + +snippet direction "direction: ltr|rtl (direction)" +direction: ${1:ltr|rtl};$0 +endsnippet + +snippet display "display: block (display)" +display: block;$0 +endsnippet + +snippet display "display: common-types (display)" +display: ${1:none/inline/block/list-item/run-in/compact/marker};$0 +endsnippet + +snippet display "display: inline (display)" +display: inline;$0 +endsnippet + +snippet display "display: table-types (display)" +display: ${1:table/inline-table/table-row-group/table-header-group/table-footer-group/table-row/table-column-group/table-column/table-cell/table-caption};$0 +endsnippet + +snippet float "float: left:right:none (float)" +float: ${1:left/right/none};$0 +endsnippet + +snippet font "font-family: family (font)" +font-family: ${1:Arial, "MS Trebuchet"}, ${2:sans-}serif;$0 +endsnippet + +snippet font "font-size: size (font)" +font-size: ${1:100%};$0 +endsnippet + +snippet font "font-style: normal:italic:oblique (font)" +font-style: ${1:normal/italic/oblique};$0 +endsnippet + +snippet font "font-variant: normal:small-caps (font)" +font-variant: ${1:normal/small-caps};$0 +endsnippet + +snippet font "font-weight: weight (font)" +font-weight: ${1:normal/bold};$0 +endsnippet + +snippet font "font: style variant weight size:line-height font -family (font)" +font: ${1:normal/italic/oblique} ${2:normal/small-caps} ${3:normal/bold} ${4:1em/1.5em} ${5:Arial}, ${6:sans-}serif;$0 +endsnippet + +snippet font "font: size font (font)" +font: ${1:75%} ${2:"Lucida Grande", "Trebuchet MS", Verdana,} ${3:sans-}serif;$0 +endsnippet + +snippet letter "letter-spacing: length-em (letter)" +letter-spacing: $1em;$0 +endsnippet + +snippet letter "letter-spacing: length-px (letter)" +letter-spacing: $1px;$0 +endsnippet + +snippet list "list-style-image: url (list)" +list-style-image: url($1);$0 +endsnippet + +snippet list "list-style-position: pos (list)" +list-style-position: ${1:inside/outside};$0 +endsnippet + +snippet list "list-style-type: asian (list)" +list-style-type: ${1:cjk-ideographic/hiragana/katakana/hiragana-iroha/katakana-iroha};$0 +endsnippet + +snippet list "list-style-type: marker(list)" +list-style-type: ${1:none/disc/circle/square};$0 +endsnippet + +snippet list "list-style-type: numeric (list)" +list-style-type: ${1:decimal/decimal-leading-zero/zero};$0 +endsnippet + +snippet list "list-style-type: other (list)" +list-style-type: ${1:hebrew/armenian/georgian};$0 +endsnippet + +snippet list "list-style-type: roman-alpha-greek (list)" +list-style-type: ${1:lower-roman/upper-roman/lower-alpha/upper-alpha/lower-greek/lower-latin/upper-latin};$0 +endsnippet + +snippet list "list-style: type position image (list)" +list-style: ${1:none/disc/circle/square/decimal/zero} ${2:inside/outside} url($3);$0 +endsnippet + +snippet margin "margin-bottom: length (margin)" +margin-bottom: ${1:20px};$0 +endsnippet + +snippet margin "margin-left: length (margin)" +margin-left: ${1:20px};$0 +endsnippet + +snippet margin "margin-right: length (margin)" +margin-right: ${1:20px};$0 +endsnippet + +snippet margin "margin-top: length (margin)" +margin-top: ${1:20px};$0 +endsnippet + +snippet margin "margin: all (margin)" +margin: ${1:20px};$0 +endsnippet + +snippet margin "margin: T R B L (margin)" +margin: ${1:20px} ${2:0px} ${3:40px} ${4:0px};$0 +endsnippet + +snippet margin "margin: V H (margin)" +margin: ${1:20px} ${2:0px};$0 +endsnippet + +snippet marker "marker-offset: auto (marker)" +marker-offset: auto;$0 +endsnippet + +snippet marker "marker-offset: length (marker)" +marker-offset: ${1:10px};$0 +endsnippet + +snippet overflow "overflow: type (overflow)" +overflow: ${1:visible/hidden/scroll/auto};$0 +endsnippet + +snippet padding "padding-bottom: length (margin)" +padding-bottom: ${1:20px};$0 +endsnippet + +snippet padding "padding-left: length (margin)" +padding-left: ${1:20px};$0 +endsnippet + +snippet padding "padding-right: length (margin)" +padding-right: ${1:20px};$0 +endsnippet + +snippet padding "padding-top: length (margin)" +padding-top: ${1:20px};$0 +endsnippet + +snippet padding "padding: T R B L (padding)" +padding: ${1:20px} ${2:0px} ${3:40px} ${4:0px};$0 +endsnippet + +snippet padding "padding: V H (padding)" +padding: ${1:20px} ${2:0px};$0 +endsnippet + +snippet padding "padding: all (padding)" +padding: ${1:20px};$0 +endsnippet + +snippet position "position: type (position)" +position: ${1:static/relative/absolute/fixed};$0 +endsnippet + +snippet { "properties { } ( } )" +{ + /* $1 */ + $0 + +endsnippet + +snippet scrollbar "scrollbar" +scrollbar-base-color: ${1:#CCCCCC};${2: +scrollbar-arrow-color: ${3:#000000}; +scrollbar-track-color: ${4:#999999}; +scrollbar-3dlight-color: ${5:#EEEEEE}; +scrollbar-highlight-color: ${6:#FFFFFF}; +scrollbar-face-color: ${7:#CCCCCC}; +scrollbar-shadow-color: ${9:#999999}; +scrollbar-darkshadow-color: ${8:#666666};} +endsnippet + +snippet selection "selection" +$1::-moz-selection, +$1::selection { + color: ${2:inherit}; + background: ${3:inherit}; +} +endsnippet + +snippet text "text-align: left:center:right (txt)" +text-align: ${1:left/right/center/justify};$0 +endsnippet + +snippet text "text-decoration: none:underline:overline:line-through:blink (text)" +text-decoration: ${1:none/underline/overline/line-through/blink};$0 +endsnippet + +snippet text "text-indent: length (text)" +text-indent: ${1:10}px;$0 +endsnippet + +snippet text "text-shadow: color-hex x y blur (text)" +text-shadow: #${1:DDD} ${2:10px} ${3:10px} ${4:2px};$0 +endsnippet + +snippet text "text-shadow: color-rgb x y blur (text)" +text-shadow: rgb(${1:255},${2:255},${3:255}) ${4:10px} ${5:10px} ${6:2px};$0 +endsnippet + +snippet text "text-shadow: none (text)" +text-shadow: none;$0 +endsnippet + +snippet text "text-transform: capitalize:upper:lower (text)" +text-transform: ${1:capitalize/uppercase/lowercase};$0 +endsnippet + +snippet text "text-transform: none (text)" +text-transform: none;$0 +endsnippet + +snippet vertical "vertical-align: type (vertical)" +vertical-align: ${1:baseline/sub/super/top/text-top/middle/bottom/text-bottom/length/%};$0 +endsnippet + +snippet visibility "visibility: type (visibility)" +visibility: ${1:visible/hidden/collapse};$0 +endsnippet + +snippet white "white-space: normal:pre:nowrap (white)" +white-space: ${1:normal/pre/nowrap};$0 +endsnippet + +snippet word "word-spacing: length (word)" +word-spacing: ${1:10px};$0 +endsnippet + +snippet word "word-spacing: normal (word)" +word-spacing: normal;$0 +endsnippet + +snippet z "z-index: index (z)" +z-index: $1;$0 +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/d.snippets b/UltiSnips/d.snippets new file mode 100644 index 0000000..3a718c3 --- /dev/null +++ b/UltiSnips/d.snippets @@ -0,0 +1,584 @@ +# Simple shortcuts + +priority -50 + +snippet imp "import (imp)" b +import ${1:std.stdio}; +endsnippet + +snippet pimp "public import (pimp)" b +public import ${1:/*module*/}; +endsnippet + +snippet over "override (over)" b +override ${1:/*function*/} +endsnippet + +snippet al "alias (al)" +alias ${1:/*orig*/} ${2:/*alias*/}; +endsnippet + +snippet mixin "mixin (mixin)" b +mixin ${1:/*mixed_in*/} ${2:/*name*/}; +endsnippet + +snippet new "new (new)" +new ${1}(${2}); +endsnippet + +snippet scpn "@safe const pure nothrow (scpn)" +@safe const pure nothrow +endsnippet + +snippet spn "@safe pure nothrow (spn)" +@safe pure nothrow +endsnippet + +snippet cont "continue (cont)" +continue; +endsnippet + +snippet dis "@disable (dis)" b +@disable ${1:/*method*/}; +endsnippet + +snippet pub "public (pub)" b +public: + ${1:/*members*/} +endsnippet + +snippet priv "private (priv)" b +private: + ${1:/*members*/} +endsnippet + +snippet prot "protected (prot)" b +protected: + ${1:/*members*/} +endsnippet + +snippet pack "package (pack)" b +package: + ${1:/*members*/} +endsnippet + +snippet ret "return (ret)" +return ${1:/*value to return*/}; +endsnippet + +snippet auto "auto (auto)" b +auto ${1:/*variable*/} = ${2:/*value*/}; +endsnippet + +snippet con "const (con)" b +const ${1:/*variable*/} = ${2:/*value*/}; +endsnippet + +snippet siz "size_t (siz)" b +size_t ${1:/*variable*/} = ${2:/*value*/}; +endsnippet + +snippet sup "super (sup)" b +super(${1:/*args*/}); +endsnippet + +# Phobos + +snippet tup "tuple (tup)" +tuple(${1:/*args*/}) +endsnippet + +snippet wr "writeln (wr)" +writeln(${1:/*args*/}); +endsnippet + +snippet to "to (to)" +to!(${1:/*type*/})(${2:/*arg*/}) +endsnippet + +snippet enf "enforce (enf)" b +enforce(${1:/*condition*/}, + new ${2}Exception(${3:/*args*/})); +endsnippet + +# Branches + +snippet if "if .. (if)" +if(${1:/*condition*/}) +{ + ${VISUAL}${0:/*code*/} +} +endsnippet + +snippet ife "if .. else (ife)" b +if(${1:/*condition*/}) +{ + ${2:/*code*/} +} +else +{ + ${3:/*else*/} +} +endsnippet + +snippet el "else (el)" b +else +{ + ${VISUAL}${1:/*code*/} +} +endsnippet + +snippet elif "else if (elif)" b +else if(${1:/*condition*/}) +{ + ${VISUAL}${0:/*code*/} +} +endsnippet + +snippet sw "switch (sw)" +switch(${1:/*var*/}) +{ + case ${2:/*value*/}: + ${3:/*code*/} + break; + case ${4:/*value*/}: + ${5:/*code*/} + break; + ${7:/*more cases*/} + default: + ${6:assert(false);} +} +endsnippet + +snippet fsw "final switch (fsw)" +switch(${1:/*var*/}) +{ + case ${2:/*value*/}: + ${3:/*code*/} + break; + case ${4:/*value*/}: + ${5:/*code*/} + break; + ${7:/*more cases*/} +} +endsnippet + +snippet case "case (case)" b +case ${1:/*value*/}: + ${2:/*code*/} + break; +endsnippet + +snippet ?: "ternary operator (?:)" +${1:/*condition*/} ? ${2:/*then*/} : ${3:/*else*/}$4 +endsnippet + +# Loops + +snippet do "do while (do)" b +do +{ + ${VISUAL}${2:/*code*/} +} while(${1:/*condition*/}); +endsnippet + +snippet wh "while (wh)" b +while(${1:/*condition*/}) +{ + ${VISUAL}${2:/*code*/} +} +endsnippet + +snippet for "for (for)" b +for (${4:size_t} ${2:i} = 0; $2 < ${1:count}; ${3:++$2}) +{ + ${VISUAL}${0:/*code*/} +} +endsnippet + +snippet forever "forever (forever)" b +for(;;) +{ + ${VISUAL}${0:/*code*/} +} +endsnippet + +snippet fore "foreach (fore)" +foreach(${1:/*elem*/}; ${2:/*range*/}) +{ + ${VISUAL}${3:/*code*/} +} +endsnippet + +snippet forif "foreach if (forif)" b +foreach(${1:/*elem*/}; ${2:/*range*/}) if(${3:/*condition*/}) +{ + ${VISUAL}${4:/*code*/} +} +endsnippet + +# Contracts +snippet in "in contract (in)" b +in +{ + assert(${1:/*condition*/}, "${2:error message}"); + ${3} +} +body +endsnippet + +snippet out "out contract (out)" b +out${1:(result)} +{ + assert(${2:/*condition*/}, "${3:error message}"); + ${4} +} +body +endsnippet + +snippet inv "invariant (inv)" b +invariant() +{ + assert(${1:/*condition*/}, "${2:error message}"); + ${3} +} +endsnippet + +# Functions (generic) + +snippet fun "function definition (fun)" +${1:void} ${2:/*function name*/}(${3:/*args*/}) ${4:@safe pure nothrow} +{ + ${VISUAL}${5:/*code*/} +} +endsnippet + +snippet void "void function definition (void)" +void ${1:/*function name*/}(${2:/*args*/}) ${3:@safe pure nothrow} +{ + ${VISUAL}${4:/*code*/} +} +endsnippet + +snippet this "ctor (this)" w +this(${1:/*args*/}) +{ + ${VISUAL}${2:/*code*/} +} +endsnippet + +snippet get "getter property (get)" +@property ${1:/*type*/} ${2:/*member_name*/}() const pure nothrow {return ${3:$2_};} +endsnippet + +snippet set "setter property (set)" +@property void ${1:/*member_name*/}(${2:/*type*/} rhs) pure nothrow {${3:$1_} = rhs;} +endsnippet + +# Functions (concrete) + +snippet main "Main" b +void main(string[] args) +{ + ${VISUAL}${0: /*code*/} +} +endsnippet + +# Mixins + +snippet signal "signal (signal)" b +mixin Signal!(${1:/*args*/}) ${2:/*name*/}; +endsnippet + +# Scope + +snippet scope "scope (scope)" b +scope(${1:exit}) +{ + ${VISUAL}${2:/*code*/} +} +endsnippet + +# With + +snippet with "with (with)" +with(${1}) +{ + ${VISUAL}${2:/*code*/} +} +endsnippet + +# Exception handling + +snippet try "try/catch (try)" b +try +{ + ${VISUAL}${1:/*code to try*/} +} +catch(${2}Exception e) +{ + ${3:/*handle exception*/} +} +endsnippet + +snippet tryf "try/catch/finally (tryf)" b +try +{ + ${VISUAL}${1:/*code to try*/} +} +catch(${2}Exception e) +{ + ${3:/*handle exception*/} +} +finally +{ + ${4:/*cleanup*/} +} +endsnippet + +snippet catch "catch (catch)" b +catch(${1}Exception e) +{ + ${2:/*handle exception*/} +} +endsnippet + +snippet thr "throw (thr)" +throw new ${1}Exception("${2}"); +endsnippet + + +# Type declarations + +snippet struct "struct (struct)" +struct ${1:`!p snip.rv = (snip.basename or "name")`} +{ + ${2} +} +endsnippet + +snippet union "union (union)" +union ${1:`!p snip.rv = (snip.basename or "name")`} +{ + ${2} +} +endsnippet + +snippet class "class (class)" +class ${1:`!p snip.rv = (snip.basename or "name")`} +{ + ${2} +} +endsnippet + +snippet inter "interface (inter)" +interface ${1:`!p snip.rv = (snip.basename or "name")`} +{ + ${2} +} +endsnippet + +snippet enum "enum (enum)" +enum ${1:`!p snip.rv = (snip.basename or "name")`} +{ + ${2} +} +endsnippet + + +# Exception declarations + +snippet exc "exception declaration (exc)" b +/// ${3:/*documentation*/} +class ${1}Exception : ${2}Exception +{ + public this(string msg, string file = __FILE__, int line = __LINE__) + { + super(msg, file, line); + } +} +endsnippet + + +# Conditional compilation + +snippet version "version (version)" b +version(${1:/*version name*/}) +{ + ${VISUAL}${2:/*code*/} +} +endsnippet + +snippet debug "debug" b +debug +{ + ${VISUAL}${1:/*code*/} +} +endsnippet + + +# Templates + +snippet temp "template (temp)" b +template ${2:/*name*/}(${1:/*args*/}) +{ + ${3:/*code*/} +} +endsnippet + + +# Asserts + +snippet ass "assert (ass)" b +assert(${1:false}, "${2:TODO}"); + +endsnippet + + +# Unittests + +snippet unittest "unittest (unittest)" b +unittest +{ + ${1:/*code*/} +} +endsnippet + + +# Common member functions + +snippet opDis "opDispatch (opDis)" b +${1:/*return type*/} opDispatch(string s)() +{ + ${2:/*code*/}; +} +endsnippet + +snippet op= "opAssign (op=)" b +void opAssign(${1} rhs) ${2:@safe pure nothrow} +{ + ${2:/*code*/} +} +endsnippet + +snippet opCmp "opCmp (opCmp)" b +int opCmp(${1} rhs) @safe const pure nothrow +{ + ${2:/*code*/} +} +endsnippet + +snippet opApply "opApply (opApply)" b +int opApply(int delegate(ref ${1:/*iterated type/s*/}) dg) +{ + int result = 0; + ${2:/*loop*/} + { + result = dg(${3:/*arg/s*/}); + if(result){break;} + } + return result; +} +endsnippet + +snippet toString "toString (toString)" b +string toString() @safe const pure nothrow +{ + ${1:/*code*/} +} +endsnippet + + +# Comments + + +snippet todo "TODO (todo)" +// TODO: ${1} +endsnippet + + +# DDoc + +snippet doc "generic ddoc block (doc)" b +/// ${1:description} +/// +/// ${2:details} +endsnippet + +snippet fdoc "function ddoc block (fdoc)" b +/// ${1:description} +/// +/// ${2:Params: ${3:param} = ${4:param description} +/// ${5}} +/// +/// ${6:Returns: ${7:return value}} +/// +/// ${8:Throws: ${9}Exception ${10}} +endsnippet + +snippet Par "Params (Par)" +Params: ${1:param} = ${2:param description} +/// ${3} +endsnippet + +snippet Ret "Returns (Ret)" +Returns: ${1:return value/s} +endsnippet + +snippet Thr "Throws (Thr)" +Throws: ${1}Exception ${2} +endsnippet + +snippet Example "Examples (Example)" +Examples: +/// -------------------- +/// ${1:example code} +/// -------------------- +endsnippet + + +# License blocks + +snippet gpl "GPL (gpl)" b +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// Copyright (C) ${1:Author}, `!v strftime("%Y")` + +${2} +endsnippet + +snippet boost "Boost (boost)" b +// Copyright ${1:Author} `!v strftime("%Y")`. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +${2} +endsnippet + + +# New module + +snippet module "New module (module)" b +// Copyright ${1:Author} `!v strftime("%Y")`. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +module ${2}.`!v Filename('$1', 'name')`; + + +${3} +endsnippet diff --git a/UltiSnips/django.snippets b/UltiSnips/django.snippets new file mode 100644 index 0000000..9d6ce27 --- /dev/null +++ b/UltiSnips/django.snippets @@ -0,0 +1,238 @@ +priority -50 + +# 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 $1 %} +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/UltiSnips/erlang.snippets b/UltiSnips/erlang.snippets new file mode 100644 index 0000000..e27fbef --- /dev/null +++ b/UltiSnips/erlang.snippets @@ -0,0 +1,100 @@ +########################################################################### +# TEXTMATE SNIPPETS # +########################################################################### + +priority -50 + +snippet pat "Case:Receive:Try Clause" +${1:pattern}${2: when ${3:guard}} ->; + ${4:body} +endsnippet + +snippet beh "Behaviour Directive" +-behaviour (${1:behaviour}). +endsnippet + +snippet case "Case Expression" +case ${1:expression} of + ${2:pattern}${3: when ${4:guard}} -> + ${5:body} +end +endsnippet + +snippet def "Define Directive" +-define (${1:macro}${2: (${3:param})}, ${4:body}). +endsnippet + +snippet exp "Export Directive" +-export ([${1:function}/${2:arity}]). +endsnippet + +snippet fun "Fun Expression" +fun + (${1:pattern})${2: when ${3:guard}} -> + ${4:body} +end +endsnippet + +snippet fu "Function" +${1:function} (${2:param})${3: when ${4:guard}} -> + ${5:body} +endsnippet + +snippet if "If Expression" +if + ${1:guard} -> + ${2:body} +end +endsnippet + +snippet ifdef "Ifdef Directive" +-ifdef (${1:macro}). +endsnippet + +snippet ifndef "Ifndef Directive" +-ifndef (${1:macro}). +endsnippet + +snippet imp "Import Directive" +-import (${1:module}, [${2:function}/${3:arity}]). +endsnippet + +snippet inc "Include Directive" +-include ("${1:file}"). +endsnippet + +snippet mod "Module Directive" +-module (${1:`!p snip.rv = snip.basename or "module"`}). +endsnippet + +snippet rcv "Receive Expression" +receive +${1: ${2:pattern}${3: when ${4:guard}} -> + ${5:body}} +${6:after + ${7:expression} -> + ${8:body}} +end +endsnippet + +snippet rec "Record Directive" +-record (${1:record}, {${2:field}${3: = ${4:value}}}). +endsnippet + +snippet try "Try Expression" +try${1: ${2:expression}${3: of + ${4:pattern}${5: when ${6:guard}} -> + ${7:body}}} +${8:catch + ${9:pattern}${10: when ${11:guard}} -> + ${12:body}} +${13:after + ${14:body}} +end +endsnippet + +snippet undef "Undef Directive" +-undef (${1:macro}). +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/eruby.snippets b/UltiSnips/eruby.snippets new file mode 100644 index 0000000..cd87c1c --- /dev/null +++ b/UltiSnips/eruby.snippets @@ -0,0 +1,280 @@ +priority -50 + +# TextMate added these variables to cope with changes in ERB handling +# in different versions of Rails -- for instance, Rails 3 automatically +# strips whitespace so that it's no longer necessary to use a form like +# <% end -%>, but if you're still maintaining Rails 2 projects, you +# can't omit the minus sign and get the same behavior. +# +# The following regex replace substitutes the function below for the +# TextMate variable references after the snippets are converted: +# +# /\v\$\{(TM_RAILS_TEMPLATE_([^_]+)_RUBY_([^_\s]+))\}/`!p textmate_var('\1', snip)`/g +# +global !p +def textmate_var(var, snip): + lookup = dict( + TM_RAILS_TEMPLATE_START_RUBY_EXPR = snip.opt('g:tm_rails_template_start_ruby_expr', '<%= '), + TM_RAILS_TEMPLATE_END_RUBY_EXPR = snip.opt('g:tm_rails_template_end_ruby_expr', ' %>'), + TM_RAILS_TEMPLATE_START_RUBY_INLINE = snip.opt('g:tm_rails_template_start_ruby_inline', '<% '), + TM_RAILS_TEMPLATE_END_RUBY_INLINE = snip.opt('g:tm_rails_template_end_ruby_inline', ' %>'), + TM_RAILS_TEMPLATE_END_RUBY_BLOCK = '<% end %>' + ) + snip.rv = lookup[var] + return +endglobal + + +########################################################################### +# GENERATED FROM get_tm_snippets.py + REGEX REPLACE # +########################################################################### + +snippet fi "<%= Fixtures.identify(:symbol) %>" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`Fixtures.identify(:${1:name})`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)`$0 +endsnippet + +snippet ft "form_tag" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_INLINE', snip)`form_tag(${1::action => "${5:update}"}${6:, {:${8:class} => "${9:form}"\}}) do`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` + $0 +`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_BLOCK', snip)` +endsnippet + +snippet end "end (ERB)" +<% end -%> +endsnippet + +snippet for "for loop (ERB)" +<% if !${1:list}.blank? %> + <% for ${2:item} in ${1} %> + $3 + <% end %> +<% else %> + $4 +<% end %> + +endsnippet + +snippet ffcb "form_for check_box" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.check_box :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffff "form_for file_field 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.file_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffhf "form_for hidden_field 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.hidden_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffl "form_for label 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.label :${1:attribute}${2:, "${3:${1/[[:alpha:]]+|(_)/(?1: :\u$0)/g}}"}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffpf "form_for password_field 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.password_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffrb "form_for radio_box 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.radio_box :${1:attribute}, :${2:tag_value}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffs "form_for submit 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.submit "${1:Submit}"${2:, :disable_with => '${3:$1ing...}'}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffta "form_for text_area 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.text_area :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet fftf "form_for text_field 2" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.text_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet fields "fields_for" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_INLINE', snip)`fields_for :${1:model}, @${2:$1} do |$1|`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_INLINE', snip)` + $0 +`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_BLOCK', snip)` +endsnippet + +snippet f. "f_fields_for (nff)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_INLINE', snip)`f.fields_for :${1:attribute} do |${2:f}|`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_INLINE', snip)` +$0 +`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_BLOCK', snip)` +endsnippet + +snippet f. "f.checkbox" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.check_box :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.file_field" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.file_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.hidden_field" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.hidden_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.label" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.label :${1:attribute}${2:, "${3:${1/[[:alpha:]]+|(_)/(?1: :\u$0)/g}}"}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.password_field" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.password_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.radio_box" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.radio_box :${1:attribute}, :${2:tag_value}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.submit" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.submit "${1:Submit}"${2:, :disable_with => '${3:$1ing...}'}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.text_area" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.text_area :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet f. "f.text_field" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`f.text_field :${1:attribute}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet ffe "form_for with errors" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`error_messages_for :${1:model}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` + +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`form_for @${2:$1} do |f|`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` + $0 +`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_BLOCK', snip)` +endsnippet + +snippet ff "form_for" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`form_for @${1:model} do |f|`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` + $0 +`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_BLOCK', snip)` +endsnippet + +snippet ist "image_submit_tag" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`image_submit_tag("${1:agree.png}"${2:${3:, :id => "${4:${1/^(\w+)(\.\w*)?$/$1/}}"}${5:, :name => "${6:${1/^(\w+)(\.\w*)?$/$1/}}"}${7:, :class => "${8:${1/^(\w+)(\.\w*)?$/$1/}-button}"}${9:, :disabled => ${10:false}}})`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet it "image_tag" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`image_tag "$1${2:.png}"${3:${4:, :title => "${5:title}"}${6:, :class => "${7:class}"}}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet layout "layout" +layout "${1:template_name}"${2:${3:, :only => ${4:[:${5:action}, :${6:action}]}}${7:, :except => ${8:[:${9:action}, :${10:action}]}}} +endsnippet + +snippet jit "javascript_include_tag" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`javascript_include_tag ${1::all}${2:, :cache => ${3:true}}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet lia "link_to (action)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to "${1:link text...}", :action => "${2:index}"`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet liai "link_to (action, id)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to "${1:link text...}", :action => "${2:edit}", :id => ${3:@item}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet lic "link_to (controller)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to "${1:link text...}", :controller => "${2:items}"`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet lica "link_to (controller, action)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to "${1:link text...}", :controller => "${2:items}", :action => "${3:index}"`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet licai "link_to (controller, action, id)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to "${1:link text...}", :controller => "${2:items}", :action => "${3:edit}", :id => ${4:@item}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet linpp "link_to (nested path plural)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to ${1:"${2:link text...}"}, ${3:${10:parent}_${11:child}_path(${12:@}${13:${10}})}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet linp "link_to (nested path)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to ${1:"${2:link text...}"}, ${3:${12:parent}_${13:child}_path(${14:@}${15:${12}}, ${16:@}${17:${13}})}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet lipp "link_to (path plural)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to ${1:"${2:link text...}"}, ${3:${4:model}s_path}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet lip "link_to (path)" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to ${1:"${2:link text...}"}, ${3:${12:model}_path(${13:@}${14:${12}})}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet lim "link_to model" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to ${1:model}.${2:name}, ${3:${4:$1}_path(${14:$1})}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet hide "page.hide (*ids)" +page.hide ${1:"${2:id(s)}"} +endsnippet + +snippet ins "page.insert_html (position, id, partial)" +page.insert_html :${1:top}, ${2:"${3:id}"}, :${4:partial => "${5:template}"} +endsnippet + +snippet rep "page.replace (id, partial)" +page.replace ${1:"${2:id}"}, :${3:partial => "${4:template}"} +endsnippet + +snippet reph "page.replace_html (id, partial)" +page.replace_html ${1:"${2:id}"}, :${3:partial => "${4:template}"} +endsnippet + +snippet show "page.show (*ids)" +page.show ${1:"${2:id(s)}"} +endsnippet + +snippet tog "page.toggle (*ids)" +page.toggle ${1:"${2:id(s)}"} +endsnippet + +snippet vis "page.visual_effect (effect, id)" +page.visual_effect :${1:toggle_slide}, ${2:"${3:DOM ID}"} +endsnippet + +snippet rp "render (partial) (rp)" +render :partial => "${1:item}" +endsnippet + +snippet rpc "render (partial,collection) (rpc)" +render :partial => "${1:item}", :collection => ${2:@$1s} +endsnippet + +snippet rpl "render (partial,locals) (rpl)" +render :partial => "${1:item}", :locals => { :${2:$1} => ${3:@$1}$0 } +endsnippet + +snippet rpo "render (partial,object) (rpo)" +render :partial => "${1:item}", :object => ${2:@$1} +endsnippet + +snippet rps "render (partial,status) (rps)" +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)` +endsnippet + +snippet st "submit_tag" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`submit_tag "${1:Save changes}"${2:, :id => "${3:submit}"}${4:, :name => "${5:$3}"}${6:, :class => "${7:form_$3}"}${8:, :disabled => ${9:false}}${10:, :disable_with => "${11:Please wait...}"}`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +snippet else "else (ERB)" +<% else %> + $0 +endsnippet + +snippet if "if (ERB)" +<% if ${1:condition} %>$0 +endsnippet + +snippet lf "link_to_function" +`!p textmate_var('TM_RAILS_TEMPLATE_START_RUBY_EXPR', snip)`link_to_function ${1:"${2:Greeting}"}, "${3:alert('Hello world!')}"$4`!p textmate_var('TM_RAILS_TEMPLATE_END_RUBY_EXPR', snip)` +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/go.snippets b/UltiSnips/go.snippets new file mode 100644 index 0000000..d01e3f1 --- /dev/null +++ b/UltiSnips/go.snippets @@ -0,0 +1,131 @@ +# Snippets for Go + +priority -50 + +# when to abbriviate and when not? +# b doesn't work here, because it ignores whitespace +# optional local name? +snippet /^import/ "Import declaration" r +import ( + "${1:package}" +) +endsnippet + +snippet /^package/ "Package declaration" r +// Package $1 provides ... +package ${1:main} +endsnippet + +# Mostly converted from: https://github.com/AlanQuatermain/go-tmbundle +snippet /^cons/ "Constants declaration" r +const ( + ${1:constant}${2/(.+)/ /}${2:type} = ${0:value} +) +endsnippet + +snippet /^con/ "Constant declaration" r +const ${1:name}${2/(.+)/ /}${2:type} = ${0:value} +endsnippet + +snippet iota "Iota constant generator" b +const ( + ${1:constant}${2/(.+)/ /}${2:type} = iota +) +endsnippet + +snippet struct "Struct declaration" b +type ${1:Struct} struct { + ${0:${VISUAL}} +} +endsnippet + +snippet interface "Interface declaration" b +type ${1:Interface} interface { + ${0:${VISUAL}} +} +endsnippet + +# statements +snippet for "For loop" b +for ${1:condition}${1/(.+)/ /}{ + ${0:${VISUAL}} +} +endsnippet + +snippet forr "For range loop" b +for ${2:name} := range ${1:collection} { + ${0:${VISUAL}} +} +endsnippet + +snippet if "If statement" b +if ${1:condition}${1/(.+)/ /}{ + ${0:${VISUAL}} +} +endsnippet + +snippet switch "Switch statement" b +switch ${1:expression}${1/(.+)/ /}{ +case${0} +} +endsnippet + +snippet select "Select statement" b +select { +case${0} +} +endsnippet + +snippet case "Case clause" b +case ${1:condition}: + ${0:${VISUAL}} +endsnippet + +snippet default "Default clause" b +default: + ${0:${VISUAL}} +endsnippet + +# functions +snippet /^main/ "Main function" r +func main() { + ${0:${VISUAL}} +} +endsnippet + +snippet /^meth/ "Method" r +func (${1:receiver} ${2:type}) ${3:name}(${4:params})${5/(.+)/ /}${5:type} { + ${0:${VISUAL}} +} +endsnippet + +snippet func "Function" b +func ${1:name}(${2:params})${3/(.+)/ /}${3:type} { + ${0:${VISUAL}} +} +endsnippet + +# types and variables +snippet map "Map type" b +map[${1:keytype}]${2:valtype} +endsnippet + +snippet : "Variable declaration :=" b +${1:name} := ${0:value} +endsnippet + +snippet var "Variable declaration" b +var ${1:name}${2/(.+)/ /}${2:type}${3: = ${0:value}} +endsnippet + +snippet vars "Variables declaration" b +var ( + ${1:name}${2/(.+)/ /}${2:type}${3: = ${0:value} } +) +endsnippet + +snippet json "JSON field" +\`json:"${1:displayName}"\` +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/haskell.snippets b/UltiSnips/haskell.snippets new file mode 100644 index 0000000..ad217fd --- /dev/null +++ b/UltiSnips/haskell.snippets @@ -0,0 +1,63 @@ +priority -50 + +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/UltiSnips/help.snippets b/UltiSnips/help.snippets new file mode 100644 index 0000000..6132738 --- /dev/null +++ b/UltiSnips/help.snippets @@ -0,0 +1,32 @@ +# Snippets for VIM Help Files + +priority -50 + +global !p +def sec_title(snip, t): + file_start = snip.fn.split('.')[0] + sec_name = t[1].strip("1234567890. ").lower().replace(' ', '-') + return ("*%s-%s*" % (file_start, sec_name)).rjust(78-len(t[1])) +endglobal + +snippet sec "Section marker" b +============================================================================== +${1:SECTION}`!p snip.rv = sec_title(snip, t)` + +$0 +endsnippet + +snippet ssec "Sub section marker" b +${1:Subsection}`!p snip.rv = sec_title(snip, t) +snip += "-"*len(t[1])` + +$0 +endsnippet + +snippet sssec "Subsub Section marker" b +${1:SubSubsection}:`!p snip.rv = sec_title(snip, t)` + +$0 +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/html.snippets b/UltiSnips/html.snippets new file mode 100644 index 0000000..31f7cc3 --- /dev/null +++ b/UltiSnips/html.snippets @@ -0,0 +1,302 @@ +priority -50 + +########################################################################### +# TextMate Snippets # +########################################################################### + +global !p +def x(snip): + if snip.ft.startswith("x"): + snip.rv = '/' + else: + snip.rv = "" +endglobal + +############ +# Doctypes # +############ +snippet doctype "DocType XHTML 1.0 Strict" b + + +endsnippet + +snippet doctype "DocType XHTML 1.0 Transitional" b + + +endsnippet + +snippet doctype "DocType XHTML 1.1" b + + +endsnippet + +snippet doctype "HTML - 4.0 Transitional (doctype)" b + + +endsnippet + +snippet doctype "HTML - 5.0 (doctype)" b + + +endsnippet + +############# +# Shortcuts # +############# +snippet down "Down (down)" +↓ +endsnippet + +snippet enter "Enter (enter)" +⌅ +endsnippet + +snippet escape "Escape (escape)" +⎋ +endsnippet + +snippet shift "Shift (shift)" +⇧ +endsnippet + +snippet tab "Tab (tab)" +⇥ +endsnippet + +snippet up "Up (up)" +↑ +endsnippet + +snippet return "Return (return)" +↩ +endsnippet + +snippet right "Right (right)" +→ +endsnippet + +snippet left "Left (left)" +← +endsnippet + +snippet option "Option (option)" +⌥ +endsnippet + +####################### +# Conditional inserts # +####################### +snippet ! "IE Conditional Comment: Internet Explorer 5_0 only" +$0 +endsnippet + +snippet ! "IE Conditional Comment: Internet Explorer 5_5 only" +$0 +endsnippet + +snippet ! "IE Conditional Comment: Internet Explorer 5_x" +$0 +endsnippet + +snippet ! "IE Conditional Comment: Internet Explorer 6 and below" +$0 +endsnippet + +snippet ! "IE Conditional Comment: Internet Explorer 6 only" +$0 +endsnippet + +snippet ! "IE Conditional Comment: Internet Explorer 7+" +$0 +endsnippet + +snippet ! "IE Conditional Comment: Internet Explorer" +$0 +endsnippet + +snippet ! "IE Conditional Comment: NOT Internet Explorer" +${1: IE Conditional Comment: NOT Internet Explorer }$0 +endsnippet + +############# +# HTML TAGS # +############# +snippet input "Input with Label" w + + +endsnippet + +snippet input "XHTML " w + +endsnippet + + +snippet opt "Option" w +${3:$2} +endsnippet + +snippet select "Select Box" w + +endsnippet + + +snippet textarea "XHTML +endsnippet + +snippet mailto "XHTML " w +${3:email me} +endsnippet + +snippet base "XHTML " w + +endsnippet + +snippet img "XHTML " w + +endsnippet + +snippet body "XHTML " + + $0 + +endsnippet + +snippet div "XHTML
" w + + $0 +
+endsnippet + +snippet form "XHTML
" w + + $0 + +

+
+endsnippet + +snippet h1 "XHTML

" w +

${1}

+endsnippet + +snippet head "XHTML " + + + ${1:`!p snip.rv = snip.basename or "Page Title"`} + $0 + +endsnippet + +snippet link "XHTML " w + +endsnippet + +snippet meta "XHTML " w + +endsnippet + +snippet scriptsrc "XHTML +endsnippet + +snippet script "XHTML +endsnippet + +snippet style "XHTML +endsnippet + +snippet table "XHTML " w +
+ + +
${5:Header}
${0:Data}
+endsnippet + +snippet a "Link" w +${4:Anchor Text} +endsnippet + +snippet p "paragraph" w +

$0

+endsnippet + +snippet li "list item" w +
  • $0
  • +endsnippet + +snippet ul "unordered list" w +
      +$0 +
    +endsnippet + +snippet td "table cell" w +$0 +endsnippet + +snippet tr "table row" w +$0 +endsnippet + +snippet title "XHTML " w +<title>${1:`!p snip.rv = snip.basename or "Page Title"`} +endsnippet + +snippet fieldset "Fieldset" w +
    + $1 + $0 +
    +endsnippet + +snippet movie "Embed QT movie (movie)" b + + + + + + +endsnippet + +snippet html5 "HTML5 Template" + + + + ${1} + + + +
    + ${2} +
    +
    + ${4} +
    + + +endsnippet +# vim:ft=snippets: diff --git a/UltiSnips/htmldjango.snippets b/UltiSnips/htmldjango.snippets new file mode 100644 index 0000000..5836a2f --- /dev/null +++ b/UltiSnips/htmldjango.snippets @@ -0,0 +1,3 @@ +priority -50 + +extends html, django diff --git a/UltiSnips/htmljinja.snippets b/UltiSnips/htmljinja.snippets new file mode 100644 index 0000000..fa3b3c2 --- /dev/null +++ b/UltiSnips/htmljinja.snippets @@ -0,0 +1,3 @@ +priority -50 + +extends html, jinja2 diff --git a/UltiSnips/java.snippets b/UltiSnips/java.snippets new file mode 100644 index 0000000..96cc7a9 --- /dev/null +++ b/UltiSnips/java.snippets @@ -0,0 +1,431 @@ +priority -50 + +# Many of the snippets here use a global option called +# "g:ultisnips_java_brace_style" which, if set to "nl" will put a newline +# before '{' braces. +# Setting "g:ultisnips_java_junit" will change how the test method snippet +# looks, it is defaulted to junit4, setting this option to 3 will remove the +# @Test annotation from the method + +global !p +def junit(snip): + if snip.opt("g:ultisnips_java_junit", "") == "3": + snip += "" + else: + snip.rv += "@Test\n\t" + +def nl(snip): + if snip.opt("g:ultisnips_java_brace_style", "") == "nl": + snip += "" + else: + snip.rv += " " +def getArgs(group): + import re + word = re.compile('[a-zA-Z><.]+ \w+') + return [i.split(" ") for i in word.findall(group) ] + +def camel(word): + return word[0].upper() + word[1:] + +endglobal + +snippet sleep "try sleep catch" b +try { + Thread.sleep(${1:1000}); +} catch (InterruptedException e){ + e.printStackTrace(); +} +endsnippet + +snippet /i|n/ "new primitive or int" br +${1:int} ${2:i} = ${3:1}; +$0 +endsnippet + +snippet /o|v/ "new Object or variable" br +${1:Object} ${2:var} = new $1(${3}); +endsnippet + +snippet f "field" b +${1:private} ${2:String} ${3:`!p snip.rv = t[2].lower()`}; +endsnippet + +snippet ab "abstract" b +abstract $0 +endsnippet + +snippet as "assert" b +assert ${1:test}${2/(.+)/(?1: \: ")/}${2:Failure message}${2/(.+)/(?1:")/};$0 +endsnippet + +snippet at "assert true" b +assertTrue(${1:actual}); +endsnippet + +snippet af "assert false" b +assertFalse(${1:actual});$0 +endsnippet + +snippet ae "assert equals" b +assertEquals(${1:expected}, ${2:actual}); +endsnippet + +snippet br "break" +break; + +endsnippet + +snippet cs "case" b +case $1: + $2 +$0 +endsnippet + +snippet ca "catch" b +catch (${1:Exception} ${2:e})`!p nl(snip)`{ + $0 +} +endsnippet + +snippet cle "class extends" b +public class ${1:`!p +snip.rv = snip.basename or "untitled"`} ${2:extends ${3:Parent} }${4:implements ${5:Interface} }{ + $0 +} +endsnippet + +snippet clc "class with constructor, fields, setter and getters" b +public class `!p +snip.rv = snip.basename or "untitled"` { +`!p +args = getArgs(t[1]) +if len(args) == 0: snip.rv = "" +for i in args: + snip.rv += "\n\tprivate " + i[0] + " " + i[1]+ ";" +if len(args) > 0: + snip.rv += "\n"` + public `!p snip.rv = snip.basename or "unknown"`($1) { `!p +args = getArgs(t[1]) +for i in args: + snip.rv += "\n\t\tthis." + i[1] + " = " + i[1] + ";" +if len(args) == 0: + snip.rv += "\n"` + }$0 +`!p +args = getArgs(t[1]) +if len(args) == 0: snip.rv = "" +for i in args: + snip.rv += "\n\tpublic void set" + camel(i[1]) + "(" + i[0] + " " + i[1] + ") {\n" + "\ + \tthis." + i[1] + " = " + i[1] + ";\n\t}\n" + + snip.rv += "\n\tpublic " + i[0] + " get" + camel(i[1]) + "() {\ + \n\t\treturn " + i[1] + ";\n\t}\n" +` +} +endsnippet + +snippet clc "class with constructor, with field names" b +public class `!p +snip.rv = snip.basename or "untitled"` { +`!p +args = getArgs(t[1]) +for i in args: + snip.rv += "\n\tprivate " + i[0] + " " + i[1]+ ";" +if len(args) > 0: + snip.rv += "\n"` + public `!p snip.rv = snip.basename or "unknown"`($1) { `!p +args = getArgs(t[1]) +for i in args: + snip.rv += "\n\t\tthis." + i[1] + " = " + i[1] +if len(args) == 0: + snip.rv += "\n"` + } +} +endsnippet + +snippet clc "class and constructor" b +public class `!p +snip.rv = snip.basename or "untitled"` { + + public `!p snip.rv = snip.basename or "untitled"`($2) { + $0 + } +} +endsnippet + +snippet cl "class" b +public class ${1:`!p +snip.rv = snip.basename or "untitled"`} { + $0 +} +endsnippet + +snippet cos "constant string" b +public static final String ${1:var} = "$2";$0 +endsnippet + +snippet co "constant" b +public static final ${1:String} ${2:var} = $3;$0 +endsnippet + +snippet de "default" b +default: + $0 +endsnippet + +snippet elif "else if" b +else if ($1)`!p nl(snip)`{ + $0 +} +endsnippet + +snippet /el(se)?/ "else" br +else`!p nl(snip)`{ + $0 +} +endsnippet + +snippet fi "final" b +final $0 +endsnippet + +snippet fore "for (each)" b +for ($1 : $2)`!p nl(snip)`{ + $0 +} +endsnippet + +snippet fori "for" b +for (int ${1:i} = 0; $1 < ${2:10}; $1++)`!p nl(snip)`{ + $0 +} +endsnippet + +snippet for "for" b +for ($1; $2; $3)`!p nl(snip)`{ + $0 +} +endsnippet + +snippet if "if" b +if ($1)`!p nl(snip)`{ + $0 +} +endsnippet + +snippet imt "import junit_framework_TestCase;" b +import junit.framework.TestCase; +$0 +endsnippet + +snippet im "import" b +import ${1:java}.${2:util}.$0 +endsnippet + +snippet in "interface" b +interface ${1:`!p snip.rv = snip.basename or "untitled"`} ${2:extends ${3:Parent} }{ + $0 +} +endsnippet + +snippet cc "constructor call or setter body" +this.${1:var} = $1; +endsnippet + +snippet list "Collections List" b +List<${1:String}> ${2:list} = new ${3:Array}List<$1>(); +endsnippet + +snippet map "Collections Map" b +Map<${1:String}, ${2:String}> ${3:map} = new ${4:Hash}Map<$1, $2>(); +endsnippet + +snippet set "Collections Set" b +Set<${1:String}> ${2:set} = new ${3:Hash}Set<$1>(); +endsnippet + +snippet /Str?|str/ "String" br +String $0 +endsnippet + +snippet cn "Constructor" b +public `!p snip.rv = snip.basename or "untitled"`(${1:}) { + $0 +} +endsnippet + +snippet cn "constructor, \w fields + assigments" b + `!p +args = getArgs(t[1]) +for i in args: + snip.rv += "\n\tprivate " + i[0] + " " + i[1]+ ";" +if len(args) > 0: + snip.rv += "\n"` +public `!p snip.rv = snip.basename or "unknown"`($1) { `!p +args = getArgs(t[1]) +for i in args: + snip.rv += "\n\t\tthis." + i[1] + " = " + i[1] +if len(args) == 0: + snip.rv += "\n"` +} +endsnippet + +snippet j.b "java_beans_" i +java.beans. +endsnippet + +snippet j.i "java_io" i +java.io. +endsnippet + +snippet j.m "java_math" i +java.math. +endsnippet + +snippet j.n "java_net_" i +java.net. +endsnippet + +snippet j.u "java_util_" i +java.util. +endsnippet + +snippet main "method (main)" b +public static void main(String[] args)`!p nl(snip)`{ + $0 +} +endsnippet + +snippet try "try/catch" b +try { + $1 +} catch(${2:Exception} ${3:e}){ + ${4:e.printStackTrace();} +} +endsnippet + +snippet mt "method throws" b +${1:private} ${2:void} ${3:method}(${4}) ${5:throws $6 }{ + $0 +} +endsnippet + +snippet m "method" b +${1:private} ${2:void} ${3:method}(${4}) { + $0 +} +endsnippet + +snippet md "Method With javadoc" b +/** + * ${7:Short Description}`!p +for i in getArgs(t[4]): + snip.rv += "\n\t * @param " + i[1] + " usage..."` + * `!p +if "throws" in t[5]: + snip.rv = "\n\t * @throws " + t[6] +else: + snip.rv = ""` `!p +if not "void" in t[2]: + snip.rv = "\n\t * @return object" +else: + snip.rv = ""` + **/ +${1:public} ${2:void} ${3:method}($4) ${5:throws $6 }{ + $0 +} +endsnippet + +snippet /get(ter)?/ "getter" br +public ${1:String} get${2:Name}() { + return `!p snip.rv = t[2].lower()`; +} +endsnippet + +snippet /set(ter)?/ "setter" br +public void set${1:Name}(${2:String} $1) { + return this.`!p snip.rv = t[1].lower()` = `!p snip.rv = t[1].lower()`; +} +endsnippet + +snippet /se?tge?t|ge?tse?t|gs/ "setter and getter" br +public void set${1:Name}(${2:String} `!p snip.rv = t[1].lower()`) { + this.`!p snip.rv = t[1].lower()` = `!p snip.rv = t[1].lower()`; +} + +public $2 get$1() { + return `!p snip.rv = t[1].lower()`; +} +endsnippet + +snippet pa "package" b +package $0 +endsnippet + +snippet p "print" b +System.out.print($1);$0 +endsnippet + +snippet pl "println" b +System.out.println($1);$0 +endsnippet + +snippet pr "private" b +private $0 +endsnippet + +snippet po "protected" b +protected $0 +endsnippet + +snippet pu "public" b +public $0 +endsnippet + +snippet re "return" b +return $0 +endsnippet + +snippet st "static" +static $0 +endsnippet + +snippet sw "switch" b +switch ($1)`!p nl(snip)`{ + case $2: $0 +} +endsnippet + +snippet sy "synchronized" +synchronized $0 +endsnippet + +snippet tc "test case" +public class ${1:`!p snip.rv = snip.basename or "untitled"`} extends ${2:TestCase}`!p nl(snip)`{ + $0 +} +endsnippet + +snippet t "test" b +`!p junit(snip)`public void test${1:Name}() { + $0 +} +endsnippet + +snippet tt "test throws" b +`!p junit(snip)`public void test${1:Name}() ${2:throws Exception }{ + $0 +} +endsnippet + +snippet th "throw" b +throw new $0 +endsnippet + +snippet wh "while" b +while ($1)`!p nl(snip)`{ + $0 +} +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/javascript.snippets b/UltiSnips/javascript.snippets new file mode 100644 index 0000000..f8d4790 --- /dev/null +++ b/UltiSnips/javascript.snippets @@ -0,0 +1,162 @@ +priority -50 + +########################################################################### +# TextMate Snippets # +########################################################################### +snippet get "Get Elements" +getElement${1/(T)|.*/(?1:s)/}By${1:T}${1/(T)|(I)|.*/(?1:agName)(?2:d)/}('$2') +endsnippet + +snippet '':f "object method string" +'${1:${2:#thing}:${3:click}}': function(element) { + ${VISUAL}$0 +}${10:,} +endsnippet + +snippet :f "Object Method" +${1:method_name}: function(${3:attribute}) { + ${VISUAL}$0 +}${10:,} +endsnippet + +snippet :, "Object Value JS" +${1:value_name}: ${0:value}, +endsnippet + +snippet : "Object key key: 'value'" +${1:key}: ${2:"${3:value}"}${4:, } +endsnippet + +snippet proto "Prototype (proto)" +${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) { + ${VISUAL}$0 +}; + +endsnippet + +snippet for "for (...) {...} (counting up)" b +for (var ${1:i} = 0, ${2:len} = ${3:Things.length}; $1 < $2; $1++) { + ${VISUAL}$0 +} +endsnippet + +snippet ford "for (...) {...} (counting down, faster)" b +for (var ${2:i} = ${1:Things.length} - 1; $2 >= 0; $2--) { + ${VISUAL}$0 +} +endsnippet + +snippet fun "function (fun)" +function ${1:function_name}(${2:argument}) { + ${VISUAL}$0 +} +endsnippet + +snippet iife "Immediately-Invoked Function Expression (iife)" +(function (${1:argument}) { + ${VISUAL}$0 +}(${2:$1})); +endsnippet + +snippet ife "if ___ else" +if (${1:condition}) { + ${2://code} +} +else { + ${3://code} +} +endsnippet + +snippet if "if" +if (${1:condition}) { + ${VISUAL}$0 +} +endsnippet + +snippet timeout "setTimeout function" +setTimeout(function() { + ${VISUAL}$0 +}${2:.bind(${3:this})}, ${1:10}); +endsnippet + +# Snippets for Console Debug Output + +snippet ca "console.assert" b +console.assert(${1:assertion}, ${2:"${3:message}"}); +endsnippet + +snippet cclear "console.clear" b +console.clear(); +endsnippet + +snippet cdir "console.dir" b +console.dir(${1:object}); +endsnippet + +snippet cdirx "console.dirxml" b +console.dirxml(${1:object}); +endsnippet + +snippet ce "console.error" b +console.error(${1:"${2:value}"}); +endsnippet + +snippet cgroup "console.group" b +console.group("${1:label}"); +${VISUAL}$0 +console.groupEnd(); +endsnippet + +snippet cgroupc "console.groupCollapsed" b +console.groupCollapsed("${1:label}"); +${VISUAL}$0 +console.groupEnd(); +endsnippet + +snippet ci "console.info" b +console.info(${1:"${2:value}"}); +endsnippet + +snippet cl "console.log" b +console.log(${1:"${2:value}"}); +endsnippet + +snippet cprof "console.profile" b +console.profile("${1:label}"); +${VISUAL}$0 +console.profileEnd(); +endsnippet + +snippet ctable "console.table" b +console.table(${1:"${2:value}"}); +endsnippet + +snippet ctime "console.time" b +console.time("${1:label}"); +${VISUAL}$0 +console.timeEnd("$1"); +endsnippet + +snippet ctimestamp "console.timeStamp" b +console.timeStamp("${1:label}"); +endsnippet + +snippet ctrace "console.trace" b +console.trace(); +endsnippet + +snippet cw "console.warn" b +console.warn(${1:"${2:value}"}); +endsnippet + +# AMD (Asynchronous Module Definition) snippets + +snippet def "define an AMD module" +define(${1:optional_name, }[${2:'jquery'}], ${3:callback}); +endsnippet + +snippet req "require an AMD module" +require([${1:'dependencies'}], ${2:callback}); +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/javascript_jasmine.snippets b/UltiSnips/javascript_jasmine.snippets new file mode 100644 index 0000000..0d8f7af --- /dev/null +++ b/UltiSnips/javascript_jasmine.snippets @@ -0,0 +1,169 @@ +priority -50 +extends javascript +priority -49 + +# JavaScript versions -- from the TextMate bundle + some additions +# for jasmine-jquery matchers +# + +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/UltiSnips/javascript_jsdoc.snippets b/UltiSnips/javascript_jsdoc.snippets new file mode 100644 index 0000000..ca943fc --- /dev/null +++ b/UltiSnips/javascript_jsdoc.snippets @@ -0,0 +1,51 @@ +priority -50 + +# JSDoc snippets + +snippet /* "A JSDoc comment" b +/** + * ${1:${VISUAL}}$0 + */ +endsnippet + +snippet @au "@author email (First Last)" +@author ${1:`!v g:snips_author_email`} (${2:`!v g:snips_author`}) +endsnippet + +snippet @li "@license Description" +@license ${1:MIT}$0 +endsnippet + +snippet @ver "@version Semantic version" +@version ${1:0.1.0}$0 +endsnippet + +snippet @fileo "@fileoverview Description" b +/** + * @fileoverview ${1:${VISUAL:A description of the file}}$0 + */ +endsnippet + +snippet @constr "@constructor" +@constructor +endsnippet + +snippet @p "@param {Type} varname Description" +@param {${1:Type}} ${2:varname} ${3:Description} +endsnippet + +snippet @ret "@return {Type} Description" +@return {${1:Type}} ${2:Description} +endsnippet + +snippet @pri "@private" +@private +endsnippet + +snippet @over "@override" +@override +endsnippet + +snippet @pro "@protected" +@protected +endsnippet diff --git a/UltiSnips/jinja2.snippets b/UltiSnips/jinja2.snippets new file mode 100644 index 0000000..ded01dc --- /dev/null +++ b/UltiSnips/jinja2.snippets @@ -0,0 +1,209 @@ +priority -50 + +# http://jinja.pocoo.org/ + +# jinja2 is a full featured template engine for Python. It has full +# unicode support, an optional integrated sandboxed execution +# environment, widely used and BSD licensed. + +# possible extends: +#extends html + + +snippet block "block" b +{% block ${1:name} %} + $2 +{% endblock $1 %} +endsnippet + + +snippet {{ "variable" b +{{ $1 }} +endsnippet + + +snippet {# "comment" b +{# $1 #} +endsnippet + + +snippet # "comment" b +{# $1 #} +endsnippet + + +snippet raw "escaped block" b +{% raw %} + $1 +{% endraw %} +endsnippet + + +snippet extends "extends" b +{% extends "${1:template}" %} +endsnippet + + +snippet include "include" b +{% include "${1:template}" %} +endsnippet + + +snippet import "import" b +{% import "${1:template}" %} +endsnippet + + +snippet from "from/import/as" b +{% from "${1:template}" import ${2:name}${3: as ${4:$2}} %} +endsnippet + + +snippet filter "filter" b +{% filter ${1:filter} %} + $2 +{% endfilter %} +endsnippet + + +# Being able to quickly remove the whole 'else' block seems faster to me than +# choosing between 'for' and 'for/else' snippets from the menu. +# snippet for "for" b +# {% for ${1:item} in ${2:sequence} %} +# $3${4: +# {% else %} +# $5} +# {% endfor %} +# endsnippet + + +snippet for "for" b +{% for ${1:item} in ${2:sequence} %} + $3 +{% endfor %} +endsnippet + + +snippet for "for/else" b +{% for ${1:item} in ${2:sequence} %} + $3 +{% else %} + $4 +{% endfor %} +endsnippet + + +snippet if "if" b +{% if ${1:expr} %} + $2 +{% endif %} +endsnippet + + +snippet if "if/else" b +{% if ${1:expr} %} + $2 +{% else %} + $3 +{% endif %} +endsnippet + + +snippet if "if/elif/else" b +{% if ${1:expr} %} + $2 +{% elif %} + $3 +{% else %} + $4 +{% endif %} +endsnippet + + +snippet macro "macro" b +{% macro ${1:name}(${2:args}) %} + $3 +{% endmacro %} +endsnippet + + +snippet call "call" b +{% call ${1:name}(${2:args}) %} + $3 +{% endcall %} +endsnippet + + +snippet set "set" b +{% set ${1:name} = ${2:'value'} %} +endsnippet + + +snippet trans "translation" b +{% trans %} + $1 +{% endtrans %} +endsnippet + + +snippet with "with" b +{% with %} + $1 +{% endwith %} +endsnippet + +snippet autoescape "autoescape" b +{% autoescape ${1:true} %} + $2 +{% endautoescape %} +endsnippet + +# Filters +# @todo: expand only when snippet is preceeded by a | + +snippet batch "batch items" w +batch(linecount=$1, fill_with=${2:None}) +endsnippet + + +snippet dictsort "sort and yield (key, value) pairs" w +dictsort(case_sensitive=${1:False}, by=${2:'key'}) +endsnippet + + +snippet round "round number" w +round(precision=${1:0}, method=${2:'common|ceil|floor'}) +endsnippet + + +snippet urlize "convert plain-text url to " w +urlize(trim_url_limit=${1:None}, nofollow=${2:False}) +endsnippet + + +snippet wordwrap "wordwrap" w +wordwrap(width=${1:79}, break_long_words=${2:True}) +endsnippet + + +snippet truncate "truncate" w +truncate(lenght=${1:79}, killwords=${2:False}, end=${3:'...''}) +endsnippet + + +snippet sum "sum of sequence of numbers + start" w +sum(attribute=${1:None}, start=${2:0}) +endsnippet + + +snippet sort "sort an iterable" w +sort(reverse=${1:False}, case_sensitive=${2:False}, attribute=${3:None}) +endsnippet + + +snippet indent "indent" w +indent(width=${1:4}, indentfirst=${2:False}) +endsnippet + + +# vim:ft=snippets: diff --git a/UltiSnips/json.snippets b/UltiSnips/json.snippets new file mode 100644 index 0000000..b0cad83 --- /dev/null +++ b/UltiSnips/json.snippets @@ -0,0 +1,20 @@ +priority -50 + +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/UltiSnips/ledger.snippets b/UltiSnips/ledger.snippets new file mode 100644 index 0000000..4bf4691 --- /dev/null +++ b/UltiSnips/ledger.snippets @@ -0,0 +1,8 @@ +priority -50 + +snippet t "Transaction" b +${1:`!v strftime("%Y")`}-${2:`!v strftime("%m")`}-${3:`!v strftime("%d")`} ${4:*} ${5:Payee} + ${6:Expenses} \$${7:0.00} + ${8:Assets:Checking} +$0 +endsnippet diff --git a/UltiSnips/lhaskell.snippets b/UltiSnips/lhaskell.snippets new file mode 100644 index 0000000..29169a5 --- /dev/null +++ b/UltiSnips/lhaskell.snippets @@ -0,0 +1,3 @@ +priority -50 + +extends haskell diff --git a/UltiSnips/lua.snippets b/UltiSnips/lua.snippets new file mode 100644 index 0000000..bc59c60 --- /dev/null +++ b/UltiSnips/lua.snippets @@ -0,0 +1,39 @@ +priority -50 + +################################# +# Snippets for the Lua language # +################################# +snippet #! "Shebang header" b +#!/usr/bin/env lua +$0 +endsnippet + +snippet !fun(ction)?! "New function" br +function ${1:new_function}(${2:args}) + $0 +end +endsnippet + +snippet forp "pair for loop" b +for ${1:name},${2:val} in pairs(${3:table_name}) do + $0 +end +endsnippet + +snippet fori "ipair for foop" b +for ${1:idx},${2:val} in ipairs(${3:table_name}) do + $0 +end +endsnippet + +snippet for "numeric for loop" b +for ${1:i}=${2:first},${3:last}${4/^..*/(?0:,:)/}${4:step} do + $0 +end +endsnippet + +snippet local "local x = 1" +local ${1:x} = ${0:1} +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/mako.snippets b/UltiSnips/mako.snippets new file mode 100644 index 0000000..fb31ec8 --- /dev/null +++ b/UltiSnips/mako.snippets @@ -0,0 +1,92 @@ +priority -50 + +################# +# From snipmate # +################# +snippet def "definition" b +<%def name="${1:name}"> + ${2:} + +endsnippet + +snippet call "call" b +<%call expr="${1:name}"> + ${2:} + +endsnippet + +snippet doc "doc" b +<%doc> + ${1:} + +endsnippet + +snippet text "text" b +<%text> + ${1:} + +endsnippet + +snippet for "for" b +% for ${1:i} in ${2:iter}: + ${3:} +% endfor +endsnippet + +snippet if "if " b +% if ${1:condition}: + ${2:} +% endif +endsnippet + +snippet if "if/else" b +% if ${1:condition}: + ${2:} +% else: + ${3:} +% endif +endsnippet + +snippet try "try" b +% try: + ${1:} +% except${2:}: + ${3:pass} +% endtry +endsnippet + +snippet wh "wh" b +% while ${1:}: + ${2:} +% endwhile +endsnippet + +snippet $ "$" i +${${1:}} +endsnippet + +snippet <% "<%" b +<% ${1:} %> +endsnippet + +snippet +endsnippet + +snippet inherit "inherit" b +<%inherit file="${1:filename}" /> +endsnippet + +snippet include "include" b +<%include file="${1:filename}" /> +endsnippet + +snippet namespace "namespace" b +<%namespace file="${1:name}" /> +endsnippet + +snippet page "page" b +<%page args="${1:}" /> +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/markdown.snippets b/UltiSnips/markdown.snippets new file mode 100644 index 0000000..fa708ab --- /dev/null +++ b/UltiSnips/markdown.snippets @@ -0,0 +1,42 @@ +priority -50 + +########################### +# Sections and Paragraphs # +########################### +snippet sec "Section" b +# ${1:Section Name} # +$0 +endsnippet + +snippet ssec "Sub Section" b +## ${1:Section Name} ## +$0 +endsnippet + +snippet sssec "SubSub Section" b +### ${1:Section Name} ### +$0 +endsnippet + +snippet par "Paragraph" b +#### ${1:Paragraph Name} #### +$0 +endsnippet + +snippet spar "Paragraph" b +##### ${1:Paragraph Name} ##### +$0 +endsnippet + +################ +# Common stuff # +################ +snippet link "Link to something" +[${1:${VISUAL:Text}}](${3:http://${2:www.url.com}})$0 +endsnippet + +snippet img "Image" +![${1:pic alt}](${2:path}${3/.+/ "/}${3:opt title}${3/.+/"/})$0 +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/objc.snippets b/UltiSnips/objc.snippets new file mode 100644 index 0000000..45e41fc --- /dev/null +++ b/UltiSnips/objc.snippets @@ -0,0 +1,272 @@ +priority -50 + +########################################################################### +# TextMate Snippets # +########################################################################### + +snippet imp "#import (imp)" b +#import "${1:`!p snip.rv = re.sub(r'\..*$', '.h', fn)`}" +endsnippet + +snippet Imp "#import <> (Imp)" +#import <${1:Cocoa/Cocoa.h}> +endsnippet + +snippet cl "020 Class (objc)" +@interface ${1:`!p +if len(fn): + snip.rv = re.sub(r'\..*$', '', fn) +else: + snip.rv = "object" +`} : ${2:NSObject} +{ +} +@end + +@implementation $1 +- (id)init +{ + if((self = [super init])) + {$0 + } + return self; +} +@end +endsnippet + +snippet array "NSArray (array)" +NSMutableArray *${1:array} = [NSMutableArray array]; +endsnippet + +snippet dict "NSDictionary (dict)" +NSMutableDictionary *${1:dict} = [NSMutableDictionary dictionary]; +endsnippet + +snippet forarray "for NSArray loop (forarray)" +unsigned int ${1:object}Count = [${2:array} count]; + +for(unsigned int index = 0; index < $1Count; index += 1) +{ + ${3:id} $1 = [$2 objectAtIndex:index]; + $0 +} +endsnippet + +snippet objacc "Object Accessors (objacc)" +- (${1:id})${2:thing} +{ + return $2; +} + +- (void)set${2/./\u$0/}:($1)aValue +{ + $0${1/( \*)?$/(?1:$1: )/}old${2/./\u$0/} = $2; + $2 = [aValue retain]; + [old${2/./\u$0/} release]; +} +endsnippet + +snippet sel "@selector" +@selector(${1:method}:) +endsnippet + +snippet cdacc "CoreData Accessors Implementation" +- (${1:id})${2:attribute} +{ + [self willAccessValueForKey:@"$2"]; + $1 value = [self primitiveValueForKey:@"$2"]; + [self didAccessValueForKey:@"$2"]; + return value; +} + +- (void)set${2/./\u$0/}:($1)aValue +{ + [self willChangeValueForKey:@"$2"]; + [self setPrimitiveValue:aValue forKey:@"$2"]; + [self didChangeValueForKey:@"$2"]; +} +endsnippet + +snippet delegate "Delegate Responds to Selector" +if([${1:[self delegate]} respondsToSelector:@selector(${2:selfDidSomething:})]) + [$1 ${3:${2/((^\s*([A-Za-z0-9_]*:)\s*)|(:\s*$)|(:\s*))/(?2:$2self :\:<>)(?4::)(?5: :)/g}}]; + +endsnippet + +snippet thread "Detach New NSThread" +[NSThread detachNewThreadSelector:@selector(${1:method}:) toTarget:${2:aTarget} withObject:${3:anArgument}] +endsnippet + +snippet ibo "IBOutlet (ibo)" +IBOutlet ${1:NSSomeClass} *${2:${1/^[A-Z](?:[A-Z]+|[a-z]+)([A-Z]\w*)/\l$1/}}; +endsnippet + +snippet I "Initialize Implementation (I)" ++ (void)initialize +{ + [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: + $0@"value", @"key", + nil]]; +} +endsnippet + +snippet bind "Key:value binding (bind)" +bind:@"${1:binding}" toObject:${2:observableController} withKeyPath:@"${3:keyPath}" options:${4:nil} +endsnippet + +snippet arracc "LoD array (arracc)" +- (void)addObjectTo${1:Things}:(${2:id})anObject +{ + [${3:${1/./\l$0/}} addObject:anObject]; +} + +- (void)insertObject:($2)anObject in$1AtIndex:(unsigned int)i +{ + [$3 insertObject:anObject atIndex:i]; +} + +- ($2)objectIn$1AtIndex:(unsigned int)i +{ + return [$3 objectAtIndex:i]; +} + +- (unsigned int)indexOfObjectIn$1:($2)anObject +{ + return [$3 indexOfObject:anObject]; +} + +- (void)removeObjectFrom$1AtIndex:(unsigned int)i +{ + [$3 removeObjectAtIndex:i]; +} + +- (unsigned int)countOf$1 +{ + return [$3 count]; +} + +- (NSArray *${1/./\l$0/} +{ + return $3; +} + +- (void)set$1:(NSArray *)new$1 +{ + [$3 setArray:new$1]; +} +endsnippet + +snippet arracc "LoD array interface (arracc)" +- (void)addObjectTo${1:Things}:(${2:id})anObject; +- (void)insertObject:($2)anObject in$1AtIndex:(unsigned int)i; +- ($2)objectIn$1AtIndex:(unsigned int)i; +- (unsigned int)indexOfObjectIn$1:($2)anObject; +- (void)removeObjectFrom$1AtIndex:(unsigned int)i; +- (unsigned int)countOf$1; +- (NSArray *)${1/./\l$0/}; +- (void)set$1:(NSArray *)new$1; +endsnippet + +snippet focus "Lock Focus" +[self lockFocus]; +$0 +[self unlockFocus]; +endsnippet + +snippet pool "NSAutoreleasePool (pool)" +NSAutoreleasePool *pool = [NSAutoreleasePool new]; +$0 +[pool drain]; +endsnippet + +snippet log "NSLog (log) 2" +NSLog(@"$1"${1/[^%]*(%)?.*/(?1:, :\);)/}$2${1/[^%]*(%)?.*/(?1:\);)/} +endsnippet + +snippet alert "NSRunAlertPanel (alert)" +int choice = NSRunAlertPanel(@"${1:Something important!}", @"${2:Something important just happend, and now I need to ask you, do you want to continue?}", @"${3:Continue}", @"${4:Cancel}", nil); +if(choice == NSAlertDefaultReturn) // "$3" +{ + $0; +} +else if(choice == NSAlertAlternateReturn) // "$4" +{ + $0 +} +endsnippet + +snippet format "NSString stringWithFormat (format)" +[NSString stringWithFormat:@"$1", $2]$0 +endsnippet + +snippet objacc "Object Accessors Interface (objacc)" +- (${1:id})${2:thing}; +- (void)set${2/./\u$0/}:($1)aValue; +endsnippet + +snippet prop "Property" +@property (${1/^(e)$|.*/(?1:r)/}${1:r}${1/^(?:(r)|(e)|(c)|(a))$|.*/(?1:etain)(?2:adonly)(?3:opy)(?4:ssign)/}) ${2:NSSomeClass}$ *${3:${2/^[A-Z](?:[A-Z]+|[a-z]+)([A-Z]\w*)/\l$1/}}; +endsnippet + +snippet getprefs "Read from defaults (getprefs)" +[[NSUserDefaults standardUserDefaults] objectForKey:${1:key}]; +endsnippet + +snippet obs "Register for Notification" +[[NSNotificationCenter defaultCenter] addObserver:${1:self} selector:@selector(${3:${2/^([A-Z]{2})?(.+?)(Notification)?$/\l$2/}}:) name:${2:NSWindowDidBecomeMainNotification} object:${4:nil}]; +endsnippet + +snippet responds "Responds to Selector" +if ([${1:self} respondsToSelector:@selector(${2:someSelector:})]) +{ + [$1 ${3:${2/((:\s*$)|(:\s*))/:<>(?3: )/g}}]; +} +endsnippet + +snippet gsave "Save and Restore Graphics Context (gsave)" +[NSGraphicsContext saveGraphicsState]; +$0 +[NSGraphicsContext restoreGraphicsState]; + +endsnippet + +snippet acc "Scalar Accessors (acc)" +- (${1:unsigned int})${2:thing} +{ + return ${3:$2}; +} + +- (void)set${2/./\u$0/}:(${1:unsigned int})new${2/./\u$0/} +{ + $3 = new${2/./\u$0/}; +} +endsnippet + +snippet acc "Scalar Accessors Interface (acc)" +- (${1:unsigned int})${2:thing}; +- (void)set${2/./\u$0/}:($1)new${2/./\u$0/}; +endsnippet + +snippet stracc "String Accessors (stracc)" +- (NSString *)${1:thing} +{ + return ${2:$1}; +} + +- (void)set${1/.*/\u$0/}:(NSString *)/})${3:a${1/.*/\u$0/}} +{ + $3 = [$3 copy]; + [$2 release]; + $2 = $3; +} +endsnippet + +snippet syn "Synthesize" +@synthesize ${1:property}; +endsnippet + +snippet setprefs "Write to defaults (setprefs)" +[[NSUserDefaults standardUserDefaults] setObject:${1:object} forKey:${2:key}]; +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/ocaml.snippets b/UltiSnips/ocaml.snippets new file mode 100644 index 0000000..1ebc347 --- /dev/null +++ b/UltiSnips/ocaml.snippets @@ -0,0 +1,174 @@ +priority -50 + +snippet rs "raise" b +raise (${1:Not_found}) +endsnippet + +snippet open "open" +let open ${1:module} in +${2:e} +endsnippet + +snippet try "try" +try ${1:e} +with ${2:Not_found} -> ${3:()} +endsnippet + +snippet ref "ref" +let ${1:name} = ref ${2:val} in +${3:e} +endsnippet + +snippet matchl "pattern match on a list" +match ${1:list} with +| [] -> ${2:()} +| x::xs -> ${3:()} +endsnippet + +snippet matcho "pattern match on an option type" +match ${1:x} with +| Some(${2:y}) -> ${3:()} +| None -> ${4:()} +endsnippet + +snippet fun "anonymous function" +(fun ${1:x} -> ${2:x}) +endsnippet + +snippet cc "commment" +(* ${1:comment} *) +endsnippet + +snippet let "let .. in binding" +let ${1:x} = ${2:v} in +${3:e} +endsnippet + +snippet lr "let rec" +let rec ${1:f} = + ${2:expr} +endsnippet + +snippet if "if" +if ${1:(* condition *)} then + ${2:(* A *)} +else + ${3:(* B *)} +endsnippet + +snippet If "If" +if ${1:(* condition *)} then + ${2:(* A *)} +endsnippet + +snippet while "while" +while ${1:(* condition *)} do + ${2:(* A *)} +done +endsnippet + +snippet for "for" +for ${1:i} = ${2:1} to ${3:10} do + ${4:(* BODY *)} +done +endsnippet + +snippet match "match" +match ${1:(* e1 *)} with +| ${2:p} -> ${3:e2} +endsnippet + +snippet Match "match" +match ${1:(* e1 *)} with +| ${2:p} -> ${3:e2} +endsnippet + +snippet class "class" +class ${1:name} = object + ${2:methods} +end +endsnippet + +snippet obj "obj" +object + ${2:methods} +end +endsnippet + +snippet Obj "object" +object (self) + ${2:methods} +end +endsnippet + +snippet {{ "object functional update" +{< ${1:x} = ${2:y} >} +endsnippet + +snippet beg "beg" +begin + ${1:block} +end +endsnippet + +snippet ml "module instantiantion with functor" +module ${1:Mod} = ${2:Functor}(${3:Arg}) +endsnippet + +snippet mod "module - no signature" +module ${1:(* Name *)} = struct + ${2:(* BODY *)} +end +endsnippet + +snippet Mod "module with signature" +module ${1:(* Name *)} : ${2:(* SIG *)} = struct + ${3:(* BODY *)} +end +endsnippet + +snippet sig "anonymous signature" +sig + ${2:(* BODY *)} +end +endsnippet + +snippet sigf "functor signature or anonymous functor" +functor (${1:Arg} : ${2:ARG}) -> ${3:(* BODY *)} +endsnippet + +snippet func "define functor - no signature" +module ${1:M} (${2:Arg} : ${3:ARG}) = struct + ${4:(* BODY *)} +end +endsnippet + +snippet Func "define functor - with signature" +module ${1:M} (${2:Arg} : ${3:ARG}) : ${4:SIG} = struct + ${5:(* BODY *)} +end +endsnippet + +snippet mot "Declare module signature" +module type ${1:(* Name *)} = sig + ${2:(* BODY *)} +end +endsnippet + +snippet module "Module with anonymous signature" +module ${1:(* Name *)} : sig + ${2:(* SIGNATURE *)} +end = struct + ${3:(* BODY *)} +end +endsnippet + +snippet oo "odoc" +(** ${1:odoc} *) +endsnippet + +snippet qt "inline qtest" +(*$T ${1:name} + ${2:test} +*) +endsnippet diff --git a/UltiSnips/perl.snippets b/UltiSnips/perl.snippets new file mode 100644 index 0000000..abaae3f --- /dev/null +++ b/UltiSnips/perl.snippets @@ -0,0 +1,132 @@ +priority -50 + +########################################################################### +# TextMate Snippets # +########################################################################### +snippet ife "Conditional if..else (ife)" +if ($1) { + ${2:# body...} +} +else { + ${3:# else...} +} + +endsnippet + +snippet ifee "Conditional if..elsif..else (ifee)" +if ($1) { + ${2:# body...} +} +elsif ($3) { + ${4:# elsif...} +} +else { + ${5:# else...} +} + +endsnippet + +snippet xunless "Conditional one-line (unless)" +${1:expression} unless ${2:condition}; + +endsnippet + +snippet xif "Conditional one-line (xif)" +${1:expression} if ${2:condition}; + +endsnippet + +snippet sub "Function (sub)" +sub ${1:function_name} { + ${2:# body...} +} + +endsnippet + +snippet xfore "Loop one-line (xforeach)" +${1:expression} foreach @${2:array}; + +endsnippet + +snippet xwhile "Loop one-line (xwhile)" +${1:expression} while ${2:condition}; + +endsnippet + +snippet test "Test" +#!/usr/bin/env perl -w + +use strict; +use Test::More tests => ${1:1}; +use ${2:ModuleName}; + +ok(${3:assertion}); + +endsnippet + +snippet class "class" +package ${1:ClassName}; + +${2:use parent qw(${3:ParentClass});}${2/.+/\n\n/}sub new { + my $class = shift; + $class = ref $class if ref $class; + my $self = bless {}, $class; + $self; +} + +1; + +endsnippet + +snippet eval "eval" +local $@; +eval { + ${1:# do something risky...} +}; +if (my $${2:exception} = $@) { + ${3:# handle failure...} +} + +endsnippet + +snippet for "for" +for (my $${1:var} = 0; $$1 < ${2:expression}; $$1++) { + ${3:# body...} +} + +endsnippet + +snippet fore "foreach" +foreach ${1:my $${2:x}} (@${3:array}) { + ${4:# body...} +} + +endsnippet + +snippet if "if" +if ($1) { + ${2:# body...} +} + +endsnippet + +snippet slurp "slurp" +my $${1:var} = do { local $/ = undef; open my $fh, '<', ${2:$file}; <$fh> }; + +endsnippet + +snippet unless "unless" +unless ($1) { + ${2:# body...} +} + +endsnippet + +snippet while "while" +while ($1) { + ${2:# body...} +} + +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/php.snippets b/UltiSnips/php.snippets new file mode 100644 index 0000000..24f6cc5 --- /dev/null +++ b/UltiSnips/php.snippets @@ -0,0 +1,264 @@ +priority -50 + +## Snippets from SnipMate, taken from +## https://github.com/scrooloose/snipmate-snippets.git + +snippet array "array" +$${1:arrayName} = array('${2}' => ${3});${4} +endsnippet + +snippet def "def" +define('${1}'${2});${3} +endsnippet + +snippet do "do" +do { + ${2:// code... } +} while (${1:/* condition */});" +endsnippet + +snippet doc_f "doc_f" +/** + * $2 + * @return ${4:void} + * @author ${5:`!v g:snips_author`} + **/ +${1:public }function ${2:someFunc}(${3}) +{${6} +} +endsnippet + +snippet doc_i "doc_i" +/** + * $1 + * @package ${2:default} + * @author ${3:`!v g:snips_author`} + **/ +interface ${1:someClass} +{${4} +} // END interface $1" +endsnippet + +snippet else "else" +else { + ${1:// code...} +} +endsnippet + +snippet for "for" +for ($${2:i} = 0; $$2 < ${1:count}; $$2${3:++}) { + ${4:// code...} +} +endsnippet + +snippet foreachk "foreachk" +foreach ($${1:variable} as $${2:key} => $${3:value}){ + ${4:// code...} +} +endsnippet + +snippet get "get" +$_GET['${1}']${2} +endsnippet + +snippet if "if" +if (${1:/* condition */}) { + ${2:// code...} +} +endsnippet + +snippet inc "inc" +include '${1:file}';${2} +endsnippet + +snippet log "log" +error_log(var_export(${1}, true));${2} +endsnippet + +snippet post "post" +$_POST['${1}']${2} +endsnippet + +snippet req1 "req1" +require_once '${1:file}';${2} +endsnippet + +snippet session "session" +$_SESSION['${1}']${2} +endsnippet + +snippet t "t" +$${1:retVal} = (${2:condition}) ? ${3:a} : ${4:b};${5} +endsnippet + +snippet var "var" +var_export(${1});${2} +endsnippet + +snippet getter "PHP Class Getter" b +/* + * Getter for $1 + */ +public function get${1/\w+\s*/\u$0/}() +{ + return $this->$1;$2 +} +$4 +endsnippet + +snippet setter "PHP Class Setter" b +/* + * Setter for $1 + */ +public function set${1/\w+\s*/\u$0/}($$1) +{ + $this->$1 = $$1;$3 + ${4:return $this;} +} +$0 +endsnippet + +snippet gs "PHP Class Getter Setter" b +/* + * Getter for ${1/(\w+)\s*;/$1/} + */ +public function get${1/(\w+)\s*;/\u$1/}() +{ + return $this->${1/(\w+)\s*;/$1/};$2 +} + +/* + * Setter for ${1/(\w+)\s*;/$1/} + */ +public function set${1/(\w+)\s*;/\u$1/}($${1/(\w+)\s*;/$1/}) +{ + $this->${1/(\w+)\s*;/$1/} = $${1/(\w+)\s*;/$1/};$3 + ${4:return $this;} +} +$0 +endsnippet + +snippet pub "Public function" b +public function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet pro "Protected function" b +protected function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet pri "Private function" b +private function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet pubs "Public static function" b +public static function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet pros "Protected static function" b +protected static function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet pris "Private static function" b +private static function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet fu "Function snip" b +function ${1:name}(${2:$param}) +{ + ${VISUAL}${3:return null;} +} +$0 +endsnippet + +snippet fore "Foreach loop" +foreach ($${1:variable} as $${3:value}){ + ${VISUAL}${4} +} +$0 +endsnippet + +snippet new "New class instance" b +$$1 = new $1($2); +$0 +endsnippet + +snippet ife "if else" +if (${1:/* condition */}) { + ${2:// code...} +} else { + ${3:// code...} +} +$0 +endsnippet + +snippet class "Class declaration template" b +/** + * Class ${1:`!p snip.rv=snip.fn.split('.')[0]`} + * @author ${2:`!v g:snips_author`} + */ +class $1 +{ + public function ${3:__construct}(${4:$options}) + { + ${4:// code} + } +} +$0 +endsnippet + +snippet construct "__construct()" b +/** + * @param $2mixed ${1/, /\n * \@param mixed /g} + */ +public function __construct(${1:$dependencies}) +{${1/\$(\w+)(, )*/\n $this->$1 = $$1;/g} +} +$0 +endsnippet + +snippet pr "Dumb debug helper in HTML" +echo '
    ' . var_export($1, 1) . '
    ';$0 +endsnippet + +snippet pc "Dumb debug helper in cli" +var_export($1);$0 +endsnippet + +# Symfony 2 based snippets +snippet sfa "Symfony 2 Controller action" +/** +* @Route("/${1:route_name}", name="$1") +* @Template() +*/ +public function $1Action($2) +{ + $3 + return ${4:array();}$0 +} +endsnippet + +# :vim:ft=snippets: diff --git a/UltiSnips/puppet.snippets b/UltiSnips/puppet.snippets new file mode 100644 index 0000000..a8fc1ed --- /dev/null +++ b/UltiSnips/puppet.snippets @@ -0,0 +1,232 @@ +priority -50 + +######################################################################### +# Python helper code # +######################################################################### + +global !p +import vim +import os.path +def get_module_namespace_and_basename(): + """This function will try to guess the current class or define name you are + trying to create. Note that for this to work you should be using the module + structure as per the style guide. Examples inputs and it's output + * /home/nikolavp/puppet/modules/collectd/manifests/init.pp -> collectd + * /home/nikolavp/puppet/modules/collectd/manfistes/mysql.pp -> collectd::mysql + """ + first_time = True + current_file_path_without_ext = vim.eval('expand("%:p:r")') or "" + if not current_file_path_without_ext: + return "name" + parts = os.path.split(current_file_path_without_ext) + namespace = '' + while parts[0] and parts[0] != '/': + if parts[1] == 'init' and first_time and not namespace: + first_time = False + parts = os.path.split(parts[0]) + continue + if parts[1] == 'manifests': + return os.path.split(parts[0])[1] + ('::' + namespace).rstrip(':') + else: + namespace = parts[1] + '::' + namespace + parts = os.path.split(parts[0]) + # couldn't guess the namespace. The user is editing a raw file in no module like the site.pp file + return "name" +endglobal + +############################################################################### +# Puppet Language Constructs # +# See http://docs.puppetlabs.com/puppet/latest/reference/lang_summary.html # +############################################################################### + +snippet class "Class declaration" b +class ${1:`!p snip.rv = get_module_namespace_and_basename()`} { + ${0:# body} +} +endsnippet + +snippet define "Definition" b +define ${1:`!p snip.rv = get_module_namespace_and_basename()`} { + ${0:# body} +} +endsnippet + +################################################################# +# Puppet Types # +# See http://docs.puppetlabs.com/references/latest/type.html # +################################################################# + +snippet cron "Cron resource type" b +cron { '${1:name}': + user => ${2:user}, + command => '${3:command}', + minute => ${3:minute}, + hour => ${4:hour}, +} +endsnippet + +snippet exec "Exec resource type" b +exec { '${1:command}': + refreshonly => true, +} +endsnippet + +snippet file "File resource type" b +file { '${1:name}': + source => "puppet://${2:path}", + mode => ${3:mode}, +endsnippet + +snippet File "Defaults for file" b +File { + owner => ${1:username}, + group => ${2:groupname}, +} +endsnippet + +snippet group "Group resource type" b +group { '${1:groupname}': + ensure => ${3:present}, + gid => ${2:gid}, +endsnippet + +snippet mount "Mount resource type" b +mount { '${1:path}': + device => '${2:/dev}', + fstype => '${3:filesystem}', + ensure => mounted, + options => 'rw,errors=remount-ro', +} +endsnippet + +snippet package "Package resource type" b +package { '${1:name}': + ensure => ${2:installed}, +} +endsnippet + +snippet user "user resource type" b +user { '${1:username}': + ensure => ${2:present}, + uid => ${3:uid}, + gid => ${4:gid}, + comment => ${5:gecos}, + home => ${6:homedirectory}, + managehome => false, + require => Group['${7:group'}], +endsnippet + +snippet service "Service resource type" b +service { '${1:name}': + hasstatus => true, + enable => true, + ensure => running, +} +endsnippet + +######################################################################## +# Puppet Functions # +# See http://docs.puppetlabs.com/references/latest/function.html # +######################################################################## + +snippet alert "Alert Function" b +alert("${1:message}")${0} +endsnippet + +snippet crit "Crit Function" b +crit("${1:message}")${0} +endsnippet + +snippet debug "Debug Function" b +debug("${1:message}")${0} +endsnippet + +snippet defined "Defined Function" b +defined(${1:Resource}["${2:name}"])${0} +endsnippet + +snippet emerg "Emerg Function" b +emerg("${1:message}")${0} +endsnippet + +snippet extlookup "Simple Extlookup" b +$${1:Variable} = extlookup("${2:Lookup}")${0} +endsnippet + +snippet extlookup "Extlookup with defaults" b +$${1:Variable} = extlookup("${2:Lookup}", ${3:Default})${0} +endsnippet + +snippet extlookup "Extlookup with defaults and custom data file" b +$${1:Variable} = extlookup("${2:Lookup}", ${3:Default}, ${4:Data Source})${0} +endsnippet + +snippet fail "Fail Function" b +fail("${1:message}")${0} +endsnippet + +snippet hiera "Hiera Function" b +$${1:Variable} = hiera("${2:Lookup}")${0} +endsnippet + +snippet hiera "Hiera with defaults" b +$${1:Variable} = hiera("${2:Lookup}", ${3:Default})${0} +endsnippet + +snippet hiera "Hiera with defaults and override" b +$${1:Variable} = hiera("${2:Lookup}", ${3:Default}, ${4:Override})${0} +endsnippet + +snippet hiera_hash "Hiera Hash Function" b +$${1:Variable} = hiera_hash("${2:Lookup}")${0} +endsnippet + +snippet hiera_hash "Hiera Hash with defaults" b +$${1:Variable} = hiera_hash("${2:Lookup}", ${3:Default})${0} +endsnippet + +snippet hiera_hash "Hiera Hash with defaults and override" b +$${1:Variable} = hiera_hash("${2:Lookup}", ${3:Default}, ${4:Override})${0} +endsnippet + +snippet hiera_include "Hiera Include Function" b +hiera_include("${1:Lookup}")${0} +endsnippet + +snippet include "Include Function" b +include ${1:classname}${0} +endsnippet + +snippet info "Info Function" b +info("${1:message}")${0} +endsnippet + +snippet inline_template "Inline Template Function" b +inline_template("<%= ${1:template} %>")${0} +endsnippet + +snippet notice "Notice Function" b +notice("${1:message}")${0} +endsnippet + +snippet realize "Realize Function" b +realize(${1:Resource}["${2:name}"])${0} +endsnippet + +snippet regsubst "Regsubst Function" b +regsubst($${1:Target}, '${2:regexp}', '${3:replacement}')${0} +endsnippet + +snippet split "Split Function" b +$${1:Variable} = split($${1:Target}, '${2:regexp}')${0} +endsnippet + +snippet versioncmp "Version Compare Function" b +$${1:Variable} = versioncmp('${1:version}', '${2:version}')${0} +endsnippet + +snippet warning "Warning Function" b +warning("${1:message}")${0} +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/python.snippets b/UltiSnips/python.snippets new file mode 100644 index 0000000..357d01d --- /dev/null +++ b/UltiSnips/python.snippets @@ -0,0 +1,533 @@ +priority -50 + +########################################################################### +# TEXTMATE SNIPPETS # +########################################################################### + +#! header +snippet #! "Shebang header for python scripts" b +#!/usr/bin/env python +# encoding: utf-8 +$0 +endsnippet + +snippet ifmain "ifmain" b +if __name__ == '__main__': + ${1:main()}$0 +endsnippet + +snippet for "for loop" b +for ${1:item} in ${2:iterable}: + ${3:pass} +endsnippet + +########## +# COMMON # +########## + +# The smart def and smart class snippets use a global option called +# "g:ultisnips_python_style" which, if set to "doxygen" will use doxygen +# style comments in docstrings. + +global !p + +NORMAL = 0x1 +DOXYGEN = 0x2 +SPHINX = 0x3 + +SINGLE_QUOTES = 0x1 +DOUBLE_QUOTES = 0x2 + +def get_args(arglist): + args = [arg.split('=')[0].strip() for arg in arglist.split(',') if arg] + args = [arg for arg in args if arg and arg != "self"] + + return args + + +def get_quoting_style(snip): + style = snip.opt("g:ultisnips_python_quoting_style", "double") + if style == 'single': + return SINGLE_QUOTES + return DOUBLE_QUOTES + +def tripple_quotes(snip): + if get_quoting_style(snip) == SINGLE_QUOTES: + return "'''" + return '"""' + +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 + + +def format_return(style): + if style == DOXYGEN: + return "@return: @todo" + elif style in (NORMAL, SPHINX): + return ":returns: @todo" + + +def write_docstring_args(args, snip): + if not args: + snip.rv += ' {0}'.format(tripple_quotes(snip)) + return + + snip.rv += '\n' + snip.mkline('', indent='') + + style = get_style(snip) + + for arg in args: + snip += format_arg(arg, style) + + +def write_init_body(args, parents, snip): + parents = [p.strip() for p in parents.split(",")] + parents = [p for p in parents if p != 'object'] + + for p in parents: + snip += p + ".__init__(self)" + + if parents: + snip.rv += '\n' + snip.mkline('', indent='') + + for arg in args: + snip += "self._%s = %s" % (arg, arg) + + +def write_slots_args(args, snip): + args = ['"_%s"' % arg for arg in args] + snip += '__slots__ = (%s,)' % ', '.join(args) + +endglobal + +######################################## +# Class & Special Method Name Snippets # +######################################## + +snippet class "class with docstrings" b +class ${1:MyClass}(${2:object}): + + `!p snip.rv = tripple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = tripple_quotes(snip)` + + def __init__(self$4): + `!p snip.rv = tripple_quotes(snip)`${5:@todo: to be defined1.}`!p +snip.rv = "" +snip >> 2 + +args = get_args(t[4]) + +write_docstring_args(args, snip) +if args: + snip.rv += '\n' + snip.mkline('', indent='') + snip += '{0}'.format(tripple_quotes(snip)) + +write_init_body(args, t[2], snip) +` + $0 +endsnippet + + +snippet slotclass "class with slots and docstrings" b +class ${1:MyClass}(${2:object}): + + `!p snip.rv = tripple_quotes(snip)`${3:Docstring for $1. }`!p snip.rv = tripple_quotes(snip)` +`!p +snip >> 1 +args = get_args(t[4]) +write_slots_args(args, snip) +` + + def __init__(self$4): + `!p snip.rv = tripple_quotes(snip)`${5:@todo: to be defined.}`!p +snip.rv = "" +snip >> 2 + +args = get_args(t[4]) + +write_docstring_args(args, snip) +if args: + snip.rv += '\n' + snip.mkline('', indent='') + snip += tripple_quotes(snip) + +write_init_body(args, t[2], snip) +` + $0 +endsnippet + + +snippet contain "methods for emulating a container type" b +def __len__(self): + ${1:pass} + +def __getitem__(self, key): + ${2:pass} + +def __setitem__(self, key, value): + ${3:pass} + +def __delitem__(self, key): + ${4:pass} + +def __iter__(self): + ${5:pass} + +def __reversed__(self): + ${6:pass} + +def __contains__(self, item): + ${7:pass} +endsnippet + + +snippet context "context manager methods" b +def __enter__(self): + ${1:pass} + +def __exit__(self, exc_type, exc_value, traceback): + ${2:pass} +endsnippet + + +snippet attr "methods for customizing attribute access" b +def __getattr__(self, name): + ${1:pass} + +def __setattr__(self, name, value): + ${2:pass} + +def __delattr__(self, name): + ${3:pass} +endsnippet + + +snippet desc "methods implementing descriptors" b +def __get__(self, instance, owner): + ${1:pass} + +def __set__(self, instance, value): + ${2:pass} + +def __delete__(self, instance): + ${3:pass} +endsnippet + + +snippet cmp "methods implementing rich comparison" +def __eq__(self, other): + ${1:pass} + +def __ne__(self, other): + ${2:pass} + +def __lt__(self, other): + ${3:pass} + +def __le__(self, other): + ${4:pass} + +def __gt__(self, other): + ${5:pass} + +def __ge__(self, other): + ${6:pass} + +def __cmp__(self, other): + ${7:pass} +endsnippet + + +snippet repr "methods implementing string representation" +def __repr__(self): + ${1:pass} + +def __str__(self): + ${2:pass} + +def __unicode__(self): + ${3:pass} +endsnippet + + +# note: reflected operands and augmented arithmeitc assignements have been +# intentionally ommited to reduce verbosity. +snippet numeric "methods for emulating a numeric type" b +def __add__(self, other): + ${1:pass} + +def __sub__(self, other): + ${2:pass} + +def __mul__(self, other): + ${3:pass} + +def __div__(self, other): + ${4:pass} + +def __truediv__(self, other): + ${5:pass} + +def __floordiv__(self, other): + ${6:pass} + + +def __mod__(self, other): + ${7:pass} + +def __divmod__(self, other): + ${8:pass} + +def __pow__(self, other): + ${9:pass} + + +def __lshift__(self, other): + ${10:pass} + +def __rshift__(self, other): + ${11:pass} + +def __and__(self, other): + ${12:pass} + +def __xor__(self, other): + ${13:pass} + +def __or__(self, other): + ${14:pass} + + +def __neg__(self): + ${15:pass} + +def __pos__(self): + ${16:pass} + +def __abs__(self): + ${17:pass} + +def __invert__(self): + ${18:pass} + + +def __complex__(self): + ${19:pass} + +def __int__(self): + ${20:pass} + +def __long__(self): + ${21:pass} + +def __float__(self): + ${22:pass} + + +def __oct__(self): + ${22:pass} + +def __hex__(self): + ${23:pass} + + +def __index__(self): + ${24:pass} + +def __coerce__(self, other): + ${25:pass} +endsnippet + +snippet def "function with docstrings" b +def ${1:function}(`!p +if snip.indent: + snip.rv = 'self' + (", " if len(t[2]) else "")`${2:arg1}): + `!p snip.rv = tripple_quotes(snip)`${4:@todo: Docstring for $1.}`!p +snip.rv = "" +snip >> 1 + +args = get_args(t[2]) +if args: + write_docstring_args(args, snip) + +style = get_style(snip) +snip += format_return(style) +snip.rv += '\n' + snip.mkline('', indent='') +snip += tripple_quotes(snip) ` + ${0:pass} +endsnippet + + +# doesn't expand when there is a word in front +snippet /(^|(?<=\W))\./ "self." r +self. +endsnippet + +snippet from "from module import name" b +from ${1:module} import ${2:Stuff} +endsnippet + + +############## +# PROPERTIES # +############## +snippet roprop "Read Only Property" b +@property +def ${1:name}(self): + ${2:return self._$1}$0 +endsnippet + +snippet rwprop "Read write property" b +def ${1:name}(): + `!p snip.rv = tripple_quotes(snip) if t[2] else '' +`${2:@todo: Docstring for $1.}`!p +if t[2]: + snip >> 1 + + style = get_style(snip) + snip.rv += '\n' + snip.mkline('', indent='') + snip += format_return(style) + snip.rv += '\n' + snip.mkline('', indent='') + snip += tripple_quotes(snip) +else: + snip.rv = ""` + def fget(self): + return self._$1$0 + + def fset(self, value): + self._$1 = value + return locals() + +$1 = property(**$1(), doc=$1.__doc__) +endsnippet + + +#################### +# If / Else / Elif # +#################### +snippet if "If" b +if ${1:condition}: + ${2:pass} +endsnippet + +snippet ife "If / Else" b +if ${1:condition}: + ${2:pass} +else: + ${3:pass} +endsnippet + +snippet ifee "If / Elif / Else" b +if ${1:condition}: + ${2:pass} +elif ${3:condition}: + ${4:pass} +else: + ${5:pass} +endsnippet + + +########################## +# Try / Except / Finally # +########################## +snippet try "Try / Except" b +try: + ${1:pass} +except ${2:Exception}, ${3:e}: + ${4:raise $3} +endsnippet + +snippet try "Try / Except / Else" b +try: + ${1:pass} +except ${2:Exception}, ${3:e}: + ${4:raise $3} +else: + ${5:pass} +endsnippet + +snippet try "Try / Except / Finally" b +try: + ${1:pass} +except ${2:Exception}, ${3:e}: + ${4:raise $3} +finally: + ${5:pass} +endsnippet + +snippet try "Try / Except / Else / Finally" b +try: + ${1:pass} +except${2: ${3:Exception}, ${4:e}}: + ${5:raise} +else: + ${6:pass} +finally: + ${7:pass} +endsnippet + + +##################### +# Assertions & Tests # +##################### + +snippet pdb "Set PDB breakpoint" b +import pdb; pdb.set_trace() +endsnippet + +snippet ipdb "Set IPDB breakpoint" b +import ipdb; ipdb.set_trace() +endsnippet + +snippet pudb "Set PUDB breakpoint" b +import pudb; pudb.set_trace() +endsnippet + +snippet ae "Assert equal" b +self.assertEqual(${1:first},${2:second}) +endsnippet + +snippet at "Assert True" b +self.assertTrue(${0:exp}) +endsnippet + +snippet af "Assert False" b +self.assertFalse(${1:expression}) +endsnippet + +snippet aae "Assert almost equal" b +self.assertAlmostEqual(${1:first},${2:second}) +endsnippet + +snippet ar "Assert raises" b +self.assertRaises(${1:exception}, ${2:func}${3/.+/, /}${3:arguments}) +endsnippet + + +snippet testcase "pyunit testcase" b +class Test${1:Class}(${2:unittest.TestCase}): + + `!p snip.rv = tripple_quotes(snip)`${3:Test case docstring.}`!p snip.rv = tripple_quotes(snip)` + + def setUp(self): + ${4:pass} + + def tearDown(self): + ${5:pass} + + def test_${6:name}(self): + ${7:pass} +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/rails.snippets b/UltiSnips/rails.snippets new file mode 100644 index 0000000..5c52179 --- /dev/null +++ b/UltiSnips/rails.snippets @@ -0,0 +1,904 @@ +priority -50 + +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?} \}}} + +endsnippet + +snippet tcbi "Create binary column" +t.binary :${1:title}${2:, :limit => ${3:2}.megabytes} +$0 +endsnippet + +snippet tcb "Create boolean column" +t.boolean :${1:title} +$0 +endsnippet + +snippet cla "Create controller class" +class ${1:Model}Controller < ApplicationController + before_filter :find_${2:model} + + $0 + + private + def find_${2} + @$2 = ${3:$1}.find(params[:id]) if params[:id] + end +end +endsnippet + +snippet tcda "Create date column" +t.date :${1:title} +$0 +endsnippet + +snippet tcdt "Create datetime column" +t.datetime :${1:title} +$0 +endsnippet + +snippet tcd "Create decimal column" +t.decimal :${1:title}${2:${3:, :precision => ${4:10}}${5:, :scale => ${6:2}}} +$0 +endsnippet + +snippet tcf "Create float column" +t.float :${1:title} +$0 +endsnippet + +snippet cla "Create functional test class" +require 'test_helper' + +class ${1:Model}ControllerTest < ActionController::TestCase + test$0 +end + +endsnippet + +snippet tci "Create integer column" +t.integer :${1:title} +$0 +endsnippet + +snippet tcl "Create lock_version column" +t.integer :lock_version, :null => false, :default => 0 +$0 +endsnippet + +# FIXME: handling literal bracket pair inside of nested tab groups? +snippet tcr "Create references column" +t.references :${1:taggable}${2:, :polymorphic => ${3:{ :default => '${4:Photo}' \}}} +$0 +endsnippet + +snippet resources "Create resources controller class" +class ${1:Model}sController < ApplicationController + before_filter :find_${1/./\l$0/}, :only => [:show, :edit, :update, :destroy] + + # GET /${1/./\l$0/}s + # GET /${1/./\l$0/}s.xml + def index + @${1/./\l$0/}s = ${1:Model}.all + + respond_to do |wants| + wants.html # index.html.erb + wants.xml { render :xml => @${1/./\l$0/}s } + end + end + + # GET /${1/./\l$0/}s/1 + # GET /${1/./\l$0/}s/1.xml + def show + respond_to do |wants| + wants.html # show.html.erb + wants.xml { render :xml => @${1/./\l$0/} } + end + end + + # GET /${1/./\l$0/}s/new + # GET /${1/./\l$0/}s/new.xml + def new + @${1/./\l$0/} = ${1:Model}.new + + respond_to do |wants| + wants.html # new.html.erb + wants.xml { render :xml => @${1/./\l$0/} } + end + end + + # GET /${1/./\l$0/}s/1/edit + def edit + end + + # POST /${1/./\l$0/}s + # POST /${1/./\l$0/}s.xml + def create + @${1/./\l$0/} = ${1:Model}.new(params[:${1/./\l$0/}]) + + respond_to do |wants| + if @${1/./\l$0/}.save + flash[:notice] = '${1:Model} was successfully created.' + wants.html { redirect_to(@${1/./\l$0/}) } + wants.xml { render :xml => @${1/./\l$0/}, :status => :created, :location => @${1/./\l$0/} } + else + wants.html { render :action => "new" } + wants.xml { render :xml => @${1/./\l$0/}.errors, :status => :unprocessable_entity } + end + end + end + + # PUT /${1/./\l$0/}s/1 + # PUT /${1/./\l$0/}s/1.xml + def update + respond_to do |wants| + if @${1/./\l$0/}.update_attributes(params[:${1/./\l$0/}]) + flash[:notice] = '${1:Model} was successfully updated.' + wants.html { redirect_to(@${1/./\l$0/}) } + wants.xml { head :ok } + else + wants.html { render :action => "edit" } + wants.xml { render :xml => @${1/./\l$0/}.errors, :status => :unprocessable_entity } + end + end + end + + # DELETE /${1/./\l$0/}s/1 + # DELETE /${1/./\l$0/}s/1.xml + def destroy + @${1/./\l$0/}.destroy + + respond_to do |wants| + wants.html { redirect_to(${1/./\l$0/}s_url) } + wants.xml { head :ok } + end + end + + private + def find_${1/./\l$0/} + @${1/./\l$0/} = ${1:Model}.find(params[:id]) + end + +end + +endsnippet + +snippet tcs "Create string column" +t.string :${1:title} +$0 +endsnippet + +snippet tct "Create text column" +t.text :${1:title} +$0 +endsnippet + +snippet tcti "Create time column" +t.time :${1:title} +$0 +endsnippet + +snippet tcts "Create timestamp column" +t.timestamp :${1:title} +$0 +endsnippet + +snippet tctss "Create timestamps columns" +t.timestamps +$0 +endsnippet + +snippet mcol "Migration Create Column (mcc)" +t.column ${1:title}, :${2:string} +$0 +endsnippet + +snippet mccc "Migration Create Column Continue (mccc)" +t.column ${1:title}, :${2:string} +mccc$0 +endsnippet + +snippet mtab "Migration Drop Create Table (mdct)" +drop_table :${1:table}${2: [press tab twice to generate create_table]} +endsnippet + +snippet mcol "Migration Remove and Add Column (mrac)" +remove_column :${1:table}, :${2:column}${3: [press tab twice to generate add_column]} +endsnippet + +snippet rdb "RAILS_DEFAULT_LOGGER.debug (rdb)" +RAILS_DEFAULT_LOGGER.debug "${1:message}"$0 +endsnippet + +snippet tre "Table column(s) rename" +t.rename(:${1:old_column_name}, :${2:new_column_name}) +$0 +endsnippet + +snippet art "Test Assert Redirected To (art)" +assert_redirected_to ${2::action => "${1:index}"} +endsnippet + +snippet asre "Test Assert Response (are)" +assert_response :${1:success}, @response.body$0 +endsnippet + +snippet aftc "after_create" +after_create $0 +endsnippet + +snippet aftd "after_destroy" +after_destroy $0 +endsnippet + +snippet afts "after_save" +after_save $0 +endsnippet + +snippet aftu "after_update" +after_update $0 +endsnippet + +snippet aftv "after_validation" +after_validation $0 +endsnippet + +snippet aftvoc "after_validation_on_create" +after_validation_on_create $0 +endsnippet + +snippet aftvou "after_validation_on_update" +after_validation_on_update $0 +endsnippet + +snippet asg "assert(var = assigns(:var))" +assert(${1:var} = assigns(:${1}), "Cannot find @${1}") +$0 +endsnippet + +snippet asd "assert_difference" +assert_difference "${1:Model}.${2:count}", ${3:1} do + $0 +end +endsnippet + +snippet asnd "assert_no_difference" +assert_no_difference "${1:Model}.${2:count}" do + $0 +end +endsnippet + +snippet artnpp "assert_redirected_to (nested path plural)" +assert_redirected_to ${10:${2:parent}_${3:child}_path(${4:@}${5:${2}})} +endsnippet + +snippet artnp "assert_redirected_to (nested path)" +assert_redirected_to ${2:${12:parent}_${13:child}_path(${14:@}${15:${12}}, ${16:@}${17:${13}})} +endsnippet + +snippet artpp "assert_redirected_to (path plural)" +assert_redirected_to ${10:${2:model}s_path} +endsnippet + +snippet artp "assert_redirected_to (path)" +assert_redirected_to ${2:${12:model}_path(${13:@}${14:${12}})} +endsnippet + +snippet asrj "assert_rjs" +assert_rjs :${1:replace}, ${2:"${3:dom id}"} +endsnippet + +snippet ass "assert_select" +assert_select '${1:path}'${2:, :${3:text} => ${4:'${5:inner_html}'}}${6: do + $0 +end} +endsnippet + +snippet befc "before_create" +before_create $0 +endsnippet + +snippet befd "before_destroy" +before_destroy $0 +endsnippet + +snippet befs "before_save" +before_save $0 +endsnippet + +snippet befu "before_update" +before_update $0 +endsnippet + +snippet befv "before_validation" +before_validation $0 +endsnippet + +snippet befvoc "before_validation_on_create" +before_validation_on_create $0 +endsnippet + +snippet befvou "before_validation_on_update" +before_validation_on_update +endsnippet + +snippet bt "belongs_to (bt)" +belongs_to :${1:object}${2:, :class_name => "${3:${1/[[:alpha:]]+|(_)/(?1::\u$0)/g}}", :foreign_key => "${4:${1}_id}"} +endsnippet + +snippet crw "cattr_accessor" +cattr_accessor :${0:attr_names} +endsnippet + +snippet defcreate "def create - resource" +def create + @${1:model} = ${2:${1/[[:alpha:]]+|(_)/(?1::\u$0)/g}}.new(params[:$1]) + $0 + respond_to do |wants| + if @$1.save + flash[:notice] = '$2 was successfully created.' + wants.html { redirect_to(@$1) } + wants.xml { render :xml => @$1, :status => :created, :location => @$1 } + else + wants.html { render :action => "new" } + wants.xml { render :xml => @$1.errors, :status => :unprocessable_entity } + end + end +end + +endsnippet + +snippet test "test do..end" +test "${1:something interesting}" do + $0 +end +endsnippet + +snippet deftg "def get request" +def test_should_get_${1:action} + ${2:@${3:model} = ${4:$3s}(:${5:fixture_name}) + }get :${1}${6:, :id => @$3.to_param} + assert_response :success + $0 +end +endsnippet + +snippet deftp "def post request" +def test_should_post_${1:action} + ${3:@$2 = ${4:$2s}(:${5:fixture_name}) + }post :${1}${6:, :id => @$2.to_param}, :${2:model} => { $0 } + assert_response :redirect + +end +endsnippet + +snippet fina "find(:all)" +find(:all${1:, :conditions => ['${2:${3:field} = ?}', ${5:true}]}) +endsnippet + +snippet finf "find(:first)" +find(:first${1:, :conditions => ['${2:${3:field} = ?}', ${5:true}]}) +endsnippet + +snippet fini "find(id)" +find(${1:id}) +endsnippet + +snippet fine "find_each" +find_each(${1::conditions => {:${2:field} => ${3:true}\}}) do |${4:${TM_CURRENT_WORD/(\w+)\./\L$1/g}}| + $0 +end +endsnippet + +snippet finb "find_in_batches" +find_in_batches(${1::conditions => {:${2:field} => ${3:true}\}}) do |${4:${TM_CURRENT_WORD/(\w+)\./\L$1/g}}s| + $4s.each do |$4| + $0 + end +end +endsnippet + +snippet habtm "has_and_belongs_to_many (habtm)" +has_and_belongs_to_many :${1:object}${2:, :join_table => "${3:table_name}", :foreign_key => "${4:${1}_id}"} +endsnippet + +snippet hm "has_many (hm)" +has_many :${1:object}s${2:, :class_name => "${1}", :foreign_key => "${4:reference}_id"} +endsnippet + +snippet hmt "has_many (through)" +has_many :${1:objects}, :through => :${2:join_association}${3:, :source => :${4:${2}_table_foreign_key_to_${1}_table}} +endsnippet + +snippet hmd "has_many :dependent => :destroy" +has_many :${1:object}s${2:, :class_name => "${1}", :foreign_key => "${4:reference}_id"}, :dependent => :destroy$0 +endsnippet + +snippet ho "has_one (ho)" +has_one :${1:object}${2:, :class_name => "${3:${1/[[:alpha:]]+|(_)/(?1::\u$0)/g}}", :foreign_key => "${4:${1}_id}"} +endsnippet + +snippet logd "logger.debug" +${1:Rails.}logger.debug { "${1:message}" }$0 +endsnippet + +snippet loge "logger.error" +logger.error { "${1:message}" }$0 +endsnippet + +snippet logf "logger.fatal" +logger.fatal { "${1:message}" }$0 +endsnippet + +snippet logi "logger.info" +logger.info { "${1:message}" }$0 +endsnippet + +snippet logw "logger.warn" +logger.warn { "${1:message}" }$0 +endsnippet + +snippet mp "map(&:sym_proc)" +map(&:${1:id}) +endsnippet + +snippet mapca "map.catch_all" +${1:map}.catch_all "*${2:anything}", :controller => "${3:default}", :action => "${4:error}" + +endsnippet + +snippet map "map.named_route" +${1:map}.${2:connect} '${3::controller/:action/:id}' +endsnippet + +snippet mapr "map.resource" +${1:map}.resource :${2:resource}${10: do |${11:$2}| + $0 +end} +endsnippet + +snippet maprs "map.resources" +${1:map}.resources :${2:resource}${10: do |${11:$2}| + $0 +end} +endsnippet + +snippet mapwo "map.with_options" +${1:map}.with_options :${2:controller} => '${3:thing}' do |${4:$3}| + $0 +end + +endsnippet + +snippet mrw "mattr_accessor" +mattr_accessor :${0:attr_names} +endsnippet + +snippet ncl "named_scope lambda" +named_scope :name, lambda { |${1:param}| { :conditions => ${3:['${4:${5:field} = ?}', ${6:$1}]} } } + +endsnippet + +snippet nc "named_scope" +named_scope :name${1:, :joins => :${2:table}}, :conditions => ${3:['${4:${5:field} = ?}', ${6:true}]} + +endsnippet + +snippet dscope "default_scope" +default_scope ${1:order(${2:'${3:created_at DESC}'})} +endsnippet + +snippet flash "flash[...]" +flash[:${1:notice}] = "${2:Successfully created...}"$0 +endsnippet + +snippet rea "redirect_to (action)" +redirect_to :action => "${1:index}" +endsnippet + +snippet reai "redirect_to (action, id)" +redirect_to :action => "${1:show}", :id => ${0:@item} +endsnippet + +snippet rec "redirect_to (controller)" +redirect_to :controller => "${1:items}" +endsnippet + +snippet reca "redirect_to (controller, action)" +redirect_to :controller => "${1:items}", :action => "${2:list}" +endsnippet + +snippet recai "redirect_to (controller, action, id)" +redirect_to :controller => "${1:items}", :action => "${2:show}", :id => ${0:@item} +endsnippet + +snippet renpp "redirect_to (nested path plural)" +redirect_to(${2:${10:parent}_${11:child}_path(${12:@}${13:${10}})}) +endsnippet + +snippet renp "redirect_to (nested path)" +redirect_to(${2:${12:parent}_${13:child}_path(${14:@}${15:${12}}, ${16:@}${17:${13}})}) +endsnippet + +snippet repp "redirect_to (path plural)" +redirect_to(${2:${10:model}s_path}) +endsnippet + +snippet rep "redirect_to (path)" +redirect_to(${2:${12:model}_path(${13:@}${14:${12}})}) +endsnippet + +snippet reb "redirect_to :back" +redirect_to :back +endsnippet + +snippet ra "render (action)... (ra)" +render :action => "${1:action}" +endsnippet + +snippet ral "render (action,layout) (ral)" +render :action => "${1:action}", :layout => "${2:layoutname}" +endsnippet + +snippet rf "render (file) (rf)" +render :file => "${1:filepath}" +endsnippet + +snippet rfu "render (file,use_full_path) (rfu)" +render :file => "${1:filepath}", :use_full_path => ${2:false} +endsnippet + +snippet ri "render (inline) (ri)" +render :inline => "${1:<%= 'hello' %>}" +endsnippet + +snippet ril "render (inline,locals) (ril)" +render :inline => "${1:<%= 'hello' %>}", :locals => { ${2::name} => "${3:value}"$4 } +endsnippet + +snippet rit "render (inline,type) (rit)" +render :inline => "${1:<%= 'hello' %>}", :type => ${2::rxml} +endsnippet + +snippet rl "render (layout) (rl)" +render :layout => "${1:layoutname}" +endsnippet + +snippet rn "render (nothing) (rn)" +render :nothing => ${1:true} +endsnippet + +snippet rns "render (nothing,status) (rns)" +render :nothing => ${1:true}, :status => ${2:401} +endsnippet + +snippet rt "render (text) (rt)" +render :text => "${1:text to render...}" +endsnippet + +snippet rtl "render (text,layout) (rtl)" +render :text => "${1:text to render...}", :layout => "${2:layoutname}" +endsnippet + +snippet rtlt "render (text,layout => true) (rtlt)" +render :text => "${1:text to render...}", :layout => ${2:true} +endsnippet + +snippet rts "render (text,status) (rts)" +render :text => "${1:text to render...}", :status => ${2:401} +endsnippet + +snippet ru "render (update)" +render :update do |${2:page}| + $2.$0 +end +endsnippet + +snippet rest "respond_to" +respond_to do |wants| + wants.${1:html}${2: { $0 \}} +end +endsnippet + +snippet resw "respond_with" +respond_with(${1:@${2:model}})${3: do |format| + format.${4:html} { $0 \} +end} +endsnippet + +# FIXME +snippet returning "returning do |variable| ... end" +returning ${1:variable} do${2/(^(?\s*[a-z_][a-zA-Z0-9_]*\s*)(,\g)*,?\s*$)|.*/(?1: |)/}${2:v}${2/(^(?\s*[a-z_][a-zA-Z0-9_]*\s*)(,\g)*,?\s*$)|.*/(?1:|)/} + $0 +end +endsnippet + +snippet t. "t.binary (tcbi)" +t.binary :${1:title}${2:, :limit => ${3:2}.megabytes} +t.$0 +endsnippet + +snippet t. "t.boolean (tcb)" +t.boolean :${1:title} +t.$0 +endsnippet + +snippet t. "t.date (tcda)" +t.date :${1:title} +t.$0 +endsnippet + +snippet t. "t.datetime (tcdt)" +t.datetime :${1:title} +t.$0 +endsnippet + +snippet t. "t.decimal (tcd)" +t.decimal :${1:title}${2:${3:, :precision => ${4:10}}${5:, :scale => ${6:2}}} +t.$0 +endsnippet + +snippet t. "t.float (tcf)" +t.float :${1:title} +t.$0 +endsnippet + +snippet t. "t.integer (tci)" +t.integer :${1:title} +t.$0 +endsnippet + +snippet t. "t.lock_version (tcl)" +t.integer :lock_version, :null => false, :default => 0 +t.$0 +endsnippet + +snippet t. "t.references (tcr)" +t.references :${1:taggable}${2:, :polymorphic => ${3:{ :default => '${4:Photo}' \}}} +t.$0 +endsnippet + +snippet t. "t.rename (tre)" +t.rename(:${1:old_column_name}, :${2:new_column_name}) +t.$0 +endsnippet + +snippet t. "t.string (tcs)" +t.string :${1:title} +t.$0 +endsnippet + +snippet t. "t.text (tct)" +t.text :${1:title} +t.$0 +endsnippet + +snippet t. "t.time (tcti)" +t.time :${1:title} +t.$0 +endsnippet + +snippet t. "t.timestamp (tcts)" +t.timestamp :${1:title} +t.$0 +endsnippet + +snippet t. "t.timestamps (tctss)" +t.timestamps +t.$0 +endsnippet + +snippet vaoif "validates_acceptance_of if" +validates_acceptance_of :${1:terms}${2:${3:, :accept => "${4:1}"}${5:, :message => "${6:You must accept the terms of service}"}}, :if => proc { |obj| ${7:obj.condition?} }} +endsnippet + +snippet vao "validates_acceptance_of" +validates_acceptance_of :${1:terms}${2:${3:, :accept => "${4:1}"}${5:, :message => "${6:You must accept the terms of service}"}} +endsnippet + +snippet va "validates_associated (va)" +validates_associated :${1:attribute}${2:, :on => :${3:create}} +endsnippet + +snippet vaif "validates_associated if (vaif)" +validates_associated :${1:attribute}${2:, :on => :${3:create}, :if => proc { |obj| ${5:obj.condition?} }} +endsnippet + +snippet vc "validates_confirmation_of (vc)" +validates_confirmation_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:should match confirmation}"} +endsnippet + +snippet vcif "validates_confirmation_of if (vcif)" +validates_confirmation_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:should match confirmation}", :if => proc { |obj| ${5:obj.condition?} }} +endsnippet + +snippet ve "validates_exclusion_of (ve)" +validates_exclusion_of :${1:attribute}${2:, :in => ${3:%w( ${4:mov avi} )}, :on => :${5:create}, :message => "${6:extension %s is not allowed}"} +endsnippet + +snippet veif "validates_exclusion_of if (veif)" +validates_exclusion_of :${1:attribute}${2:, :in => ${3:%w( ${4:mov avi} )}, :on => :${5:create}, :message => "${6:extension %s is not allowed}"}, :if => proc { |obj| ${7:obj.condition?} }} +endsnippet + +snippet vfif "validates_format_of if" +validates_format_of :${1:attribute}, :with => /${2:^[${3:\w\d}]+\$}/${4:, :on => :${5:create}, :message => "${6:is invalid}"}, :if => proc { |obj| ${7:obj.condition?} }} +endsnippet + +snippet vf "validates_format_of" +validates_format_of :${1:attribute}, :with => /${2:^[${3:\w\d}]+\$}/${4:, :on => :${5:create}, :message => "${6:is invalid}"} +endsnippet + +snippet viif "validates_inclusion_of if" +validates_inclusion_of :${1:attribute}${2:, :in => ${3:%w( ${4:mov avi} )}, :on => :${5:create}, :message => "${6:extension %s is not included in the list}"}, :if => proc { |obj| ${7:obj.condition?} }} +endsnippet + +snippet vi "validates_inclusion_of" +validates_inclusion_of :${1:attribute}${2:, :in => ${3:%w( ${4:mov avi} )}, :on => :${5:create}, :message => "${6:extension %s is not included in the list}"} +endsnippet + +snippet vl "validates_length_of (vl)" +validates_length_of :${1:attribute}, :within => ${2:3..20}${3:, :on => :${4:create}, :message => "${5:must be present}"} +endsnippet + +snippet vlif "validates_length_of if" +validates_length_of :${1:attribute}, :within => ${2:3..20}${3:, :on => :${4:create}, :message => "${5:must be present}"}, :if => proc { |obj| ${6:obj.condition?} }} +endsnippet + +snippet vnif "validates_numericality_of if" +validates_numericality_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:is not a number}"}, :if => proc { |obj| ${5:obj.condition?} }} +endsnippet + +snippet vn "validates_numericality_of" +validates_numericality_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:is not a number}"} +endsnippet + +snippet vp "validates_presence_of (vp)" +validates_presence_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:can't be blank}"} +endsnippet + +snippet vpif "validates_presence_of if (vpif) 2" +validates_presence_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:can't be blank}"}, :if => proc { |obj| ${5:obj.condition?} }} +endsnippet + +snippet vu "validates_uniqueness_of (vu)" +validates_uniqueness_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:must be unique}"} +endsnippet + +snippet vuif "validates_uniqueness_of if (vuif)" +validates_uniqueness_of :${1:attribute}${2:, :on => :${3:create}, :message => "${4:must be unique}", :if => proc { |obj| ${6:obj.condition?} }} +endsnippet + +snippet verify "verify -- render" +verify :only => [:$1], :method => :post, :render => {:status => 500, :text => "use HTTP-POST"} + +endsnippet + +snippet verify "verify -- redirect" +verify :only => [:$1], :session => :user, :params => :id, :redirect_to => {:action => '${2:index}'} + +endsnippet + +snippet wants "wants_format" +wants.${1:js|xml|html}${2: { $0 \}} +endsnippet + +snippet xdelete "xhr delete" +xhr :delete, :${1:destroy}, :id => ${2:1}$0 +endsnippet + +snippet xget "xhr get" +xhr :get, :${1:show}${2:, :id => ${3:1}}$0 +endsnippet + +snippet xpost "xhr post" +xhr :post, :${1:create}, :${2:object} => { $3 } +endsnippet + +snippet xput "xhr put" +xhr :put, :${1:update}, :id => ${2:1}, :${3:object} => { $4 }$0 +endsnippet + +snippet finl "find(:last)" +find(:last${1:, :conditions => ['${2:${3:field} = ?}', ${5:true}]}) +endsnippet + +snippet sweeper "Create sweeper class" +class ${1:Model}Sweeper < ActionController::Caching::Sweeper + observe ${1:Model} + + def after_save(${1/./\l$0/}) + expire_cache(${1/./\l$0/}) + end + + def after_destroy(${1/./\l$0/}) + expire_cache(${1/./\l$0/}) + end + + private + + def expire_cache(${1/./\l$0/}) + ${0:expire_page ${1/./\l$0/}s_path + expire_page ${1/./\l$0/}_path(${1/./\l$0/})} + end + +end +endsnippet + +snippet col "collection routes" +collection do + ${1:get :${2:action}} + ${3:put :${4:action}} + ${5:post :${6:action}} + ${7:delete :${8:action}} +end +endsnippet + +snippet format "format (respond_with)" +format.${1:html|xml|json|js|any} { $0 } +endsnippet + +snippet gem "gem" +gem '${1:name}'${2:${3:, "${4:1.0}"}${5:${6:, :require => ${7:"${8:$1}"}}${9:, :group => :${10:test}}}} +endsnippet + +snippet gemg "gem :git" +gem '${1:paperclip}', :git => "${2:git://github.com/thoughtbot/paperclip.git}"${3:, :branch => "${4:rails3}"} +endsnippet + +snippet match "match" +match '${1:${2::controller}${3:/${4::action}${5:/${6::id}${7:(.:format)}}}}'${8: => '${9:$2}#${10:$4}'${11:, :as => :${12:$10}}} +endsnippet + +snippet member "member routes" +member do + ${1:get :${2:action}} + ${3:put :${4:action}} + ${5:post :${6:action}} + ${7:delete :${8:action}} +end +endsnippet + +snippet res "resources" +resources :${1:posts}${2: do + $3 +end} +endsnippet + +snippet scope "scope" +scope :${1:name}, ${2:joins(:${3:table}).}where(${4:'${5:$3.${6:field}} = ?', ${7:'${8:value}'}}) +endsnippet + +snippet scopel "scope lambda" +scope :${1:name}, lambda { |${2:param}| ${3:where(${4::${5:field} => ${6:"${7:value}"}})} } +endsnippet + +snippet scopee "scope with extension" +scope :${1:name}, ${2:where(${3::${4:field} => ${5:'${6:value}'}})} do + def ${7:method_name} + $0 + end +end +endsnippet + +snippet sb "scoped_by" +scoped_by_${1:attribute}(${2:id}) +endsnippet + +snippet setup "setup do..end" +setup do + $0 +end +endsnippet + +snippet trans "Translation snippet" +I18n.t('`!v substitute(substitute(substitute(@%, substitute(getcwd() . "/", "\/", "\\\\/", "g"), "", ""), "\\(\\.\\(html\\|js\\)\\.\\(haml\\|erb\\)\\|\\(_controller\\)\\?\\.rb\\)$", "", ""), "/", ".", "g")`.${2:${1/[^\w]/_/g}}${3}', :default => "${1:some_text}"${4})${5:$0} +endsnippet + +snippet route_spec +it 'routes to #${1:action}' do + ${2:get}('/${3:url}').should route_to('`!v substitute(expand('%:t:r'), '_routing_spec$', '', '')`#$1'${4:, ${5:params}})${6} +end +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/rst.snippets b/UltiSnips/rst.snippets new file mode 100644 index 0000000..0894ef3 --- /dev/null +++ b/UltiSnips/rst.snippets @@ -0,0 +1,61 @@ +priority -50 + +########################################################################### +# General Stuff # +########################################################################### +snippet part "Part" b +`!p snip.rv = len(t[1])*'#'` +${1:Part name} +`!p snip.rv = len(t[1])*'#'` + +$0 +endsnippet + +snippet sec "Section" b +${1:Section name} +`!p snip.rv = len(t[1])*'='` + +$0 +endsnippet + +snippet ssec "Subsection" b +${1:Section name} +`!p snip.rv = len(t[1])*'-'` + +$0 +endsnippet + +snippet sssec "Subsubsection" b +${1:Section name} +`!p snip.rv = len(t[1])*'^'` + +$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. # +########################################################################### +snippet cb "Code Block" b +.. code-block:: ${1:lua} + + ${2:code} + +$0 +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/ruby.snippets b/UltiSnips/ruby.snippets new file mode 100644 index 0000000..09a114f --- /dev/null +++ b/UltiSnips/ruby.snippets @@ -0,0 +1,570 @@ +priority -50 + +snippet "^#!" "#!/usr/bin/env ruby" r +#!/usr/bin/env ruby +$0 +endsnippet + + +snippet "^# ?[uU][tT][fF]-?8" "# encoding: UTF-8" r +# encoding: UTF-8 +$0 +endsnippet + + + +snippet If " if " +${1:command} if ${0:expression} +endsnippet + + + +snippet Unless " unless " +${1:command} unless ${0:expression} +endsnippet + + + +snippet if "if ... end" +if ${1:condition} + ${2:# TODO} +end +endsnippet + + + +snippet ife "if ... else ... end" +if ${1:condition} + ${2:# TODO} +else + ${3:# TODO} +end +endsnippet + + + +snippet ifee "if ... elseif ... else ... end" +if ${1:condition} + ${2:# TODO} +elsif ${3:condition} + ${4:# TODO} +else + ${0:# TODO} +end +endsnippet + + + +snippet unless "unless ... end" +unless ${1:condition} + ${0:# TODO} +end +endsnippet + + + +snippet unlesse "unless ... else ... end" +unless ${1:condition} + ${2:# TODO} +else + ${0:# TODO} +end +endsnippet + + + +snippet unlesee "unless ... elseif ... else ... end" +unless ${1:condition} + ${2:# TODO} +elsif ${3:condition} + ${4:# TODO} +else + ${0:# TODO} +end +endsnippet + + + +snippet "\b(de)?f" "def ..." r +def ${1:function_name}${2: ${3:*args}} + ${0:# TODO} +end +endsnippet + + + +snippet defi "def initialize ..." +def initialize${1: ${2:*args}} + ${0:# TODO} +end +endsnippet + + + +snippet defr "def ... rescue ..." +def ${1:function_name}${2: ${3:*args}} + ${4:# TODO} +rescue + ${0:# TODO} +end +endsnippet + + + +snippet For "(..).each { || }" +(${1:from}..${2:to}).each { |${3:i}| ${4:# TODO} } +endsnippet + + + +snippet for "(..).each do || end" +(${1:from}..${2:to}).each do |${3:i}| + ${0:# TODO} +end +endsnippet + + + +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 "(\S+)\.merge!" ".merge!() do |,,| end" r +`!p snip.rv=match.group(1)`.merge!(${1:other_hash}) do |${2:key},${3:oldval},${4:newval}| + ${0:block} +end +endsnippet + + + +snippet "(\S+)\.Del(ete)?_?if" ".delete_if { |,| }" r +`!p snip.rv=match.group(1)`.delete_if { |${1:key},${2:value}| ${3:# TODO} } +endsnippet + + + +snippet "(\S+)\.del(ete)?_?if" ".delete_if do |,| end" r +`!p snip.rv=match.group(1)`.delete_if do |${1:key},${2:value}| + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.Keep_?if" ".keep_if { |,| }" r +`!p snip.rv=match.group(1)`.keep_if { |${1:key},${2:value}| ${3:# TODO} } +endsnippet + + + +snippet "(\S+)\.keep_?if" ".keep_if do ,| end" r +`!p snip.rv=match.group(1)`.keep_if do |${1:key},${2:value}| + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.Reject" ".reject { |,| }" r +`!p snip.rv=match.group(1)`.reject { |${1:key},${2:value}| ${3:# TODO} } +endsnippet + + + +snippet "(\S+)\.reject" ".reject do ,| end" r +`!p snip.rv=match.group(1)`.reject do |${1:key},${2:value}| + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.Select" ".select { || }" r +`!p snip.rv=match.group(1)`.select { |${1:item}| ${2:block} } +endsnippet + + + +snippet "(\S+)\.select" ".select do || end" r +`!p snip.rv=match.group(1)`.select do |${1:item}| + ${0:block} +end +endsnippet + + + +snippet "(\S+)\.Sort" ".sort { |
    ,| }" r +`!p snip.rv=match.group(1)`.sort { |${1:a},${2:b}| ${3:# TODO} } +endsnippet + + + +snippet "(\S+)\.sort" ".sort do |,| end" r +`!p snip.rv=match.group(1)`.sort do |${1:a},${2:b}| + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.Each_?k(ey)?" ".each_key { || }" r +`!p snip.rv=match.group(1)`.each_key { |${1:key}| ${2:# TODO} } +endsnippet + + + +snippet "(\S+)\.each_?k(ey)?" ".each_key do |key| end" r +`!p snip.rv=match.group(1)`.each_key do |${1:key}| + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.Each_?val(ue)?" ".each_value { || }" r +`!p snip.rv=match.group(1)`.each_value { |${1:value}| ${2:# TODO} } +endsnippet + + + +snippet "(\S+)\.each_?val(ue)?" ".each_value do || end" r +`!p snip.rv=match.group(1)`.each_value do |${1:value}| + ${0:# TODO} +end +endsnippet + + + +snippet Each ".each { || }" +${1:elements}.each { |${2:${1/s$//}}| ${3:# TODO} } +endsnippet + + + +snippet each ".each do || end" +${1:elements}.each do |${2:${1/s$//}}| + ${0:# TODO} +end +endsnippet + + + +snippet "each_?s(lice)?" ".each_slice(n) do |slice| end" r +${1:elements}.each_slice(${2:2}) do |${3:slice}| + ${0:# TODO} +end +endsnippet + + + +snippet "Each_?s(lice)?" ".each_slice(n) { |slice| }" r +${1:elements}.each_slice(${2:2}) { |${3:slice}| ${0:# 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) +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:# TODO} } +endsnippet + + + +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) +try: + wmatch = re.search("([A-Za-z][A-Za-z0-9_]+)$", ematch.group(1)) + snip.rv = wmatch.group(1).lower() +except: + snip.rv = 'element' +`}| + ${0:# TODO} +end +endsnippet + + + +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) +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:# TODO} } +endsnippet + + + +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) +try: + wmatch = re.search("([A-Za-z][A-Za-z0-9_]+)$", ematch.group(1)) + snip.rv = wmatch.group(1).lower() +except: + snip.rv = 'element' +`}| + ${0:# TODO} +end +endsnippet + + + +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) +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:# TODO} } +endsnippet + + + +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) +try: + wmatch = re.search("([A-Za-z][A-Za-z0-9_]+)$", ematch.group(1)) + snip.rv = wmatch.group(1).lower() +except: + snip.rv = 'element' +`}| + ${0:# TODO} +end +endsnippet + + + + +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 "(\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 "(\S+)\.Each_?p(air)?" ".each_pair { |,| }" r +`!p snip.rv=match.group(1)`.each_pair { |${1:key},${2:value}| ${3:# TODO} } +endsnippet + + + +snippet "(\S+)\.each_?p(air)?" ".each_pair do |,| end" r +`!p snip.rv=match.group(1)`.each_pair do |${1:key},${2:value}| + ${0:# TODO} +end +endsnippet + + + +snippet "(\S+)\.sub" ".sub() { }" r +`!p snip.rv=match.group(1)`.sub(${1:expression}) { ${2:"replace_with"} } +endsnippet + + + +snippet "(\S+)\.gsub" ".gsub() { }" r +`!p snip.rv=match.group(1)`.gsub(${1:expression}) { ${2:"replace_with"} } +endsnippet + + + +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:args}| + $0 +end +endsnippet + + + +snippet Do "do ... end" i +do + $0 +end +endsnippet + + +snippet until "until ... end" +until ${1:expression} + ${0:# TODO} +end +endsnippet + + + +snippet Until "begin ... end until " +begin + ${0:# TODO} +end until ${1:expression} +endsnippet + + + +snippet while "while ... end" +while ${1:expression} + ${0:# TODO} +end +endsnippet + + + +snippet While "begin ... end while " +begin + ${0:# TODO} +end while ${1:expression} +endsnippet + + + +snippet "\b(r|attr)" "attr_reader :" r +attr_reader :${0:attr_names} +endsnippet + + + +snippet "\b(w|attr)" "attr_writer :" r +attr_writer :${0:attr_names} +endsnippet + + + +snippet "\b(rw|attr)" "attr_accessor :" r +attr_accessor :${0:attr_names} +endsnippet + + + +snippet begin "begin ... rescue ... end" +begin + ${1:# TODO} +rescue + ${0:# TODO} +end +endsnippet + + + +snippet begin "begin ... rescue ... else ... ensure ... end" +begin + ${1:# Raise exception} +rescue Exception => e + puts e.message + puts e.backtrace.inspect + ${2:# Rescue} +else + ${3:# other exception} +ensure + ${0:# always excute} +end +endsnippet + + + +snippet rescue +rescue Exception => e + puts e.message + puts e.backtrace.inspect + ${0:# Rescue} +endsnippet + + + +snippet "\b(case|sw(itch)?)" "case when ... end" r +case ${1:variable} +when ${2:expression} +$0 +end +endsnippet + + + +snippet alias "alias : :" +alias :${1:new_name} :${2:old_name} +endsnippet + + + +snippet class "class def initialize ... end end" +class ${1:class_name} + 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/UltiSnips/scss.snippets b/UltiSnips/scss.snippets new file mode 100644 index 0000000..70a44a0 --- /dev/null +++ b/UltiSnips/scss.snippets @@ -0,0 +1,55 @@ +priority -50 + +snippet /@?imp/ "@import '...';" br +@import '${1:file}'; +endsnippet + +snippet /@?inc/ "@include mixin(...);" br +@include ${1:mixin}(${2:arguments}); +endsnippet + +snippet /@?ext?/ "@extend %placeholder;" br +@extend %${1:placeholder}; +endsnippet + +snippet /@?mixin/ "@mixin (...) { ... }" br +@mixin ${1:name}(${2:arguments}) { + ${VISUAL}$0 +} +endsnippet + +snippet /@?fun/ "@function (...) { ... }" br +@function ${1:name}(${2:arguments}) { + ${VISUAL}$0 +} +endsnippet + +snippet /@?if/ "@if (...) { ... }" br +@if ${1:condition} { + ${VISUAL}$0 +} +endsnippet + +snippet /(} )?@?else/ "@else { ... }" br +@else ${1:condition} { + ${VISUAL}$0 +} +endsnippet + +snippet /@?for/ "@for loop" br +@for ${1:$i} from ${2:1} through ${3:3} { + ${VISUAL}$0 +} +endsnippet + +snippet /@?each/ "@each loop" br +@each ${1:$item} in ${2:item, item, item} { + ${VISUAL}$0 +} +endsnippet + +snippet /@?while/ "@while loop" br +@while ${1:$i} ${2:>} ${3:0} { + ${VISUAL}$0 +} +endsnippet diff --git a/UltiSnips/sh.snippets b/UltiSnips/sh.snippets new file mode 100644 index 0000000..9cc4577 --- /dev/null +++ b/UltiSnips/sh.snippets @@ -0,0 +1,92 @@ +priority -50 + +global !p +import vim + +# Tests for the existence of a variable declared by Vim's filetype detection +# suggesting the type of shell script of the current file +def testShell(scope, shell): + return vim.eval("exists('" + scope + ":is_" + shell + "')") + +# Loops over the possible variables, checking for global variables +# first since they indicate an override by the user. +def getShell(): + for scope in ["g", "b"]: + for shell in ["bash", "posix", "sh", "kornshell"]: + if testShell(scope, shell) == "1": + if shell == "kornshell": + return "ksh" + if shell == "posix": + return "sh" + return shell + return "sh" +endglobal + +########################################################################### +# TextMate Snippets # +########################################################################### +snippet #! +`!p snip.rv = '#!/bin/' + getShell() + "\n\n" ` +endsnippet + +snippet !env "#!/usr/bin/env (!env)" +`!p snip.rv = '#!/usr/bin/env ' + getShell() + "\n\n" ` +endsnippet + +snippet temp "Tempfile" +${1:TMPFILE}="$(mktemp -t ${2:`!p +snip.rv = re.sub(r'[^a-zA-Z]', '_', snip.fn) or "untitled" +`})" +${3:${4/(.+)/trap "/}${4:rm -f '$${1/.*\s//}'}${4/(.+)/" 0 # EXIT\n/}${5/(.+)/trap "/}${5:rm -f '$${1/.*\s//}'; exit 1}${5/(.+)/" 2 # INT\n/}${6/(.+)/trap "/}${6:rm -f '$${1/.*\s//}'; exit 1}${6/(.+)/" 1 15 # HUP TERM\n/}} + +endsnippet + +snippet case "case .. esac (case)" +case ${1:word} in + ${2:pattern} ) + $0;; +esac +endsnippet + +snippet elif "elif .. (elif)" +elif ${2:[[ ${1:condition} ]]}; then + ${0:#statements} +endsnippet + +snippet for "for ... done (for)" +for (( i = 0; i < ${1:10}; i++ )); do + ${0:#statements} +done +endsnippet + +snippet forin "for ... in ... done (forin)" +for ${1:i}${2/.+/ in /}${2:words}; do + ${0:#statements} +done +endsnippet + +snippet here "here document (here)" +<<-${2:'${1:TOKEN}'} + $0 +${1/['"`](.+)['"`]/$1/} +endsnippet + +snippet if "if ... then (if)" +if ${2:[[ ${1:condition} ]]}; then + ${0:#statements} +fi +endsnippet + +snippet until "until ... (done)" +until ${2:[[ ${1:condition} ]]}; do + ${0:#statements} +done +endsnippet + +snippet while "while ... (done)" +while ${2:[[ ${1:condition} ]]}; do + ${0:#statements} +done +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/snippets.snippets b/UltiSnips/snippets.snippets new file mode 100644 index 0000000..ee0c8c7 --- /dev/null +++ b/UltiSnips/snippets.snippets @@ -0,0 +1,21 @@ +priority -50 + +# We use a little hack so that the snippet is expanded +# and parsed correctly +snippet snip "Snippet definition" b +`!p snip.rv = "snippet"` ${1:Tab_trigger} "${2:Description}" ${3:b} +$0 +`!p snip.rv = "endsnippet"` +endsnippet + +snippet global "Global snippet" b +`!p snip.rv = "global"` !p +$0 +`!p snip.rv = "endglobal"` +endsnippet + +snippet vis "${VISUAL}" i +\$\{VISUAL${1:${2:default}${3:/transform/}}\} +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/tcl.snippets b/UltiSnips/tcl.snippets new file mode 100644 index 0000000..6584915 --- /dev/null +++ b/UltiSnips/tcl.snippets @@ -0,0 +1,52 @@ +priority -50 + +########################################################################### +# TEXTMATE SNIPPETS # +########################################################################### +snippet for "for... (for)" b +for {${1:set i 0}} {${2:\$i < \$n}} {${3:incr i}} { + ${4} +} + +endsnippet + +snippet foreach "foreach... (foreach)" +foreach ${1:var} ${2:\$list} { + ${3} +} + +endsnippet + +snippet if "if... (if)" b +if {${1:condition}} { + ${2} +} + +endsnippet + +snippet proc "proc... (proc)" b +proc ${1:name} {${2:args}} \ +{ + ${3} +} + +endsnippet + +snippet switch "switch... (switch)" b +switch ${1:-exact} -- ${2:\$var} { + ${3:match} { + ${4} + } + default {${5}} +} + +endsnippet + +snippet while "while... (while)" b +while {${1:condition}} { + ${2} +} + +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/tex.snippets b/UltiSnips/tex.snippets new file mode 100644 index 0000000..c32d21f --- /dev/null +++ b/UltiSnips/tex.snippets @@ -0,0 +1,110 @@ +priority -50 + +extends texmath + +snippet "b(egin)?" "begin{} / end{}" br +\begin{${1:something}} + ${0:${VISUAL}} +\end{$1} +endsnippet + +snippet tab +\begin{${1:t}${1/(t)$|(a)$|(.*)/(?1:abular)(?2:rray)/}}{${2:c}} +$0${2/((?<=.)c|l|r)|./(?1: & )/g} +\end{$1${1/(t)$|(a)$|(.*)/(?1:abular)(?2:rray)/}} +endsnippet + +snippet fig "Figure environment" b +\begin{figure}${2:[htpb]} + \centering + \includegraphics[width=${3:0.8}\linewidth]{${4:name.ext}} + \caption{${4/(\w+)\.\w+/\u$1/}$0} + \label{fig:${4/(\w+)\.\w+/$1/}} +\end{figure} +endsnippet + +snippet enum "Enumerate" b +\begin{enumerate} + \item $0 +\end{enumerate} +endsnippet + +snippet item "Itemize" b +\begin{itemize} + \item $0 +\end{itemize} +endsnippet + +snippet desc "Description" b +\begin{description} + \item[$1] $0 +\end{description} +endsnippet + +snippet it "Individual item" b +\item ${1} +$0 +endsnippet + +snippet part "Part" b +\part{${1:part name}} +\label{prt:${2:${1/(\w+)|\W+/(?1:\L$0\E:_)/ga}}} + +${0} +endsnippet + +snippet cha "Chapter" b +\chapter{${1:chapter name}} +\label{cha:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} + +${0} +endsnippet + +snippet sec "Section" b +\section{${1:section name}} +\label{sec:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} + +${0} +endsnippet + +snippet sub "Subsection" b +\subsection{${1:subsection name}} +\label{sub:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} + +${0} +endsnippet + +snippet ssub "Subsubsection" b +\subsubsection{${1:subsubsection name}} +\label{ssub:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} + +${0} +endsnippet + +snippet par "Paragraph" b +\paragraph{${1:paragraph name}} +\label{par:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} + +${0} +endsnippet + +snippet subp "Subparagraph" b +\subparagraph{${1:subparagraph name}} +\label{par:${2:${1/\\\w+\{(.*?)\}|\\(.)|(\w+)|([^\w\\]+)/(?4:_:\L$1$2$3\E)/ga}}} + +${0} +endsnippet + +snippet ni "Non-indented paragraph" b +\noindent +${0} +endsnippet + +snippet pac "Package" b +\usepackage[${1:options}]{${2:package}}$0 +endsnippet + +snippet lp "Long parenthesis" +\left(${1:${VISUAL:contents}}\right)$0 +endsnippet +# vim:ft=snippets: diff --git a/UltiSnips/texmath.snippets b/UltiSnips/texmath.snippets new file mode 100644 index 0000000..d0a25e9 --- /dev/null +++ b/UltiSnips/texmath.snippets @@ -0,0 +1,56 @@ +priority -50 + +############## +# MATH STUFF # +############## +snippet eq "Equation" b +\begin{equation} + $0 +\end{equation} +endsnippet + +snippet eqnn "Equation without number" b +\begin{equation*} + $0 +\end{equation*} +endsnippet + +snippet eqa "Equation array" b +\begin{eqnarray} + $1 & $2 & $0 +\end{eqnarray} +endsnippet + +snippet eqann "Equation array without numbers" b +\begin{eqnarray*} + $1 & $2 & $0 +\end{eqnarray*} + +endsnippet +snippet frac "Fraction" w +\frac{${1:${VISUAL:nom}}}{${2:denom}} +endsnippet + +snippet mat "Smart Matrix" +\begin{${1:p/b/v/V/B/small}matrix} + $0 +\end{$1matrix} +endsnippet + +snippet lr( "left( right)" w +\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 + +snippet lr[ "left[ right]" w +\left[ ${1:${VISUAL}} \right] +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/vim.snippets b/UltiSnips/vim.snippets new file mode 100644 index 0000000..5ff22d2 --- /dev/null +++ b/UltiSnips/vim.snippets @@ -0,0 +1,60 @@ +priority -50 + +########################################################################### +# SnipMate Snippets # +########################################################################### +snippet header +" File: ${1:`!v expand('%:t')`} +" Author: ${2:`!v g:snips_author`} +" Description: ${3} +${4:" Last Modified: `!v strftime("%B %d, %Y")`} + +$0 +endsnippet + +snippet gvar "Global / configuration variable" +if !exists("g:${1:MyUltraImportantVar}") + let g:$1 = ${2:"${3:}"} +endif +endsnippet + +snippet guard +if exists('${1:did_`!p snip.rv = snip.fn.replace('.','_')`}') || &cp${2: || version < 700} + finish +endif +let $1 = 1${3} +endsnippet + +snippet f +fun ${1:function_name}(${2}) + ${3:" code} +endf +endsnippet + +snippet for +for ${1:needle} in ${2:haystack} + ${3:" code} +endfor +endsnippet + +snippet wh +while ${1:condition} + ${2:" code} +endw +endsnippet + +snippet if +if ${1:condition} + ${2:" code} +endif +endsnippet + +snippet ife +if ${1:condition} + ${2} +else + ${3} +endif +endsnippet + +# vim:ft=snippets: diff --git a/UltiSnips/xhtml.snippets b/UltiSnips/xhtml.snippets new file mode 100644 index 0000000..a9c5a29 --- /dev/null +++ b/UltiSnips/xhtml.snippets @@ -0,0 +1,3 @@ +priority -50 + +extends html diff --git a/UltiSnips/xml.snippets b/UltiSnips/xml.snippets new file mode 100644 index 0000000..92dfb6e --- /dev/null +++ b/UltiSnips/xml.snippets @@ -0,0 +1,16 @@ +priority -50 + +snippet xml "XML declaration" b + + +endsnippet + +snippet t "Simple tag" b +<${1:tag}> + ${2:content} + +endsnippet + +snippet ti "Inline tag" b +<${1:tag}>${2:content} +endsnippet diff --git a/UltiSnips/zsh.snippets b/UltiSnips/zsh.snippets new file mode 100644 index 0000000..f7986ea --- /dev/null +++ b/UltiSnips/zsh.snippets @@ -0,0 +1,17 @@ +priority -50 + +extends sh + +priority -49 + +snippet #! "shebang" b +#!/bin/zsh + +endsnippet + +snippet !env "#!/usr/bin/env (!env)" b +#!/usr/bin/env zsh + +endsnippet + +# vim:ft=snippets: diff --git a/after/plugin/UltiSnips_after.vim b/after/plugin/UltiSnips_after.vim new file mode 100644 index 0000000..ca885a6 --- /dev/null +++ b/after/plugin/UltiSnips_after.vim @@ -0,0 +1,13 @@ +" File: UltiSnips_after.vim +" Author: Holger Rapp +" Description: Called after everything else to reclaim keys (Needed for +" Supertab) +" Last Modified: July 27, 2009 + +if exists('did_UltiSnips_after') || &cp || version < 700 + finish +endif + +call UltiSnips#map_keys#MapKeys() + +let did_UltiSnips_after=1 diff --git a/autoload/UltiSnips.vim b/autoload/UltiSnips.vim new file mode 100644 index 0000000..c09d5c3 --- /dev/null +++ b/autoload/UltiSnips.vim @@ -0,0 +1,188 @@ +" File: UltiSnips.vim +" Author: Holger Rapp +" Description: The Ultimate Snippets solution for Vim + +if exists('did_UltiSnips_autoload') || &cp || version < 700 + finish +endif + +" Define dummy version of function called by autocommand setup in +" ftdetect/UltiSnips.vim. If the function isn't defined (probably due to +" using a copy of vim without python support) it will cause an error anytime a +" new file is opened. +function! UltiSnips#FileTypeChanged() +endfunction + +if !exists("g:UltiSnipsUsePythonVersion") + let g:_uspy=":py3 " + if !has("python3") + if !has("python") + if !exists("g:UltiSnipsNoPythonWarning") + echo "UltiSnips requires py >= 2.6 or any py3" + endif + 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 + + +" FUNCTIONS {{{ +function! s:compensate_for_pum() + """ 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() + exec g:_uspy "UltiSnips_Manager._cursor_moved()" + endif +endfunction + +function! UltiSnips#Edit(...) + if a:0 == 1 && a:1 != '' + let type = a:1 + else + 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') + if g:UltiSnipsEditSplit == 'vertical' + let mode = 'vs' + elseif g:UltiSnipsEditSplit == 'horizontal' + let mode = 'sp' + endif + endif + exe ':'.mode.' '.file +endfunction + +function! UltiSnips#AddFiletypes(filetypes) + exec g:_uspy "UltiSnips_Manager.add_buffer_filetypes('" . a:filetypes . ".all')" + return "" +endfunction + +function! UltiSnips#FileTypeComplete(arglead, cmdline, cursorpos) + let ret = {} + let items = map( + \ split(globpath(&runtimepath, 'syntax/*.vim'), '\n'), + \ 'fnamemodify(v:val, ":t:r")' + \ ) + call insert(items, 'all') + for item in items + if !has_key(ret, item) && item =~ '^'.a:arglead + let ret[item] = 1 + endif + endfor + + return sort(keys(ret)) +endfunction + +function! UltiSnips#ExpandSnippet() + exec g:_uspy "UltiSnips_Manager.expand()" + return "" +endfunction + +function! UltiSnips#ExpandSnippetOrJump() + call s:compensate_for_pum() + exec g:_uspy "UltiSnips_Manager.expand_or_jump()" + return "" +endfunction + +function! UltiSnips#ListSnippets() + exec g:_uspy "UltiSnips_Manager.list_snippets()" + return "" +endfunction + +function! UltiSnips#SnippetsInCurrentScope() + let g:current_ulti_dict = {} + exec g:_uspy "UltiSnips_Manager.snippets_in_current_scope()" + return g:current_ulti_dict +endfunction + +function! UltiSnips#SaveLastVisualSelection() + exec g:_uspy "UltiSnips_Manager._save_last_visual_selection()" + return "" +endfunction + +function! UltiSnips#JumpBackwards() + call s:compensate_for_pum() + exec g:_uspy "UltiSnips_Manager.jump_backwards()" + return "" +endfunction + +function! UltiSnips#JumpForwards() + call s:compensate_for_pum() + 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, description, options, ...) + " Takes the same arguments as SnippetManager.add_snippet. + echoerr "Deprecated UltiSnips#AddSnippet called. Please use UltiSnips#AddSnippetWithPriority." | sleep 1 + 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 "description = vim.eval(\"a:description\")" + exec g:_uspy "options = vim.eval(\"a:options\")" + exec g:_uspy "UltiSnips_Manager.add_snippet(trigger, value, description, options, *args)" + return "" +endfunction + +function! UltiSnips#AddSnippetWithPriority(trigger, value, description, options, filetype, priority) + exec g:_uspy "trigger = vim.eval(\"a:trigger\")" + exec g:_uspy "value = vim.eval(\"a:value\")" + exec g:_uspy "description = vim.eval(\"a:description\")" + exec g:_uspy "options = vim.eval(\"a:options\")" + exec g:_uspy "filetype = vim.eval(\"a:filetype\")" + exec g:_uspy "priority = vim.eval(\"a:priority\")" + exec g:_uspy "UltiSnips_Manager.add_snippet(trigger, value, description, options, filetype, priority)" + return "" +endfunction + +function! UltiSnips#Anon(value, ...) + " Takes the same arguments as SnippetManager.expand_anon: + " (value, trigger="", description="", options="") + 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#CursorMoved() + exec g:_uspy "UltiSnips_Manager._cursor_moved()" +endf + +function! UltiSnips#LeavingBuffer() + exec g:_uspy "UltiSnips_Manager._leaving_buffer()" +endf + +function! UltiSnips#LeavingInsertMode() + exec g:_uspy "UltiSnips_Manager._leaving_insert_mode()" +endfunction +" }}} + +" Expand our path +exec g:_uspy "import vim, os, sys" +exec g:_uspy "new_path = os.path.abspath(os.path.join( + \ vim.eval('expand(\":h\")'), '..', 'pythonx'))" +exec g:_uspy "vim.command(\"let g:UltiSnipsPythonPath = '%s'\" % new_path)" +exec g:_uspy "if not hasattr(vim, 'VIM_SPECIAL_PATH'): sys.path.append(new_path)" +exec g:_uspy "from UltiSnips import UltiSnips_Manager" + +let did_UltiSnips_autoload=1 diff --git a/autoload/UltiSnips/map_keys.vim b/autoload/UltiSnips/map_keys.vim new file mode 100644 index 0000000..aa0bce9 --- /dev/null +++ b/autoload/UltiSnips/map_keys.vim @@ -0,0 +1,38 @@ +call UltiSnips#variables#WasRun() + +function! UltiSnips#map_keys#MapKeys() + " Map the keys correctly + if g:UltiSnipsExpandTrigger == g:UltiSnipsJumpForwardTrigger + + exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips#ExpandSnippetOrJump()" + exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips#ExpandSnippetOrJump()" + else + exec "inoremap " . g:UltiSnipsExpandTrigger . " =UltiSnips#ExpandSnippet()" + exec "snoremap " . g:UltiSnipsExpandTrigger . " :call UltiSnips#ExpandSnippet()" + endif + exec 'xnoremap ' . g:UltiSnipsExpandTrigger. ' :call UltiSnips#SaveLastVisualSelection()gvs' + exec "inoremap " . g:UltiSnipsListSnippets . " =UltiSnips#ListSnippets()" + exec "snoremap " . g:UltiSnipsListSnippets . " :call UltiSnips#ListSnippets()" + + snoremap c + snoremap c + snoremap c +endf + +function! UltiSnips#map_keys#MapInnerKeys() + if g:UltiSnipsExpandTrigger != g:UltiSnipsJumpForwardTrigger + exec "inoremap " . g:UltiSnipsJumpForwardTrigger . " =UltiSnips#JumpForwards()" + exec "snoremap " . g:UltiSnipsJumpForwardTrigger . " :call UltiSnips#JumpForwards()" + endif + exec "inoremap " . g:UltiSnipsJumpBackwardTrigger . " =UltiSnips#JumpBackwards()" + exec "snoremap " . g:UltiSnipsJumpBackwardTrigger . " :call UltiSnips#JumpBackwards()" +endf + +function! UltiSnips#map_keys#RestoreInnerKeys() + if g:UltiSnipsExpandTrigger != g:UltiSnipsJumpForwardTrigger + exec "iunmap " . g:UltiSnipsJumpForwardTrigger + exec "sunmap " . g:UltiSnipsJumpForwardTrigger + endif + exec "iunmap " . g:UltiSnipsJumpBackwardTrigger + exec "sunmap " . g:UltiSnipsJumpBackwardTrigger +endf diff --git a/autoload/UltiSnips/variables.vim b/autoload/UltiSnips/variables.vim new file mode 100644 index 0000000..d5555c9 --- /dev/null +++ b/autoload/UltiSnips/variables.vim @@ -0,0 +1,48 @@ +" Kludge to make sure that this file is really run. +function! UltiSnips#variables#WasRun() +endfunction + +" The trigger used to expand a snippet. +" NOTE: expansion and forward jumping can, but needn't be the same trigger +if !exists("g:UltiSnipsExpandTrigger") + let g:UltiSnipsExpandTrigger = "" +endif + +" The trigger used to display all triggers that could possible +" match in the current position. +if !exists("g:UltiSnipsListSnippets") + let g:UltiSnipsListSnippets = "" +endif + +" The trigger used to jump forward to the next placeholder. +" NOTE: expansion and forward jumping can, but needn't be the same trigger +if !exists("g:UltiSnipsJumpForwardTrigger") + let g:UltiSnipsJumpForwardTrigger = "" +endif + +" The trigger to jump backward inside a snippet +if !exists("g:UltiSnipsJumpBackwardTrigger") + let g:UltiSnipsJumpBackwardTrigger = "" +endif + +" Should UltiSnips unmap select mode mappings automagically? +if !exists("g:UltiSnipsRemoveSelectModeMappings") + let g:UltiSnipsRemoveSelectModeMappings = 1 +end + +" If UltiSnips should remove Mappings, which should be ignored +if !exists("g:UltiSnipsMappingsToIgnore") + let g:UltiSnipsMappingsToIgnore = [] +endif + +" UltiSnipsEdit will use this variable to decide if a new window +" is opened when editing. default is "normal", allowed are also +" "vertical", "horizontal" +if !exists("g:UltiSnipsEditSplit") + let g:UltiSnipsEditSplit = 'normal' +endif + +" A list of directory names that are searched for snippets. +if !exists("g:UltiSnipsSnippetDirectories") + let g:UltiSnipsSnippetDirectories = [ "UltiSnips" ] +endif diff --git a/doc/UltiSnips.txt b/doc/UltiSnips.txt new file mode 100644 index 0000000..b29d79c --- /dev/null +++ b/doc/UltiSnips.txt @@ -0,0 +1,1417 @@ +*UltiSnips.txt* For Vim version 7.0 or later. + + The Ultimate Plugin for Snippets in Vim~ + +UltiSnips *snippet* *snippets* *UltiSnips* + +1. Description |UltiSnips-description| + 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| + 3.2.1 Using your own trigger functions |UltiSnips-trigger-functions| + 3.2.2 Path to Python Module |UltiSnips-python-module-path| + 3.3 Snippet Search Path |UltiSnips-snippet-search-path| + 3.4 Warning About Select Mode Mappings |UltiSnips-warning-smappings| + 3.5 Functions |UltiSnips-functions| + 3.5.1 UltiSnips#AddSnippetWithPriority |UltiSnips#AddSnippetWithPriority| + 3.5.2 UltiSnips#Anon |UltiSnips#Anon| + 3.5.3 UltiSnips#SnippetsInCurrentScope |UltiSnips#SnippetsInCurrentScope| + 3.6 Missing python support |UltiSnips-python-warning| +4. Syntax |UltiSnips-syntax| + 4.1 Adding Snippets |UltiSnips-adding-snippets| + 4.1.1 Character Escaping |UltiSnips-character-escaping| + 4.2 Plaintext Snippets |UltiSnips-plaintext-snippets| + 4.3 Visual Placeholder |UltiSnips-visual-placeholder| + 4.4 Interpolation |UltiSnips-interpolation| + 4.4.1 Shellcode |UltiSnips-shellcode| + 4.4.2 VimScript |UltiSnips-vimscript| + 4.4.3 Python |UltiSnips-python| + 4.4.4 Global Snippets |UltiSnips-globals| + 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. Support for other plugins |UltiSnips-other-plugins| +6. Helping Out |UltiSnips-helping| +7. Contact |UltiSnips-contact| +8. Contributors |UltiSnips-contributors| + 8.1 Patches & Coding |UltiSnips-contricoding| + 8.2 Snippets |UltiSnips-contrisnippets| + +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} + + +============================================================================== +1. Description *UltiSnips-description* + +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 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. + +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/ + + +1.1 Requirements *UltiSnips-requirements* +---------------- + +This plugin works with Vim version 7.0 or later. It only works if the +'compatible' setting is not set. + +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") +The python version Vim is linked against can be found with: > + :py import sys; print(sys.version) + +Test if Vim is compiled with python version 3.x: > + :echo has("python3") +The python version Vim is linked against can be found with: > + :py3 import sys; print(sys.version) + +Note that Vim is maybe not using your system-wide installed python version, so +make sure to check the Python version inside of Vim. + +UltiSnips attempts to auto-detect 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* + +The recommended way of getting ultisnips is to track SirVer/ultisnips on +github. The master branch is always stable. + +Using Pathogen: *UltiSnips-using-pathogen* + +If you are a pathogen user, you can track the official mirror of UltiSnips on +github: > + + $ cd ~/.vim/ + $ git submodule add git://github.com/SirVer/ultisnips.git bundle/ultisnips + +See the pathogen documentation for more details on how to update a bundle. + + +Using a downloaded packet: *UltiSnips-using-a-downloaded-packet* + +Download the packet and unpack into a directory of your choice. Then add this +directory to your Vim runtime path by adding this line to your vimrc file. > + set runtimepath+=~/.vim/ultisnips_rep + +UltiSnips also needs that Vim sources files from the ftdetect/ directory. +Unfortunately, Vim only allows this directory in the .vim directory. You +therefore have to symlink/copy the files: > + mkdir -p ~/.vim/ftdetect/ + ln -s ~/.vim/ultisnips_rep/ftdetect/* ~/.vim/ftdetect/ + +Restart Vim and UltiSnips should work. To access the help, use > + :helptags ~/.vim/ultisnips_rep/doc + :help UltiSnips + +============================================================================= +3. Settings & Commands *UltiSnips-settings* + +3.1 Commands *UltiSnips-commands* +------------ + *:UltiSnipsEdit* +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 opened. 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 snippets when using +UltiSnipsEdit and because rails snippets 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 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 + +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="" + +UltiSnips will only map the jump triggers while a snippet is active to +interfer as little as possible with other mappings. + +The default value for g:UltiSnipsJumpBackwardTrigger interferes with the +built-in complete function: |i_CTRL-X_CTRL-K|. A workaround is to add the +following to your vimrc file or switching to a plugin like Supertab or +YouCompleteMe. > + inoremap + +3.2.1 Using your own trigger functions *UltiSnips-trigger-functions* +-------------------------------------- + +For advanced users there are four functions that you can map directly to a +key and that correspond to some of the triggers previously defined: + g:UltiSnipsExpandTrigger <--> UltiSnips#ExpandSnippet + g:UltiSnipsJumpForwardTrigger <--> UltiSnips#JumpForwards + g:UltiSnipsJumpBackwardTrigger <--> UltiSnips#JumpBackwards + +If you have g:UltiSnipsExpandTrigger and g:UltiSnipsJumpForwardTrigger set +to the same value then the function you are actually going to use is +UltiSnips#ExpandSnippetOrJump. + +Each time any of the functions UltiSnips#ExpandSnippet, +UltiSnips#ExpandSnippet, UltiSnips#JumpBackwards or UltiSnips#JumpBackwards is +called a global variable is set that contains the return value of the +corresponding function. + +The corresponding variables and functions are: +UltiSnips#ExpandSnippet --> g:ulti_expand_res (0: fail, 1: success) +UltiSnips#ExpandSnippetOrJump --> g:ulti_expand_or_jump_res (0: fail, + 1: expand, 2: jump) +UltiSnips#JumpForwards --> g:ulti_jump_forwards_res (0: fail, 1: success) +UltiSnips#JumpBackwards --> g:ulti_jump_backwards_res (0: fail, 1: success) + +To see how these return values may come in handy, suppose that you want to map +a key to expand or jump, but if none of these actions is successful you want +to call another function. UltiSnips already does this automatically for +supertab, but this allows you individual fine tuning of your Tab key usage. + +Usage is as follows: You define a function > + + let g:ulti_expand_or_jump_res = 0 "default value, just set once + function! Ulti_ExpandOrJump_and_getRes() + call UltiSnips#ExpandSnippetOrJump() + return g:ulti_expand_or_jump_res + endfunction + +then you define your mapping as > + + inoremap =(Ulti_ExpandOrJump_and_getRes() > 0)?"":IMAP_Jumpfunc('', 0) + +and if the you can't expand or jump from the current location then the +alternative function IMAP_Jumpfunc('', 0) is called. + +3.2.2 Path to Python module *UltiSnips-python-module-path* +--------------------------- + +For even more advanced usage, you can directly write python functions using +UltiSnip's python modules. + +Here is a small example funtion that expands a snippet: > + + function! s:Ulti_ExpandSnip() + Python << EOF + import sys, vim + from UltiSnips import UltiSnips_Manager + UltiSnips_Manager.expand() + EOF + return "" + endfunction + +3.3 Snippet Search Path *UltiSnips-snippet-search-path* +----------------------- + +UltiSnips snippet definition files are stored in one or more directories. +There are several variables used to indicate those directories and to define +how UltiSnips loads snippets. + +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"] + +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 to use the snippets that come with UltiSnips, define the +variable accordingly. > + let g:UltiSnipsSnippetDirectories=["mycoolsnippets"] + +You can also redefine the search path on a buffer by buffer basis by setting +the variable b:UltiSnipsSnippetDirectories. This variable takes precedence +over the global variable. + +|UltiSnips-adding-snippets| explains which files are parsed for a given filetype. + + +3.4 Warning About Select Mode Mappings *UltiSnips-warning-smappings* +-------------------------------------- + +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. + +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 behavior is not desired, you can disable it by adding this line to +your vimrc file. > + let g:UltiSnipsRemoveSelectModeMappings = 0 + +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. > + + let g:UltiSnipsRemoveSelectModeMappings = 1 + let g:UltiSnipsMappingsToIgnore = [ "somePlugin", "otherPlugin" ] + + +3.5 Functions *UltiSnips-functions* +------------- + +UltiSnips provides some functions for extending core functionality. + + + 3.5.1 UltiSnips#AddSnippetWithPriority *UltiSnips#AddSnippetWithPriority* + +The first function is UltiSnips#AddSnippetWithPriority(trigger, value, description, +options, filetyp, priority). 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. The +Priority is a number that defines which snippet should be preferred over +others. See the priority keyword in|UltiSnips-add-snippets|. + + + 3.5.2 UltiSnips#Anon *UltiSnips#Anon* + +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#AddSnippetWithPriority| function of the same name. The trigger and +options arguments can change the way the snippet expands. The description is +unused at this point. + +An example use case might be this line from a reStructuredText plugin file: + + inoremap $$ $$=UltiSnips#Anon(':latex:\`$1\`', '$$') + +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. + + 3.5.3 UltiSnips#SnippetsInCurrentScope *UltiSnips#SnippetsInCurrentScope* + +A third function is UltiSnips#SnippetsInCurrentScope which is the equivalent +of snipmate GetSnipsInCurrentScope function. +This function simply returns a vim dictionary with the snippets whose trigger +matches the current word. +This function does not add any new functionality to ultisnips directly but +allows to use third party plugins to integrate the current available snippets. + +An example of such third party plugin is SnippetCompleteSnipMate which uses +the function GetSnipsInCurrentScope to integrate the current available +snippets with user defined abbreviations and provides these and a completion +menu. +This script is located in +http://www.vim.org/scripts/script.php?script_id=4276. +Note: If you check the above website it lists two dependencies: the +SnippetComplete plugin and snipmate. +You do need the SnippetComplete plugin but you obviously don't need snipmate, +you just have to define the function GetSnipsInCurrentScope. Put the following +in your vimrc: + +function! GetSnipsInCurrentScope() + return UltiSnips#SnippetsInCurrentScope() +endfunction + + +As a second example on how to use this function consider the following +function and mapping definition: + +function! ExpandPossibleShorterSnippet() + if len(UltiSnips#SnippetsInCurrentScope()) == 1 "only one candidate... + let curr_key = keys(UltiSnips#SnippetsInCurrentScope())[0] + normal diw + exe "normal a" . curr_key + exe "normal a " + return 1 + endif + return 0 +endfunction +inoremap =(ExpandPossibleShorterSnippet() == 0? '': UltiSnips#ExpandSnippet()) + +If the trigger for your snippet is lorem, you type lor, and you have no other +snippets whose trigger matches lor then hitting will expand to whatever +lorem expands to. + + +3.6 Warning about missing python support *UltiSnips-python-warning* +---------------------------------------- + +When UltiSnips is loaded, it will check that the running Vim was compiled with +python support. If no support is detected, a warning will be displayed and +loading of UltiSnips will be skipped. + +If you would like to suppress this warning message, you may add the following +line to your vimrc file. + + let g:UltiSnipsNoPythonWarning = 1 + +This may be useful if your Vim configuration files are shared across several +systems where some of them may not have Vim compiled with python support. + +============================================================================= +4. Syntax *UltiSnips-syntax* + +This chapter describes how to write your own snippets and snippet definition +syntax. Examples are used to help illustrate. + + +4.1 Adding Snippets *UltiSnips-adding-snippets* +------------------- + +See |UltiSnips-snippet-search-path| for an explanation of where directories +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 fit well in the all.snippets file. + +UltiSnips understands Vim's dotted filetype syntax. For example, if you define +a dotted filetype for the CUDA C++ framework, e.g. ":set ft=cuda.cpp", then +UltiSnips will search for and activate snippets for both the cuda and cpp +filetypes. + +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 'extends' provides a 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 +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. + + +A line beginning with the keyword 'priority' sets the priority for all +snippets defined in the current file after this line. The default priority for +a file is always 0. When a snippet should be expanded, UltiSnips will collect +all snippet definitons from all sources that match the trigger and keep only +the ones with the highest priority. For example, all shipped snippets have a +priority < 0, so that user defined snippets always overwrite shipped 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: > + + snippet tab_trigger [ "description" [ options ] ] + +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 ] ] + +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 ] ] + +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: > + 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 + defined by the 'iskeyword' setting. 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 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. + + s Remove whitespace immediately before the cursor at the end of a line + before jumping to the next tabstop. This is useful if there is a + tabstop with optional text at the end of a line. + +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* +---------------------- + +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. +- Arthur, King of Britain +endsnippet +------------------- SNAP ------------------- + +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}. 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:inside text/should/is/g} +endsnippet +------------------- SNAP ------------------- + +Start with this line of text: > + 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* + +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. + +Here are some examples. This snippet uses a shell command to insert the +current date. + +------------------- SNIP ------------------- +snippet today +Today is the `date +%d.%m.%y`. +endsnippet +------------------- SNAP ------------------- + +today -> +Today is the 15.07.09. + + +This example inserts the current date using perl. + +------------------- SNIP ------------------- +snippet today +Today is `#!/usr/bin/perl +@a = localtime(); print $a[3] . '.' . $a[4] . '.' . ($a[5]+1900);`. +endsnippet +------------------- SNAP ------------------- +today -> +Today is 15.6.2009. + + + 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 +Indent is: `!v indent(".")`. +endsnippet +------------------- SNAP ------------------- + (note the 4 spaces in front): indent -> + (note the 4 spaces in front): Indent is: 4. + + + 4.4.3 Python: *UltiSnips-python* + +Python interpolation is by far 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] 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: > + + snip.mkline(line="", indent=None): + Returns a line ready to be appended to the result. If indent + is None, then mkline prepends spaces and/or tabs appropriate to the + current 'tabstop' and 'expandtab' variables. + + snip.shift(amount=1): + Shifts the default indentation level used by mkline right by the + 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. + + 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 the + variable's value; otherwise, it returns the value of 'default'. + +The 'snip' object provides some properties as well: > + + snip.rv: + '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 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. + + snip.basename: + The current filename with the extension removed. + + snip.ft: + The current filetype. + +For your convenience, the 'snip' object also provides the following +operators: > + + snip >> amount: + Equivalent to snip.shift(amount) + snip << amount: + Equivalent to snip.unshift(amount) + snip += 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. + +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 +${1:Text}`!p snip.rv = (75-2*len(t[1]))*' '+t[1].upper()` +endsnippet +------------------- SNAP ------------------- +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 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 +def upper_right(inp): + return (75 - 2 * len(inp))*' ' + inp.upper() +endglobal + +snippet wow +${1:Text}`!p snip.rv = upper_right(t[1])` +endsnippet +------------------- SNAP ------------------- +wowHello World -> +Hello World HELLO WORLD + +Python global functions can be stored in a python module and then imported. +This makes global functions easily accessible to all snippet files. Since Vim +7.4 you can just drop python files into ~/.vim/pythonx and import them +directly inside your snippets. For example to use +~/.vim/pythonx/my_snippets_helpers.py > + + global !p + from my_snippet_helpers import * + endglobals + + +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 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. + +It is often 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 ------------------- + +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. + +------------------- SNIP ------------------- +snippet a + + $0 + +endsnippet +------------------- SNAP ------------------- + +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. + +agoogle.comGoogle -> + + Google + + +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 -> + + Google + + +ahttp://www.google.comGoogle -> + + Google + + +The default text of tabstops can also contain mirrors, transformations or +interpolation. + + +4.6 Mirrors *UltiSnips-mirrors* +----------- + +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 +\begin{${1:enumerate}} + $0 +\end{$1} +endsnippet +------------------- SNAP ------------------- +envitemize -> +\begin{itemize} + +\end{itemize} + +------------------- SNIP ------------------- +snippet ifndef +#ifndef ${1:SOME_DEFINE} +#define $1 +$0 +#endif /* $1 */ +endsnippet +------------------- SNAP ------------------- +ifndefWIN32 -> +#ifndef WIN32 +#define WIN32 + +#endif /* WIN32 */ + + +4.7 Transformations *UltiSnips-transformations* +------------------- + +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 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 following syntax: > + ${ + 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 + 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. + a - ascii conversion + By default, transformation are made on the raw utf-8 string. With + this option, matching is done on the corresponding ASCII string + instead, for example 'à' will become 'a'. + This option required the python package 'unidecode'. + +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. + +The syntax for the replacement string is unique. The next paragraph describes +it in detail. + + + 4.7.1 Replacement String: *UltiSnips-replacement-string* + +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 + \L - Lowercase everything till the next \E + \E - End upper or lowercase started with \L or \U + \n - A newline + \t - A literal tab + +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* + +Transformations are very powerful but often the syntax is convoluted. +Hopefully the demos below help illustrate transformation features. + +Demo: Uppercase one character +------------------- SNIP ------------------- +snippet title "Title transformation" +${1:a text} +${1/\w+\s*/\u$0/} +endsnippet +------------------- SNAP ------------------- +titlebig small -> +big small +Big small + + +Demo: Uppercase one character and global replace +------------------- SNIP ------------------- +snippet title "Titlelize in the Transformation" +${1:a text} +${1/\w+\s*/\u$0/g} +endsnippet +------------------- SNAP ------------------- +titlethis is a title -> +this is a title +This Is A Title + + +Demo: ASCII transformation +------------------- SNIP ------------------- +snippet ascii "Replace non ascii chars" +${1: an accentued text} +${1/.*/$0/a} +endsnippet +------------------- SNAP ------------------- +asciià la pêche aux moules +à la pêche aux moules +a la peche aux moules + + +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:\);)/} +endsnippet +------------------- SNAP ------------------- +printfHello // End of line -> +printf("Hello\n"); // End of line + +But +printfA is: %sA // End of line -> +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. + +------------------- SNIP ------------------- +clearsnippets +------------------- SNAP ------------------- + +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'. + + +------------------- SNIP ------------------- +clearsnippets trigger1 trigger2 +------------------- SNAP ------------------- + +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. Support for other plugins *UltiSnips-other-plugins* + +UltiSnips has built-in support for some common plugins and there are others +that are aware of UltiSnips and use it to improve the user experience. This is +an incomplete list - if you want to have your plugin listed here, just sent me +a pull request. + +YouCompleteMe - comes with out of the box completion support for UltiSnips. It +offers a really nice completion dialogue for snippets. + +Supertab - UltiSnips has built-in support for Supertab. Just use a recent +enough version of both plugins and will either expand a snippet or defer +to Supertab for expansion. + +neocomplcache - Stanislav Golovanov (JazzCore) has made an integration plugin +to use UltiSnips as engine inside of neocomplcache. You can find his work at +https://github.com/JazzCore/neocomplcache-ultisnips. + + +============================================================================= +6. Helping Out *UltiSnips-helping* + +UltiSnips needs the help of the Vim community to keep improving. Please +consider joining this effort by providing new snippets, new features or bug +reports. + +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 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 (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. + +You can contribute by fixing or reporting bugs in our issue tracker: +https://github.com/sirver/ultisnips/issues + +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. + + +============================================================================= +7. Contact *UltiSnips-contact* + +You can reach me at SirVer -AT- gmx -ADOT- de. + +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 add an issues to our issues +tracker. + +============================================================================= +8. Contributors *UltiSnips-contributors* + +The primary developer of UltiSnips is SirVer (Holger Rapp). The following +individuals have contributed to UltiSnips. + + +8.1 Patches & Coding *UltiSnips-contricoding* +-------------------- + +Contributors listed in chronological order: + + JCEB - Jan Christoph Ebersbach + Michael Henry + Chris Chambers + Ryan Wooden + rupa - Rupa Deadwyler + Timo Schmiade + blueyed - Daniel Hahler + expelledboy - Anthony Jackson + allait - Alexey Bezhan + peacech - Charles Gunawan + guns - Sung Pae + shlomif - Shlomi Fish + pberndt - Phillip Berndt + thanatermesis-elive - Thanatermesis + rico-ambiescent - Rico Sta. Cruz + Cody Frazer + suy - Alejandro Exojo + grota - Giuseppe Rota + iiijjjii - Jim Karsten + fgalassi - Federico Galassi + lucapette + Psycojoker - Laurent Peuch + aschrab - Aaron Schrab + stardiviner - NagatoPain + skeept - Jorge Rodrigues + buztard + stephenmckinney - Steve McKinney + Pedro Algarvio - s0undt3ch + Eric Van Dewoestine - ervandew + Matt Patterson - fidothe + Mike Morearty - mmorearty + Stanislav Golovanov - JazzCore + David Briscoe - DavidBriscoe + Keith Welch - paralogiki + Zhao Cai - zhaocai + John Szakmeister - jszakmeister + Jonas Diemer - diemer + Romain Giot - rgiot + Sergey Alexandrov - taketwo + Brian Mock - saikobee + Gernot Höflechner - LFDM + Marcelo D Montu - mMontu + + +8.2 Snippets *UltiSnips-contrisnippets* +------------ + +Contributors listed in chronological order: + + Alec Thomas + Ryan Wooden + Ches Martin + Gordin (g0rdin) + Jan Mollowitz (phux) + Georgi Valkov (gvalkov) + Miek Gieben (miek) + Aldis Berjoza (graudeejs) + Jorge Rodrigues (skeept) + Martin Grenfell (scrooloose) + Laughedelic + Anthony Wilson (anthonywilson) + Nick Anderson (nickanderson) + Timothy Mellor (mellort) + Chris Lasher (gotgenes) + Chen Houwu (chenhouwu) + Harry Zhxu (harryzhxu) + Pavel Puchkin (neoascetic) + Jacek Wysocki (exu) + Alexander Kondratskiy (KholdStare) + Martin Krauskopf (martin-krauskopf) + Theocrite (theocrite) + Ferdinand Majerech (kiith-sa) + Vivien Didelot + Øystein Walle (osse) + Pedro Algarvio (s0undt3ch) + Steven Humphrey (shumphrey) + Björn Winckler (b4winckler) + David Brown (Nali4Freedom) + Harry Xu (harryxu) + Tom Cammann (takac) + Paolo Cretaro (melko) + Sergey Alexandrov (taketwo) + Jaromír Hradílek (jhradilek) + Vangelis Tsoumenis (kioopi) + Rudi Grinberg (rgrinberg) + javipolo + Matthew Strawbridge (pxc) + Josh Strater (jstrater) + jinzhu + Rene Vergara (ravl1084) + Johan Haals (JHaals) + Danilo Bargen (dbrgn) + Bernhard Vallant (lazerscience) + Von Welch (von) + Nikola Petrov (nikolavp) + Maarten Slagter (slagtermaarten) + +Thank you for your support. + +vim:tw=78:ts=8:ft=help:norl: diff --git a/ftdetect/UltiSnips.vim b/ftdetect/UltiSnips.vim new file mode 100644 index 0000000..9ec5b7b --- /dev/null +++ b/ftdetect/UltiSnips.vim @@ -0,0 +1,5 @@ +" 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/ftdetect/snippets.vim b/ftdetect/snippets.vim new file mode 100644 index 0000000..2a783ce --- /dev/null +++ b/ftdetect/snippets.vim @@ -0,0 +1,4 @@ +" recognize .snippet files +if has("autocmd") + autocmd BufNewFile,BufRead *.snippets setf snippets +endif diff --git a/ftplugin/snippets.vim b/ftplugin/snippets.vim new file mode 100644 index 0000000..134fe01 --- /dev/null +++ b/ftplugin/snippets.vim @@ -0,0 +1,16 @@ +" Set some sane defaults for snippet files + +" Fold by syntax, but open all folds by default +setlocal foldmethod=syntax +setlocal foldlevel=99 + +setlocal commentstring=#%s + +setlocal noexpandtab + +" Define match words for use with matchit plugin +" http://www.vim.org/scripts/script.php?script_id=39 +if exists("loaded_matchit") && !exists("b:match_words") + let b:match_ignorecase = 0 + let b:match_words = '^snippet\>:^endsnippet\>,^global\>:^endglobal\>,\${:}' +endif diff --git a/plugin/UltiSnips.vim b/plugin/UltiSnips.vim new file mode 100644 index 0000000..0f9617f --- /dev/null +++ b/plugin/UltiSnips.vim @@ -0,0 +1,69 @@ +" File: UltiSnips.vim +" Author: Holger Rapp +" Description: The Ultimate Snippets solution for Vim +" +" Testing Info: +" See directions at the top of the test.py script located one +" directory above this file. + +if exists('did_UltiSnips_plugin') || &cp || version < 700 + finish +endif + +" The Commands we define. +command! -nargs=? -complete=customlist,UltiSnips#FileTypeComplete UltiSnipsEdit + \ :call UltiSnips#Edit() + +command! -nargs=1 UltiSnipsAddFiletypes :call UltiSnips#AddFiletypes() + +" Backwards compatible functions. Prefer the ones in autoload/. +function! UltiSnips_FileTypeChanged() + echoerr "Deprecated UltiSnips_FileTypeChanged called. Please use UltiSnips#FileTypeChanged." | sleep 1 + return UltiSnips#FileTypeChanged() +endfunction + +function! UltiSnips_ExpandSnippet() + echoerr "Deprecated UltiSnips_ExpandSnippet called. Please use UltiSnips#ExpandSnippet." | sleep 1 + return UltiSnips#ExpandSnippet() +endfunction + +function! UltiSnips_ExpandSnippetOrJump() + echoerr "Deprecated UltiSnips_ExpandSnippetOrJump called. Please use UltiSnips#ExpandSnippetOrJump." | sleep 1 + return UltiSnips#ExpandSnippetOrJump() +endfunction + +function! UltiSnips_SnippetsInCurrentScope() + echoerr "Deprecated UltiSnips_SnippetsInCurrentScope called. Please use UltiSnips#SnippetsInCurrentScope." | sleep 1 + return UltiSnips#SnippetsInCurrentScope() +endfunction + +function! UltiSnips_JumpBackwards() + echoerr "Deprecated UltiSnips_JumpBackwards called. Please use UltiSnips#JumpBackwards." | sleep 1 + return UltiSnips#JumpBackwards() +endfunction + +function! UltiSnips_JumpForwards() + echoerr "Deprecated UltiSnips_JumpForwards called. Please use UltiSnips#JumpForwards." | sleep 1 + return UltiSnips#JumpForwards() +endfunction + +function! UltiSnips_AddSnippet(...) + echoerr "Deprecated UltiSnips_AddSnippet called. Please use UltiSnips#AddSnippetWithPriority." | sleep 1 + return call(function('UltiSnips#AddSnippet'), a:000) +endfunction + +function! UltiSnips_Anon(...) + echoerr "Deprecated UltiSnips_Anon called. Please use UltiSnips#Anon." | sleep 1 + return call(function('UltiSnips#Anon'), a:000) +endfunction + +au CursorMovedI * call UltiSnips#CursorMoved() +au CursorMoved * call UltiSnips#CursorMoved() +au BufLeave * call UltiSnips#LeavingBuffer() +au InsertLeave * call UltiSnips#LeavingInsertMode() + +call UltiSnips#map_keys#MapKeys() + +let did_UltiSnips_plugin=1 + +" vim: ts=8 sts=4 sw=4 diff --git a/plugin/snipMate_compatibility.vim b/plugin/snipMate_compatibility.vim new file mode 100644 index 0000000..f88c25b --- /dev/null +++ b/plugin/snipMate_compatibility.vim @@ -0,0 +1,28 @@ +" File: snipMate_compatibility.vim +" Author: Phillip Berndt +" Description: Snipmate compatibility helper functions for UltiSnips +" +" Snipmate defines a function named Filename and a variable called +" g:snips_author for use in snippet subtitutions. See +" https://github.com/msanders/snipmate.vim/blob/master/doc/snipMate.txt +" for details. +" + +if exists('did_UltiSnips_snipmate_compatibility') + finish +endif +let did_UltiSnips_snipmate_compatibility = 1 + +" Define g:snips_author; some snipmate snippets use this +if ! exists('g:snips_author') + let g:snips_author = "John Doe" +endif + +" Filename function, taken from snipMate.vim {{{ +fun! Filename(...) + let filename = expand('%:t:r') + if filename == '' | return a:0 == 2 ? a:2 : '' | endif + return !a:0 || a:1 == '' ? filename : substitute(a:1, '$1', filename, 'g') +endf +" }}} + diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..5790281 --- /dev/null +++ b/pylintrc @@ -0,0 +1,268 @@ +[MASTER] + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +init-hook='import sys; sys.path.append("pythonx/")' + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS,compatibility_py3 + +# Pickle collected data for later comparisons. +persistent=no + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable= + attribute-defined-outside-init, + fixme, + redefined-builtin, + too-few-public-methods, + too-many-arguments, + too-many-branches, + too-many-instance-attributes, + too-many-locals, + too-many-public-methods, + too-many-return-statements, + too-many-statements, + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +msg-template="{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}" + + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=_?[a-z_][a-z0-9_]{2,50}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,50}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,50}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{1,50}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{1,50}$ + +# Regular expression which should only match correct attribute names in class +# bodies +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,a,b,x,y,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=(__.*__|wrapper) + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=TODO + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/pythonx/UltiSnips/__init__.py b/pythonx/UltiSnips/__init__.py new file mode 100644 index 0000000..9566f08 --- /dev/null +++ b/pythonx/UltiSnips/__init__.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Entry point for all thinks UltiSnips.""" + +import vim # pylint:disable=import-error + +from UltiSnips.snippet_manager import SnippetManager + +UltiSnips_Manager = SnippetManager( # pylint:disable=invalid-name + vim.eval('g:UltiSnipsExpandTrigger'), + vim.eval('g:UltiSnipsJumpForwardTrigger'), + vim.eval('g:UltiSnipsJumpBackwardTrigger')) diff --git a/pythonx/UltiSnips/_diff.py b/pythonx/UltiSnips/_diff.py new file mode 100644 index 0000000..f2a030b --- /dev/null +++ b/pythonx/UltiSnips/_diff.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Commands to compare text objects and to guess how to transform from one to +another.""" + +from collections import defaultdict +import sys + +from UltiSnips import _vim +from UltiSnips.position import Position + +def is_complete_edit(initial_line, original, wanted, cmds): + """Returns true if 'original' is changed to 'wanted' with the edit commands + in 'cmds'. Initial line is to change the line numbers in 'cmds'.""" + buf = original[:] + 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(wanted) and + all(j == k for j, k in zip(buf, wanted))) + +def guess_edit(initial_line, last_text, current_text, vim_state): + """ + 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. 'initial_text' is the index of where the comparison + starts, 'last_text' is the last text of the snippet, 'current_text' is the + current text of the snippet and 'vim_state' is the cached vim state. + + Returns (True, edit_cmds) when the edit could be guessed, (False, None) + otherwise. + """ + if not len(last_text) and not len(current_text): + return True, () + pos = vim_state.pos + ppos = vim_state.ppos + + # All text deleted? + if (len(last_text) and + (not current_text or + (len(current_text) == 1 and not current_text[0])) + ): + es = [] + if not current_text: + current_text = [''] + for i in last_text: + 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, last_text, current_text, 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, + last_text[sv.line - initial_line][sv.col:ev.col+1])) + if sv != pos and sv.line == pos.line: + es.append(("I", sv.line, sv.col, + current_text[sv.line - initial_line][sv.col:pos.col+1])) + if is_complete_edit(initial_line, last_text, current_text, es): + return True, es + if pos.line == ppos.line: + if len(last_text) == len(current_text): # Movement only in one line + llen = len(last_text[ppos.line - initial_line]) + clen = len(current_text[pos.line - initial_line]) + if ppos < pos and clen > llen: # maybe only chars have been added + es = ( + ("I", ppos.line, ppos.col, + current_text[ppos.line - initial_line] + [ppos.col:pos.col]), + ) + if is_complete_edit(initial_line, last_text, current_text, es): + return True, es + if clen < llen: + if ppos == pos: # 'x' or DEL or dt or something + es = ( + ("D", pos.line, pos.col, + last_text[ppos.line - initial_line] + [ppos.col:ppos.col + (llen - clen)]), + ) + if is_complete_edit(initial_line, last_text, + current_text, es): + return True, es + if pos < ppos: # Backspacing or dT dF? + es = ( + ("D", pos.line, pos.col, + last_text[pos.line - initial_line] + [pos.col:pos.col + llen - clen]), + ) + if is_complete_edit(initial_line, last_text, + current_text, es): + return True, es + elif len(current_text) < len(last_text): + # where some lines deleted? (dd or so) + es = [] + for i in range(len(last_text)-len(current_text)): + es.append(("D", pos.line, 0, + last_text[pos.line - initial_line + i])) + es.append(("D", pos.line, 0, '\n')) + if is_complete_edit(initial_line, last_text, + current_text, 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, last_text, + current_text, 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 happens. 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) # pylint:disable=invalid-name + seen = defaultdict(lambda: sys.maxsize) + + d[0] = [(0, 0, sline, 0, ())] + cost = 0 + deletion_cost = len(a)+len(b) + insertion_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 = (deletion_cost + insertion_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 + (insertion_cost + ncol) // 2 + ): + seen[x, y+1] = cost + (insertion_cost + ncol) // 2 + d[cost + (insertion_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 + insertion_cost + ncol: + seen[x, y+1] = cost + insertion_cost + ncol + d[cost + ncol + insertion_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 + deletion_cost // 2 + ): + seen[x+1, y] = cost + deletion_cost // 2 + d[cost + deletion_cost // 2].append( + (x+1, y, line, col, what[:-1] + ( + ("D", line, col, what[-1][-1] + a[x]),)) + ) + elif seen[x+1, y] > cost + deletion_cost: + seen[x+1, y] = cost + deletion_cost + d[cost + deletion_cost].append((x+1, y, line, col, what + + (("D", line, col, a[x]),)) + ) + cost += 1 diff --git a/pythonx/UltiSnips/_vim.py b/pythonx/UltiSnips/_vim.py new file mode 100644 index 0000000..579de1d --- /dev/null +++ b/pythonx/UltiSnips/_vim.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Wrapper functionality around the functions we need from Vim.""" + +import re + +import vim # pylint:disable=import-error +from vim import error # pylint:disable=import-error,unused-import + +from UltiSnips.compatibility import col2byte, byte2col, \ + as_unicode, as_vimencoding +from UltiSnips.position import Position + +class VimBuffer(object): + """Wrapper around the current Vim buffer.""" + + 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): # pylint:disable=no-self-use + 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): # pylint:disable=no-self-use + vim.current.buffer[i:j] = [as_vimencoding(l) for l in text] + + def __len__(self): + return len(vim.current.buffer) + + @property + def line_till_cursor(self): # pylint:disable=no-self-use + """Returns the text before the cursor.""" + # Note: we want byte position here + _, col = vim.current.window.cursor + line = vim.current.line + before = as_unicode(line[:col]) + return before + + @property + def number(self): # pylint:disable=no-self-use + """The bufnr() of this buffer.""" + return int(eval("bufnr('%')")) + + @property + def cursor(self): # pylint:disable=no-self-use + """ + The current windows cursor. Note that this is 0 based in col and 0 + based in line which is different from Vim's cursor. + """ + line, nbyte = vim.current.window.cursor + col = byte2col(line, nbyte) + return Position(line - 1, col) + + @cursor.setter + def cursor(self, pos): # pylint:disable=no-self-use + """See getter.""" + nbyte = col2byte(pos.line + 1, pos.col) + vim.current.window.cursor = pos.line + 1, nbyte +buf = VimBuffer() # pylint:disable=invalid-name + +def escape(inp): + """Creates a vim-friendly string from a group of + dicts, lists and strings.""" + def conv(obj): + """Convert 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(cmd): + """Wraps vim.command.""" + return as_unicode(vim.command(as_vimencoding(cmd))) + +def eval(text): + """Wraps vim.eval.""" + rv = vim.eval(as_vimencoding(text)) + if not isinstance(rv, (dict, list)): + return as_unicode(rv) + return rv + +def feedkeys(keys, mode='n'): + """Wrapper around vim's feedkeys function. Mainly for convenience.""" + command(as_unicode(r'call feedkeys("%s", "%s")') % (keys, mode)) + +def new_scratch_buffer(text): + """Create a new scratch buffer with the text given""" + vim.command("botright new") + vim.command("set ft=") + vim.command("set buftype=nofile") + + vim.current.buffer[:] = text.splitlines() + + feedkeys(r"\") + +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) + +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 map in maps: + # The first three chars are the modes, that might be listed. + # We are not interested in them here. + trig = map[3:].split()[0] if len(map[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: # pylint:disable=bare-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 + +class _RealLangMapTranslator(object): + """This cares 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 = {} + _SEMICOLONS = re.compile(r"(? 1: + from_char, to_char = [a.replace("\\;", ";") for a in res] + from_chars += from_char + to_chars += to_char + else: + from_chars += char[::2] + to_chars += char[1::2] + self._maps[langmap] = (from_chars, to_chars) + + def translate(self, text): + """Inverse map 'text' through langmap.""" + langmap = eval("&langmap").strip() + if langmap == "": + return text + text = as_unicode(text) + if langmap not in self._maps: + self._create_translation(langmap) + for before, after in zip(*self._maps[langmap]): + text = text.replace(before, after) + return text + +class _DummyLangMapTranslator(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 = _RealLangMapTranslator +if not int(eval('has("langmap")')): + _LangMapTranslator = _DummyLangMapTranslator diff --git a/pythonx/UltiSnips/compatibility.py b/pythonx/UltiSnips/compatibility.py new file mode 100644 index 0000000..7e14123 --- /dev/null +++ b/pythonx/UltiSnips/compatibility.py @@ -0,0 +1,85 @@ +#!/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 # pylint:disable=import-error + +def _vim_dec(string): + """Decode 'string' using &encoding.""" + try: + return string.decode(vim.eval("&encoding")) + except UnicodeDecodeError: + # At least we tried. There might be some problems down the road now + return string + +def _vim_enc(string): + """Encode 'string' using &encoding.""" + try: + return string.encode(vim.eval("&encoding")) + except UnicodeEncodeError: + return string + +if sys.version_info >= (3, 0): + 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(_vim_enc(pre_chars)) + + 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] + raw_bytes = _vim_enc(line)[:nbyte] + return len(_vim_dec(raw_bytes)) + + def as_unicode(string): + """Return 'string' as unicode instance.""" + if isinstance(string, bytes): + return _vim_dec(string) + return str(string) + + def as_vimencoding(string): + """Return 'string' as Vim internal encoding.""" + return string +else: + import warnings + warnings.filterwarnings("ignore", category=DeprecationWarning) + + def col2byte(line, col): + """ + Convert a valid column index into a byte index inside + of vims buffer. + """ + pre_chars = _vim_dec(vim.current.buffer[line-1])[:col] + return len(_vim_enc(pre_chars)) + + 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(_vim_dec(line[:nbyte])) + + def as_unicode(string): + """Return 'string' as unicode instance.""" + if isinstance(string, str): + return _vim_dec(string) + return unicode(string) + + def as_vimencoding(string): + """Return 'string' as unicode instance.""" + return _vim_enc(string) diff --git a/pythonx/UltiSnips/debug.py b/pythonx/UltiSnips/debug.py new file mode 100644 index 0000000..10c34ec --- /dev/null +++ b/pythonx/UltiSnips/debug.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Convenience methods that help with debugging. They should never be used in +production code.""" + +import sys + +from UltiSnips.compatibility import as_unicode + +DUMP_FILENAME = "/tmp/file.txt" if not sys.platform.lower().startswith("win") \ + else "C:/windows/temp/ultisnips.txt" +with open(DUMP_FILENAME, "w"): + pass # clears the file + +def echo_to_hierarchy(text_object): + """Outputs the given 'text_object' and its children hierarchically.""" + # pylint:disable=protected-access + parent = text_object + while parent._parent: + parent = parent._parent + + def _do_print(text_object, indent=""): + """prints recursively.""" + debug(indent + as_unicode(text_object)) + try: + for child in text_object._children: + _do_print(child, indent=indent + " ") + except AttributeError: + pass + _do_print(parent) + +def debug(msg): + """Dumb 'msg' into the debug file.""" + msg = as_unicode(msg) + with open(DUMP_FILENAME, "ab") as dump_file: + dump_file.write((msg + '\n').encode("utf-8")) + +def print_stack(): + """Dump a stack trace into the debug file.""" + import traceback + with open(DUMP_FILENAME, "ab") as dump_file: + traceback.print_stack(file=dump_file) diff --git a/pythonx/UltiSnips/escaping.py b/pythonx/UltiSnips/escaping.py new file mode 100644 index 0000000..7cfbdc8 --- /dev/null +++ b/pythonx/UltiSnips/escaping.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Utilities to deal with text escaping.""" + +def unescape(text): + """Removes '\\' escaping from 'text'.""" + rv = "" + i = 0 + while i < len(text): + if i+1 < len(text) and text[i] == '\\': + rv += text[i+1] + i += 1 + else: + rv += text[i] + i += 1 + return rv + +def fill_in_whitespace(text): + """Returns 'text' with escaped whitespace replaced through whitespaces.""" + text = text.replace(r"\n", "\n") + text = text.replace(r"\t", "\t") + text = text.replace(r"\r", "\r") + text = text.replace(r"\a", "\a") + text = text.replace(r"\b", "\b") + return text diff --git a/pythonx/UltiSnips/indent_util.py b/pythonx/UltiSnips/indent_util.py new file mode 100644 index 0000000..769af7e --- /dev/null +++ b/pythonx/UltiSnips/indent_util.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""See module doc.""" + +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.shiftwidth = int(_vim.eval("&shiftwidth")) + self._expandtab = (_vim.eval("&expandtab") == "1") + self._tabstop = int(_vim.eval("&tabstop")) + + def ntabs_to_proper_indent(self, ntabs): + """Convert 'ntabs' number of tabs to the proper indent prefix.""" + line_ind = ntabs * self.shiftwidth * " " + 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._tabstop) + right = (len(indent) - len(indent.rstrip(" "))) * " " + indent = indent.replace(" ", "") + indent = indent.replace('\t', " " * self._tabstop) + return indent + right + + def spaces_to_indent(self, indent): + """ Converts spaces to proper indentation respecting Vim settings """ + if not self._expandtab: + indent = indent.replace(" " * self._tabstop, '\t') + return indent diff --git a/pythonx/UltiSnips/position.py b/pythonx/UltiSnips/position.py new file mode 100644 index 0000000..d22d04f --- /dev/null +++ b/pythonx/UltiSnips/position.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Represents a Position in a text file: (0 based line index, 0 based column +index) and provides methods for moving them around.""" + +class Position(object): + """See module docstring.""" + + def __init__(self, line, col): + self.line = line + self.col = col + + def move(self, pivot, delta): + """'pivot' is the position of the first changed character, 'delta' is + how text after it moved""" + if self < pivot: + return + if delta.line == 0: + if self.line == pivot.line: + self.col += delta.col + elif delta.line > 0: + if self.line == pivot.line: + self.col += delta.col - pivot.col + self.line += delta.line + else: + self.line += delta.line + if self.line == pivot.line: + self.col += - delta.col + pivot.col + + def delta(self, pos): + """Returns the difference that the cursor must move to come from 'pos' + to us.""" + assert isinstance(pos, Position) + 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 __add__(self, pos): + assert isinstance(pos, Position) + return Position(self.line + pos.line, self.col + pos.col) + + def __sub__(self, pos): + assert isinstance(pos, Position) + 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/pythonx/UltiSnips/providers/__init__.py b/pythonx/UltiSnips/providers/__init__.py new file mode 100644 index 0000000..b6f2ce5 --- /dev/null +++ b/pythonx/UltiSnips/providers/__init__.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Sources of snippet definitions.""" + +# TODO(sirver): these should register themselves with the Manager, so that +# other plugins can extend them more easily. +from UltiSnips.providers.snippet_file import UltiSnipsFileProvider, \ + base_snippet_files_for +from UltiSnips.providers.added_snippets_provider import AddedSnippetsProvider diff --git a/pythonx/UltiSnips/providers/_base.py b/pythonx/UltiSnips/providers/_base.py new file mode 100644 index 0000000..d94efff --- /dev/null +++ b/pythonx/UltiSnips/providers/_base.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Base class for snippet providers.""" + +from collections import defaultdict + +from UltiSnips.providers._snippet_dictionary import SnippetDictionary + +class SnippetProvider(object): + """See module docstring.""" + + def __init__(self): + self._snippets = defaultdict(SnippetDictionary) + + def get_snippets(self, filetypes, before, possible): + """Returns the snippets for all 'filetypes' (in order) and their + parents matching the text 'before'. If 'possible' is true, a partial + match is enough.""" + found_snippets = [] + for ft in filetypes: + found_snippets += self._find_snippets(ft, before, possible) + return found_snippets + + def _find_snippets(self, ft, trigger, potentially=False, seen=None): + """Find snippets matching 'trigger' for 'ft'. If 'potentially' is True, + partial matches are enough.""" + snips = self._snippets.get(ft, None) + if not snips: + return [] + if not seen: + seen = set() + seen.add(ft) + parent_results = [] + # TODO(sirver): extends information is not bound to one + # provider. It should be tracked further up. + for parent_ft in snips.extends: + if parent_ft not in seen: + seen.add(parent_ft) + parent_results += self._find_snippets(parent_ft, trigger, + potentially, seen) + return parent_results + snips.get_matching_snippets( + trigger, potentially) diff --git a/pythonx/UltiSnips/providers/_snippet_dictionary.py b/pythonx/UltiSnips/providers/_snippet_dictionary.py new file mode 100644 index 0000000..a74be8b --- /dev/null +++ b/pythonx/UltiSnips/providers/_snippet_dictionary.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Implements a container for parsed snippets.""" + +import hashlib +import os + +def _hash_file(path): + """Returns a hashdigest of 'path'""" + if not os.path.isfile(path): + return False + return hashlib.sha1(open(path, "rb").read()).hexdigest() + +# TODO(sirver): This class should not hash any files nor keep track of extends. +class SnippetDictionary(object): + """See module docstring.""" + + def __init__(self): + self._added = [] + self._extends = [] + self._files = {} + self._snippets = [] + + def add_snippet(self, snippet, filename): + """Add 'snippet' to this dictionary. If 'filename' is given, also watch + the original file for changes.""" + if filename: + self._snippets.append(snippet) + if filename not in self.files: + self.addfile(filename) + else: + self._added.append(snippet) + + def get_matching_snippets(self, trigger, potentially): + """Returns all snippets matching the given trigger. If 'potentially' is + true, returns all that could_match().""" + all_snippets = self._added + self._snippets + if not potentially: + return [s for s in all_snippets if s.matches(trigger)] + else: + return [s for s in all_snippets if s.could_match(trigger)] + + def clear_snippets(self, triggers=None): + """Remove all snippets that match each trigger in 'triggers'. When + 'triggers' is None, empties this dictionary completely.""" + if triggers is None: + triggers = [] + if triggers: + for trigger in triggers: + for snippet in self.get_matching_snippets(trigger, False): + if snippet in self._snippets: + self._snippets.remove(snippet) + if snippet in self._added: + self._added.remove(snippet) + else: + self._snippets = [] + self._added = [] + + def addfile(self, path): + """Add this file to the files we read triggers from.""" + self.files[path] = _hash_file(path) + + def has_any_file_changed(self): + """Returns True if any of our watched files has changed since we read + it last.""" + for path, hash in self.files.items(): + if not hash or hash != _hash_file(path): + return True + return False + + @property + def files(self): + """All files we have read snippets from.""" + return self._files + + @property + def extends(self): + """The list of filetypes this filetype extends.""" + return self._extends diff --git a/pythonx/UltiSnips/providers/added_snippets_provider.py b/pythonx/UltiSnips/providers/added_snippets_provider.py new file mode 100644 index 0000000..068bd38 --- /dev/null +++ b/pythonx/UltiSnips/providers/added_snippets_provider.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Handles manually added snippets UltiSnips_Manager.add_snippet().""" + +from UltiSnips.providers._base import SnippetProvider + +class AddedSnippetsProvider(SnippetProvider): + """See module docstring.""" + + def add_snippet(self, ft, snippet): + """Adds the given 'snippet' for 'ft'.""" + self._snippets[ft].add_snippet(snippet, None) diff --git a/pythonx/UltiSnips/providers/snippet_file.py b/pythonx/UltiSnips/providers/snippet_file.py new file mode 100644 index 0000000..e65c313 --- /dev/null +++ b/pythonx/UltiSnips/providers/snippet_file.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Code to provide access to UltiSnips files from disk.""" + +import glob +import os + +from UltiSnips.providers._base import SnippetProvider +from UltiSnips.providers.ultisnips_file import parse_snippets_file +from UltiSnips.snippet_definition import SnippetDefinition +import UltiSnips._vim as _vim + +def _plugin_dir(): + """Calculates the plugin directory for UltiSnips.""" + directory = __file__ + for _ in range(10): + directory = os.path.dirname(directory) + if (os.path.isdir(os.path.join(directory, "plugin")) and + os.path.isdir(os.path.join(directory, "doc"))): + return directory + raise Exception("Unable to find the plugin directory.") + +def base_snippet_files_for(ft, default=True): + """Returns a list of snippet files matching the given filetype (ft). + If default is set to false, it doesn't include shipped files. + + Searches through each path in 'runtimepath' in reverse order, + in each of these, it searches each directory name listed in + 'g:UltiSnipsSnippetDirectories' in order, then looks for files in these + directories called 'ft.snippets' or '*_ft.snippets' replacing ft with + the filetype. + """ + if _vim.eval("exists('b:UltiSnipsSnippetDirectories')") == "1": + snippet_dirs = _vim.eval("b:UltiSnipsSnippetDirectories") + else: + snippet_dirs = _vim.eval("g:UltiSnipsSnippetDirectories") + + paths = _vim.eval("&runtimepath").split(',') + base_snippets = os.path.realpath(os.path.join(_plugin_dir(), "UltiSnips")) + ret = [] + 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", os.path.join("%s", "*")] + if not default and pth == base_snippets: + patterns.remove("%s.snippets") + + for pattern in patterns: + for fn in glob.glob(os.path.join(pth, pattern % ft)): + if fn not in ret: + ret.append(fn) + return ret + +class SnippetSyntaxError(RuntimeError): + """Thrown when a syntax error is found in a file.""" + def __init__(self, filename, line_index, msg): + RuntimeError.__init__(self, "%s in %s:%d" % ( + msg, filename, line_index)) + +class UltiSnipsFileProvider(SnippetProvider): + """Manages all snippets definitions found in rtp.""" + + def get_snippets(self, filetypes, before, possible): + for ft in filetypes: + self._ensure_loaded(ft) + + return SnippetProvider.get_snippets(self, filetypes, before, possible) + + def _ensure_loaded(self, ft, already_loaded=None): + """Make sure that the snippets for 'ft' and everything it extends are + loaded.""" + if not already_loaded: + already_loaded = set() + + if ft in already_loaded: + return + already_loaded.add(ft) + + if self._needs_update(ft): + self._load_snippets_for(ft) + + for parent in self._snippets[ft].extends: + self._ensure_loaded(parent, already_loaded) + + def _needs_update(self, ft): + """Returns true if any files for 'ft' have changed and must be + reloaded.""" + if ft not in self._snippets: + return True + elif self._snippets[ft].has_any_file_changed(): + return True + else: + cur_snips = set(base_snippet_files_for(ft)) + old_snips = set(self._snippets[ft].files) + if cur_snips - old_snips: + return True + return False + + def _load_snippets_for(self, ft): + """Load all snippets for the given 'ft'.""" + if ft in self._snippets: + del self._snippets[ft] + for fn in base_snippet_files_for(ft): + self._parse_snippets(ft, fn) + # Now load for the parents + for parent_ft in self._snippets[ft].extends: + if parent_ft not in self._snippets: + self._load_snippets_for(parent_ft) + + def _parse_snippets(self, ft, filename): + """Parse the file 'filename' for the given 'ft' and watch it for + changes in the future. 'file_data' can be injected in tests.""" + current_snippet_priority = 0 + self._snippets[ft].addfile(filename) + file_data = open(filename, "r").read() + for event, data in parse_snippets_file(file_data): + if event == "error": + msg, line_index = data + filename = _vim.eval("""fnamemodify(%s, ":~:.")""" % + _vim.escape(filename)) + raise SnippetSyntaxError(filename, line_index, msg) + elif event == "clearsnippets": + # TODO(sirver): clear snippets should clear for + # more providers, not only ultisnips files. + triggers, = data + self._snippets[ft].clear_snippets(triggers) + elif event == "extends": + # TODO(sirver): extends information is more global + # than one snippet provider. + filetypes, = data + self._add_extending_info(ft, filetypes) + elif event == "snippet": + trigger, value, description, options, global_pythons = data + self._snippets[ft].add_snippet( + SnippetDefinition(current_snippet_priority, trigger, value, + description, options, global_pythons), filename + ) + elif event == "priority": + priority, = data + current_snippet_priority = priority + else: + assert False, "Unhandled %s: %r" % (event, data) + + def _add_extending_info(self, ft, parents): + """Add the list of 'parents' as being extended by the 'ft'.""" + sd = self._snippets[ft] + for parent in parents: + if parent in sd.extends: + continue + sd.extends.append(parent) diff --git a/pythonx/UltiSnips/providers/ultisnips_file.py b/pythonx/UltiSnips/providers/ultisnips_file.py new file mode 100644 index 0000000..c8a4b48 --- /dev/null +++ b/pythonx/UltiSnips/providers/ultisnips_file.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Parsing of snippet files.""" + +from collections import defaultdict + +class _LineIterator(object): + """Convenience class that keeps track of line numbers.""" + + def __init__(self, text): + self._line_index = None + self._lines = enumerate(text.splitlines(True), 1) + + def __iter__(self): + return self + + def __next__(self): + """Returns the next line.""" + self._line_index, line = next(self._lines) + return line + next = __next__ # for python2 + + @property + def line_index(self): + """The 1 based line index in the current file.""" + return self._line_index + +def _handle_snippet_or_global(line, lines, globals): + """Parses the snippet that begins at the current line.""" + + descr = "" + opts = "" + + # Ensure this is a snippet + snip = line.split()[0] + + # Get and strip options if they exist + remain = line[len(snip):].strip() + words = remain.split() + if len(words) > 2: + # second to last word ends with a quote + if '"' not in words[-1] and words[-2][-1] == '"': + opts = words[-1] + remain = remain[:-len(opts) - 1].rstrip() + + # Get and strip description if it exists + remain = remain.strip() + if len(remain.split()) > 1 and remain[-1] == '"': + left = remain[:-1].rfind('"') + if left != -1 and left != 0: + descr, remain = remain[left:], remain[:left] + + # The rest is the trigger + trig = remain.strip() + if len(trig.split()) > 1 or "r" in opts: + if trig[0] != trig[-1]: + return "error", ("Invalid multiword trigger: '%s'" % trig, + lines.line_index) + trig = trig[1:-1] + end = "end" + snip + content = "" + + found_end = False + for line in lines: + if line.rstrip() == end: + content = content[:-1] # Chomp the last newline + found_end = True + break + content += line + + if not found_end: + return "error", ("Missing 'endsnippet' for %r" % trig, lines.line_index) + + if snip == "global": + globals[trig].append(content) + elif snip == "snippet": + return "snippet", (trig, content, descr, opts, globals) + else: + return "error", ("Invalid snippet type: '%s'" % snip, lines.line_index) + +def _head_tail(line): + """Returns the first word in 'line' and the rest of 'line' or None if the + line is too short.""" + generator = (t.strip() for t in line.split(None, 1)) + head = next(generator).strip() + tail = '' + try: + tail = next(generator).strip() + except StopIteration: + pass + return head, tail + + +def parse_snippets_file(data): + """Parse 'data' assuming it is a snippet file. Yields events in the + file.""" + + globals = defaultdict(list) + lines = _LineIterator(data) + for line in lines: + if not line.strip(): + continue + + head, tail = _head_tail(line) + if head == "extends": + if tail: + yield "extends", ([p.strip() for p in tail.split(',')],) + else: + yield "error", ("'extends' without file types", + lines.line_index) + elif head in ("snippet", "global"): + snippet = _handle_snippet_or_global(line, lines, globals) + if snippet is not None: + yield snippet + elif head == "clearsnippets": + yield "clearsnippets", (tail.split(),) + elif head == "priority": + try: + priority = int(tail.split()[0]) + yield "priority", (priority,) + except (ValueError, IndexError): + yield "error", ("Invalid priority %r" % tail, lines.line_index) + elif head and not head.startswith('#'): + yield "error", ("Invalid line %r" % line.rstrip(), lines.line_index) diff --git a/pythonx/UltiSnips/snippet_definition.py b/pythonx/UltiSnips/snippet_definition.py new file mode 100644 index 0000000..a46a759 --- /dev/null +++ b/pythonx/UltiSnips/snippet_definition.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Snippet representation after parsing.""" + +import re + +from UltiSnips.compatibility import as_unicode +from UltiSnips.text_objects import SnippetInstance +from UltiSnips.indent_util import IndentUtil +import UltiSnips._vim as _vim + + +def _words_for_line(trigger, before, num_words=None): + """ Gets the final 'num_words' words from 'before'. + If num_words is None, then use the number of words in + 'trigger'. + """ + if not len(before): + return '' + + if num_words is None: + num_words = len(trigger.split()) + + word_list = before.split() + if len(word_list) <= num_words: + return before.strip() + else: + before_words = before + for i in range(-1, -(num_words + 1), -1): + left = before_words.rfind(word_list[i]) + before_words = before_words[:left] + return before[len(before_words):].strip() + + +class SnippetDefinition(object): + """Represents a snippet as parsed from a file.""" + + _INDENT = re.compile(r"^[ \t]*") + _TABS = re.compile(r"^\t*") + + def __init__(self, priority, trigger, value, description, options, globals): + self._priority = priority + self._trigger = as_unicode(trigger) + self._value = as_unicode(value) + self._description = as_unicode(description) + self._opts = options + self._matched = "" + self._last_re = None + self._globals = globals + + def __repr__(self): + return "SnippetDefinition(%r,%s,%s,%s)" % ( + self._priority, self._trigger, self._description, self._opts) + + def _re_match(self, trigger): + """ Test if a the current regex trigger matches + `trigger`. If so, set _last_re and _matched. + """ + for match in re.finditer(self._trigger, trigger): + if match.end() != len(trigger): + continue + else: + self._matched = trigger[match.start():match.end()] + + self._last_re = match + return match + return False + + def has_option(self, opt): + """ Check if the named option is set """ + return opt in self._opts + + def matches(self, trigger): + """Returns True if this snippet matches 'trigger'.""" + # If user supplies both "w" and "i", it should perhaps be an + # error, but if permitted it seems that "w" should take precedence + # (since matching at word boundary and within a word == matching at word + # boundary). + self._matched = "" + + # Don't expand on whitespace + if trigger and trigger.rstrip() != trigger: + return False + + words = _words_for_line(self._trigger, trigger) + + if "r" in self._opts: + match = self._re_match(trigger) + elif "w" in self._opts: + words_len = len(self._trigger) + words_prefix = words[:-words_len] + words_suffix = words[-words_len:] + match = (words_suffix == self._trigger) + if match and words_prefix: + # Require a word boundary between prefix and suffix. + boundary_chars = words_prefix[-1:] + words_suffix[:1] + boundary_chars = boundary_chars.replace('"', '\\"') + match = _vim.eval('"%s" =~# "\\\\v.<."' % boundary_chars) != '0' + elif "i" in self._opts: + match = words.endswith(self._trigger) + else: + match = (words == self._trigger) + + # By default, we match the whole trigger + if match and not self._matched: + self._matched = self._trigger + + # Ensure the match was on a word boundry if needed + if "b" in self._opts and match: + text_before = trigger.rstrip()[:-len(self._matched)] + if text_before.strip(" \t") != '': + self._matched = "" + return False + return match + + def could_match(self, trigger): + """Return True if this snippet could match the (partial) 'trigger'.""" + self._matched = "" + + # List all on whitespace. + if trigger and trigger[-1] in (" ", "\t"): + trigger = "" + if trigger and trigger.rstrip() is not trigger: + return False + + words = _words_for_line(self._trigger, trigger) + + if "r" in self._opts: + # Test for full match only + match = self._re_match(trigger) + elif "w" in self._opts: + # Trim non-empty prefix up to word boundary, if present. + qwords = words.replace('"', '\\"') + words_suffix = _vim.eval( + 'substitute("%s", "\\\\v^.+<(.+)", "\\\\1", "")' % qwords) + match = self._trigger.startswith(words_suffix) + self._matched = words_suffix + + # TODO: list_snippets() function cannot handle partial-trigger + # matches yet, so for now fail if we trimmed the prefix. + if words_suffix != words: + match = False + elif "i" in self._opts: + # TODO: It is hard to define when a inword snippet could match, + # therefore we check only for full-word trigger. + match = self._trigger.startswith(words) + else: + match = self._trigger.startswith(words) + + # By default, we match the words from the trigger + if match and not self._matched: + self._matched = words + + # Ensure the match was on a word boundry if needed + if "b" in self._opts and match: + text_before = trigger.rstrip()[:-len(self._matched)] + if text_before.strip(" \t") != '': + self._matched = "" + return False + + return match + + @property + def description(self): + """Descriptive text for this snippet.""" + return ("(%s) %s" % (self._trigger, self._description)).strip() + + @property + def priority(self): + """The snippets priority, which defines which snippet will be preferred + over others with the same trigger.""" + return self._priority + + @property + def trigger(self): + """The trigger text for the snippet.""" + return self._trigger + + @property + def matched(self): + """The last text that matched this snippet in match() or + could_match().""" + return self._matched + + def launch(self, text_before, visual_content, parent, start, end): + """Launch this snippet, overwriting the text 'start' to 'end' and + keeping the 'text_before' on the launch line. 'Parent' is the parent + snippet instance if any.""" + indent = self._INDENT.match(text_before).group(0) + lines = (self._value + "\n").splitlines() + ind_util = IndentUtil() + + # Replace leading tabs in the snippet definition via proper indenting + snippet_definition = [] + for line_num, line in enumerate(lines): + if "t" in self._opts: + tabs = 0 + else: + tabs = len(self._TABS.match(line).group(0)) + + line_ind = ind_util.ntabs_to_proper_indent(tabs) + + if line_num != 0: + line_ind = indent + line_ind + + snippet_definition.append(line_ind + line[tabs:]) + snippet_definition = '\n'.join(snippet_definition) + + si = SnippetInstance(self, parent, indent, snippet_definition, start, + end, visual_content, last_re=self._last_re, + globals=self._globals) + + return si diff --git a/pythonx/UltiSnips/snippet_manager.py b/pythonx/UltiSnips/snippet_manager.py new file mode 100644 index 0000000..c803094 --- /dev/null +++ b/pythonx/UltiSnips/snippet_manager.py @@ -0,0 +1,526 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Contains the SnippetManager facade used by all Vim Functions.""" + +from collections import defaultdict +from functools import wraps +import os +import traceback + +from UltiSnips._diff import diff, guess_edit +from UltiSnips.compatibility import as_unicode +from UltiSnips.position import Position +from UltiSnips.providers import UltiSnipsFileProvider, \ + base_snippet_files_for, AddedSnippetsProvider +from UltiSnips.snippet_definition import SnippetDefinition +from UltiSnips.vim_state import VimState, VisualContentPreserver +import UltiSnips._vim as _vim + +def _ask_snippets(snippets): + """ Given a list of snippets, ask the user which one they + want to use, and return it. + """ + display = [as_unicode("%i: %s") % (i+1, s.description) for + i, s in enumerate(snippets)] + try: + 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: + # Likely "invalid expression", but might be translated. We have no way + # of knowing the exact error, therefore, we ignore all errors silently. + return None + except KeyboardInterrupt: + return None + + +def err_to_scratch_buffer(func): + """Decorator that will catch any Exception that 'func' throws and displays + it in a new Vim scratch buffer.""" + @wraps(func) + def wrapper(self, *args, **kwds): + try: + return func(self, *args, **kwds) + except: # pylint: disable=bare-except + msg = \ +"""An error occured. This is either a bug in UltiSnips or a bug in a +snippet definition. If you think this is a bug, please report it to +https://github.com/SirVer/ultisnips/issues/new. + +Following is the full stack trace: +""" + msg += traceback.format_exc() + # Vim sends no WinLeave msg here. + self._leaving_buffer() # pylint:disable=protected-access + _vim.new_scratch_buffer(msg) + return wrapper + + +# TODO(sirver): This class is still too long. It should only contain public +# facing methods, most of the private methods should be moved outside of it. +class SnippetManager(object): + """The main entry point for all UltiSnips functionality. All Vim functions + call methods in this class.""" + + def __init__(self, expand_trigger, forward_trigger, backward_trigger): + self.expand_trigger = expand_trigger + self.forward_trigger = forward_trigger + self.backward_trigger = backward_trigger + self._supertab_keys = None + self._csnippets = [] + self._reset() + + @err_to_scratch_buffer + def jump_forwards(self): + """Jumps to the next tabstop.""" + _vim.command("let g:ulti_jump_forwards_res = 1") + if not self._jump(): + _vim.command("let g:ulti_jump_forwards_res = 0") + return self._handle_failure(self.forward_trigger) + + @err_to_scratch_buffer + def jump_backwards(self): + """Jumps to the previous tabstop.""" + _vim.command("let g:ulti_jump_backwards_res = 1") + if not self._jump(True): + _vim.command("let g:ulti_jump_backwards_res = 0") + return self._handle_failure(self.backward_trigger) + + @err_to_scratch_buffer + def expand(self): + """Try to expand a snippet at the current position.""" + _vim.command("let g:ulti_expand_res = 1") + if not self._try_expand(): + _vim.command("let g:ulti_expand_res = 0") + self._handle_failure(self.expand_trigger) + + @err_to_scratch_buffer + def expand_or_jump(self): + """ + This function is used for people who wants to have the same trigger for + expansion and forward jumping. It first tries to expand a snippet, if + this fails, it tries to jump forward. + """ + _vim.command('let g:ulti_expand_or_jump_res = 1') + rv = self._try_expand() + if not rv: + _vim.command('let g:ulti_expand_or_jump_res = 2') + rv = self._jump() + if not rv: + _vim.command('let g:ulti_expand_or_jump_res = 0') + self._handle_failure(self.expand_trigger) + + @err_to_scratch_buffer + def snippets_in_current_scope(self): + """Returns the snippets that could be expanded to Vim as a global + variable.""" + before = _vim.buf.line_till_cursor + snippets = self._snips(before, True) + + # Sort snippets alphabetically + snippets.sort(key=lambda x: x.trigger) + for snip in snippets: + description = snip.description[snip.description.find(snip.trigger) + + len(snip.trigger) + 2:] + + key = as_unicode(snip.trigger) + description = as_unicode(description) + + # remove surrounding "" or '' in snippet description if it exists + if len(description) > 2: + if (description[0] == description[-1] and + description[0] in "'\""): + description = description[1:-1] + + _vim.command(as_unicode( + "let g:current_ulti_dict['{key}'] = '{val}'").format( + key=key.replace("'", "''"), + val=description.replace("'", "''"))) + + @err_to_scratch_buffer + def list_snippets(self): + """Shows the snippets that could be expanded to the User and let her + select one.""" + before = _vim.buf.line_till_cursor + snippets = self._snips(before, True) + + if len(snippets) == 0: + self._handle_failure(self.backward_trigger) + return True + + # Sort snippets alphabetically + snippets.sort(key=lambda x: x.trigger) + + if not snippets: + return True + + snippet = _ask_snippets(snippets) + if not snippet: + return True + + self._do_snippet(snippet, before) + + return True + + @err_to_scratch_buffer + def add_snippet(self, trigger, value, description, + options, ft="all", priority=0): + """Add a snippet to the list of known snippets of the given 'ft'.""" + self._added_snippets_provider.add_snippet(ft, SnippetDefinition( + priority, trigger, value, description, options, {}) + ) + + @err_to_scratch_buffer + def expand_anon(self, value, trigger="", description="", options=""): + """Expand an anonymous snippet right here.""" + before = _vim.buf.line_till_cursor + snip = SnippetDefinition(0, trigger, value, description, options, {}) + + if not trigger or snip.matches(before): + self._do_snippet(snip, before) + return True + else: + return False + + def reset_buffer_filetypes(self): + """Reset the filetypes for the current buffer.""" + if _vim.buf.number in self._filetypes: + del self._filetypes[_vim.buf.number] + + 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. """ + buf_fts = self._filetypes[_vim.buf.number] + 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.number].insert(idx + 1, ft) + idx += 1 + + @err_to_scratch_buffer + def _cursor_moved(self): + """Called whenever the cursor moved.""" + self._vstate.remember_position() + if _vim.eval("mode()") not in 'in': + return + + if self._ignore_movements: + self._ignore_movements = False + return + + 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: + # Rather do nothing than throwing an error. It will be correct + # most of the time + pass + + self._check_if_still_inside_snippet() + if self._csnippets: + self._csnippets[0].update_textobjects() + self._vstate.remember_buffer(self._csnippets[0]) + + @err_to_scratch_buffer + def _reset(self): + """Reset the class to the state it had directly after creation.""" + self._vstate = VimState() + self._filetypes = defaultdict(lambda: ['all']) + self._visual_content = VisualContentPreserver() + self._snippet_providers = [ + AddedSnippetsProvider(), + UltiSnipsFileProvider() + ] + self._added_snippets_provider = self._snippet_providers[0] + + while len(self._csnippets): + self._current_snippet_is_done() + + self._reinit() + + @err_to_scratch_buffer + def _save_last_visual_selection(self): + """ + This is called when the expand trigger is pressed in visual mode. + Our job is to remember everything between '< and '> and pass it on to + ${VISUAL} in case it will be needed. + """ + self._visual_content.conserve() + + + def _leaving_buffer(self): + """Called when the user switches tabs/windows/buffers. It basically + means that all snippets must be properly terminated.""" + while len(self._csnippets): + self._current_snippet_is_done() + self._reinit() + + def _reinit(self): + """Resets transient state.""" + self._ctab = None + self._ignore_movements = False + + def _check_if_still_inside_snippet(self): + """Checks if the cursor is outside of the current snippet.""" + 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): + """The current snippet should be terminated.""" + self._csnippets.pop() + if not self._csnippets: + _vim.command("call UltiSnips#map_keys#RestoreInnerKeys()") + + def _jump(self, backwards=False): + """Helper method that does the actual jump.""" + jumped = False + if self._cs: + self._ctab = self._cs.select_next_tab(backwards) + if self._ctab: + if self._cs.snippet.has_option("s"): + lineno = _vim.buf.cursor.line + _vim.buf[lineno] = _vim.buf[lineno].rstrip() + _vim.select(self._ctab.start, self._ctab.end) + jumped = True + if self._ctab.number == 0: + self._current_snippet_is_done() + 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() + self._vstate.remember_unnamed_register(self._ctab.current_text) + self._ignore_movements = True + return jumped + + def _leaving_insert_mode(self): + """Called whenever we leave the insert mode.""" + self._vstate.restore_unnamed_register() + + def _handle_failure(self, trigger): + """Mainly make sure that we play well with SuperTab.""" + if trigger.lower() == "": + feedkey = "\\" + trigger + elif trigger.lower() == "": + feedkey = "\\" + trigger + else: + feedkey = None + mode = "n" + if not self._supertab_keys: + if _vim.eval("exists('g:SuperTabMappingForward')") != "0": + self._supertab_keys = ( + _vim.eval("g:SuperTabMappingForward"), + _vim.eval("g:SuperTabMappingBackward"), + ) + else: + self._supertab_keys = ['', ''] + + for idx, sttrig in enumerate(self._supertab_keys): + if trigger.lower() == sttrig.lower(): + if idx == 0: + feedkey = r"\SuperTabForward" + mode = "n" + elif idx == 1: + feedkey = r"\SuperTabBackward" + mode = "p" + # Use remap mode so SuperTab mappings will be invoked. + break + + if (feedkey == r"\SuperTabForward" or + feedkey == r"\SuperTabBackward"): + _vim.command("return SuperTab(%s)" % _vim.escape(mode)) + elif feedkey: + _vim.command("return %s" % _vim.escape(feedkey)) + + 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._filetypes[_vim.buf.number][::-1] + matching_snippets = defaultdict(list) + for provider in self._snippet_providers: + for snippet in provider.get_snippets(filetypes, before, possible): + matching_snippets[snippet.trigger].append(snippet) + if not matching_snippets: + return [] + + # Now filter duplicates and only keep the one with the highest + # priority. Only keep the snippets with the highest priority. + snippets = [] + for snippets_with_trigger in matching_snippets.values(): + highest_priority = max(s.priority for s in snippets_with_trigger) + snippets.extend(s for s in snippets_with_trigger + if s.priority == highest_priority) + return snippets + + def _do_snippet(self, snippet, before): + """Expands the given snippet, and handles everything + that needs to be done with it.""" + _vim.command("call UltiSnips#map_keys#MapInnerKeys()") + + # Adjust before, maybe the trigger is not the complete word + text_before = before + if snippet.matched: + text_before = before[:-len(snippet.matched)] + + if self._cs: + start = Position(_vim.buf.cursor.line, len(text_before)) + end = Position(_vim.buf.cursor.line, len(before)) + + # It could be that our trigger contains the content of TextObjects + # in our containing snippet. If this is indeed the case, we have to + # make sure that those are properly killed. We do this by + # pretending that the user deleted and retyped the text that our + # trigger matched. + edit_actions = [ + ("D", start.line, start.col, snippet.matched), + ("I", start.line, start.col, snippet.matched), + ] + self._csnippets[0].replay_user_edits(edit_actions) + + si = snippet.launch(text_before, self._visual_content, + self._cs.find_parent_for_new_to(start), start, end) + else: + 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) + + self._visual_content.reset() + self._csnippets.append(si) + + self._ignore_movements = True + self._vstate.remember_buffer(self._csnippets[0]) + + self._jump() + + def _try_expand(self): + """Try to expand a snippet in the current place.""" + before = _vim.buf.line_till_cursor + if not before: + return False + snippets = self._snips(before, False) + if not snippets: + # No snippet found + return False + elif len(snippets) == 1: + snippet = snippets[0] + else: + snippet = _ask_snippets(snippets) + if not snippet: + return True + self._do_snippet(snippet, before) + return True + + @property + def _cs(self): + """The current snippet or None.""" + if not len(self._csnippets): + return None + return self._csnippets[-1] + + + @property + def _primary_filetype(self): + """This filetype will be edited when UltiSnipsEdit is called without + any arguments.""" + return self._filetypes[_vim.buf.number][0] + + # TODO(sirver): this should talk directly to the UltiSnipsFileProvider. + def _file_to_edit(self, ft): # pylint: disable=no-self-use + """ Gets a file to edit based on the given filetype. + 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 + """ + # This method is not using self, but is called by UltiSnips.vim and is + # therefore in this class because it is the facade to Vim. + edit = None + existing = base_snippet_files_for(ft, False) + filename = ft + ".snippets" + + 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 = [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, ".vim", us) + for dirname in [".vim", "vimfiles"]: + pth = os.path.join(home, dirname) + if pth in rtp: + path = os.path.join(pth, us) + + if not os.path.isdir(path): + os.mkdir(path) + + edit = os.path.join(path, filename) + return edit diff --git a/pythonx/UltiSnips/test_diff.py b/pythonx/UltiSnips/test_diff.py new file mode 100644 index 0000000..6e13e73 --- /dev/null +++ b/pythonx/UltiSnips/test_diff.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# encoding: utf-8 + +# pylint: skip-file + +import unittest + +from _diff import diff, guess_edit +from position 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/pythonx/UltiSnips/test_position.py b/pythonx/UltiSnips/test_position.py new file mode 100644 index 0000000..7c209a3 --- /dev/null +++ b/pythonx/UltiSnips/test_position.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# encoding: utf-8 + +# pylint: skip-file + +import unittest + +from position import Position + +class _MPBase(object): + def runTest(self): + obj = Position(*self.obj) + for pivot, delta, wanted in self.steps: + obj.move(Position(*pivot), Position(*delta)) + 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/pythonx/UltiSnips/text_objects/__init__.py b/pythonx/UltiSnips/text_objects/__init__.py new file mode 100644 index 0000000..d9f89ba --- /dev/null +++ b/pythonx/UltiSnips/text_objects/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Public facing classes for TextObjects.""" + +from ._snippet_instance import SnippetInstance diff --git a/pythonx/UltiSnips/text_objects/_base.py b/pythonx/UltiSnips/text_objects/_base.py new file mode 100644 index 0000000..8ddc103 --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_base.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Base classes for all text objects.""" + +import UltiSnips._vim as _vim +from UltiSnips.position import Position + +def _calc_end(text, start): + """Calculate the end position of the 'text' starting at 'start.""" + 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 _text_to_vim(start, end, text): + """Copy the given text to the current buffer, overwriting the span 'start' + to 'end'.""" + lines = text.split('\n') + + new_end = _calc_end(lines, start) + + before = _vim.buf[start.line][:start.col] + after = _vim.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 + _vim.buf[start.line:end.line + 1] = new_lines + + # Open any folds this might have created + _vim.buf.cursor = start + _vim.command("normal! zv") + + return new_end + +# These classes use their subclasses a lot and we really do not want to expose +# their functions more globally. +# pylint: disable=protected-access +class TextObject(object): + """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 + + 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 _move(self, pivot, diff): + """Move this object by 'diff' while 'pivot' is the point of change.""" + self._start.move(pivot, diff) + self._end.move(pivot, diff) + + def __lt__(self, other): + me_tuple = (self.start.line, self.start.col, + self._tiebreaker.line, self._tiebreaker.col) + other_tuple = (other._start.line, other._start.col, + other._tiebreaker.line, other._tiebreaker.col) + return me_tuple < other_tuple + + def __le__(self, other): + me_tuple = (self._start.line, self._start.col, + self._tiebreaker.line, self._tiebreaker.col) + other_tuple = (other._start.line, other._start.col, + other._tiebreaker.line, other._tiebreaker.col) + return me_tuple <= other_tuple + + 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) + + @property + def current_text(self): + """The current text of this object.""" + 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) + + @property + def start(self): + """The start position.""" + return self._start + + @property + def end(self): + """The end position.""" + return self._end + + def overwrite(self, gtext=None): + """Overwrite the text of this object in the Vim Buffer and update its + length information. If 'gtext' is None use the initial text of this + object. + """ + # We explicitly do not want to move our children 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 = _text_to_vim( + self._start, self._end, gtext or self._initial_text) + if self._parent: + self._parent._child_has_moved( + self._parent._children.index(self), min(old_end, self._end), + self._end.delta(old_end) + ) + + def _update(self, done): + """Update this object inside the Vim Buffer. + + Return False if you need to be called again for this edit cycle. + Otherwise return True. + """ + raise NotImplementedError("Must be implemented by subclasses.") + +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._children = [] + self._tabstops = {} + + ############## + # Properties # + ############## + @property + def children(self): + """List of all children.""" + return self._children + + @property + def _editable_children(self): + """List of all children that are EditableTextObjects""" + return [child for child in self._children if + isinstance(child, EditableTextObject)] + + #################### + # Public Functions # + #################### + def find_parent_for_new_to(self, pos): + """Figure out the parent object for something at 'pos'.""" + for children in self._editable_children: + if children._start <= pos < children._end: + return children.find_parent_for_new_to(pos) + return self + + ############################### + # Private/Protected functions # + ############################### + def _do_edit(self, cmd): + """Apply the edit 'cmd' to this object.""" + ctype, line, col, text = cmd + assert ('\n' not in text) or (text == "\n") + pos = Position(line, col) + + to_kill = set() + new_cmds = [] + for child in self._children: + if ctype == "I": # Insertion + if (child._start < pos < + Position(child._end.line, child._end.col) and + isinstance(child, NoneditableTextObject)): + to_kill.add(child) + new_cmds.append(cmd) + break + elif ((child._start <= pos <= child._end) and + isinstance(child, EditableTextObject)): + child._do_edit(cmd) + return + else: # Deletion + delend = pos + Position(0, len(text)) if text != "\n" \ + else Position(line + 1, 0) + if ((child._start <= pos < child._end) and + (child._start < delend <= child._end)): + # this edit command is completely for the child + if isinstance(child, NoneditableTextObject): + to_kill.add(child) + new_cmds.append(cmd) + break + else: + child._do_edit(cmd) + return + elif ((pos < child._start and child._end <= delend) or + (pos <= child._start and child._end < delend)): + # Case: this deletion removes the child + to_kill.add(child) + new_cmds.append(cmd) + break + elif (pos < child._start and + (child._start < delend <= child._end)): + # Case: partially for us, partially for the child + my_text = text[:(child._start-pos).col] + c_text = text[(child._start-pos).col:] + new_cmds.append((ctype, line, col, my_text)) + new_cmds.append((ctype, line, col, c_text)) + break + elif (delend >= child._end and ( + child._start <= pos < child._end)): + # Case: partially for us, partially for the child + c_text = text[(child._end-pos).col:] + my_text = text[:(child._end-pos).col] + new_cmds.append((ctype, line, col, c_text)) + new_cmds.append((ctype, line, col, my_text)) + break + + for child in to_kill: + self._del_child(child) + if len(new_cmds): + for child in new_cmds: + self._do_edit(child) + return + + # We have to handle this ourselves + delta = Position(1, 0) if text == "\n" else Position(0, len(text)) + if ctype == "D": + # Makes no sense to delete in empty textobject + if self._start == self._end: + return + delta.line *= -1 + delta.col *= -1 + pivot = Position(line, col) + idx = -1 + for cidx, child in enumerate(self._children): + if child._start < pivot <= child._end: + idx = cidx + self._child_has_moved(idx, pivot, delta) + + def _move(self, pivot, diff): + TextObject._move(self, pivot, diff) + + for child in self._children: + child._move(pivot, diff) + + def _child_has_moved(self, idx, pivot, diff): + """Called when a the child with 'idx' has moved behind 'pivot' by + 'diff'.""" + self._end.move(pivot, diff) + + for child in self._children[idx+1:]: + child._move(pivot, diff) + + if self._parent: + self._parent._child_has_moved( + self._parent._children.index(self), pivot, diff + ) + + def _get_next_tab(self, number): + """Returns the next tabstop after 'number'.""" + if not len(self._tabstops.keys()): + return + tno_max = max(self._tabstops.keys()) + + possible_sol = [] + i = number + 1 + while i <= tno_max: + if i in self._tabstops: + possible_sol.append((i, self._tabstops[i])) + break + i += 1 + + child = [c._get_next_tab(number) for c in self._editable_children] + child = [c for c in child if c] + + possible_sol += child + + if not len(possible_sol): + return None + + return min(possible_sol) + + + def _get_prev_tab(self, number): + """Returns the previous tabstop before 'number'.""" + if not len(self._tabstops.keys()): + return + tno_min = min(self._tabstops.keys()) + + possible_sol = [] + i = number - 1 + while i >= tno_min and i > 0: + if i in self._tabstops: + possible_sol.append((i, self._tabstops[i])) + break + i -= 1 + + child = [c._get_prev_tab(number) for c in self._editable_children] + child = [c for c in child if c] + + possible_sol += child + + if not len(possible_sol): + return None + + return max(possible_sol) + + def _get_tabstop(self, requester, number): + """Returns the tabstop 'number'. 'requester' is the class that is + interested in this.""" + if number in self._tabstops: + return self._tabstops[number] + for child in self._editable_children: + if child is requester: + continue + rv = child._get_tabstop(self, number) + if rv is not None: + return rv + if self._parent and requester is not self._parent: + return self._parent._get_tabstop(self, number) + + def _update(self, done): + if all((child in done) for child in self._children): + assert self not in done + done.add(self) + return True + + def _add_child(self, child): + """Add 'child' as a new child of this text object.""" + self._children.append(child) + self._children.sort() + + def _del_child(self, child): + """Delete this 'child'.""" + child._parent = None + self._children.remove(child) + + # If this is a tabstop, delete it + try: + del self._tabstops[child.number] + except AttributeError: + pass + +class NoneditableTextObject(TextObject): + """All passive text objects that the user can't edit by hand.""" + def _update(self, done): + return True diff --git a/pythonx/UltiSnips/text_objects/_escaped_char.py b/pythonx/UltiSnips/text_objects/_escaped_char.py new file mode 100644 index 0000000..c197abd --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_escaped_char.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""See module comment.""" + +from UltiSnips.text_objects._base import NoneditableTextObject + +class EscapedChar(NoneditableTextObject): + r""" + 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/pythonx/UltiSnips/text_objects/_lexer.py b/pythonx/UltiSnips/text_objects/_lexer.py new file mode 100644 index 0000000..3703726 --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_lexer.py @@ -0,0 +1,349 @@ +#!/usr/bin/env python +# encoding: utf-8 + +""" +Not really a lexer in the classical sense, but code to convert snippet +definitions into logical units called Tokens. +""" + +import string +import re + +from UltiSnips.compatibility import as_unicode +from UltiSnips.position import Position +from UltiSnips.escaping import unescape + +class _TextIterator(object): + """Helper class to make iterating over text easier.""" + + def __init__(self, text, offset): + self._text = as_unicode(text) + self._line = offset.line + self._col = offset.col + + self._idx = 0 + + def __iter__(self): + """Iterator interface.""" + return self + + def __next__(self): + """Returns the next character.""" + if self._idx >= len(self._text): + raise StopIteration + + rv = self._text[self._idx] + if self._text[self._idx] in ('\n', '\r\n'): + self._line += 1 + self._col = 0 + else: + self._col += 1 + self._idx += 1 + return rv + next = __next__ # for python2 + + def peek(self, count=1): + """Returns the next 'count' characters without advancing the stream.""" + if count > 1: # This might return '' if nothing is found + return self._text[self._idx:self._idx + count] + try: + return self._text[self._idx] + except IndexError: + return None + + @property + def pos(self): + """Current position in the text.""" + return Position(self._line, self._col) + +def _parse_number(stream): + """ + Expects the stream to contain a number next, returns the number + without consuming any more bytes + """ + rv = "" + while stream.peek() and stream.peek() in string.digits: + rv += next(stream) + + return int(rv) + +def _parse_till_closing_brace(stream): + """ + Returns all chars till a non-escaped } is found. Other + non escaped { are taken into account and skipped over. + + Will also consume the closing }, but not return it + """ + rv = "" + in_braces = 1 + while True: + if EscapeCharToken.starts_here(stream, '{}'): + rv += next(stream) + next(stream) + else: + char = next(stream) + if char == '{': + in_braces += 1 + elif char == '}': + in_braces -= 1 + if in_braces == 0: + break + rv += char + return rv + +def _parse_till_unescaped_char(stream, chars): + """ + Returns all chars till a non-escaped char is found. + + Will also consume the closing char, but and return it as second + return value + """ + rv = "" + while True: + escaped = False + for char in chars: + if EscapeCharToken.starts_here(stream, char): + rv += next(stream) + next(stream) + escaped = True + if not escaped: + char = next(stream) + if char in chars: + break + rv += char + return rv, char + +class Token(object): + """Represents a Token as parsed from a snippet definition.""" + + def __init__(self, gen, indent): + self.initial_text = as_unicode("") + self.start = gen.pos + self._parse(gen, indent) + self.end = gen.pos + + def _parse(self, stream, indent): + """Parses the token from 'stream' with the current 'indent'.""" + pass # Does nothing + +class TabStopToken(Token): + """${1:blub}""" + CHECK = re.compile(r'^\${\d+[:}]') + + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return cls.CHECK.match(stream.peek(10)) is not None + + def _parse(self, stream, indent): + next(stream) # $ + next(stream) # { + + self.number = _parse_number(stream) + + if stream.peek() == ":": + next(stream) + self.initial_text = _parse_till_closing_brace(stream) + + def __repr__(self): + return "TabStopToken(%r,%r,%r,%r)" % ( + self.start, self.end, self.number, self.initial_text + ) + +class VisualToken(Token): + """${VISUAL}""" + CHECK = re.compile(r"^\${VISUAL[:}/]") + + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return cls.CHECK.match(stream.peek(10)) is not None + + def _parse(self, stream, indent): + for _ in range(8): # ${VISUAL + next(stream) + + if stream.peek() == ":": + next(stream) + self.alternative_text, char = _parse_till_unescaped_char(stream, '/}') + self.alternative_text = unescape(self.alternative_text) + + if char == '/': # 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)" % ( + self.start, self.end + ) + +class TransformationToken(Token): + """${1/match/replace/options}""" + + CHECK = re.compile(r'^\${\d+\/') + + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return cls.CHECK.match(stream.peek(10)) is not None + + def _parse(self, stream, indent): + next(stream) # $ + next(stream) # { + + self.number = _parse_number(stream) + + next(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): + return "TransformationToken(%r,%r,%r,%r,%r)" % ( + self.start, self.end, self.number, self.search, self.replace + ) + +class MirrorToken(Token): + """$1""" + CHECK = re.compile(r'^\$\d+') + + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return cls.CHECK.match(stream.peek(10)) is not None + + def _parse(self, stream, indent): + next(stream) # $ + self.number = _parse_number(stream) + + def __repr__(self): + return "MirrorToken(%r,%r,%r)" % ( + self.start, self.end, self.number + ) + +class EscapeCharToken(Token): + """\\n""" + @classmethod + def starts_here(cls, stream, chars=r'{}\$`'): + """Returns true if this token starts at the current position in + 'stream'.""" + cs = stream.peek(2) + if len(cs) == 2 and cs[0] == '\\' and cs[1] in chars: + return True + + def _parse(self, stream, indent): + next(stream) # \ + self.initial_text = next(stream) + + def __repr__(self): + return "EscapeCharToken(%r,%r,%r)" % ( + self.start, self.end, self.initial_text + ) + +class ShellCodeToken(Token): + """`! echo "hi"`""" + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return stream.peek(1) == '`' + + def _parse(self, stream, indent): + next(stream) # ` + self.code = _parse_till_unescaped_char(stream, '`')[0] + + def __repr__(self): + return "ShellCodeToken(%r,%r,%r)" % ( + self.start, self.end, self.code + ) + +class PythonCodeToken(Token): + """`!p snip.rv = "Hi"`""" + CHECK = re.compile(r'^`!p\s') + + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return cls.CHECK.match(stream.peek(4)) is not None + + def _parse(self, stream, indent): + for _ in range(3): + next(stream) # `!p + if stream.peek() in '\t ': + next(stream) + + code = _parse_till_unescaped_char(stream, '`')[0] + + # Strip the indent if any + if len(indent): + lines = code.splitlines() + self.code = lines[0] + '\n' + self.code += '\n'.join([l[len(indent):] + for l in lines[1:]]) + else: + self.code = code + self.indent = indent + + def __repr__(self): + return "PythonCodeToken(%r,%r,%r)" % ( + self.start, self.end, self.code + ) + +class VimLCodeToken(Token): + """`!v g:hi`""" + CHECK = re.compile(r'^`!v\s') + + @classmethod + def starts_here(cls, stream): + """Returns true if this token starts at the current position in + 'stream'.""" + return cls.CHECK.match(stream.peek(4)) is not None + + def _parse(self, stream, indent): + for _ in range(4): + next(stream) # `!v + self.code = _parse_till_unescaped_char(stream, '`')[0] + + def __repr__(self): + return "VimLCodeToken(%r,%r,%r)" % ( + self.start, self.end, self.code + ) + +class EndOfTextToken(Token): + """Appears at the end of the text.""" + def __repr__(self): + return "EndOfText(%r)" % self.end + +__ALLOWED_TOKENS = [ + EscapeCharToken, VisualToken, TransformationToken, TabStopToken, + MirrorToken, PythonCodeToken, VimLCodeToken, ShellCodeToken +] +def tokenize(text, indent, offset): + """Returns an iterator of tokens of 'text'['offset':] which is assumed to + have 'indent' as the whitespace of the begging of the lines.""" + stream = _TextIterator(text, offset) + try: + while True: + done_something = False + for token in __ALLOWED_TOKENS: + if token.starts_here(stream): + yield token(stream, indent) + done_something = True + break + if not done_something: + next(stream) + except StopIteration: + yield EndOfTextToken(stream, indent) diff --git a/pythonx/UltiSnips/text_objects/_mirror.py b/pythonx/UltiSnips/text_objects/_mirror.py new file mode 100644 index 0000000..b4e512c --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_mirror.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""A Mirror object contains the same text as its related tabstop.""" + +from UltiSnips.text_objects._base import NoneditableTextObject + +class Mirror(NoneditableTextObject): + """See module docstring.""" + + def __init__(self, parent, tabstop, token): + NoneditableTextObject.__init__(self, parent, token) + + self._ts = tabstop + + def _update(self, done): + if self._ts.is_killed: + self.overwrite("") + self._parent._del_child(self) # pylint:disable=protected-access + return True + + if self._ts not in done: + return False + + self.overwrite(self._get_text()) + return True + + def _get_text(self): + """Returns the text used for mirroring. Overwritten by base classes.""" + return self._ts.current_text diff --git a/pythonx/UltiSnips/text_objects/_parser.py b/pythonx/UltiSnips/text_objects/_parser.py new file mode 100644 index 0000000..bc76e8b --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_parser.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Parses tokens into text objects.""" + +from UltiSnips.text_objects._lexer import tokenize, EscapeCharToken, \ + VisualToken, TransformationToken, TabStopToken, MirrorToken, \ + PythonCodeToken, VimLCodeToken, ShellCodeToken +from UltiSnips.position import Position +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 + +_TOKEN_TO_TEXTOBJECT = { + EscapeCharToken: EscapedChar, + VisualToken: Visual, + ShellCodeToken: ShellCode, + PythonCodeToken: PythonCode, + VimLCodeToken: VimLCode, +} + +def _resolve_ambiguity(all_tokens, seen_ts): + """$1 could be a Mirror or a TabStop. This figures this out.""" + for parent, token in all_tokens: + if isinstance(token, MirrorToken): + if token.number not in seen_ts: + seen_ts[token.number] = TabStop(parent, token) + else: + Mirror(parent, seen_ts[token.number], token) + +def _create_transformations(all_tokens, seen_ts): + """Create the objects that need to know about tabstops.""" + for parent, token in all_tokens: + if isinstance(token, TransformationToken): + if token.number not in seen_ts: + raise RuntimeError( + "Tabstop %i is not known but is used by a Transformation" + % token.number) + Transformation(parent, seen_ts[token.number], token) + +def _do_parse(all_tokens, seen_ts, parent_to, text, indent): + """Recursive function that actually creates the objects.""" + tokens = list(tokenize(text, indent, parent_to.start)) + for token in tokens: + all_tokens.append((parent_to, token)) + if isinstance(token, TabStopToken): + ts = TabStop(parent_to, token) + seen_ts[token.number] = ts + + _do_parse(all_tokens, seen_ts, ts, token.initial_text, indent) + else: + klass = _TOKEN_TO_TEXTOBJECT.get(token.__class__, None) + if klass is not None: + klass(parent_to, token) + +def parse_text_object(parent_to, text, indent): + """Parses a text object from 'text' assuming the current 'indent'. Will + instantiate all the objects and link them as children to parent_to. Will + also put the initial text into Vim.""" + seen_ts = {} + all_tokens = [] + + _do_parse(all_tokens, seen_ts, parent_to, text, indent) + _resolve_ambiguity(all_tokens, seen_ts) + _create_transformations(all_tokens, seen_ts) + + if 0 not in seen_ts: + mark = all_tokens[-1][1].end # Last token is always EndOfText + m1 = Position(mark.line, mark.col) + TabStop(parent_to, 0, mark, m1) + parent_to.replace_initial_text() diff --git a/pythonx/UltiSnips/text_objects/_python_code.py b/pythonx/UltiSnips/text_objects/_python_code.py new file mode 100644 index 0000000..c9c3e66 --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_python_code.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Implements `!p ` interpolation.""" + +import os +from collections import namedtuple + +from UltiSnips.compatibility import as_unicode +from UltiSnips.indent_util import IndentUtil +from UltiSnips.text_objects._base import NoneditableTextObject +import UltiSnips._vim as _vim + + +class _Tabs(object): + """Allows access to tabstop content via t[] inside of python code.""" + def __init__(self, to): + self._to = to + + def __getitem__(self, no): + ts = self._to._get_tabstop(self._to, int(no)) # pylint:disable=protected-access + if ts is None: + return "" + return ts.current_text + +_VisualContent = namedtuple('_VisualContent', ['mode', 'text']) + +class SnippetUtil(object): + """Provides easy access to indentation, etc. This is the 'snip' object in + python code.""" + + 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._cur = 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.shiftwidth * 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.shiftwidth * amount + try: + self.indent = self.indent[:by] + except IndexError: + self.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 is 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): # pylint:disable=no-self-use,invalid-name + """The filename.""" + return _vim.eval('expand("%:t")') or "" + + @property + def basename(self): # pylint:disable=no-self-use + """The filename without extension.""" + return _vim.eval('expand("%:t:r")') or "" + + @property + def ft(self): # pylint:disable=invalid-name + """The filetype.""" + return self.opt("&filetype", "") + + @property + def rv(self): # pylint:disable=invalid-name + """The return value. The text to insert at the location of the + placeholder.""" + return self._rv + + @rv.setter + def rv(self, value): # pylint:disable=invalid-name + """See getter.""" + self._changed = True + self._rv = value + + @property + def _rv_changed(self): + """True if rv has changed.""" + return self._changed + + @property + def c(self): # pylint:disable=invalid-name + """The current text of the placeholder.""" + return self._cur + + @property + def v(self): # pylint:disable=invalid-name + """Content of visual expansions""" + return self._visual + + def opt(self, option, default=None): # pylint:disable=no-self-use + """Gets a Vim variable.""" + if _vim.eval("exists('%s')" % option) == "1": + try: + return _vim.eval(option) + except _vim.error: + pass + return default + + def __add__(self, value): + """Appends the given line to rv using mkline.""" + self.rv += '\n' # pylint:disable=invalid-name + 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): + """See module docstring.""" + + def __init__(self, parent, token): + + # Find our containing snippet for snippet local data + snippet = parent + while snippet: + try: + self._locals = snippet.locals + text = snippet.visual_content.text + mode = snippet.visual_content.mode + break + except AttributeError: + snippet = snippet._parent # pylint:disable=protected-access + self._snip = SnippetUtil(token.indent, mode, text) + + self._codes = (( + "import re, os, vim, string, random", + "\n".join(snippet.globals.get("!p", [])).replace("\r\n", "\n"), + token.code.replace("\\`", "`") + )) + NoneditableTextObject.__init__(self, parent, token) + + def _update(self, done): + path = _vim.eval('expand("%")') or "" + ct = self.current_text + self._locals.update({ + 't': _Tabs(self._parent), + 'fn': os.path.basename(path), + 'path': path, + 'cur': ct, + 'res': ct, + 'snip': self._snip, + }) + self._snip._reset(ct) # pylint:disable=protected-access + + for code in self._codes: + exec(code, self._locals) # pylint:disable=exec-used + + rv = as_unicode( + self._snip.rv if self._snip._rv_changed # pylint:disable=protected-access + else as_unicode(self._locals['res']) + ) + + if ct != rv: + self.overwrite(rv) + return False + return True diff --git a/pythonx/UltiSnips/text_objects/_shell_code.py b/pythonx/UltiSnips/text_objects/_shell_code.py new file mode 100644 index 0000000..3e9099a --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_shell_code.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Implements `echo hi` shell code interpolation.""" + +import os +import platform +from subprocess import Popen, PIPE +import stat +import tempfile + +from UltiSnips.compatibility import as_unicode +from UltiSnips.text_objects._base import NoneditableTextObject + +def _chomp(string): + """Rather than rstrip(), remove only the last newline and preserve + purposeful whitespace.""" + if len(string) and string[-1] == '\n': + string = string[:-1] + if len(string) and string[-1] == '\r': + string = string[:-1] + return string + +def _run_shell_command(cmd, tmpdir): + """Write the code to a temporary file""" + cmdsuf = '' + if platform.system() == 'Windows': + # suffix required to run command on windows + cmdsuf = '.bat' + # turn echo off + cmd = '@echo off\r\n' + cmd + handle, path = tempfile.mkstemp(text=True, dir=tmpdir, suffix=cmdsuf) + os.write(handle, cmd.encode("utf-8")) + os.close(handle) + os.chmod(path, stat.S_IRWXU) + + # Execute the file and read stdout + proc = Popen(path, shell=True, stdout=PIPE, stderr=PIPE) + proc.wait() + stdout, _ = proc.communicate() + os.unlink(path) + return _chomp(as_unicode(stdout)) + +def _get_tmp(): + """Find an executable tmp directory.""" + userdir = os.path.expanduser("~") + for testdir in [tempfile.gettempdir(), os.path.join(userdir, '.cache'), + os.path.join(userdir, '.tmp'), userdir]: + if (not os.path.exists(testdir) or + not _run_shell_command('echo success', testdir) == 'success'): + continue + return testdir + return '' + +class ShellCode(NoneditableTextObject): + """See module docstring.""" + + def __init__(self, parent, token): + NoneditableTextObject.__init__(self, parent, token) + self._code = token.code.replace("\\`", "`") + self._tmpdir = _get_tmp() + + def _update(self, done): + if not self._tmpdir: + output = \ + "Unable to find executable tmp directory, check noexec on /tmp" + else: + output = _run_shell_command(self._code, self._tmpdir) + self.overwrite(output) + self._parent._del_child(self) # pylint:disable=protected-access + return True diff --git a/pythonx/UltiSnips/text_objects/_snippet_instance.py b/pythonx/UltiSnips/text_objects/_snippet_instance.py new file mode 100644 index 0000000..a9c12a6 --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_snippet_instance.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""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. """ + +from UltiSnips.position import Position +import UltiSnips._vim as _vim +from UltiSnips.text_objects._base import EditableTextObject, \ + NoneditableTextObject +from UltiSnips.text_objects._parser import parse_text_object + +class SnippetInstance(EditableTextObject): + """See module docstring.""" + # pylint:disable=protected-access + + def __init__(self, snippet, 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.snippet = snippet + self._cts = 0 + + self.locals = {"match" : last_re} + self.globals = globals + self.visual_content = visual_content + + EditableTextObject.__init__(self, parent, start, end, initial_text) + + parse_text_object(self, initial_text, indent) + + self.update_textobjects() + + def replace_initial_text(self): + """Puts the initial text of all text elements into Vim.""" + def _place_initial_text(obj): + """recurses on the children to do the work.""" + obj.overwrite() + if isinstance(obj, EditableTextObject): + for child in obj._children: + _place_initial_text(child) + _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): + """Finds all text objects and puts them into 'not_done'.""" + if isinstance(obj, EditableTextObject): + for child in obj._children: + _find_recursive(child) + not_done.add(obj) + _find_recursive(self) + + counter = 10 + while (done != not_done) and counter: + # Order matters for python locals! + for obj in sorted(not_done - done): + if obj._update(done): + done.add(obj) + counter -= 1 + if not counter: + raise RuntimeError( + "The snippets content did not converge: Check for Cyclic " + "dependencies or random strings in your snippet. You can use " + "'if not snip.c' to make sure to only expand random output " + "once.") + vc.to_vim() + self._del_child(vc) + + def select_next_tab(self, backwards=False): + """Selects the next tabstop or the previous if 'backwards' is True.""" + 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 + cached_parent = self._parent + self._parent = None + rv = EditableTextObject._get_tabstop(self, requester, no) + self._parent = cached_parent + return rv + + +class _VimCursor(NoneditableTextObject): + """Helper class to keep track of the Vim Cursor when text objects expand + and move.""" + + def __init__(self, parent): + NoneditableTextObject.__init__( + self, parent, _vim.buf.cursor, _vim.buf.cursor, + tiebreaker=Position(-1, -1)) + + def to_vim(self): + """Moves the cursor in the Vim to our position.""" + assert self._start == self._end + _vim.buf.cursor = self._start diff --git a/pythonx/UltiSnips/text_objects/_tabstop.py b/pythonx/UltiSnips/text_objects/_tabstop.py new file mode 100644 index 0000000..4eff6af --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_tabstop.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""This is the most important TextObject. A TabStop is were the cursor +comes to rest when the user taps through the Snippet.""" + +from UltiSnips.text_objects._base import EditableTextObject + +class TabStop(EditableTextObject): + """See module docstring.""" + + def __init__(self, parent, token, start=None, end=None): + if start is not None: + self._number = token + EditableTextObject.__init__(self, parent, start, end) + else: + self._number = token.number + EditableTextObject.__init__(self, parent, token) + parent._tabstops[self._number] = self # pylint:disable=protected-access + + @property + def number(self): + """The tabstop number.""" + return self._number + + @property + def is_killed(self): + """True if this tabstop has been typed over and the user therefore can + no longer jump to it.""" + return self._parent is None diff --git a/pythonx/UltiSnips/text_objects/_transformation.py b/pythonx/UltiSnips/text_objects/_transformation.py new file mode 100644 index 0000000..bf8f495 --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_transformation.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Implements TabStop transformations.""" + +import re +import sys +from UltiSnips.text_objects._mirror import Mirror +from UltiSnips.escaping import unescape, fill_in_whitespace + +def _find_closing_brace(string, start_pos): + """Finds the corresponding closing brace after start_pos.""" + bracks_open = 1 + for idx, char in enumerate(string[start_pos:]): + if char == '(': + if string[idx+start_pos-1] != '\\': + bracks_open += 1 + elif char == ')': + if string[idx+start_pos-1] != '\\': + bracks_open -= 1 + if not bracks_open: + return start_pos+idx+1 + +def _split_conditional(string): + """Split the given conditional 'string' into its arguments.""" + bracks_open = 0 + args = [] + carg = "" + for idx, char in enumerate(string): + if char == '(': + if string[idx-1] != '\\': + bracks_open += 1 + elif char == ')': + if string[idx-1] != '\\': + bracks_open -= 1 + elif char == ':' and not bracks_open and not string[idx-1] == '\\': + args.append(carg) + carg = "" + continue + carg += char + args.append(carg) + return args + +def _replace_conditional(match, string): + """Replaces a conditional match in a transformation.""" + conditional_match = _CONDITIONAL.search(string) + while conditional_match: + start = conditional_match.start() + end = _find_closing_brace(string, start+4) + args = _split_conditional(string[start+4:end-1]) + rv = "" + if match.group(int(conditional_match.group(1))): + rv = unescape(_replace_conditional(match, args[0])) + elif len(args) > 1: + rv = unescape(_replace_conditional(match, args[1])) + string = string[:start] + rv + string[end:] + conditional_match = _CONDITIONAL.search(string) + return string + +_ONE_CHAR_CASE_SWITCH = re.compile(r"\\([ul].)", re.DOTALL) +_LONG_CASEFOLDINGS = re.compile(r"\\([UL].*?)\\E", re.DOTALL) +_DOLLAR = re.compile(r"\$(\d+)", re.DOTALL) +_CONDITIONAL = re.compile(r"\(\?(\d+):", re.DOTALL) +class _CleverReplace(object): + """Mimics TextMates replace syntax.""" + + def __init__(self, expression): + self._expression = expression + + def replace(self, match): + """Replaces 'match' through the correct replacement string.""" + transformed = self._expression + # Replace all $? with capture groups + transformed = _DOLLAR.subn( + lambda m: match.group(int(m.group(1))), transformed)[0] + + # Replace Case switches + def _one_char_case_change(match): + """Replaces one character case changes.""" + if match.group(1)[0] == 'u': + return match.group(1)[-1].upper() + else: + return match.group(1)[-1].lower() + transformed = _ONE_CHAR_CASE_SWITCH.subn( + _one_char_case_change, transformed)[0] + + def _multi_char_case_change(match): + """Replaces multi character case changes.""" + if match.group(1)[0] == 'U': + return match.group(1)[1:].upper() + else: + return match.group(1)[1:].lower() + transformed = _LONG_CASEFOLDINGS.subn( + _multi_char_case_change, transformed)[0] + transformed = _replace_conditional(match, transformed) + return unescape(fill_in_whitespace(transformed)) + +# flag used to display only one time the lack of unidecode +UNIDECODE_ALERT_RAISED = False +class TextObjectTransformation(object): + """Base class for Transformations and ${VISUAL}.""" + + def __init__(self, token): + self._convert_to_ascii = False + + 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 + if "a" in token.options: + self._convert_to_ascii = True + + self._find = re.compile(token.search, flags | re.DOTALL) + self._replace = _CleverReplace(token.replace) + + def _transform(self, text): + """Do the actual transform on the given text.""" + global UNIDECODE_ALERT_RAISED # pylint:disable=global-statement + if self._convert_to_ascii: + try: + import unidecode + text = unidecode.unidecode(text) + except Exception: # pylint:disable=broad-except + if UNIDECODE_ALERT_RAISED == False: + UNIDECODE_ALERT_RAISED = True + sys.stderr.write( + "Please install unidecode python package in order to " + "be able to make ascii conversions.\n") + if self._find is None: + return text + return self._find.subn( + self._replace.replace, text, self._match_this_many)[0] + +class Transformation(Mirror, TextObjectTransformation): + """See module docstring.""" + + 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/pythonx/UltiSnips/text_objects/_viml_code.py b/pythonx/UltiSnips/text_objects/_viml_code.py new file mode 100644 index 0000000..18ffd85 --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_viml_code.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Implements `!v ` VimL interpolation.""" + +import UltiSnips._vim as _vim +from UltiSnips.text_objects._base import NoneditableTextObject + +class VimLCode(NoneditableTextObject): + """See module docstring.""" + def __init__(self, parent, token): + self._code = token.code.replace("\\`", "`").strip() + + NoneditableTextObject.__init__(self, parent, token) + + def _update(self, done): + self.overwrite(_vim.eval(self._code)) + return True diff --git a/pythonx/UltiSnips/text_objects/_visual.py b/pythonx/UltiSnips/text_objects/_visual.py new file mode 100644 index 0000000..af5ca4e --- /dev/null +++ b/pythonx/UltiSnips/text_objects/_visual.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""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. """ + +import re +import textwrap + +import UltiSnips._vim as _vim +from UltiSnips.indent_util import IndentUtil +from UltiSnips.text_objects._transformation import TextObjectTransformation +from UltiSnips.text_objects._base import NoneditableTextObject + +_REPLACE_NON_WS = re.compile(r"[^ \t]") +class Visual(NoneditableTextObject, TextObjectTransformation): + """See module docstring.""" + + 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 # pylint:disable=protected-access + 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): + if self._mode == "v": # Normal selection. + text = self._text + else: # Block selection or line selection. + text_before = _vim.buf[self.start.line][:self.start.col] + indent = _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(textwrap.dedent( + self._text).splitlines(True)): + if idx != 0: + text += indent + text += line + text = text[:-1] # Strip final '\n' + + text = self._transform(text) + self.overwrite(text) + self._parent._del_child(self) # pylint:disable=protected-access + + return True diff --git a/pythonx/UltiSnips/vim_state.py b/pythonx/UltiSnips/vim_state.py new file mode 100644 index 0000000..ccaded8 --- /dev/null +++ b/pythonx/UltiSnips/vim_state.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# encoding: utf-8 + +"""Some classes to conserve Vim's state for comparing over time.""" + +from collections import deque + +from UltiSnips.compatibility import as_unicode, byte2col +from UltiSnips.position import Position +import UltiSnips._vim as _vim + +class VimPosition(Position): + """Represents the current position in the buffer, together with some status + variables that might change our decisions down the line.""" + + def __init__(self): + pos = _vim.buf.cursor + self._mode = _vim.eval("mode()") + Position.__init__(self, pos.line, pos.col) + + @property + def mode(self): + """Returns the mode() this position was created.""" + return self._mode + +class VimState(object): + """Caches some state information from Vim to better guess what editing + tasks the user might have done in the last step.""" + + def __init__(self): + self._poss = deque(maxlen=5) + self._lvb = None + + self._text_to_expect = None + self._unnamed_reg_cache = None + self._unnamed_reg_cached = False + + def remember_unnamed_register(self, text_to_expect): + """Save the unnamed register. 'text_to_expect' is text that we expect + to be contained in the register the next time this method is called - + this could be text from the tabstop that was selected and might have + been overwritten. We will not cash that then.""" + self._unnamed_reg_cached = True + unnamed_reg = _vim.eval('@"') + if unnamed_reg != self._text_to_expect: + self._unnamed_reg_cache = unnamed_reg + self._text_to_expect = text_to_expect + + def restore_unnamed_register(self): + """Restores the unnamed register and forgets what we cached.""" + if not self._unnamed_reg_cached: + return + escaped_cache = self._unnamed_reg_cache.replace("'", "''") + _vim.command("let @\"='%s'" % escaped_cache) + self._unnamed_reg_cached = False + + def remember_position(self): + """Remember the current position as a previous pose.""" + self._poss.append(VimPosition()) + + def remember_buffer(self, to): + """Remember the content of the buffer and the position.""" + 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): + """Returns the difference in the length of the current buffer compared + to the remembered.""" + return len(_vim.buf) - self._lvb_len + + @property + def pos(self): + """The last remembered position.""" + return self._poss[-1] + + @property + def ppos(self): + """The second to last remembered position.""" + return self._poss[-2] + + @property + def remembered_buffer(self): + """The content of the remembered buffer.""" + return self._lvb[:] + +class VisualContentPreserver(object): + """Saves the current visual selection and the selection mode it was done in + (e.g. line selection, block selection or regular selection.)""" + + def __init__(self): + self.reset() + + def reset(self): + """Forget the preserved state.""" + self._mode = "" + self._text = as_unicode("") + + def conserve(self): + """Save the last visual selection ond the mode it was made in.""" + 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()") + + _vim_line_with_eol = lambda ln: _vim.buf[ln] + '\n' + + if sl == el: + text = _vim_line_with_eol(sl-1)[sc:ec+1] + else: + 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] + self._text = text + + @property + def text(self): + """The conserved text.""" + return self._text + + @property + def mode(self): + """The conserved visualmode().""" + return self._mode diff --git a/syntax/snippets.vim b/syntax/snippets.vim new file mode 100644 index 0000000..085b408 --- /dev/null +++ b/syntax/snippets.vim @@ -0,0 +1,72 @@ +" Syntax highlighting for snippet files (used for UltiSnips.vim) +" Revision: 26/03/11 19:53:33 + +if exists("b:current_syntax") + finish +endif + +syntax include @Python syntax/python.vim +syntax include @Viml syntax/vim.vim + +" global matches +syn match snipComment "^#.*" contains=snipTODO +syn keyword snipTODO FIXME NOTE NOTES TODO XXX contained + +syn match snipDocString '"[^"]*"$' +syn match snipString '"[^"]*"' +syn match snipTabsOnly "^\t\+$" +syn match snipLeadingSpaces "^\t* \+" + +syn match snipKeyword "\(\<\(end\)\?\(snippet\|global\)\>\)\|extends\|clearsnippets\|priority" contained + +" extends definitions +syn match snipExtends "^extends.*" contains=snipKeyword + +" snippet definitions +syn match snipStart "^snippet.*" contained contains=snipKeyword,snipDocString +syn match snipEnd "^endsnippet" contained contains=snipKeyword +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,snipLeadingSpaces,snipCommand,snipVarExpansion,snipVar,snipVisual + +" global definitions +syn match snipGlobalStart "^global.*" contained contains=snipKeyword,snipString +syn match snipGlobalEnd "^endglobal" contained contains=snipKeyword +syn region snipGlobal fold keepend start="^global" end="^endglobal" contains=snipGlobalStart,snipGlobalEnd,snipLeadingSpaces,snipTabsOnly,snipCommand,snipVarExpansion,snipVar,@Python + +" snippet clearing +syn match snipClear "^clearsnippets" +syn match snipPriority "^priority" + +" highlighting rules + +hi link snipComment Comment +hi link snipLeadingSpaces Error +hi link snipString String +hi link snipDocString String +hi link snipTabsOnly Error + +hi link snipKeyword Keyword + +hi link snipExtends Statement + +hi link snipStart Statement +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 +hi link snipGlobalEnd Statement +hi link snipGlobal Normal + +hi link snipClear Statement +hi link snipPriority Statement + +let b:current_syntax = "snippet" diff --git a/test.py b/test.py new file mode 100755 index 0000000..26e8628 --- /dev/null +++ b/test.py @@ -0,0 +1,3300 @@ +#!/usr/bin/env python +# encoding: utf-8 +# +# To execute this test requires two terminals, one for running Vim and one +# for executing the test script. Both terminals should have their current +# working directories set to this directory (the one containing this test.py +# script). +# +# In one terminal, launch a GNU ``screen`` session named ``vim``: +# $ screen -S vim +# +# Within this new session, launch Vim with the absolute bare minimum settings +# to ensure a consistent test environment: +# $ vim -u NONE +# +# The '-u NONE' disables normal .vimrc and .gvimrc processing (note +# that '-u NONE' implies '-U NONE'). +# +# All other settings are configured by the test script. +# +# Now, from another terminal, launch the testsuite: +# $ ./test.py +# +# 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) + +# pylint: skip-file + +from textwrap import dedent +import os +import platform +import random +import re +import shutil +import string +import subprocess +import sys +import tempfile +import time +import unittest + +try: + import unidecode + UNIDECODE_IMPORTED = True +except ImportError: + UNIDECODE_IMPORTED = False + +# Some constants for better reading +BS = '\x7f' +ESC = '\x1b' +ARR_L = '\x1bOD' +ARR_R = '\x1bOC' +ARR_U = '\x1bOA' +ARR_D = '\x1bOB' + +# multi-key sequences generating a single key press +SEQUENCES = [ARR_L, ARR_R, ARR_U, ARR_D] + +# Defined Constants +JF = "?" # Jump forwards +JB = "+" # Jump backwards +LS = "@" # List snippets +EX = "\t" # EXPAND +EA = "#" # Expand anonymous + +COMPL_KW = chr(24)+chr(14) +COMPL_ACCEPT = chr(25) + +def running_on_windows(): + if platform.system() == "Windows": + return "Does not work on Windows." + +def no_unidecode_available(): + if not UNIDECODE_IMPORTED: + return "unidecode is not available." + +def random_string(n): + return ''.join(random.choice(string.ascii_lowercase) for x in range(n)) + +def silent_call(cmd): + """Calls 'cmd' and returns the exit value.""" + return subprocess.call(cmd, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + +class VimInterface: + def focus(title=None): + pass + + def get_buffer_data(self): + handle, fn = tempfile.mkstemp(prefix="UltiSnips_Test",suffix=".txt") + os.close(handle) + os.unlink(fn) + + self.send(ESC + ":w! %s\n" % fn) + + # Read the output, chop the trailing newline + tries = 50 + while tries: + if os.path.exists(fn): + if sys.version_info >= (3,0): + return open(fn,"r", encoding="utf-8").read()[:-1] + else: + return open(fn,"r").read()[:-1] + time.sleep(.05) + tries -= 1 + +class VimInterfaceScreen(VimInterface): + def __init__(self, session): + self.session = session + self.need_screen_escapes = 0 + self.detect_parsing() + + def send(self, s): + if self.need_screen_escapes: + # escape characters that are special to some versions of screen + repl = lambda m: '\\' + m.group(0) + s = re.sub( r"[$^#\\']", repl, s ) + + if sys.version_info >= (3,0): + s = s.encode("utf-8") + + while True: + rv = 0 + if len(s) > 30: + rv |= silent_call(["screen", "-x", self.session, "-X", "register", "S", s]) + rv |= silent_call(["screen", "-x", self.session, "-X", "paste", "S"]) + else: + rv |= silent_call(["screen", "-x", self.session, "-X", "stuff", s]) + if not rv: break + time.sleep(.2) + + def detect_parsing(self): + # Clear the buffer + self.send("bggVGd") + + # Send a string where the interpretation will depend on version of screen + string = "$TERM" + self.send("i" + string + ESC) + output = self.get_buffer_data() + + # If the output doesn't match the input, need to do additional escaping + if output != string: + self.need_screen_escapes = 1 + +class VimInterfaceTmux(VimInterface): + def __init__(self, session): + self.session = session + self._check_version() + + def send(self, s): + # I did not find any documentation on what needs escaping when sending + # to tmux, but it seems like this is all that is needed for now. + s = s.replace(';', r'\;') + + if sys.version_info >= (3,0): + s = s.encode("utf-8") + silent_call(["tmux", "send-keys", "-t", self.session, "-l", s]) + + def _check_version(self): + stdout, _ = subprocess.Popen(["tmux", "-V"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() + if sys.version_info >= (3,0): + stdout = stdout.decode("utf-8") + m = re.match(r"tmux (\d+).(\d+)", stdout) + if not m or not (int(m.group(1)), int(m.group(2))) >= (1, 9): + raise RuntimeError("Need at least tmux 1.9, you have %s." % stdout.strip()) + +class VimInterfaceWindows(VimInterface): + BRACES = re.compile("([}{])") + WIN_ESCAPES = ["+", "^", "%", "~", "[", "]", "<", ">", "(", ")"] + WIN_REPLACES = [ + (BS, "{BS}"), + (ARR_L, "{LEFT}"), + (ARR_R, "{RIGHT}"), + (ARR_U, "{UP}"), + (ARR_D, "{DOWN}"), + ("\t", "{TAB}"), + ("\n", "~"), + (ESC, "{ESC}"), + + # On my system ` waits for a second keystroke, so `+SPACE = "`". On + # most systems, `+Space = "` ". I work around this, by sending the host + # ` as `+_+BS. Awkward, but the only way I found to get this working. + ("`", "`_{BS}"), + ("´", "´_{BS}"), + ("{^}", "{^}_{BS}"), + ] + + def __init__(self): + self.seq_buf = [] + # import windows specific modules + import win32com.client, win32gui + self.win32gui = win32gui + self.shell = win32com.client.Dispatch("WScript.Shell") + + def is_focused(self, title=None): + cur_title = self.win32gui.GetWindowText(self.win32gui.GetForegroundWindow()) + if (title or "- GVIM") in cur_title: + return True + return False + + def focus(self, title=None): + if not self.shell.AppActivate(title or "- GVIM"): + raise Exception("Failed to switch to GVim window") + time.sleep(1) + + def convert_keys(self, keys): + keys = self.BRACES.sub(r"{\1}", keys) + for k in self.WIN_ESCAPES: + keys = keys.replace(k, "{%s}" % k) + for f, r in self.WIN_REPLACES: + keys = keys.replace(f, r) + return keys + + def send(self, keys): + self.seq_buf.append(keys) + seq = "".join(self.seq_buf) + + for f in SEQUENCES: + if f.startswith(seq) and f != seq: + return + self.seq_buf = [] + + seq = self.convert_keys(seq) + + if not self.is_focused(): + time.sleep(2) + self.focus() + if not self.is_focused(): + # This is the only way I can find to stop test execution + raise KeyboardInterrupt("Failed to focus GVIM") + + self.shell.SendKeys(seq) + +class _VimTest(unittest.TestCase): + snippets = ("dummy", "donotdefine") + snippets_test_file = ("", "") # filetype, file content + text_before = " --- some text before --- \n\n" + text_after = "\n\n --- some text after --- " + expected_error = "" + wanted = "" + keys = "" + sleeptime = 0.00 + output = None + # Skip this test for the given reason or None for not skipping it. + skip_if = lambda self: None + + def send(self,s): + self.vim.send(s) + + def send_py(self,s): + # Do not delete the file so that Vim can safely read it. + with tempfile.NamedTemporaryFile( + prefix="UltiSnips_Python", suffix=".py", delete=False + ) as temporary_file: + if sys.version_info >= (3,0): + s = s.encode("utf-8") + + temporary_file.write(s) + temporary_file.close() + + if sys.version_info < (3,0): + self.send(":pyfile %s\n" % temporary_file.name) + else: + self.send(":py3file %s\n" % temporary_file.name) + + def check_output(self): + wanted = self.text_before + self.wanted + self.text_after + if self.expected_error: + self.assertRegexpMatches(self.output, self.expected_error) + return + for i in range(self.retries): + if self.output != wanted: + # Redo this, but slower + self.sleeptime += 0.02 + self.send(ESC) + self.setUp() + self.assertEqual(self.output, wanted) + + def runTest(self): self.check_output() + + def _options_on(self): + pass + + def _options_off(self): + pass + + def _create_snippet_file(self, ft, content): + """Create a snippet file and makes sure that it is found on the + runtimepath to be parsed.""" + self._temporary_directory = tempfile.mkdtemp(prefix="UltiSnips_Test") + snippet_dir = random_string(20) + abs_snippet_dir = os.path.join(self._temporary_directory, snippet_dir) + os.mkdir(abs_snippet_dir) + with open(os.path.join(abs_snippet_dir, "%s.snippets" % ft), "w") as snippet_file: + snippet_file.write(dedent(content + "\n")) + self.vim.send(":let g:UltiSnipsSnippetDirectories=['%s']\n" % snippet_dir) + self.vim.send(""":set runtimepath=$VIMRUNTIME,%s,.\n""" % self._temporary_directory) + + def setUp(self): + reason_for_skipping = self.skip_if() + if reason_for_skipping is not None: + return self.skipTest(reason_for_skipping) + + # Escape for good measure + self.send(ESC + ESC + ESC) + + # Close all scratch buffers + self.send(":silent! close\n") + + # Reset UltiSnips + self.send_py("UltiSnips_Manager._reset()") + + # Make it unlikely that we do parse any shipped snippets. + self.send(":let g:UltiSnipsSnippetDirectories=['']\n") + + # Clear the buffer + self.send("bggVGd") + + if len(self.snippets) and not isinstance(self.snippets[0],tuple): + self.snippets = ( self.snippets, ) + + for s in self.snippets: + sv, content = s[:2] + description = "" + options = "" + priority = 0 + if len(s) > 2: + description = s[2] + if len(s) > 3: + options = s[3] + if len(s) > 4: + priority = s[4] + + self.send_py("UltiSnips_Manager.add_snippet(%r, %r, %r, %r, priority=%i)" % + (sv, content, description, options, priority)) + + ft, file_data = self.snippets_test_file + self._temporary_directory = "" + if ft: + self._create_snippet_file(ft, file_data) + + if not self.interrupt: + # Enter insert mode + self.send("i") + + self.send(self.text_before) + self.send(self.text_after) + + # Go to the middle of the buffer + self.send(ESC + "ggjj") + + self._options_on() + + self.send("i") + + # Execute the command, but leave Vim some time to react. + for c in self.keys: + self.vim.send(c) + time.sleep(self.sleeptime) + + self.send(ESC) + + self._options_off() + + self.output = self.vim.get_buffer_data() + + def tearDown(self): + if self._temporary_directory: + self.vim.send(""":set runtimepath=$VIMRUNTIME,.\n""") + shutil.rmtree(self._temporary_directory) + +########################################################################### +# BEGINNING OF TEST # +########################################################################### +# Snippet Definition Parsing {{{# +class ParseSnippets_SimpleSnippet(_VimTest): + snippets_test_file = ("all", r""" + snippet testsnip "Test Snippet" b! + This is a test snippet! + endsnippet + """) + keys = "testsnip" + EX + wanted = "This is a test snippet!" + +class ParseSnippets_MissingEndSnippet(_VimTest): + snippets_test_file = ("all", r""" + snippet testsnip "Test Snippet" b! + This is a test snippet! + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = r"Missing 'endsnippet' for 'testsnip' in \S+:4" + +class ParseSnippets_UnknownDirective(_VimTest): + snippets_test_file = ("all", r""" + unknown directive + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = r"Invalid line 'unknown directive' in \S+:2" + +class ParseSnippets_InvalidPriorityLine(_VimTest): + snippets_test_file = ("all", r""" + priority - 50 + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = r"Invalid priority '- 50' in \S+:2" + +class ParseSnippets_InvalidPriorityLine1(_VimTest): + snippets_test_file = ("all", r""" + priority + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = r"Invalid priority '' in \S+:2" + +class ParseSnippets_ExtendsWithoutFiletype(_VimTest): + snippets_test_file = ("all", r""" + extends + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + expected_error = r"'extends' without file types in \S+:2" + +class ParseSnippets_ClearAll(_VimTest): + snippets_test_file = ("all", r""" + snippet testsnip "Test snippet" + This is a test. + endsnippet + + clearsnippets + """) + keys = "testsnip" + EX + wanted = "testsnip" + EX + +class ParseSnippets_ClearOne(_VimTest): + snippets_test_file = ("all", 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(_VimTest): + snippets_test_file = ("all", 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(_VimTest): + snippets_test_file = ("all", 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(_VimTest): + snippets_test_file = ("all", 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(_VimTest): + snippets_test_file = ("all", r""" + snippet "test snip" + This is a test. + endsnippet + """) + keys = "test snip" + EX + wanted = "This is a test." +class ParseSnippets_MultiWord_WithQuotes(_VimTest): + snippets_test_file = ("all", r""" + snippet !"test snip"! + This is a test. + endsnippet + """) + keys = '"test snip"' + EX + wanted = "This is a test." + +class ParseSnippets_MultiWord_NoContainer(_VimTest): + snippets_test_file = ("all", r""" + snippet test snip + This is a test. + endsnippet + """) + keys = "test snip" + EX + wanted = keys + expected_error = "Invalid multiword trigger: 'test snip' in \S+:2" + +class ParseSnippets_MultiWord_UnmatchedContainer(_VimTest): + snippets_test_file = ("all", r""" + snippet !inv snip/ + This is a test. + endsnippet + """) + keys = "inv snip" + EX + wanted = keys + expected_error = "Invalid multiword trigger: '!inv snip/' in \S+:2" + +class ParseSnippets_Global_Python(_VimTest): + snippets_test_file = ("all", r""" + global !p + def tex(ins): + return "a " + ins + " b" + endglobal + + snippet ab + x `!p snip.rv = tex("bob")` y + endsnippet + + snippet ac + x `!p snip.rv = tex("jon")` y + endsnippet + """) + keys = "ab" + EX + "\nac" + EX + wanted = "x a bob b y\nx a jon b y" + +class ParseSnippets_Global_Local_Python(_VimTest): + snippets_test_file = ("all", 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!") + +class SimpleExpand_ExceptCorrectResult(_SimpleExpands): + keys = "hallo" + EX + wanted = "Hallo Welt!" +class SimpleExpandTwice_ExceptCorrectResult(_SimpleExpands): + keys = "hallo" + EX + '\nhallo' + EX + wanted = "Hallo Welt!\nHallo Welt!" + +class SimpleExpandNewLineAndBackspae_ExceptCorrectResult(_SimpleExpands): + keys = "hallo" + EX + "\nHallo Welt!\n\n\b\b\b\b\b" + wanted = "Hallo Welt!\nHallo We" + def _options_on(self): + self.send(":set backspace=eol,start\n") + def _options_off(self): + self.send(":set backspace=\n") + +class SimpleExpandTypeAfterExpand_ExceptCorrectResult(_SimpleExpands): + keys = "hallo" + EX + "and again" + wanted = "Hallo Welt!and again" + +class SimpleExpandTypeAndDelete_ExceptCorrectResult(_SimpleExpands): + keys = "na du hallo" + EX + "and again\b\b\b\b\bblub" + wanted = "na du Hallo Welt!and blub" + +class DoNotExpandAfterSpace_ExceptCorrectResult(_SimpleExpands): + keys = "hallo " + EX + wanted = "hallo " + EX + +class ExitSnippetModeAfterTabstopZero(_VimTest): + snippets = ("test", "SimpleText") + keys = "test" + EX + EX + wanted = "SimpleText" + EX + +class ExpandInTheMiddleOfLine_ExceptCorrectResult(_SimpleExpands): + keys = "Wie hallo gehts" + ESC + "bhi" + EX + wanted = "Wie Hallo Welt! gehts" +class MultilineExpand_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "Hallo Welt!\nUnd Wie gehts") + keys = "Wie hallo gehts" + ESC + "bhi" + EX + wanted = "Wie Hallo Welt!\nUnd Wie gehts gehts" +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" + + +# 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 TabStopNoReplace_ExceptCorrectResult(_VimTest): + snippets = ("echo", "echo ${1:Hallo}") + keys = "echo" + EX + wanted = "echo Hallo" + +class TabStop_EscapingCharsBackticks(_VimTest): + snippets = ("test", r"snip \` literal") + keys = "test" + EX + wanted = "snip ` literal" +class TabStop_EscapingCharsDollars(_VimTest): + snippets = ("test", r"snip \$0 $$0 end") + keys = "test" + EX + "hi" + wanted = "snip $0 $hi end" +class TabStop_EscapingCharsDollars1(_VimTest): + snippets = ("test", r"a\${1:literal}") + keys = "test" + EX + wanted = "a${1:literal}" +class TabStop_EscapingCharsDollars_BeginningOfLine(_VimTest): + snippets = ("test", "\n\\${1:literal}") + keys = "test" + EX + wanted = "\n${1:literal}" +class TabStop_EscapingCharsDollars_BeginningOfDefinitionText(_VimTest): + snippets = ("test", "\\${1:literal}") + keys = "test" + EX + wanted = "${1:literal}" +class TabStop_EscapingChars_Backslash(_VimTest): + snippets = ("test", r"This \ is a backslash!") + keys = "test" + EX + wanted = "This \\ is a backslash!" +class TabStop_EscapingChars_Backslash2(_VimTest): + snippets = ("test", r"This is a backslash \\ done") + keys = "test" + EX + wanted = r"This is a backslash \ done" +class TabStop_EscapingChars_Backslash3(_VimTest): + snippets = ("test", r"These are two backslashes \\\\ done") + keys = "test" + EX + wanted = r"These are two backslashes \\ done" +class TabStop_EscapingChars_Backslash4(_VimTest): + # Test for bug 746446 + snippets = ("test", r"\\$1{$2}") + keys = "test" + EX + "hello" + JF + "world" + wanted = r"\hello{world}" +class TabStop_EscapingChars_RealLife(_VimTest): + snippets = ("test", r"usage: \`basename \$0\` ${1:args}") + keys = "test" + EX + "[ -u -v -d ]" + wanted = "usage: `basename $0` [ -u -v -d ]" + +class TabStopEscapingWhenSelected_ECR(_VimTest): + snippets = ("test", "snip ${1:default}") + keys = "test" + EX + ESC + "0ihi" + wanted = "hisnip default" +class TabStopEscapingWhenSelectedSingleCharTS_ECR(_VimTest): + snippets = ("test", "snip ${1:i}") + keys = "test" + EX + ESC + "0ihi" + wanted = "hisnip i" +class TabStopEscapingWhenSelectedNoCharTS_ECR(_VimTest): + snippets = ("test", "snip $1") + keys = "test" + EX + ESC + "0ihi" + wanted = "hisnip " + +class TabStopWithOneChar_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "nothing ${1:i} hups") + keys = "hallo" + EX + "ship" + wanted = "nothing ship hups" + +class TabStopTestJumping_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo ${2:End} mitte ${1:Beginning}") + keys = "hallo" + EX + JF + "Test" + JF + "Hi" + wanted = "hallo Test mitte BeginningHi" +class TabStopTestJumping2_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo $2 $1") + keys = "hallo" + EX + JF + "Test" + JF + "Hi" + wanted = "hallo Test Hi" +class TabStopTestJumpingRLExampleWithZeroTab_ExceptCorrectResult(_VimTest): + snippets = ("test", "each_byte { |${1:byte}| $0 }") + keys = "test" + EX + JF + "Blah" + wanted = "each_byte { |byte| Blah }" + +class TabStopTestJumpingDontJumpToEndIfThereIsTabZero_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo $0 $1") + keys = "hallo" + EX + "Test" + JF + "Hi" + JF + JF + "du" + wanted = "hallo Hi" + 2*JF + "du Test" + +class TabStopTestBackwardJumping_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo ${2:End} mitte${1:Beginning}") + keys = "hallo" + EX + "Somelengthy Text" + JF + "Hi" + JB + \ + "Lets replace it again" + JF + "Blah" + JF + JB*2 + JF + wanted = "hallo Blah mitteLets replace it again" + JB*2 + JF +class TabStopTestBackwardJumping2_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo $2 $1") + keys = "hallo" + EX + "Somelengthy Text" + JF + "Hi" + JB + \ + "Lets replace it again" + JF + "Blah" + JF + JB*2 + JF + wanted = "hallo Blah Lets replace it again" + JB*2 + JF + +class TabStopTestMultilineExpand_ExceptCorrectResult(_VimTest): + snippets = ("hallo", "hallo $0\nnice $1 work\n$3 $2\nSeem to work") + keys ="test hallo World" + ESC + "02f i" + EX + "world" + JF + "try" + \ + JF + "test" + JF + "one more" + JF + wanted = "test hallo one more" + JF + "\nnice world work\n" \ + "test try\nSeem to work World" + +class TabStop_TSInDefaultTextRLExample_OverwriteNone_ECR(_VimTest): + snippets = ("test", """\n $0\n""") + keys = "test" + EX + wanted = """
    \n \n
    """ +class TabStop_TSInDefaultTextRLExample_OverwriteFirst_NoJumpBack(_VimTest): + snippets = ("test", """\n $0\n""") + keys = "test" + EX + " blah" + JF + "Hallo" + wanted = """
    \n Hallo\n
    """ +class TabStop_TSInDefaultTextRLExample_DeleteFirst(_VimTest): + snippets = ("test", """\n $0\n""") + keys = "test" + EX + BS + JF + "Hallo" + wanted = """
    \n Hallo\n
    """ +class TabStop_TSInDefaultTextRLExample_OverwriteFirstJumpBack(_VimTest): + snippets = ("test", """\n $3 $0\n""") + keys = "test" + EX + "Hi" + JF + "Hallo" + JB + "SomethingElse" + JF + \ + "Nupl" + JF + "Nox" + wanted = """\n Nupl Nox\n""" +class TabStop_TSInDefaultTextRLExample_OverwriteSecond(_VimTest): + snippets = ("test", """\n $0\n""") + keys = "test" + EX + JF + "no" + JF + "End" + wanted = """
    \n End\n
    """ +class TabStop_TSInDefaultTextRLExample_OverwriteSecondTabBack(_VimTest): + snippets = ("test", """\n $3 $0\n""") + keys = "test" + EX + JF + "no" + JF + "End" + JB + "yes" + JF + "Begin" \ + + JF + "Hi" + wanted = """
    \n Begin Hi\n
    """ +class TabStop_TSInDefaultTextRLExample_OverwriteSecondTabBackTwice(_VimTest): + snippets = ("test", """\n $3 $0\n""") + keys = "test" + EX + JF + "no" + JF + "End" + JB + "yes" + JB + \ + " 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" + wanted = "hi this Hallo Ende" +class TabStop_TSInDefaultNested_OverwriteOneJumpToThird(_VimTest): + snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") + keys = "test" + EX + JF + JF + "Hallo" + JF + "Ende" + wanted = "hi this second Hallo Ende" +class TabStop_TSInDefaultNested_OverwriteOneJumpAround(_VimTest): + snippets = ("test", "hi ${1:this ${2:second ${3:third}}} $4") + keys = "test" + EX + JF + JF + "Hallo" + JB+JB + "Blah" + JF + "Ende" + wanted = "hi Blah Ende" + +class TabStop_TSInDefault_MirrorsOutside_DoNothing(_VimTest): + snippets = ("test", "hi ${1:this ${2:second}} $2") + keys = "test" + EX + wanted = "hi this second second" +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_Overwrite0(_VimTest): + snippets = ("test", "hi ${1:this ${2:second}} $2") + keys = "test" + EX + "Hallo" + wanted = "hi Hallo " +class TabStop_TSInDefault_MirrorsOutside_Overwrite1(_VimTest): + snippets = ("test", "$1: ${1:'${2:second}'} $2") + keys = "test" + EX + "Hallo" + wanted = "Hallo: Hallo " +class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond1(_VimTest): + snippets = ("test", "$1: ${1:'${2:second}'} $2") + keys = "test" + EX + JF + "Hallo" + wanted = "'Hallo': 'Hallo' Hallo" +class TabStop_TSInDefault_MirrorsOutside_OverwriteFirstSwitchNumbers(_VimTest): + snippets = ("test", "$2: ${2:'${1:second}'} $1") + keys = "test" + EX + "Hallo" + wanted = "'Hallo': 'Hallo' Hallo" +class TabStop_TSInDefault_MirrorsOutside_OverwriteFirst_RLExample(_VimTest): + snippets = ("test", """`!p snip.rv = t[1].split('/')[-1].lower().strip("'")` = require(${1:'${2:sys}'})""") + keys = "test" + EX + "WORLD" + JF + "End" + wanted = "world = require(WORLD)End" +class TabStop_TSInDefault_MirrorsOutside_OverwriteSecond_RLExample(_VimTest): + snippets = ("test", """`!p snip.rv = t[1].split('/')[-1].lower().strip("'")` = require(${1:'${2:sys}'})""") + keys = "test" + EX + JF + "WORLD" + JF + "End" + wanted = "world = require('WORLD')End" + +class TabStop_Multiline_Leave(_VimTest): + snippets = ("test", "hi ${1:first line\nsecond line} world" ) + keys = "test" + EX + wanted = "hi first line\nsecond line world" +class TabStop_Multiline_Overwrite(_VimTest): + snippets = ("test", "hi ${1:first line\nsecond line} world" ) + keys = "test" + EX + "Nothing" + wanted = "hi Nothing world" +class TabStop_Multiline_MirrorInFront_Leave(_VimTest): + snippets = ("test", "hi $1 ${1:first line\nsecond line} world" ) + keys = "test" + EX + wanted = "hi first line\nsecond line first line\nsecond line world" +class TabStop_Multiline_MirrorInFront_Overwrite(_VimTest): + snippets = ("test", "hi $1 ${1:first line\nsecond line} world" ) + keys = "test" + EX + "Nothing" + wanted = "hi Nothing Nothing world" +class TabStop_Multiline_DelFirstOverwriteSecond_Overwrite(_VimTest): + snippets = ("test", "hi $1 $2 ${1:first line\nsecond line} ${2:Hi} world" ) + keys = "test" + EX + BS + JF + "Nothing" + wanted = "hi Nothing Nothing world" + +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_if = lambda self: running_on_windows() + snippets = ("test", "hi `echo hallo` you!") + keys = "test" + EX + "and more" + wanted = "hi hallo you!and more" +class TabStop_Shell_WithUmlauts(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = ("test", "hi `echo höüäh` you!") + keys = "test" + EX + "and more" + wanted = "hi höüäh you!and more" +class TabStop_Shell_TextInNextLine(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = ("test", "hi `echo hallo`\nWeiter") + keys = "test" + EX + "and more" + wanted = "hi hallo\nWeiterand more" +class TabStop_Shell_InDefValue_Leave(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = ("test", "Hallo ${1:now `echo fromecho`} end") + keys = "test" + EX + JF + "and more" + wanted = "Hallo now fromecho endand more" +class TabStop_Shell_InDefValue_Overwrite(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = ("test", "Hallo ${1:now `echo fromecho`} end") + keys = "test" + EX + "overwrite" + JF + "and more" + wanted = "Hallo overwrite endand more" +class TabStop_Shell_TestEscapedChars_Overwrite(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = ("test", r"""`echo \`echo "\\$hi"\``""") + keys = "test" + EX + wanted = "$hi" +class TabStop_Shell_TestEscapedCharsAndShellVars_Overwrite(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = ("test", r"""`hi="blah"; echo \`echo "$hi"\``""") + keys = "test" + EX + wanted = "blah" + +class TabStop_Shell_ShebangPython(_VimTest): + skip_if = lambda self: running_on_windows() + 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" +# 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 + wanted = "hi Hallo End" +class PythonCodeOld_ReferencePlaceholderAfter(_VimTest): + snippets = ("test", """${1:hi} `!p res = t[1]+".blah"` End""") + keys = "test" + EX + "ho" + wanted = "ho ho.blah End" +class PythonCodeOld_ReferencePlaceholderBefore(_VimTest): + snippets = ("test", """`!p res = len(t[1])*"#"`\n${1:some text}""") + keys = "test" + EX + "Hallo Welt" + wanted = "##########\nHallo Welt" +class PythonCodeOld_TransformedBeforeMultiLine(_VimTest): + snippets = ("test", """${1/.+/egal/m} ${1:`!p +res = "Hallo"`} End""") + keys = "test" + EX + wanted = "egal Hallo End" +class PythonCodeOld_IndentedMultiline(_VimTest): + snippets = ("test", """start `!p a = 1 +b = 2 +if b > a: + res = "b isbigger a" +else: + res = "a isbigger b"` end""") + keys = " test" + EX + wanted = " start b isbigger a end" +# End: Deprecated Implementation #}}} +# New Implementation {{{# +class PythonCode_UseNewOverOld(_VimTest): + snippets = ("test", """hi `!p res = "Old" +snip.rv = "New"` End""") + keys = "test" + EX + wanted = "hi New End" + +class PythonCode_SimpleExample(_VimTest): + snippets = ("test", """hi `!p snip.rv = "Hallo"` End""") + keys = "test" + EX + wanted = "hi Hallo End" + +class PythonCode_SimpleExample_ReturnValueIsEmptyString(_VimTest): + snippets = ("test", """hi`!p snip.rv = ""`End""") + keys = "test" + EX + wanted = "hiEnd" + +class PythonCode_ReferencePlaceholder(_VimTest): + snippets = ("test", """${1:hi} `!p snip.rv = t[1]+".blah"` End""") + keys = "test" + EX + "ho" + wanted = "ho ho.blah End" + +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 +if b > a: + snip.rv = "b isbigger a" +else: + snip.rv = "a isbigger b"` end""") + keys = " test" + EX + wanted = " start b isbigger a end" + +class PythonCode_SimpleAppend(_VimTest): + snippets = ("test", """hi `!p snip.rv = "Hallo1" +snip += "Hallo2"` End""") + keys = "test" + EX + wanted = "hi Hallo1\nHallo2 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" +snip += "Hallo2" +snip += "Hallo3"` +End""") + keys = """ + test""" + EX + wanted = """ + hi + Hallo1 + Hallo2 + Hallo3 + End""" + +class PythonCode_SimpleMkline(_VimTest): + snippets = ("test", r"""hi +`!p snip.rv="Hallo1\n" +snip.rv += snip.mkline("Hallo2") + "\n" +snip.rv += snip.mkline("Hallo3")` +End""") + keys = """ + test""" + EX + wanted = """ + hi + Hallo1 + Hallo2 + Hallo3 + End""" + +class PythonCode_MultiAppendShift(_VimTest): + snippets = ("test", r"""hi +`!p snip.rv="i1" +snip += "i1" +snip >> 1 +snip += "i2" +snip << 2 +snip += "i0" +snip >> 3 +snip += "i3"` +End""") + keys = """ + test""" + EX + wanted = """ + hi + i1 + i1 + i2 +i0 + i3 + End""" + +class PythonCode_MultiAppendShiftMethods(_VimTest): + snippets = ("test", 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")` +End""") + keys = """ + test""" + EX + wanted = """ + hi + i1 + i1 + i2 +i0 + i3 + End""" + + +class PythonCode_ResetIndent(_VimTest): + snippets = ("test", r"""hi +`!p snip.rv="i1" +snip >> 1 +snip += "i2" +snip.reset_indent() +snip += "i1" +snip << 1 +snip += "i0" +snip.reset_indent() +snip += "i1"` +End""") + keys = """ + test""" + EX + wanted = """ + hi + i1 + i2 + i1 +i0 + i1 + End""" + +class PythonCode_IndentEtSw(_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") + snippets = ("test", r"""hi +`!p snip.rv = "i1" +snip >> 1 +snip += "i2" +snip << 2 +snip += "i0" +snip >> 1 +snip += "i1" +` +End""") + keys = """ test""" + EX + wanted = """ hi + i1 + i2 +i0 + i1 + End""" + +class PythonCode_IndentEtSwOffset(_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") + snippets = ("test", r"""hi +`!p snip.rv = "i1" +snip >> 1 +snip += "i2" +snip << 2 +snip += "i0" +snip >> 1 +snip += "i1" +` +End""") + keys = """ test""" + EX + wanted = """ hi + i1 + i2 + i0 + i1 + End""" + +class PythonCode_IndentNoetSwTs(_VimTest): + def _options_on(self): + self.send(":set sw=3\n") + self.send(":set ts=4\n") + def _options_off(self): + self.send(":set sw=8\n") + self.send(":set ts=8\n") + snippets = ("test", r"""hi +`!p snip.rv = "i1" +snip >> 1 +snip += "i2" +snip << 2 +snip += "i0" +snip >> 1 +snip += "i1" +` +End""") + keys = """ test""" + EX + wanted = """ hi + i1 +\t i2 +i0 + i1 + End""" + +# Test using 'opt' +class PythonCode_OptExists(_VimTest): + def _options_on(self): + self.send(':let g:UStest="yes"\n') + def _options_off(self): + self.send(":unlet g:UStest\n") + snippets = ("test", r"""hi `!p snip.rv = snip.opt("g:UStest") or "no"` End""") + keys = """test""" + EX + wanted = """hi yes End""" + +class PythonCode_OptNoExists(_VimTest): + snippets = ("test", r"""hi `!p snip.rv = snip.opt("g:UStest") or "no"` End""") + keys = """test""" + EX + wanted = """hi no End""" + +class PythonCode_IndentProblem(_VimTest): + # A test case which is likely related to bug 719649 + snippets = ("test", r"""hi `!p +snip.rv = "World" +` End""") + 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" +snip.rv = "nothing"` `!p snip.rv = a +` End""") + 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 + "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 + "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" + +# Tests for https://bugs.launchpad.net/bugs/1259349 +class Python_WeirdScoping_Error(_VimTest): + snippets = ("test", "h`!p import re; snip.rv = '%i' % len([re.search for i in 'aiiia'])`b") + keys = "test" + EX + wanted = "h5b" +# 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" + +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 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" + +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_SimpleCaseAsciiResult(_VimTest): + skip_if = lambda self: no_unidecode_available() + snippets = ("ascii", "$1 ${1/(.*)/$1/a}") + keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€" + wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoiEEACOIEU" +class Transformation_LowerCaseAsciiResult(_VimTest): + skip_if = lambda self: no_unidecode_available() + snippets = ("ascii", "$1 ${1/(.*)/\L$1\E/a}") + keys = "ascii" + EX + "éèàçôïÉÈÀÇÔÏ€" + wanted = "éèàçôïÉÈÀÇÔÏ€ eeacoieeacoieu" + +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 Visual_LineSelect_DedentLine(_VimTest): + snippets = ("if", "if {\n\t${VISUAL}$0\n}") + keys = "if" + EX + "one\n\ttwo\n\tthree" + ESC + ARR_U*2 + "V" + ARR_D + EX + "\tif" + EX + wanted = "if {\n\tif {\n\t\tone\n\t\ttwo\n\t}\n\tthree\n}" + +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" +class RecTabStops_SimpleCaseLeaveFirstSecond_ExceptCorrectResult(_VimTest): + snippets = ("m", "[ ${1:first} ${2:sec} ]") + keys = "m" + EX + "m" + EX + "hello" + JF + JF + JF + "world" + JF + "end" + wanted = "[ [ hello sec ] world ]end" + +class RecTabStops_InnerWOTabStop_ECR(_VimTest): + snippets = ( + ("m1", "Just some Text"), + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m1" + EX + "hi" + JF + "two" + JF + "end" + wanted = "[ Just some Texthi two ]end" +class RecTabStops_InnerWOTabStopTwiceDirectly_ECR(_VimTest): + snippets = ( + ("m1", "JST"), + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m1" + EX + " m1" + EX + "hi" + JF + "two" + JF + "end" + wanted = "[ JST JSThi two ]end" +class RecTabStops_InnerWOTabStopTwice_ECR(_VimTest): + snippets = ( + ("m1", "JST"), + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m1" + EX + JF + "m1" + EX + "hi" + JF + "end" + wanted = "[ JST JSThi ]end" +class RecTabStops_OuterOnlyWithZeroTS_ECR(_VimTest): + snippets = ( + ("m", "A $0 B"), + ("m1", "C $1 D $0 E"), + ) + keys = "m" + EX + "m1" + EX + "CD" + JF + "DE" + wanted = "A C CD D DE E B" +class RecTabStops_OuterOnlyWithZero_ECR(_VimTest): + snippets = ( + ("m", "A $0 B"), + ("m1", "C $1 D $0 E"), + ) + keys = "m" + EX + "m1" + EX + "CD" + JF + "DE" + wanted = "A C CD D DE E B" +class RecTabStops_ExpandedInZeroTS_ECR(_VimTest): + snippets = ( + ("m", "A $0 B $1"), + ("m1", "C $1 D $0 E"), + ) + keys = "m" + EX + "hi" + JF + "m1" + EX + "CD" + JF + "DE" + wanted = "A C CD D DE E B hi" +class RecTabStops_ExpandedInZeroTSTwice_ECR(_VimTest): + snippets = ( + ("m", "A $0 B $1"), + ("m1", "C $1 D $0 E"), + ) + keys = "m" + EX + "hi" + JF + "m" + EX + "again" + JF + "m1" + \ + EX + "CD" + JF + "DE" + wanted = "A A C CD D DE E B again B hi" +class RecTabStops_ExpandedInZeroTSSecondTime_ECR(_VimTest): + snippets = ( + ("m", "A $0 B $1"), + ("m1", "C $1 D $0 E"), + ) + keys = "m" + EX + "hi" + JF + "m" + EX + "m1" + EX + "CD" + JF + "DE" + JF + "AB" + wanted = "A A AB B C CD D DE E B hi" +class RecTabsStops_TypeInZero_ECR(_VimTest): + snippets = ( + ("v", r"\vec{$1}", "Vector", "w"), + ("frac", r"\frac{${1:one}}${0:zero}{${2:two}}", "Fractio", "w"), + ) + keys = "v" + EX + "frac" + EX + "a" + JF + "b" + JF + "frac" + EX + "aa" + JF + JF + "cc" + JF + \ + "hello frac" + EX + JF + JF + "world" + wanted = r"\vec{\frac{a}\frac{aa}cc{two}{b}}hello \frac{one}world{two}" +class RecTabsStops_TypeInZero2_ECR(_VimTest): + snippets = ( + ("m", r"_${0:explicit zero}", "snip", "i"), + ) + keys = "m" + EX + "hello m" + EX + "world m" + EX + "end" + wanted = r"_hello _world _end" +class RecTabsStops_BackspaceZero_ECR(_VimTest): + snippets = ( + ("m", r"${1:one}${0:explicit zero}${2:two}", "snip", "i"), + ) + keys = "m" + EX + JF + JF + BS + "m" + EX + wanted = r"oneoneexplicit zerotwotwo" + + +class RecTabStops_MirrorInnerSnippet_ECR(_VimTest): + snippets = ( + ("m", "[ $1 $2 ] $1"), + ("m1", "ASnip $1 ASnip $2 ASnip"), + ) + keys = "m" + EX + "m1" + EX + "Hallo" + JF + "Hi" + JF + "endone" + JF + "two" + JF + "totalend" + wanted = "[ ASnip Hallo ASnip Hi ASnipendone two ] ASnip Hallo ASnip Hi ASnipendonetotalend" + +class RecTabStops_NotAtBeginningOfTS_ExceptCorrectResult(_VimTest): + snippets = ("m", "[ ${1:first} ${2:sec} ]") + keys = "m" + EX + "hello m" + EX + "hi" + JF + "two" + JF + "ups" + JF + "three" + \ + JF + "end" + wanted = "[ hello [ hi two ]ups three ]end" +class RecTabStops_InNewlineInTabstop_ExceptCorrectResult(_VimTest): + snippets = ("m", "[ ${1:first} ${2:sec} ]") + keys = "m" + EX + "hello\nm" + EX + "hi" + JF + "two" + JF + "ups" + JF + "three" + \ + JF + "end" + wanted = "[ hello\n[ hi two ]ups three ]end" +class RecTabStops_InNewlineInTabstopNotAtBeginOfLine_ECR(_VimTest): + snippets = ("m", "[ ${1:first} ${2:sec} ]") + keys = "m" + EX + "hello\nhello again m" + EX + "hi" + JF + "two" + \ + JF + "ups" + JF + "three" + JF + "end" + wanted = "[ hello\nhello again [ hi two ]ups three ]end" + +class RecTabStops_InNewlineMultiline_ECR(_VimTest): + snippets = ("m", "M START\n$0\nM END") + keys = "m" + EX + "m" + EX + wanted = "M START\nM START\n\nM END\nM END" +class RecTabStops_InNewlineManualIndent_ECR(_VimTest): + snippets = ("m", "M START\n$0\nM END") + keys = "m" + EX + " m" + EX + "hi" + wanted = "M START\n M START\n hi\n M END\nM END" +class RecTabStops_InNewlineManualIndentTextInFront_ECR(_VimTest): + snippets = ("m", "M START\n$0\nM END") + keys = "m" + EX + " hallo m" + EX + "hi" + wanted = "M START\n hallo M START\n hi\n M END\nM END" +class RecTabStops_InNewlineMultilineWithIndent_ECR(_VimTest): + snippets = ("m", "M START\n $0\nM END") + keys = "m" + EX + "m" + EX + "hi" + wanted = "M START\n M START\n hi\n M END\nM END" +class RecTabStops_InNewlineMultilineWithNonZeroTS_ECR(_VimTest): + snippets = ("m", "M START\n $1\nM END -> $0") + keys = "m" + EX + "m" + EX + "hi" + JF + "hallo" + JF + "end" + wanted = "M START\n M START\n hi\n M END -> hallo\n" \ + "M END -> end" + +class RecTabStops_BarelyNotLeavingInner_ECR(_VimTest): + snippets = ( + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m" + EX + "a" + 3*ARR_L + JF + "hallo" + \ + JF + "ups" + JF + "world" + JF + "end" + wanted = "[ [ a hallo ]ups world ]end" +class RecTabStops_LeavingInner_ECR(_VimTest): + snippets = ( + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m" + EX + "a" + 4*ARR_L + JF + "hallo" + \ + JF + "world" + wanted = "[ [ a sec ] hallo ]world" +class RecTabStops_LeavingInnerInner_ECR(_VimTest): + snippets = ( + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m" + EX + "m" + EX + "a" + 4*ARR_L + JF + "hallo" + \ + JF + "ups" + JF + "world" + JF + "end" + wanted = "[ [ [ a sec ] hallo ]ups world ]end" +class RecTabStops_LeavingInnerInnerTwo_ECR(_VimTest): + snippets = ( + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m" + EX + "m" + EX + "a" + 6*ARR_L + JF + "hallo" + \ + JF + "end" + wanted = "[ [ [ a sec ] sec ] hallo ]end" + + +class RecTabStops_ZeroTSisNothingSpecial_ECR(_VimTest): + snippets = ( + ("m1", "[ ${1:first} $0 ${2:sec} ]"), + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m1" + EX + "one" + JF + "two" + \ + JF + "three" + JF + "four" + JF + "end" + wanted = "[ [ one three two ] four ]end" +class RecTabStops_MirroredZeroTS_ECR(_VimTest): + snippets = ( + ("m1", "[ ${1:first} ${0:Year, some default text} $0 ${2:sec} ]"), + ("m", "[ ${1:first} ${2:sec} ]"), + ) + keys = "m" + EX + "m1" + EX + "one" + JF + "two" + \ + JF + "three" + JF + "four" + JF + "end" + wanted = "[ [ one three three two ] four ]end" +class RecTabStops_ChildTriggerContainsParentTextObjects(_VimTest): + # https://bugs.launchpad.net/bugs/1191617 + snippets_test_file = ("all", r""" +global !p +def complete(t, opts): + if t: + opts = [ q[len(t):] for q in opts if q.startswith(t) ] + if len(opts) == 0: + return '' + return opts[0] if len(opts) == 1 else "(" + '|'.join(opts) + ')' +def autocomplete_options(t, string, attr=None): + return complete(t[1], [opt for opt in attr if opt not in string]) +endglobal +snippet /form_for(.*){([^|]*)/ "form_for html options" rw! +`!p +auto = autocomplete_options(t, match.group(2), attr=["id: ", "class: ", "title: "]) +snip.rv = "form_for" + match.group(1) + "{"`$1`!p if (snip.c != auto) : snip.rv=auto` +endsnippet +""") + keys = "form_for user, namespace: some_namespace, html: {i" + EX + "i" + EX + wanted = "form_for user, namespace: some_namespace, html: {(id: |class: |title: )d: " +# End: Recursive (Nested) Snippets #}}} +# List 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_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 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 = ( + ("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 Priority {{{# +class SnippetPriorities_MultiWordTriggerOverwriteExisting(_VimTest): + snippets = ( + ("test me", "${1:Hallo}", "Types Hallo"), + ("test me", "${1:World}", "Types World"), + ("test me", "We overwrite", "Overwrite the two", "", 1), + ) + keys = "test me" + EX + wanted = "We overwrite" +class SnippetPriorities_DoNotCareAboutNonMatchings(_VimTest): + snippets = ( + ("test1", "Hallo", "Types Hallo"), + ("test2", "We overwrite", "Overwrite the two", "", 1), + ) + keys = "test1" + EX + wanted = "Hallo" +class SnippetPriorities_OverwriteExisting(_VimTest): + snippets = ( + ("test", "${1:Hallo}", "Types Hallo"), + ("test", "${1:World}", "Types World"), + ("test", "We overwrite", "Overwrite the two", "", 1), + ) + keys = "test" + EX + wanted = "We overwrite" +class SnippetPriorities_OverwriteTwice_ECR(_VimTest): + snippets = ( + ("test", "${1:Hallo}", "Types Hallo"), + ("test", "${1:World}", "Types World"), + ("test", "We overwrite", "Overwrite the two", "", 1), + ("test", "again", "Overwrite again", "", 2), + ) + keys = "test" + EX + wanted = "again" +class SnippetPriorities_OverwriteThenChoose_ECR(_VimTest): + snippets = ( + ("test", "${1:Hallo}", "Types Hallo"), + ("test", "${1:World}", "Types World"), + ("test", "We overwrite", "Overwrite the two", "", 1), + ("test", "No overwrite", "Not overwritten", "", 1), + ) + keys = "test" + EX + "1\n\n" + "test" + EX + "2\n" + wanted = "We overwrite\nNo overwrite" +class SnippetPriorities_AddedHasHigherThanFile(_VimTest): + snippets_test_file = ("all", r""" + snippet test "Test Snippet" b + This is a test snippet + endsnippet + """) + snippets = ( + ("test", "We overwrite", "Overwrite the two", "", 1), + ) + keys = "test" + EX + wanted = "We overwrite" +class SnippetPriorities_FileHasHigherThanAdded(_VimTest): + snippets_test_file = ("all", r""" + snippet test "Test Snippet" b + This is a test snippet + endsnippet + """) + snippets = ( + ("test", "We do not overwrite", "Overwrite the two", "", -1), + ) + keys = "test" + EX + wanted = "This is a test snippet" +class SnippetPriorities_FileHasHigherThanAdded(_VimTest): + snippets_test_file = ("all", r""" + priority -3 + snippet test "Test Snippet" b + This is a test snippet + endsnippet + """) + snippets = ( + ("test", "We overwrite", "Overwrite the two", "", -5), + ) + keys = "test" + EX + wanted = "This is a test snippet" +# End: Snippet Priority #}}} + + +# Snippet Options {{{# +class SnippetOptions_OnlyExpandWhenWSInFront_Expand(_VimTest): + snippets = ("test", "Expand me!", "", "b") + keys = "test" + EX + wanted = "Expand me!" +class SnippetOptions_OnlyExpandWhenWSInFront_Expand2(_VimTest): + snippets = ("test", "Expand me!", "", "b") + keys = " test" + EX + wanted = " Expand me!" +class SnippetOptions_OnlyExpandWhenWSInFront_DontExpand(_VimTest): + snippets = ("test", "Expand me!", "", "b") + keys = "a test" + EX + wanted = "a test" + EX +class SnippetOptions_OnlyExpandWhenWSInFront_OneWithOneWO(_VimTest): + snippets = ( + ("test", "Expand me!", "", "b"), + ("test", "not at beginning", "", ""), + ) + keys = "a test" + EX + wanted = "a not at beginning" +class SnippetOptions_OnlyExpandWhenWSInFront_OneWithOneWOChoose(_VimTest): + snippets = ( + ("test", "Expand me!", "", "b"), + ("test", "not at beginning", "", ""), + ) + keys = " test" + EX + "1\n" + wanted = " Expand me!" + + +class SnippetOptions_ExpandInwordSnippets_SimpleExpand(_VimTest): + snippets = (("test", "Expand me!", "", "i"), ) + keys = "atest" + EX + wanted = "aExpand me!" +class SnippetOptions_ExpandInwordSnippets_ExpandSingle(_VimTest): + snippets = (("test", "Expand me!", "", "i"), ) + keys = "test" + EX + wanted = "Expand me!" +class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand(_VimTest): + snippets = (("test", "Expand me!", "", "i"), ) + keys = "$test" + EX + wanted = "$Expand me!" +class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand2(_VimTest): + snippets = (("test", "Expand me!", "", "i"), ) + keys = "-test" + EX + wanted = "-Expand me!" +class SnippetOptions_ExpandInwordSnippetsWithOtherChars_Expand3(_VimTest): + skip_if = lambda self: running_on_windows() + snippets = (("test", "Expand me!", "", "i"), ) + keys = "ßßtest" + EX + wanted = "ßßExpand me!" + +class _SnippetOptions_ExpandWordSnippets(_VimTest): + snippets = (("test", "Expand me!", "", "w"), ) +class SnippetOptions_ExpandWordSnippets_NormalExpand( + _SnippetOptions_ExpandWordSnippets): + keys = "test" + EX + wanted = "Expand me!" +class SnippetOptions_ExpandWordSnippets_NoExpand( + _SnippetOptions_ExpandWordSnippets): + keys = "atest" + EX + wanted = "atest" + EX +class SnippetOptions_ExpandWordSnippets_ExpandSuffix( + _SnippetOptions_ExpandWordSnippets): + keys = "a-test" + EX + wanted = "a-Expand me!" +class SnippetOptions_ExpandWordSnippets_ExpandSuffix2( + _SnippetOptions_ExpandWordSnippets): + keys = "a(test" + EX + wanted = "a(Expand me!" +class SnippetOptions_ExpandWordSnippets_ExpandSuffix3( + _SnippetOptions_ExpandWordSnippets): + keys = "[[test" + EX + wanted = "[[Expand me!" + +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") + self.send(":set sts=3\n") + def _options_off(self): + self.send(":set sw=8\n") + 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") + self.send(":set expandtab\n") + def _options_off(self): + self.send(":set sw=8\n") + 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") + self.send(":set expandtab\n") + def _options_off(self): + self.send(":set sw=8\n") + 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") + self.send(":set expandtab\n") + def _options_off(self): + self.send(":set sw=8\n") + 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") + self.send(":set sts=3\n") + self.send(":set ts=3\n") + self.send(":set expandtab\n") + def _options_off(self): + self.send(":set sw=8\n") + self.send(":set ts=8\n") + self.send(":set sts=0\n") + self.send(":set noexpandtab\n") + 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""" + + +class SnippetOptions_Regex_Expand(_VimTest): + snippets = ("(test)", "Expand me!", "", "r") + keys = "test" + EX + wanted = "Expand me!" +class SnippetOptions_Regex_Multiple(_VimTest): + snippets = ("(test *)+", "Expand me!", "", "r") + keys = "test test test" + EX + wanted = "Expand me!" + +class _Regex_Self(_VimTest): + snippets = ("((?<=\W)|^)(\.)", "self.", "", "r") +class SnippetOptions_Regex_Self_Start(_Regex_Self): + keys = "." + EX + wanted = "self." +class SnippetOptions_Regex_Self_Space(_Regex_Self): + keys = " ." + EX + wanted = " self." +class SnippetOptions_Regex_Self_TextAfter(_Regex_Self): + keys = " .a" + EX + wanted = " .a" + EX +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) +snip.rv += m.group(1) +`""", "", "r") + keys = "test cabfed" + EX + wanted = "test fedcab" +class SnippetOptions_Regex_PythonBlockNoMatch(_VimTest): + snippets = (r"cabfed", r"""`!p snip.rv = 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 MultiWordSnippet_Simple(_VimTest): + snippets = ("test me", "Expand me!") + keys = "test me" + EX + wanted = "Expand me!" +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!" +# Snippet Options #}}} + +# Anonymous Expansion {{{# +class _AnonBase(_VimTest): + args = "" + def _options_on(self): + self.send(":inoremap " + EA + ' =UltiSnips#Anon(' + + self.args + ')\n') + def _options_off(self): + self.send(":iunmap " + EA + '\n') + +class Anon_NoTrigger_Simple(_AnonBase): + args = '"simple expand"' + keys = "abc" + EA + wanted = "abcsimple expand" + +class Anon_NoTrigger_AfterSpace(_AnonBase): + args = '"simple expand"' + keys = "abc " + EA + wanted = "abc simple expand" + +class Anon_NoTrigger_BeginningOfLine(_AnonBase): + args = r"':latex:\`$1\`$0'" + keys = EA + "Hello" + JF + "World" + wanted = ":latex:`Hello`World" +class Anon_NoTrigger_FirstCharOfLine(_AnonBase): + args = r"':latex:\`$1\`$0'" + keys = " " + EA + "Hello" + JF + "World" + wanted = " :latex:`Hello`World" + +class Anon_NoTrigger_Multi(_AnonBase): + args = '"simple $1 expand $1 $0"' + keys = "abc" + EA + "123" + JF + "456" + wanted = "abcsimple 123 expand 123 456" + +class Anon_Trigger_Multi(_AnonBase): + args = '"simple $1 expand $1 $0", "abc"' + keys = "123 abc" + EA + "123" + JF + "456" + wanted = "123 simple 123 expand 123 456" + +class Anon_Trigger_Simple(_AnonBase): + args = '"simple expand", "abc"' + keys = "abc" + EA + wanted = "simple expand" + +class Anon_Trigger_Twice(_AnonBase): + args = '"simple expand", "abc"' + keys = "abc" + EA + "\nabc" + EX + wanted = "simple expand\nabc" + EX + +class Anon_Trigger_Opts(_AnonBase): + args = '"simple expand", ".*abc", "desc", "r"' + keys = "blah blah abc" + EA + wanted = "simple expand" +# End: Anonymous Expansion #}}} +# AddSnippet Function {{{# +class _AddFuncBase(_VimTest): + args = "" + def _options_on(self): + self.send(":call UltiSnips#AddSnippetWithPriority(" + + self.args + ')\n') + +class AddFunc_Simple(_AddFuncBase): + args = '"test", "simple expand", "desc", "", "all", 0' + keys = "abc test" + EX + wanted = "abc simple expand" + +class AddFunc_Opt(_AddFuncBase): + args = '".*test", "simple expand", "desc", "r", "all", 0' + keys = "abc test" + EX + wanted = "simple expand" +# End: AddSnippet Function #}}} + +# 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 RecTabStopsWithExpandtab_SimpleExample_ECR(_ExpandTabs): + snippets = ("m", "\tBlaahblah \t\t ") + keys = "m" + EX + wanted = " Blaahblah \t\t " + +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_if = lambda self: running_on_windows() + 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") +# Test for bug 1073816 +class ProperIndenting_FirstLineInFile_ECR(_VimTest): + text_before = "" + text_after = "" + snippets_test_file = ("all", r""" +global !p +def complete(t, opts): + if t: + opts = [ m[len(t):] for m in opts if m.startswith(t) ] + if len(opts) == 1: + return opts[0] + elif len(opts) > 1: + return "(" + "|".join(opts) + ")" + else: + return "" +endglobal + +snippet '^#?inc' "#include <>" !r +#include <$1`!p snip.rv = complete(t[1], ['cassert', 'cstdio', 'cstdlib', 'cstring', 'fstream', 'iostream', 'sstream'])`> +endsnippet + """) + keys = "inc" + EX + "foo" + wanted = "#include " +class ProperIndenting_FirstLineInFileComplete_ECR(ProperIndenting_FirstLineInFile_ECR): + keys = "inc" + EX + "cstdl" + wanted = "#include " +# 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 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" + + +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""" + + +# Tests for https://bugs.launchpad.net/bugs/719998 +class FOTextAfter_ExceptCorrectResult(_FormatoptionsBase): + 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): + 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} +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=dj,rk,nl,ln,jd,kr,DJ,RK,NL,LN,JD,KR\n") + def _options_off(self): + self.send(":set langmap=\n") + +# Test for https://bugs.launchpad.net/bugs/501727 # +class TestNonEmptyLangmapWithSemi_ExceptCorrectResult(_VimTest): + snippets = ("testme", +"""my snipped ${1:some_default} +and a mirror: $1 +$2...$3 +$0""") + keys = "testme" + EX + "hi;" + JF + "hi2" + JF + "hi3" + JF + "hi4" + ESC + ";Hello" + wanted ="""my snipped hi; +and a mirror: hi; +hi2...hi3 +hi4Hello""" + + def _options_on(self): + self.send(":set langmap=\\\\;;A\n") + def _options_off(self): + self.send(":set langmap=\n") + +# Test for bug 871357 # +class TestLangmapWithUtf8_ExceptCorrectResult(_VimTest): + skip_if = lambda self: running_on_windows() # 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 }}}" + +class PerlSyntaxFold(_VimTest): + def _options_on(self): + self.send(":set foldlevel=0\n") + self.send(":syntax enable\n") + self.send(":set foldmethod=syntax\n") + self.send(":let g:perl_fold = 1\n") + self.send(":so $VIMRUNTIME/syntax/perl.vim\n") + def _options_off(self): + self.send(":set foldmethod=manual\n") + self.send(":syntax clear\n") + + snippets = ("test", r"""package ${1:`!v printf('c%02d', 3)`}; +${0} +1;""") + keys = "test" + EX + JF + "sub junk {}" + wanted = "package c03;\nsub junk {}\n1;" +# End: Folding Interaction #}}} +# Trailing whitespace {{{# +class RemoveTrailingWhitespace(_VimTest): + snippets = ("test", """Hello\t ${1:default}\n$2""", "", "s") + wanted = """Hello\nGoodbye""" + keys = "test" + EX + BS + JF + "Goodbye" +class LeaveTrailingWhitespace(_VimTest): + snippets = ("test", """Hello \t ${1:default}\n$2""") + wanted = """Hello \t \nGoodbye""" + keys = "test" + EX + BS + JF + "Goodbye" +# End: Trailing whitespace #}}} + +# 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" + +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" +# 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: +}<-behind1 +$2<-behind2""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj<-behind1 +k<-behind2""" + +class TrailingNewline_TabStop_JustNL(_VimTest): + snippets = ("test", r""" +x${1: +} +$2""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj +k""" + +class TrailingNewline_TabStop_EndNL(_VimTest): + snippets = ("test", r""" +x${1:a +} +$2""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj +k""" + +class TrailingNewline_TabStop_StartNL(_VimTest): + snippets = ("test", r""" +x${1: +a} +$2""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj +k""" + +class TrailingNewline_TabStop_EndStartNL(_VimTest): + snippets = ("test", r""" +x${1: +a +} +$2""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj +k""" + +class TrailingNewline_TabStop_NotEndStartNL(_VimTest): + snippets = ("test", r""" +x${1:a +a} +$2""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj +k""" + +class TrailingNewline_TabStop_ExtraNL_ECR(_VimTest): + snippets = ("test", r""" +x${1:a +a} +$2 +""") + keys = "test" + EX + "j" + JF + "k" + wanted = """ +xj +k +""" + +class _MultiLineDefault(_VimTest): + snippets = ("test", r""" +x${1:a +b +c +d +e +f} +$2""") + +class MultiLineDefault_Jump(_MultiLineDefault): + keys = "test" + EX + JF + "y" + wanted = """ +xa +b +c +d +e +f +y""" + +class MultiLineDefault_Type(_MultiLineDefault): + keys = "test" + EX + "z" + JF + "y" + wanted = """ +xz +y""" + +class MultiLineDefault_BS(_MultiLineDefault): + keys = "test" + EX + BS + JF + "y" + wanted = """ +x +y""" + + + +# 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 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_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_if = lambda self: running_on_windows() # SendKeys can't send UTF characters + +class Snippet_With_Umlauts_List(_UmlautsBase): + snippets = _snip_quote('ü') + keys = 'te' + LS + "2\n" + wanted = "Expand meü!" + +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 #}}} + +# 1251994 {{{# +# Test for bug #1251994 +class Bug1251994(_VimTest): + snippets = ("test", "${2:#2} ${1:#1};$0") + keys = " test" + EX + "hello" + JF + "world" + JF + "blub" + wanted = " world hello;blub" +# End: 1251994 #}}} + +# Test for Github Pull Request #134 - Retain unnamed register {{{# +class RetainsTheUnnamedRegister(_VimTest): + snippets = ("test", "${1:hello} ${2:world} ${0}") + keys = "yank" + ESC + "by4lea test" + EX + "HELLO" + JF + JF + ESC + "p" + wanted = "yank HELLO world yank" +class RetainsTheUnnamedRegister_ButOnlyOnce(_VimTest): + snippets = ("test", "${1:hello} ${2:world} ${0}") + keys = "blahfasel" + ESC + "v" + 4*ARR_L + "xotest" + EX + ESC + ARR_U + "v0xo" + ESC + "p" + wanted = "\nblah\nhello world " +# End: Github Pull Request # 134 #}}} + +class VerifyVimDict1(_VimTest): + """check: + correct type (4 means vim dictionary) + correct length of dictionary (in this case we have on element if the use same prefix, dictionary should have 1 element) + correct description (including the apostrophe) + if the prefix is mismatched no resulting dict should have 0 elements + """ + + snippets = ('testâ', 'abc123ά', '123\'êabc') + keys = ('test=(type(UltiSnips#SnippetsInCurrentScope()) . len(UltiSnips#SnippetsInCurrentScope()) . ' + + 'UltiSnips#SnippetsInCurrentScope()["testâ"]' + ')\n' + + '=len(UltiSnips#SnippetsInCurrentScope())\n') + + wanted = 'test41123\'êabc0' + +class VerifyVimDict2(_VimTest): + """check: + can use " in trigger + """ + + snippets = ('te"stâ', 'abc123ά', '123êabc') + akey = "'te{}stâ'".format('"') + keys = ('te"=(UltiSnips#SnippetsInCurrentScope()[{}]'.format(akey) + ')\n') + wanted = 'te"123êabc' + +class VerifyVimDict3(_VimTest): + """check: + can use ' in trigger + """ + + snippets = ("te'stâ", 'abc123ά', '123êabc') + akey = '"te{}stâ"'.format("'") + keys = ("te'=(UltiSnips#SnippetsInCurrentScope()[{}]".format(akey) + ')\n') + wanted = "te'123êabc" + +########################################################################### +# END OF TEST # +########################################################################### + + +if __name__ == '__main__': + import sys + import optparse + + def parse_args(): + p = optparse.OptionParser("%prog [OPTIONS] ") + + p.set_defaults(session="vim", interrupt=False, + verbose=False, interface="screen", retries=4) + + p.add_option("-v", "--verbose", dest="verbose", action="store_true", + help="print name of tests as they are executed") + p.add_option("--interface", type=str, + help="interface to vim to use on Mac and or Linux [screen|tmux].") + p.add_option("-s", "--session", dest="session", metavar="SESSION", + help="session parameters for the terminal multiplexer SESSION [%default]") + p.add_option("-i", "--interrupt", dest="interrupt", + action="store_true", + help="Stop after defining the snippet. This allows the user " \ + "to interactively test the snippet in vim. You must give " \ + "exactly one test case on the cmdline. The test will always fail." + ) + p.add_option("-r", "--retries", dest="retries", type=int, + help="How often should each test be retried before it is " + "considered failed. Works around flakyness in the terminal " + "multiplexer and race conditions in writing to the file system.") + + o, args = p.parse_args() + if o.interface not in ("screen", "tmux"): + p.error("--interface must be [screen|tmux].") + + return o, args + + options,selected_tests = parse_args() + + # The next line doesn't work in python 2.3 + test_loader = unittest.TestLoader() + all_test_suites = test_loader.loadTestsFromModule(__import__("test")) + + if platform.system() == "Windows": + vim = VimInterfaceWindows() + else: + if options.interface == "screen": + vim = VimInterfaceScreen(options.session) + elif options.interface == "tmux": + vim = VimInterfaceTmux(options.session) + + vim.focus() + + vim.send(ESC) + + # Ensure we are not running in VI-compatible mode. + vim.send(""":set nocompatible\n""") + + # Do not mess with the X clipboard + vim.send(""":set clipboard=""\n""") + + # Set encoding and fileencodings + vim.send(""":set encoding=utf-8\n""") + vim.send(""":set fileencoding=utf-8\n""") + + # Tell vim not to complain about quitting without writing + vim.send(""":set buftype=nofile\n""") + + # Ensure runtimepath includes only Vim's own runtime files + # and those of the UltiSnips directory under test ('.'). + vim.send(""":set runtimepath=$VIMRUNTIME,.\n""") + + # Set the options + vim.send(""":let g:UltiSnipsExpandTrigger=""\n""") + vim.send(""":let g:UltiSnipsJumpForwardTrigger="?"\n""") + vim.send(""":let g:UltiSnipsJumpBackwardTrigger="+"\n""") + vim.send(""":let g:UltiSnipsListSnippets="@"\n""") + if sys.version_info >= (3,0): + vim.send(""":let g:UltiSnipsUsePythonVersion="3"\n""") + else: + vim.send(""":let g:UltiSnipsUsePythonVersion="2"\n""") + + # Now, source our runtime + vim.send(":so plugin/UltiSnips.vim\n") + time.sleep(2) # Parsing and initializing UltiSnips takes a while. + + # Inform all test case which screen session to use + suite = unittest.TestSuite() + for s in all_test_suites: + for test in s: + test.vim = vim + test.interrupt = options.interrupt + test.retries = options.retries + if len(selected_tests): + id = test.id().split('.')[1] + if not any([ id.startswith(t) for t in selected_tests ]): + continue + suite.addTest(test) + + if options.verbose: + v = 2 + else: + v = 1 + res = unittest.TextTestRunner(verbosity=v).run(suite) + +# vim:fileencoding=utf-8:foldmarker={{{#,#}}}: diff --git a/utils/convert_snipmate_snippets.py b/utils/convert_snipmate_snippets.py new file mode 100755 index 0000000..2d31558 --- /dev/null +++ b/utils/convert_snipmate_snippets.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# encoding: utf-8 +""" +Convert snipmate compatible snippets to UltiSnips compatible snippets +by Phillip Berndt +""" +import sys +import re +import os +import argparse + +def convert_snippet_contents(content): + " If the snippet contains snipmate style substitutions, convert them to ultisnips style " + content = re.sub("`([^`]+`)", "`!v \g<1>", content) + return content + +def convert_snippet_file(source): + " One file per filetype " + retval = "" + state = 0 + for line in open(source).readlines(): + # Ignore empty lines + if line.strip() == "": + continue + # The rest of the handling is stateful + if state == 0: + # Find snippet start. Keep comments. + if line[:8] == "snippet ": + snippet_info = re.match("(\S+)\s*(.*)", line[8:]) + if not snippet_info: + print >> sys.stderr, "Warning: Malformed snippet\n %s\n" % line + continue + retval += 'snippet %s "%s"' % (snippet_info.group(1), snippet_info.group(2) if snippet_info.group(2) else snippet_info.group(1)) + "\n" + state = 1 + snippet = "" + elif line[:1] == "#": + retval += line + state = 0 + elif state == 1: + # First line of snippet: Get indentation + whitespace = re.search("^\s+", line) + if not whitespace: + print >> sys.stderr, "Warning: Malformed snippet, content not indented.\n" + retval += "endsnippet\n\n" + state = 0 + else: + whitespace = whitespace.group(0) + snippet += line[len(whitespace):] + state = 2 + elif state == 2: + # In snippet: If indentation level is the same, add to snippet. Else end snippet. + if line[:len(whitespace)] == whitespace: + snippet += line[len(whitespace):] + else: + retval += convert_snippet_contents(snippet) + "endsnippet\n\n" + #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 = "" + elif line[:1] == "#": + retval += line + state = 0 + if state == 2: + retval += convert_snippet_contents(snippet) + "endsnippet\n\n" + return retval + +def convert_snippet(source): + " One file per snippet " + name = os.path.basename(source)[:-8] + return 'snippet %s "%s"' % (name, name) + "\n" + \ + convert_snippet_contents(open(source).read()) + \ + "\nendsnippet\n" + +def convert_snippets(source): + if os.path.isdir(source): + return "\n".join((convert_snippet(os.path.join(source, x)) for x in os.listdir(source) if x[-8:] == ".snippet")) + else: + return convert_snippet_file(source) + +if __name__ == '__main__': + # Parse command line + argsp = argparse.ArgumentParser(description="Convert snipmate compatible snippets to UltiSnips' file format", + epilog="example:\n %s drupal/ drupal.snippets\n will convert all drupal specific snippets from snipmate into one file drupal.snippets" % sys.argv[0], + formatter_class=argparse.RawDescriptionHelpFormatter) + argsp.add_argument("source", help="Source directory for one filetype or a snippets file") + argsp.add_argument("target", help="File to write the resulting snippets into. If omitted, the snippets will be written to stdout.", nargs="?", default="-") + args = argsp.parse_args() + + source_file_name = args.source + tmp_file_name = ''.join([args.target,'.tmp']) + try: + tmp = sys.stdout if args.target == "-" else open(tmp_file_name, "w") + except IOError: + print >> sys.stderr, "Error: Failed to open output file %s for writing" % tmp_file_name + sys.exit(1) + + snippets = convert_snippets(source_file_name) + print >> tmp, snippets + + if args.target != "-": + if os.access(args.target, os.F_OK): + os.remove(args.target) + os.rename(tmp_file_name, args.target) diff --git a/utils/get_tm_snippets.py b/utils/get_tm_snippets.py new file mode 100755 index 0000000..3684001 --- /dev/null +++ b/utils/get_tm_snippets.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import urllib +import re +from xml.etree import ElementTree +from xml.parsers.expat import ExpatError +import htmlentitydefs +import os +import glob + + +_UNESCAPE = re.compile(ur'&\w+?;', re.UNICODE) +def unescape(s): + if s is None: + return "" + def fixup(m): + ent = m.group(0)[1:-1] + return unichr(htmlentitydefs.name2codepoint[ent]) + try: + return _UNESCAPE.sub(fixup,s) + except: + print "unescape failed: %s" % repr(s) + raise + +class UnknownVariable(Exception): + pass + +class UnsupportedVariableExpression(Exception): + pass + +def replace_vars(m): + """ Replace vars in 'content' portion. + :m: match object + :returns: string""" + var = m.group(1) + default = m.group(2) + + if not re.match(r'\w+$', var): + raise UnsupportedVariableExpression(var) + + translate_vars = { + 'TM_PHP_OPEN_TAG_WITH_ECHO': 'g:UltiSnipsOpenTagWithEcho', + 'TM_PHP_OPEN_TAG': 'g:UltiSnipsOpenTag', + 'PHPDOC_AUTHOR': 'g:snips_author', + } + # TODO: TM_SELECTED_TEXT/([\t ]*).*/$1/m + + if var in translate_vars: + newvar = translate_vars[var] + else: + # TODO: this could be autogenerated + raise UnknownVariable(var) + + return "`!v exists('%s') ? %s : '%s'`" % (newvar, newvar, default) + +def parse_content(c): + try: + data = ElementTree.fromstring(c)[0] + + rv = {} + for k,v in zip(data[::2], data[1::2]): + rv[k.text] = unescape(v.text) + + if re.search( r'\$\{\D', rv["content"] ): + rv["content"] = re.sub(r'\$\{([^\d}][^}:]*)(?::([^}]*))?\}', replace_vars, rv["content"]) + + return rv + except (ExpatError, ElementTree.ParseError) as detail: + print " Syntax Error: %s" % (detail,) + print c + return None + except UnknownVariable as detail: + print " Unknown variable: %s" % (detail,) + return None + except UnsupportedVariableExpression as detail: + print " Unsupported variable expression: %s" % (detail,) + return None + +def fetch_snippets_from_svn(name): + base_url = "http://svn.textmate.org/trunk/Bundles/" + name + ".tmbundle/" + snippet_idx = base_url + "Snippets/" + + idx_list = urllib.urlopen(snippet_idx).read() + + + rv = [] + for link in re.findall("
  • (.*?)
  • ", idx_list): + m = re.match(r'(.*)', link) + link, name = m.groups() + if name == "..": + continue + + name = unescape(name.rsplit('.', 1)[0]) # remove Extension + print "Fetching data for Snippet '%s'" % name + content = urllib.urlopen(snippet_idx + link).read() + + cont = parse_content(content) + if cont: + rv.append((name, cont)) + + return rv + +def fetch_snippets_from_dir(path): + """ Fetch snippets from a given path""" + + rv = [] + for filename in glob.glob(os.path.join(path, '*.tmSnippet')): + print "Reading file %s" % filename + f = open(filename) + content = f.read() + + cont = parse_content(content) + if cont: + name = os.path.splitext(os.path.basename(filename))[0] + rv.append((name, cont)) + return rv + +def write_snippets(snip_descr, f): + + for name, d in snip_descr: + if "tabTrigger" not in d: + continue + + if "content" not in d or d["content"] is None: + print "SKIP: %s (no content)" % (d,) + continue + + f.write('snippet %s "%s"\n' % (d["tabTrigger"], name)) + f.write(d["content"].encode("utf-8") + "\n") + f.write("endsnippet\n\n") + + + +if __name__ == '__main__': + import sys + + bundle = sys.argv[1] + + if os.path.isdir(bundle): + name = sys.argv[2] + rv = fetch_snippets_from_dir(bundle) + else: + rv = fetch_snippets_from_svn(bundle) + name = bundle.lower() + + write_snippets(rv, open("tm_" + name + ".snippets","w")) +