Uma Lição de VIM #15.8: Plugins – SnipMate

(Essa é a parte que automatizamos a digitação de coisas repetidas.))

Para o oitavo plugin, iremos falar sobre SnipMate.

Como de costume, instalando pelo Vundle:

Bundle ‘msanders/snipmate.vim’

SnipMate adiciona a funcionalidade de snippets dentro do VIM. Para quem não sabe, snippets são trechos de código que são adicionados automaticamente (ou com a ação de alguma combinação de teclas) a partir de uma simples palavra.

Por exemplo, um dos snippets que já estão inclusos no pacote do SnipMate, você pode, num arquivo JavaScript, simplesmente digitar:

fun

… e, ao pressionar [Tab], o SnipMate irá adicionar, automaticamente

function function_name (argument) {
  // body…
}

… posicionando o cursor diretamente sobre function_name para que você coloque o nome da função; pressionando [Tab] irá posicionar o cursor sobre argument e pressionando [Tab] de novo, o cursor ficará sobre // body... (depois disso, [Tab] irá funcionar como tabulação, como normalmente é).

Para criar seus próprios snippets, você tem duas opções e ambas devem ficar no diretório $HOME/.vim/snippets:

A primeira forma é através de um único arquivo, com o nome do tipo de arquivo em que os snippets serão válidos (que você pode ver usando :set ft) com a extensão snippets (por exemplo, para snippets para arquivos Python, você teria um arquivo $HOME/.vim/snippets/python.snippets). Neste arquivo você deve iniciar os snippets com a palavra snippet, seguida da palavra que será utilizada para identificar o snippet, seguido pelo snippet em si, com uma tabulação na frente (quando não houver tabulação, SnipMate considera que o snippet terminou). Os pontos onde você quer que o cursor pare devem ser identificados por ${{número}:{texto}} e, se ficou confuso, é porque eu estou usando “coisas que você substituir” com {} e o próprio SnipMate usa {} para blocos, mas deve ficar mais claro com este exemplo:

snippet for
    {% for ${1:record} in ${2:list} %}
        ${3:content}
    {% endfor %}

Este snippet, para Django e Jinja, faz um loop “for”. Ao digitar “for” e pressionar [Tab], o conteúdo será adicionado, o cursor será posicionando onde ${1:record} está permitindo a alteração do mesmo, pressionando [Tab] de novo irá posicionar em ${2:list} e assim por diante.

E, caso você esteja se perguntando “E o que acontece se eu colocar o mesmo número em dois lugares diferentes?”, a resposta é: lugares com o mesmo número são alterados ao mesmo tempo. Por exemplo, o snippet:

snippet block
    {% block ${1:blockname} %}
        ${2:{% content %}}
    {% endblock $1 %}

… tem o número “1” duas vezes (uma depois de “block” e outra depois de “endblock”). Quando você colocar o nome do bloco no primeiro (do lado de “block”), o outro (depois de “endblock”) será preenchido automaticamente.

A segunda forma de adicionar snippets é através de arquivos individuais. Ao invés de ter um arquivo com o tipo de arquivo com todos os snippets dentro, você irá criar um diretório com o tipo de arquivo e cada arquivo dentro deste diretório deve ser {palavra}.snippet. Assim, como no exemplo anterior tínhamos um arquivo $HOME/.vim/snippets/htmldjango.snippets, poderíamos ter, na verdade, um diretório $HOME/.vim/snippets/htmldjango/ e, dentro deste diretório, um arquivo chamando block.snippet com o conteúdo do snippet, sem as tabulações (já que agora o SnipMate sabe exatamente onde termina o snippet: no final do arquivo).

E quando usar um ou outro? Você deve usar arquivos individuais se o SnipMate já tiver um arquivo de snippets para o tipo de arquivo especificado. Assim, se você quiser adicionar novos snippets para Python, que já tem uma série de snippets prontos incluídos no pacote do próprio SnipMate, você deve usar a segunda forma. Caso contrário, fica por preferência pessoal.

E, para concluir: Ao escrever este post, descobri que existe um fork da versão apresentada aqui. A versão do “msanders” não é atualizada a 4 anos — mas funciona perfeitamente e tenho usado sem problemas a bastante tempo. Se você quiser algo mais recente (por algum motivo), o fork está em github.com/garbas/vim-snipmate (e requer mais dependências que a versão original).

Your Editor Shows the Flaws of Your Language

In a recent update of Sublime Text 2, my programming editor of choice of these days (only ’cause I wanted a break from VIM, for the fun of having to learn how to edit things in the “normal person” way) got a “Vim mode” and I decided to enable all the other features, just for kicks. One of those features was the “auto close brackets” (or whatever name they call that these days).

The only thing I’m using the “auto close brackets” feature is to make sure all the mess with opening square brackets inside functions inside functions would have the proper closing element. It’s somewhat easy to get lost in a str_replace(' ', '', trim($param['string'])) line.

But that’s only one thing editors do that are only there to work as a “walking stick” for the language you’re working on.

  • Auto close brackets: As I mentioned, that’s because accessing most array elements requires at least two characters ("[" and "]") or 4 if you use associative arrays/dictionaries/objects. JavaScript does this right by not having associative arrays and making objects. You can kinda do the same with Python objects, but it feels somewhat wrong when you do have dictionaries. You can somewhat fix that with __getitem__ or just monkeypatching the dict object. But in some languages, there is no such option. Also, as you can imagine, the problem is “lessened” with languages where all the basic types are objects: instead of making function return the parameter of another function (like I did above), you simply call function and then the next function. The same example above in Python would be something like param['string'].trim().replace(' ', ''). This obviously reduces the changes of forgetting to close one of the parenthesis.
  • Snippets: Snippets are small pieces of code that you repeat most, but not to the point you can simply write a function to do such thing. C/C++ allow you to somewhat skip that by using macros but one must reckon that macro syntax is a bit cumbersome.
  • Templates: Templates are large snippets that encompass whole files. It seems templates are there not to just solve a language design problem, but a general “language design principle” problem. The most obvious example I can think of is using Eclipse to write a Java application to connect to a database. To do it so, it requires so much boilerplate that Eclipse itself offers a way to create the whole file to you based on a simple database definition.

I’m probably forgetting a lot more programming editors do these days just to cover languages’ asses here. But I guess you start viewing programming languages a lot different when you think any feature in the editor is just to solve a problem with the languages we use today.

The hacks are available

For some time, I kept my “hacks” available on my SVN. And by “hacks” I mean my small pieces of code, which I used to understand some function, or try something new. Now, because I’m closing “slowhome.org” down, I decided to put all code available on my notes. The files are here.