Sunday, September 18, 2011

Creating Code Snippets for any Programming Language

A snippet is a piece of often-typed text (for loops, function definitions, etc.) that you can insert into your document using a trigger word followed by a [Tab]. The snipMate plugin for Vim gives it TextMate style snippet creation abilities for literally any programming language you happen to use. It comes with many default snippets and you can easily tweak them or create your own.

The bottom line is that snipMate will save you a ton of time and is far more powerful than simple code-completion. Some people spend a lot of money on individual IDEs that only work with one or two languages. In this article I will show examples of how Vim can create powerful snippets in C, PHP, Python, Ruby, JavaScript, HTML, and more.

The perfect first example of snipMate's capabilities is generating a for loop by typing nothing more than:
 for[Tab]
Which expands to:
 for (i = 0; i < count; i++) { 
     // code
 }
If you were editing a C language file, anyway. The snipMate plugin is context sensitive, based off of the file type you're editing. For example, if you were editing a PHP file instead, then typing for[Tab] would have produced a PHP for loop:
 for ($i = 0; $i < count; $i++) {
     // code...
 }
What's more, is after expanding to a full for loop it then places your cursor on the first likely edit point - in this case it places your cursor on the word "count" and puts Vim in SELECT mode so you cans start typing to replace it with another word such as "$max", or whatever you require. If you don't want to change the selected word just hit [Tab] without changing it. Typing [Tab] again jumps you to the next edit point, which in this case goes back to the first "$i" in the loop. From there, if you were to type x, it would replace all the $i's in the loop with $x's. Typing [Tab] from there will jump your cursor to the "++" in the "$x++", in case you wanted to change it to something else like "+=2". Typing [Tab] one last time will take you down to the "// code" line. You get the picture.

To scroll backwards, use [Shift+Tab], as you might expect.

You can even enbable multiple filetypes at the same time in Vim by chaining them with dots. For example:

    :set ft=php.html

Will let you use both the PHP and HTML snippets on the file you're editing.

How does this work? Well, behind the scenes there are snippet files. In your ~/.vim/snippets/ directory exists the files: c.snippets (for C code), php.snippets (for PHP code), and so on. The plugin knows what filetype you're editing and then loads the corresponding snippet file based on the prefix of the file name. So if you're editing a PHP file, it looks in the snippets directory with file names starting with "php".

This means you can easily create your own custom additions. For example, to create more PHP snippets, you could either add them to the existing php.snippets file, or better yet, create your own new file called "php-mine.snippets". In it, you input snippets that don't come with the default snippets file. For example, I really wanted to be able to just type th[Tab] to create $this->. So in php-mine.snippets, I made the snippet:
 snippet th
     $this->${1}
It's important that you insert actual Tabstops (\t) when you indent in the snippets file. In Vim, typing Ctrl+v Tab will insert a real tabstop.

The "${1}" in the snippet indicates to snipMate where you want the cursor to jump to after the snippet expands. In the above example, I'm telling it to land directly after the "->". To tell it where to jump when a user starts pressing [Tab] you simply place it where you want and give it the corresponding number. For example: "${2}", "${3}", etc. In order to highlight certain text when your cursor jumps there, then add a colon (:) after the number followed by the text to select: ${2:foo} will jump your cursor to the string "foo", and highlight it.

Note that if you create multiple snippets with the same name, then Vim will prompt you with a drop down selection list to chose from.

Another PHP snippet you might create is:
 snippet substr
     substr(${1:string $string}, ${2:int $start} ${3:[, int $length]})
Which expands to:

    substr(string $string, int $start [, int $length])

This is useful if you often forget the parameters certain functions take.

I also like to create another snippets file called "php-unit.snippets" which contains my PHPUnit framework snippets. In here, I have snippets like:
 snippet test
     /**
     * @test
     **/
     public function ${1:}() {
         ${2:}
     }${3:}
Which, typing test[tab], expands to:

    /**
    * @test
    **/
    public function () {
    
    }

A more involved example is my getMockBuilder() method snippet:
 snippet getmockbuilder
     ${8:}$this->getMockBuilder('${1:string $OriginalCLassName}')
         ->setMethods(${2:array $methods})
         ->setConstructorArgs(${3:array $args})
         ->setMockClassName(${4:string $name})
         ${5:->disableOriginalConstructor(})
         ${6:->disableOriginalClone()}
         ${7:->disableAutoload()}
         ->getMock();
Expands to, when you type getmockbuilder[Tab]:

    $this->getMockBuilder('string $OriginalCLassName')
              ->setMethods(array $methods)
              ->setConstructorArgs(array $args)
              ->setMockClassName(string $name)
              ->disableOriginalConstructor()
              ->disableOriginalClone()
              ->disableAutoload()
              ->getMock();


Tip: To easily search through all the existing snippets of a .snippets file, type this search query in Vim:

     /snippet \zs.*

Some useful Python snippets:
    import             = imp[tab]
    function template  = def[tab]
    for loop           = for[tab]
(Also see the Python code-completion plugin for Vim I wrote called Pydiction.)

Some other useful PHP snippets include:
    php           = <?php  ?>
    echo          = ec[tab] 
    fun           = public function FunctionName() ...
    foreach       = foreach[tab]
    if            = if (/* condition */) { ...
    ife           = if/else
    else          = else { ...
    elseif        = elseif () { ...
    switch/case   = switch[tab]
    case          = case 'value': ...
    t             = $retVal = (condition) ? a : b;
    while         = wh[tab]
    do/while      = do[tab]
    Super Globals = $_[tab]
    docblock      = /*[tab]
    inc1          = include_once
    req           = require
    req1          = require_once
    $_            = List of $_GET[''], $_POST[''], etc
    globals       = $GLOBALS['variable'] = something;
    def           = define('')
    def?          = defined('')
    array         = $arrayName = array('' => );
    /*            = dockblock: /**  *  **/
    doc_h         = file header docblock
    doc_c         = class docblock
    doc_cp        = class post docblock
    doc_d         = constant docblock
    doc_fp        = function docblock
    doc_v         = class variable docblock
    doc_vp        = class variable post docblock
    doc_i         = interface docblock
Some Bash snippets:
#![tab]
expands to: #!/bin/bash
if[tab]
expands to:

        if [[ condition ]]; then
            #statements
        fi


For JavaScript:
    get[Tab]  =  getElementsByTagName('')
    gett[Tab] =  getElementById('')
    timeout   =  setTimeout(function() {}, 10;
    ...
For Ruby:
    ea      =  each { |e|  }
    array   =  Array.new(10) { |i|  }
    gre     =  grep(/pattern/) { |match|  }
    patfh   =  File.join(File.dirname(__FILE__), *%2[rel path here])
    ...
In a previous article I mentioned using Zen Coding for super fast HTML creation. Well, you can also create HTML with snipMate. This is useful when you need to do something that Zen Coding cannot do. For instance, snipMate has all the HTML Doctypes:
    docts  =  (HTML 4.01 strict)
    doct   =  (HTML 4.01 transitional)
    docx   =  (XHTML Doctype 1.1)
    docxt  =  (XHTML DocType 1.0 transitional)
    docxs  =  (XHTML Doctype 1.0 Strict)
    docxf  =  (XHTML Doctype 1.0 Frameset)
    doct5  =  (HTML 5)

Other HTML snippets include:
    head[tab]
    title[tab]
    script[tab]
    scriptsrc[tab]
    r[tab]
    base[tab]
    meta[tab]
    style[tab]
    link[tab]
    body[tab]
    table[tab]
    div[tab]
    form[tab]
    input[tab]
    textarea[tab]
    mailto[tab]
    h1[tab]
    label[tab]
    select[tab] and opt[tab] and optt[tab]
    meta[tab]
    movie[tab]
    nbs[tab]
That's all for now. If you want to share snippets you made please link to them in the comments section below.

No comments:

Post a Comment

Followers