Uma Lição de VIM #15.1: Plugins – Vundle

(Essa é a parte em que começamos a mexer ao redor do VIM.)

Vamos começar a ver como adicionar funcionalidades no VIM com plugins. E, para isso, vamos ver Vundle, que é um gerenciador de plugins.

A pergunta que você deveria estar se fazendo agora é “E por que usar o Vundle?”. Na verdade, esta pergunta tem duas respostas:

A primeira é: Apesar de ser extremamente fácil de adicionar um plugin no VIM — normalmente é uma questão de descompactar um arquivo dentro do diretório $HOME/.vim — a parte chata é manter os scripts atualizados (e ficar preso à um arquivo compactado) e removê-los depois, se você encher o saco de um.

A segunda é: Vundle não é o único gerenciador de plugins para VIM, mas consegue instalar plugins por conta própria (Pathogen requer que você baixe os plugins manualmente, assumindo depois o controle para manter atualizado); a desvantagem é que Vundle requer que os scripts tenham uma determinada estrutura de arquivos e diretórios, mas praticamente todos os scripts hoje utilizam esta estrutura.

Então vamos lá, instalar o Vundle:

Primeiro, você deve baixar o plugin em si. Para isso, você tem que ter o Git instalado e executar:

git clone https://github.com/gmarik/vundle.git ~/.vim/bundle/vundle

Simplesmente, você está copiando o repositório do vundle para um diretório do próprio VIM. Até aqui nenhuma surpresa, exceto que o diretório de plugins é $HOME/.vim/plugin (ou ~/.vim/plugin) e a colanagem colocou no diretório ~/.vim/bundle. Ou seja, o Vundle não está ativo como um plugin do VIM (ainda). O Vundle faz isso de propósito, para que os scripts instalados com o Vundle não se misturem com os plugins instalados manualmente.

A seguir, é preciso ativar o Vundle. Para isso, nós vamos adicionar o diretório do Vundle no path do VIM e chamar o script de inicialização. Para isto, adicione as seguintes linhas no seu vimrc:

set rtp+=~/.vim/bundle/vundle/
call vundle#rc()

Explicando: “rtp” é a forma curta de “runtimepath”, que identifica os diretórios onde o VIM irá procurar scripts, se preciso. No caso, estamos adicionando o diretório do Vundle, que clonamos anteriormente. A seguir é chamado o script de inicialização do Vundle.

Pronto! Agora o Vundle está instalado.

A questão é: E agora que o Vundle está instalado, “faz o que?”

O Vundle tem mais comandos disponíveis, entre eles :Bundle "{bundle}"[1]. Este comando adiciona um bundle/plugin/script na lista de bundles/plugins/scripts gerenciados pelo Vundle. A única coisa que esse comando faz é adicionar o bundle na lista; ele não vai instalar o bundle ainda, ele não vai remover o bundle, ele não vai atualizar o bundle. Apenas adicionar na lista.

O parâmetro do comando, {bundle} pode ser:

Uma vez que você tenha a lista de plugins que você quer no sistema, você pode instalar todos usando :BundleInstall; se quiser remover um plugin, você simplesmente o deixa fora da lista de plugins desejados e executa :BundleClean; e, para atualizar os plugins que estão instalados, :BundleUpdate.

Acho que você já percebeu que o problema de se manter uma lista de plugins manualmente é meio chato: Toda vez que você quiser verificar se há atualizações dos plugins, você tem que entrar a lista inteira; se você esquecer de um plugin e fizer :BundleClean irá remover esse plugin. Para evitar essa complicação, você pode adicionar os comandos Bundle diretamente no seu vimrc[2]. Assim, cada vez que você usar qualquer comando do Vundle, você não precisa se preocupar em lembrar de todos os plugins instalados.

E, como última dica, fica o seguinte: Logo após a linha do “call vundle#rc()”, adicione

Bundle 'gmarik/vundle'

.. que nada mais é que o repositório que fizemos o clone logo no começo; desta forma, quando você fizer um :BundleUpdate, o próprio Vundle poderá ser atualizado com a última versão disponível.

[1] Lembram que eu falei que plugins poderiam adicionar novos comandos e que estes teriam pelo menos a primeira letra em maiúsculas? Pois é…

[2] Lembre-se também que o vimrc é um arquivo executado em modo Ex e o modo Ex nada mais é que o modo de comando sem precisar colocar : na frente de cada comando.

Uma Lição de VIM #14: Tags

(Essa é a parte em que você vai entender Unix um pouco.)

Eu expliquei antes que haviam dois comandos para utilizar tags, [Ctrl]] e [Ctrl]t. Existem duas coisas que eu não expliquei: O que são tags e de onde elas vem.

Primeiro, tags são qualquer palavra que o editor encontre no arquivo de tags. E o arquivo de tags pode ser definido em :set tags. Por padrão, são verificados os arquivos “./tags” (“tags” no diretório atual do editor), “./TAGS”, “tags” (arquivo “tags” em algum diretório de pesquisa” e “TAGS”.

Acontece que não é qualquer arquivo com este nome que o torna válido. Existem um formato específico em que as coisas devem estar declaradas para serem detectadas como tags. E o formato é

{tagname}{tagfile}{tagaddress}

(onde “tagname” é a tag em si, “tagfile” é o nome do arquivo onde a tag se encontra e “tagaddress” é uma expressão Ex para encontrar a tag — por exemplo, “89” para ir para linha 89).

Sim, só isso. E eu sei que manter um arquivo assim é chato horrores, e por isto existem ferramentas que já fazem isso. A mais completa de todas é Exuberant CTags e pode ser encontrada em praticamente todas as distribuições Linux atuais, gerenciadores de pacotes do OS X e ainda vem um pacote para Windows.

A grande vantagem do Exuberant é a quantidade de linguagens suportadas. Assim, se você estiver num projeto em Python e depois passar para um projeto em C, você ainda pode usar o mesmo aplicativo.

A sintaxe gerado do Exuberant é “ctags {arquivos}”, onde {arquivos} são os arquivos a serem processados (expressões como “*.py” são válidas) ou, da forma mais simples “ctags -R”, para que todos os arquivos do diretório atual e subdiretórios sejam processados.

Uma vez que este arquivo tenha sido criado, dentro do editor você pode usar [Ctrl]] para tentar achar a definição da tag (que, com o uso do Exuberant significa definição de funções ou definições de variáveis) e [Ctrl]t para retornar para a localização anterior. Se houver mais de um arquivo com uma definição válida, o VIM irá mostrar uma lista das localizações e você poderá selecionar qual deve ser acessada.

A única dica que sobra aqui é cuidar com arquivos minificados. Isso porque o Exuberant entende arquivos CSS. Não que arquivos CSS sejam um problema, mas o Exuberant coloca a expressão regular da linha onde a tag se encontra e, num arquivo minificado, a expressão acaba sendo uma linha gigantesca, que fica se repetindo em vários lugares do arquivo, deixando-o gigantesco. Se você tiver algo desse tipo, use a opção “–exclude={expressão}”, onde {expressão} é a expressão regular que define o nome dos arquivos que devem ser ignorados.

Uma Lição de VIM #13: Modelines

(Essa é a parte em que você ignora seus arquivos de configuração.)

Bom, agora você sabe como configurar seu VIM, mudar configurações baseadas no tipo de arquivo… Mas o que fazer se um arquivo tem uma configuração completamente diferente do resto?

A solução são modelines. Modelines são linhas que você pode adicionar no seu arquivo e o VIM, quando carregar o arquivo, irá mudar suas configurações baseadas nesta linha.

A sintaxe da linha é, simplesmente: vim: set {configurações}:.

“Mas é um código fonte e se eu colocar um ‘vim’ no meio, o compilador vai reclamar!” você deve estar pensando agora. Acontece que o VIM procura uma linha válida em qualquer lugar, desconsiderando a sintaxe atual. Se você colocar o modeline dentro de um comentário, o VIM ainda vai encontrar e ainda vai processar o modeline e ainda vai trocar as configurações do editor (apenas para aquele arquivo).

Por exemplo, para garantir que meus templates Jinja fiquem com a sintaxe correta (usando a sintaxe de templates do Django), eu tenho colocado, como última linha do arquivo

{# vim: set ft=htmldjango: #}

“ft”, no caso, é o nome curto para “filetype”, que define o tipo de arquivo que está sendo usando e qual sintaxe será utilizada.

Assim como vimos antes, várias configurações podem ser usadas no mesmo set. Usando o exemplo acima, se eu quisesse que meus templates usassem tabulações ao invés de espaços para identação mas fossem apenas 2 espaços por tabulação, eu poderia colocar, no final do arquivo:

{# vim: set ft=htmldjango noet ts=2 sts=2 sw=2: #}

O VIM ainda aceita que as opções sejam separadas em vários comandos, com a adição de “:“:

{# vim: set ft=htmldjango:set noet:set ts=2:set sts=2:set sw=2: #}

Mas realmente não faz sentido, faz?

E apenas um aviso, que eu descobri a poucos dias antes deste post: Algumas distribuções Linux desligam modelines no arquivo global (adicionando set nomodeline no arquivo global) e, assim, modelines são completamente ignorados. Tentando descobrir o porque descobri o seguinte: O único comando que pode ser usado em modelines é “set”, ou seja, não é possível colocar um modeline que abra outro arquivo, ou mude o diretório atual ou qualquer outra coisa; nem todas as configurações pode ser alteradas (infelizmente, o help do VIM não lista quais são e quais não são permitidas); e, aparentemente, a pior forma de “ataque” seria alguém colocar um “textwidth” e seu código ficar torto na primeira edição. Se você achar que modelines não estão sendo executados, você pode adicionar no seu vimrc set modelines para que modelines sejam processados (ou troque por uma distribuição que não tenha configurações que não fazem sentido).

Uma Lição de VIM #12.2: Meu .gvimrc

(Essa é a parte em que veremos mais do mesmo.)

Na parte de configurações, eu falei de dois arquivos, vimrc e gvimrc. Vocês já viram o que eu fiz com meu vimrc, então acho justo que vejam também o que eu fiz com o meu gvimrc.

Para que fique claro, vimrc sempre é lido, não importa qual executável do VIM você está usando. gvimrc é lido depois do vimrc somente quando você iniciar um VIM gráfico.

Como o arquivo é bem menor (já que o grosso da configuração fica no vimrc), este é o arquivo inteiro que eu estou usando:

 1 set guioptions=aegit    " basically, all options, except the scrollbar, menu and toolbar
 2 set columns=116         " number of columns (uses most of my screen, in this case)
 3 set cursorline          " highlight the line with the cursor
 4 set colorcolumn=+2      " put a marker at textwidth + 2
 5 set linespace=1         " spread the lines a bit, adding a 1px line above all
 6 
 7 if has(‘mac’)
 8     set gfn=monofur:h15     " My screen size sucks, mkay?
 9     set lines=63            " number of lines, based on my screen size and font
10 else
11     set gfn=monofur\ for\ Powerline\ 12
12     set lines=54
13 endif

E explicando:

  • set guioptions=aegit: Define a aparência do editor em modo gráfico. Eu prefiro um editor limpo, sem menus, toolbars ou (e isso talvez soe estranho para alguns), sem barra de rolagem. Em ordem, as opções ativas são:
    a
    Quando estiver fazendo a seleção com o modo visual, já copia o selecionado para a área de transferência. No caso de sistemas Unix, isso significa que selecionar algo com o modo visual é o mesmo que selecionar com o botão da esquerda (e que pode ser colado diretamente usando o botão do meio).
    e
    Mostra abas (se estiver configurado para mostrar abas com “showtabline” — que eu configurei para mostrar sempre no meu vimrc).
    g
    Mostra opções do menu desabilitadas. O normal é que opções desabilitadas sequer apareçam. Esta opção só faz sentido se o menu estiver presente (com a opção m no “guioptions”) que, como você pode perceber, eu não estou usando. Em alguns sistemas (por exemplo, OS X) o controle do menu não faz sentido porque o sistema operacional sempre tem um menu ativo. Assim, quando não há necessidade de menu, esta opção é desnecessária; quando não há escapatória do menu, pelo menos todas as opções serão visíveis.
    i
    VIM tem um ícone (sim você pode configurar para o que o VIM não mostre um ícone em lugar algum). De novo, dependendo do sistema operacional, esta opção não tem efeito algum porque o próprio sistema adiciona o ícone do launcher.
    t
    Menus podem ser arrancados (quando possível). Esta é uma funcionalidade que o GTK+ até a versão 2 tinha, que permitia que os menus fosse “desconectados” da área de menu, o que facilita bastante na hora de selecionar colorschemes (e como você pode adicionar um menu a qualquer hora com :set guioptions+=m, o que eu normalmente faço — ou melhor, fazia — era adicionar um grupo de novos colorschemes, ativar o menu, “arrancar” o menu de colorschemes e sair selecionando opções até achar um colorscheme interessante).
  • set columns=116: Número de colunas da janela do editor. Se a sua tela não tiver como apresentar 116 colunas (pelo tamanho da fonte e da tela, ou por alguma restrição do gerenciador de janelas), o VIM irá reduzir a quantidade de colunas até que a janela caiba completamente.
  • set cursorline: A linha onde o cursor se encontra tem highlight. E, caso você esteja se perguntando, existe um set cursorcolumn que mostra a coluna do cursor. Tanto “cursorline” quanto “cursorcolumn” funcionam em console, mas a forma como a linha é apresentada no meu colorscheme é… estranha.[1]
  • set colorcolumn=+2: Define uma coluna para ser marcada com uma cor diferente. Se for usado uma opção relacional (não um valor absoluto, mas algo começando com “+” ou “-“), então cursorline vai usar o “textwidth” atual.
  • set linespace=1: Define um espaçamento entre linhas, em pixeis. No caso, “1” significa que as linhas terão a altura requisitada pela fonte mais um pixel.
  • set lines=???: Define a quantidade de linhas do editor. Segue todas as considerações feitas em “columns”. Ainda, aqui eu estou usando de novo a checagem de funcionalidade (has()) para ter configurações diferenciadas no OS X e em outros sistemas operacionais.
  • set gfn=???: Define a fonte a ser usada (“gfn” é a forma curta de “guifont”). Note que fontes que tem espaço no meio tem que ter os espaços “escapados” (com \ antes do espaço) ou como strings. Se você quiser selecionar alguma fonte mas não faz idéia do nome da fonte, use :set gfn=* para que o VIM mostre o seletor de fontes do sistema; depois que escolher uma fonte, se quiser que o VIM descreva como usar, use :set gfn e cole o resultado no seu arquivo de configuração.

[1] E, lembrando mais uma vez: Para desligar opções deste tipo, coloque “no” na frente. Para desligar o highlight da linha atual do cursor, use :set nocursorline; para desligar o highlight da coluna atual do cursor, use :set nocursorcolumn.

Uma Lição de VIM #12.1: Meu .vimrc

(Essa é a parte em que você vai ver um arquivo de configuração meio estranho.)

Como falamos sobre arquivo de configuração, eu vou mostrar o que eu tenho hoje configurado no meu VIM, explicando o que cada comando faz. Boa parte do que eu tenho veio da configuração global do VIM, que eu copiei apenas para garantir que não importando onde eu esteja ou qualquer alteração que seja feita neste arquivo, as funcionalidades que eu estou acostumado continuarão funcionando como esperado.

set encoding=utf-8

Garante que os arquivos salvos estarão em UTF-8, ao invés de tentar converter para o encoding do sistema operacional.

set nocompatible

Desativa o modo de compatilidade com o VI original. Existem algumas diferenças entre ambos (por exemplo, depois de um fazer um undo (u), no VI original fazer undo de novo desfazia o undo anterior (efetivamente, fazendo um “redo”) e para continuar fazendo undo, o primeiro comando depois de undo deveria ser .; no VIM, fazer um undo depois de um undo irá continuar desfazendo o que foi entrado no texto, até retornar ao estado original) e a não ser que você seja fã do VI original, eu não recomendaria usar o modo de compatilibidade.

set backspace=indent,eol,start

Apenas garante que o backspace consiga remover identações, apagar o fim da linha e o começo de uma linha (neste último, forçando a linha atual e se juntar com a anterior). Esse é o funcionamento normal de qualquer editor.

" Don’t use Ex mode, use Q for formatting
map Q gq

" Map Y to do the same (well, almost) as the D command
map Y y$

Estes dois mapeamentos eu peguei da configuração global, mas nunca efetivamente usei. Mas, por via das dúvidas…

Ainda, uma coisa que eu não havia comentado: Comentários. Você pode comentar qualquer linha começando a mesma com aspas (") sem as aspas finais (senão o VIM irá interpretar o conteúdo como string). Então: Uma aspa, comentário; duas aspas, string; mais de duas, erro.

if &t_Co > 2 ||&
  syntax on
  set hlsearch
endif

Ah, nosso primeiro encontro com ifs. Se o terminal tiver mais de duas cores (&t_Co > 2) ou estivermos rodando em GUI (has("gui_running")) então o suporte à sintaxes deve ser ligado (syntax on) e pesquisas devem marcar todas as ocorrências encontradas no último comando de pesquisa(set hlsearch)[1].

" ———————————————————————-
"  Those are my settings
" ———————————————————————-

set tabstop=4           " tabs are displayed as 4 spaces
set shiftwidth=4        " by default, when auto-identing, add 4 spaces (or 1 tabstop)
set foldmethod=marker   " fold on markers
set scrolloff=1         " always show one line around the cursor
set laststatus=2        " always show the status bar (’cause I like to see the line and column, always)
set showtabline=2       " always show the tabline
set showmatch           " show matching bracket
set noerrorbells        " no error bells
set autowrite           " write the file when switching between files or something
set nowrap              " do not wrap long lines
set nobackup            " do not keep a backup file, use versions instead
set history=50          " keep 50 lines of command line history
set ruler               " show the cursor position all the time
set showcmd             " display incomplete commands
set incsearch           " do incremental searching
set formatoptions=tcq   " wrap with textwidth, wrap comments, insert commend leader (twice), format comments
set smartindent         " smart identation
set number              " show line numbers
set wim=longest,list    " file auto-completion
set background=dark     " to follow most of the colorschemes I use
set vb t_vb=            " convert bells to visual bells and do nothing as visual bell

set t_Co=256            " 256 color terminals

let mapleader=","     " use comma to start user-defined (in plugins) functions

Um grande bloco de configurações. Vamos ver um por um:

  • set tabstop=4: Define o tamanho da tabulação. Se estiver usando o caractere “tab” ao invés de espaço, estes caracteres serão mostrados como 4 espaços (quando o padrão são 8).
  • set shiftwidth=4: Quando o VIM for identar um pedaço de texto sozinho[2]. Se “shiftwidth” for igual a “tabstop” e você não tiver configurado para usar espaços ao invés de tabulações (calma que eu já explico como se faz isso), o VIM irá adicionar uma tabulação inteira; se “shiftwidth” for menor que “tabstop”, espaços serão usados; se “shiftwidth” for maior que “tabstop”, será usada uma mistura de tabulações e espaços até que o tamanho especificado seja alcançado.
  • set foldmethod=marker: “Folding” foi algo que eu não comentei até agora porque eu até agora não consegui me aclimatar com folding (até porque eu não consegui pensar num mnemônico para lembrar dos comandos). Mas, basicamente, “folding” permite que você “oculte” partes do código com alguma condição. Alguns arquivos de sintaxe definem início e fim de funções e isso pode ser usado para ocultar toda uma função (apenas para exibição, a função continua existindo lá). “marker” define que o método de folding são marcadores e os marcadores padrão são “{{{” para o início e “}}}” para o fim.
  • set scrolloff=1: Número de linhas que devem sempre ficar visíveis ao redor do cursor. “1” significa que antes de chegar à primeira ou última linha da tela, o VIM irá rolar o texto e apresentar a linha anterior (ou próxima) — enquanto possível.
  • set laststatus=2: Quando estávamos vendo splits, você deve ter notado que o VIM adicionou uma barrinha indicando a posição do cursor (e talvez mais algumas outras informações). Esse é o padrão para “1” (mostrar a barra de status quando houver splits); “0” nunca mostra e “2” mostra sempre.
  • set showtabline=2: Assim como “laststatus”, se você estava vendo abas em modo de console, deve ter reparado que a linha com as abas aparecia apenas quando haviam duas ou mais abas. “2” define que essa linha de abas deve ser sempre mostrada, mesmo quando há apenas uma aba.
  • set showmatch: Quando estiver sobre um caractere como parênteses, colechetes ou chave, faz o highlight do elemento que abre ou fecha o correspondente.
  • set noerrorbells: Se ocorrer um erro, não utilize erros sons para notificações[3].
  • set autowrite: Quando o VIM passar o controle para outro aplicativo (“grep”, “make” ou mesmo o “shell”), salva o arquivo atual antes de passar a execução.
  • set nowrap: Quando uma linha for maior que a tela, desabilita a “quebra” da linha e, com isso, é necessário “rolar” o conteúdo horizontalmente para ver o resto. Um aviso: se você usar “wrap” (set wrap) o VIM vai continuar lidando a linha como uma coisa só, desconsiderando como a mesma está sendo apresentada; assim, se você estiver na primeira parte de uma linha que foi quebrada por wrap, usar qualquer comando que vá para a próxima linha irá ir para a próxima linha, não para a parte quebrada.
  • set nobackup: Não grava arquivos de backup. Por padrão, antes de salvar um arquivo, o VIM guarda uma cópia do original com o mesmo nome seguido de “~”.
  • set history=50: Quando você usa um comando, o VIM pode guardar esse comando para execução futura, como o prompt do shell. Aqui é definido quantos destes comandos são guardados.
  • set ruler: Sempre que possível, mostre a posição do cursor. Se “laststatus” for “0” (ou “1” e não houver nenhum split), a posição é exibida na última linha da tela, no canto direito; se “laststatus” for “2” (ou “1” e houver pelo menos um split), a posição é exibida dentro da barra de status[4].
  • set showcmd: Você deve ter notado que comandos que esperam mais informações (por exemplo, aqueles que requerem uma movimentação) não são mostrados em lugar algum. “showcmd” irá mostrar o comando até que ele seja concluído.
  • set incsearch: Enquanto você estiver digitando uma pesquisa, já vai posicionando o cursor na primeira ocorrência encontrada. “noincsearch” irá manter o cursor na mesma posição até que o mesmo seja concluído.
  • set formatoptions=tcq: Opções de formatação de textos. Cara um dos caracteres representa algo diferente: “t” indica que se “textwidth” estiver definido, o editor deve quebrar as linhas[5]; “c” significa que se o texto for quebrado durante um comentário (definido pela sintaxe atual), um novo caractere de comentário deve ser adicionado; “q” indica que comentários podem ser quebrados por “textwidth”.
  • set smartindent: Utiliza identação inteligente, se a sintaxe não definir nenhuma. Existem quatro tipos de identação: Nenhuma (“nosmartindent” indicando que ao adicionar uma nova linha, nenhuma identação é adicionada; “autoindent” para que novas linhas tenham a mesma identação da linha anterior; “smartindent”, que tenta usar o último caractere da linha para identificar se deve ser adicionada uma nova identação ou não (por exemplo, parênteses e chaves adicionam identação); e “cindent” que tenta seguir o padrão para C. Note que essa configuração só vale para arquivos que não definem uma identação no seu arquivo de sintaxe (que são bem poucos).
  • set number: Adiciona uma área na esquerda da tela com o número da linha na própria linha.
  • set wim=longest,list: Duas coisas aqui: 1) comandos de set tem um nome longo e um nome curto e “wim” é o nome curto para “wildmode”; 2) “wildmode” define como serão completados os nomes dos arquivos quando você usar um comando para abrir arquivos e usar [Tab] para tentar completar o nome do arquivo automaticamente. “longest,list” emula o padrão de shells como Bash.
  • set background=dark: Alguns colorschemes (temas de cor) definem dois padrões de cores, um claro e um escuro. “background=dark” define que, na existência de dois padrões, o padrão escuro deve ser usado.
  • set vb t_vb=: Mais uma coisa nova: Duas configurações em uma linha só. Na verdade, todas as configurações apresentadas aqui poderiam ficar em uma linha só, mas eu mantive estas duas juntas por um motivo: Como defini “noerrorbell”, o VIM cai para “visualbell” (nome longo de “vb”), que causa um “flash” no conteúdo (as cores do tema rapidamente se invertem e voltam ao normal) quando ocorre um erro; no caso, eu defini que sim, eu quero que o tipo de erro visual (“t_vb”) seja… nada. Assim, quando ocorre um erro, o VIM não bipa nem faz flash.
  • set t_Co=256: Define que o terminal terá, por padrão, 256 cores. Algumas vezes o VIM não consegue descobrir se o terminal tem suporte a mais de 16 cores ou não e esta configuração reafirma que sim, o terminal é capaz de usar 256 e, portanto, colorschemes podem ter mais cores.
  • let mapleader=",": Define a variável “mapleader”. “mapleader” é o caractere que o VIM utiliza em alguns plugins[5], quando estes define comandos em modo normal. O padrão é “/”, eu mudei para vírgula.
if has("autocmd")

Eu falei sobre auto-commands, mas na verdade é uma feature que deve ser adicionada na hora de compilar o VIM. Entretanto, até agora eu não vi um pacote disponível que não tenha essa feature. Apenas para garantir, verificamos se a funcionalidade foi adicionada mesmo ou não.

Boa parte do que tem daqui pra frente ou eu já falei ou veio do arquivo de configuração global.

  filetype plugin indent on

Ativa as configurações vindas do arquivo de sintaxe. Quando eu disse que as configurações de auto-identação vem do arquivo de sintaxe, é esta linha que garante que isso vai acontecer.

  autocmd FileType text setlocal textwidth=78

Quando o tipo de arquivo for texto (“text”) define localmente para aquele buffer que o tamanho da linha é de 78 colunas. Como “formatoptions” tem um “t”, o VIM irá automaticamente quebrar a linha (adicionando um [Enter] antes da palavra que passa do limite) na coluna 78.[7]

  " When editing a file, always jump to the last known cursor position.
  " Don’t do it when the position is invalid or when inside an event handler
  " (happens when dropping a file on gvim).
  autocmd BufReadPost *
    \ if line("’\"") > 0 && line("’\"") <= line("$") |
    \   exe "normal g`\"" |
    \ endif

Este comando existe no arquivo de configuração global, mas é bem interessante. Lendo exatamente o que ele faz: Depois de carregar qualquer arquivo, se a linha que o marcador de saída do buffer existir e estiver entre o começo do arquivo e antes do fim da linha, executa, em modo normal, g`", que efetivamente “pula” para o marcador de saída do buffer. A diferença entre ` e g` é que g` não mexe no jumplist quando pular (logo, `` não vai funcionar). Como não mexer no jumplist é algo que não se faz normalmente, nem comentei antes.

  autocmd FileType python autocmd BufWritePre <buffer> :%s/\s\+$//e

Eu falei deste comando antes, mas vamos de novo: Quando o tipo de arquivo for “python”, adicione um auto-comando que antes de gravar o buffer, execute, no buffer, a expressão regular /\s\+$//e, que basicamente, serve para remover espaços em branco no final das linhas.

  " omni completion
  au FileType python setlocal ofu=pythoncomplete#Complete
  au FileType javascript setlocal ofu=javascriptcomplete#CompleteJS
  au FileType html setlocal ofu=htmlcomplete#CompleteTags
  au FileType css setlocal ofu=csscomplete#CompleteCSS
  au FileType xml setlocal ofu=xmlcomplete#CompleteTags
  au FileType php setlocal ofu=phpcomplete#CompletePHP

  set completeopt-=preview

Eu não falei do Omni-complete antes porque até o momento o auto-complete ([Ctrl]p e [Ctrl]n em modo de inserção) tem resolvido todos meus problemas. Mas, em teoria, o omni-complete consegue detectar quais elementos fazem sentido no contexto atual, “encherga” coisas que estão no arquivo de tags e conhece toda a sintaxe da linguagem que você está usando. Mas, realmente, o simples auto-complete já resolve 99% dos problemas que tenho encontrado.

E desliga a apresentação dos resultados do omni-complete na janela de preview, que é semelhante ao quickfix, mas na minha experiência, ela quebra muito o fluxo de edição do código.

Se você quiser tentar, para usar o omni complete basta usar [Ctrl]x e depois [Ctrl]o.

  " ———————————————————————-
  "  Auto-commands
  " ———————————————————————-

  " default python style
  " (use spaces instead of tabs (expandtab), uses 4 spaces for tabs (tabstop),
  " when auto-indenting, also use 4 spaces (shiftwidth), when deleting text, 4
  " spaces are a tab (softtabstop) and break the line at column 78 (textwidth))
  au FileType python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 textwidth=78
  
  " reStructured files follow python closely, but use 3 tab stops instead of 4
  au FileType rst setlocal expandtab tabstop=3 sw=3 sts=3 textwidth=78
  
  " templates (Jinja2 in this case) will use tabs instead (to reduce file size)
  au FileType htmldjango setlocal noet tabstop=4 shiftwidth=4 softtabstop=4 textwidth=0
  au FileType jinja setlocal noet tabstop=4 shiftwidth=4 softtabstop=4 textwidth=0
  
  " the smarty filetypes doesn’t have any sort of indentation, so we set it to
  " auto
  au FileType smarty setlocal ai
  
  " PHP break lines at column 79, like Python
  au FileType php setlocal textwidth=79
  
  " svn (when editing svn commit messages, break lines at
  " column 70)
  au FileType svn setlocal tw=70
  
  " email (mostly mutt stuff)
  au FileType mail setlocal spell spelllang=en
  
  " JavaScript (who though those were "good" defaults?)
  au FileType javascript setlocal expandtab tabstop=2 sw=2 sts=2 textwidth=0

Uma série de auto-comandos baseados no tipo de arquivo. Como eu falei antes neste capítulo, você pode botar vários “set” um atrás do outro separados por espaço e sets tem versões com nomes longos e nomes curtos (“sts” é um atalho para “softtabstop”, “sw” para “shiftwidth”, “noet” para “noexpandtabs”, “ai” para “autoindent” e “tw” para “textwidth”). E sim, eu sei que não manti nenhum padrão no meio, mas pelo menos agora você alguns nomes curtos para algumas opções.

else
  set autoindent                " always set autoindenting on
endif " has("autocmd")

E, se autocmd não estiver disponível, simplesmente seta auto-indent.

" ———————————————————————-
" mapings
" ———————————————————————-

" Easy switching between tabs (just use Alt+<tab number>)
if has(‘mac’)
    map <D-1> :tabn 1<CR>
    map <D-2> :tabn 2<CR>
    map <D-3> :tabn 3<CR>
    map <D-4> :tabn 4<CR>
    map <D-5> :tabn 5<CR>
    map <D-6> :tabn 6<CR>
    map <D-7> :tabn 7<CR>
    map <D-8> :tabn 8<CR>
    map <D-9> :tabn 9<CR>
    map <D-0> :tabn 10<CR>

    imap <D-1> <ESC>:tabn 1<CR>a
    imap <D-2> <ESC>:tabn 2<CR>a
    imap <D-3> <ESC>:tabn 3<CR>a
    imap <D-4> <ESC>:tabn 4<CR>a
    imap <D-5> <ESC>:tabn 5<CR>a
    imap <D-6> <ESC>:tabn 6<CR>a
    imap <D-7> <ESC>:tabn 7<CR>a
    imap <D-8> <ESC>:tabn 8<CR>a
    imap <D-9> <ESC>:tabn 9<CR>a
    imap <D-0> <ESC>:tabn 10<CR>a
else
    map <M-1> :tabn 1<CR>
    map <M-2> :tabn 2<CR>
    map <M-3> :tabn 3<CR>
    map <M-4> :tabn 4<CR>
    map <M-5> :tabn 5<CR>
    map <M-6> :tabn 6<CR>
    map <M-7> :tabn 7<CR>
    map <M-8> :tabn 8<CR>
    map <M-9> :tabn 9<CR>
    map <M-0> :tabn 10<CR>

    imap <M-1> <ESC>:tabn 1<CR>a
    imap <M-2> <ESC>:tabn 2<CR>a
    imap <M-3> <ESC>:tabn 3<CR>a
    imap <M-4> <ESC>:tabn 4<CR>a
    imap <M-5> <ESC>:tabn 5<CR>a
    imap <M-6> <ESC>:tabn 6<CR>a
    imap <M-7> <ESC>:tabn 7<CR>a
    imap <M-8> <ESC>:tabn 8<CR>a
    imap <M-9> <ESC>:tabn 9<CR>a
    imap <M-0> <ESC>:tabn 10<CR>a
endif

Ok, este é um mapeamento que eu sempre achei interessante:

1) Existe uma diferença entre OS X e outros sistemas que a tecla “Command” é usada para praticamente tudo, inclusive trocar as abas nos browsers; já em outros sistemas, a tecla para isto é “Alt”. Um VIM compilado para OS X tem, estranhamente, uma feature chamada “mac”; checando isso você consegue descobrir se está rodando num OS X ou não.

2) Mapeamentos diferentes para modo normal e de inserção: Se estiver no modo normal, basta usar :tabn {número} para pular diretamente para uma aba (:tabn {número} é a versão de modo de comando do {número}gt do modo normal[8][9]); quando estiver em modo de inserção, saida do modo de inserção (simulando pressionar [Esc] com <ESC>, execute o mesmo comando usado no modo normal para pular para uma aba específica e volte para o modo de inserção (a).

BOOM! Você acabou de adicionar no VIM uma feature que existe nos browsers.

" custom PHP syntax file configuration
let php_smart_members=1

Essa é uma das coisas que eu falei antes: “let” permite definir variáveis, incluindo algumas dentro do arquivo de sintaxe. No caso php_smart_members altera a forma como funções membro de uma classe em PHP seja coloridas de forma diferente.

O resto do meu arquivo de configuração é usado para manter plugins, que eu vou explicar o que cada um faz mais pra frente. Se você quiser ver o arquivo original, ele pode ser encontrado no meu repositório de configurações (que eu uso para manter as configurações sincronizadas entre meu computador pessoal e o computador do trabalho).

Ah, e se você estiver se perguntando como eu fiz para colorir a configuração do VIM: Eu usei o comando :TOhtml que existe no próprio VIM. As cores que você está vendo são as cores que eu uso no meu colorscheme (Mustang, que eu vou falar na parte de plugins).

[1] Apenas para fazer um gancho com o que foi falado anteriormente: No capítulo #2.5, quando estava falando de comandos do modo de comando, eu comentei sobre :noh para desmarcar as ocorrências encontradas no último comando de pesquisa. Bom, hlsearch faz com que estas ocorrências sejam marcadas e se você colocar set nohlsearch, nenhuma ocorrência será marcada e você nunca irá precisar usar :noh.

[2] … ou quando você usar >{movimentação} ou <{movimentação} em modo normal, que eu não havia mencionado antes porque estávamos falando de edição de qualquer texto e não de código fonte. >> irá adicionar um “shiftwidth” para a direita e << irá remover um “shiftwidth” na esquerda.

[3] Aqui acabamos de ver duas configurações de flags: Uma ativando uma configuração (“showmatch”) e outra desligando (“noerrorbells”).

[4] Uma pequena nota sobre as posições apresentadas: algumas vezes, você verá o VIM apresentar a coluna como “{número}-{número}”. Isso acontece principalmente quando se está usando tabulações ao invés de espaços e o VIM está indicando a contagem de caracteres na esquerda e a coluna de exibição na direita (ou seja, o valor da direita é {quantidade de caracteres menos tabulações} + ({quantidade de tabulações} * {“tabstop”}).

[5] E quando digo “quebrar” eu quero dizer “quebrar” mesmo: Enquanto que “wrap” irá cuidar apenas da apresentação do texto, “textwidth” com “formatoptions=t” irá inserir um caractere de nova linha quando a palavra digitada ultrapassar o limite indicado.

[6] Note que o VIM define uma variável para isso, mas nada garante que o autor do plugin utilizou essa tecla. Existe um padrão em usar “mapleader” como início de comando normal de um plugin, mas nada obriga o autor do plugin à usar esta tecla.

[7] E, recapitulando, para reformatar o parágrafo caso você altere alguma coisa no texto, use gq sobre a região do mesmo. O VIM irá considerar o “textwidth” na hora de reformatar.

[8] E não, não são todos os comandos que tem versões tanto em modo normal quanto em modo de comando.

[9] E porque eu usei :tabn {número} ao invés de {número}gt? Porque quando eu pesquisei como pular de abas, este foi o primeiro resultado que eu encontrei.

Uma Lição de VIM #12: Arquivos de Configuração

(Essa é a parte em que eu menti.)

Lembram que bem no começo, quando estávamos falando dos modos de execução, eu comentei que o modo Ex não era usado?

Bom, eu menti. MUAHAHAHAHA!

muahaha

Na verdade, o Modo Ex não é chamado comumente, mas os arquivos de configuração do VIM são um grande amontoado de comandos executando em modo Ex.

E o que é o modo Ex, afinal de contas? O modo Ex nada mais é que o modo de comando sem a necessidade de usar : na frente de todos os comandos. Como ficaria complicado para, por exemplo, entrar no modo Ex, executar e arquivo, sair do modo ex e entrar em modo de inserção, até o momento temos usado o modo de comando para isso, já que economiza um monte de tecladas. Como não iremos ficar indo para o modo de inserção o tempo todo, e não faz sentido fazer um arquivo gigantesco com várias linhas começando com :, também faz sentido que o arquivo de configuração seja executado em modo Ex.

O VIM tem um arquivo de configuração global (conhecido com vimrc) e um arquivo para execução em modo gráfico (gvimrc)[1]. Ainda, existem duas versões de cada um destes arquivos: uma versão global para todos os usuários e uma versão definida para o usuário atual. Daqui pra frente, iremos ver as configurações do usuário, já que estas sobrepõem as globais.

vimrc e gvimrc ficam no diretório dos dados do usuário; em qualquer um dos sistemas operacionais hoje, você consegue descobrir o diretório destes arquivos com :echo $HOME dentro do próprio VIM. Apenas note que embora eu venho chamando os arquivos de vimrc e gvimrc, os nomes são, na verdade, .vimrc e .gvimrc (ou _vimrc e _gvimrc no caso do Windows).

Como existem muitas opções, não vou aqui explicar cada uma delas — mas, no próximo capítulo eu vou mostrar o arquivo que eu estou usando para servir de guia.

O que você vai ver quando abrir um arquivo de configuração:

set

set é, efetivamente, a forma de “setar” alguma configuração no VIM.

Existem dois tipos de configurações: As com valores e flags.

Flags é mais fácil de ser explicado: você simplesmente seta a configuração. Por exemplo, fazer com que o editor mostre uma coluna com o número de cada linha, você pode usar :set number (ou simplesmente set number dentro do arquivo de configuração). Para desligar uma opção deste tipo, você só precisa adicionar “no” na frente (para desligar number é usado :set nonumber).

“Valores” é exatamente o que significa: Ao invés de ser uma simples flag, a opção recebe uma string ou número. Por exemplo, :set tabstop=4 irá definir que o tamanho da tabulação é de 4 espaços. :set notabstop não tem efeito aqui, já que não é uma flag.

Para fazer com que uma configuração volte ao seu valor/estado original, use :set {opção}&; para verificar o valor de uma opção, use :set {opção}?.

Talvez a coisa não esteja muito clara aqui, mas quando examinarmos um arquivo de configuração real, as coisas irão clarear.

let

let é usado para definir o valor de uma variável. Uma variável tem sempre um valor — ou seja, não existem “variáveis flags”. Variáveis são normalmente utilizadas por plugins ou arquivos de sintaxe e, portanto, as variáveis que você terá que usar vão depender do que você está usando.

(Obviamente, se você estiver escrevendo seu próprio plugin — que eu não vou abordar aqui — o uso de variáveis vai ser praticamente obrigatório.)

if

if, como em qualquer linguagem de programação, serve para execução condicional. Você pode, por exemplo, verificar se alguma feature foi ativada na compilação do binário, se alguma opção está ligada, etc.

Por exemplo, para verificar se o suporte à scripts Python foi adicionado, você pode fazer:


if has('python')
" configuração em python vai aqui
end

Para verificar se alguma opção está ativa:


if &compatible
" configuração em modo de compatibilidade com o VI original
end

ou para conferir um valor:


if &t_Co > 2
" configuração quando há suporte a mais de 2 cores.
end

E assim por diante.

map, imap (e outros)

map pode ser usado para mapear teclas para outras funções. Por exemplo :map Y y$ irá mapear Y para executar y$ (copiar da posição atual do cursor até o fim da linha). Com excessão de [Shift], qualquer modificador pode ser usado:

  • C- para [Control]
  • M- para [Alt] (que normalmente é chamado de “Meta” em sistemas Unix — e por isso “M”)
  • O- para [Command] (somente em Macs)

Por exemplo, :map C-m yy irá adicionar [Ctrl]m para copiar a linha inteira.

Ainda, a diferença entre map e imap é que map é global enquanto que imap só irá funcionar em modo de inserção (e assim você pode imaginar o que nmap e vmap fazem, certo?)

au (ou autocmd)

Comandos que são executados em determinadas condições. Condições podem desde “FileType” para ações confirme o tipo de arquivo e “BufRead”, “BufWrite” e relacionados quando um buffer for aberto ou fechado.

O que seriam os “relacionados”? Bom, alem de ser na leitura/escrita do arquivo, podem ser adicionados comandos antes da execução (“BufReadPre”, “BufWritePre”), depois da execução (“BufReadPost”, “BufWritePost”) e durante (“BufReadCmd”, “BufWriteCmd”).

(Existem ainda auto-comandos para quando o editor entrar em modo de edição, abrir o VIM gráfico, VIM está fechando, e assim por diante. Para ver todos os eventos, digite :help autocmd-events.)

Por exemplo, au FileType smarty set ai para ligar a auto-identação quando VIM detectar que você está editando um arquivo Smarty (engine de templates para PHP). Ou ainda au BufRead set nocompatible irá configurar o editor para entrar em modo de não-compatibilidade com VI depois de abrir qualquer arquivo.

Ainda, é possível encadear auto-comandos, por exemplo, autocmd FileType python autocmd BufWritePre :%s/\s\+$//e irá fazer com que quando o tipo de arquivo for “python”, seja criado um auto-comando que antes de salvar o arquivo, seja executado um comando de substituição no buffer — que remove espaços em branco no final da linha).

(Se você está perdido com o que está vendo aqui, não se preocupe — a tendência é que, ao ver um arquivo de configuração real, você entenda o que está acontecendo).

[1] Existe um terceiro, .exrc, mas honestamente, em todo esse tempo usando o VIM, eu nunca tinha ouvido falar que este arquivo sequer existia.

Uma Lição de VIM #11: Abas

(Essa é a parte me que você acha coisas que já fazia antes.)

Além dos splits, que vimos no capítulo anterior, VIM também tem suporte à abas. O mais interessante é que você pode usar abas tanto no VIM gráfico (também chamado de GVim) quanto no console.

Para abrir um arquivo no VIM, sabemos que temos que usar o comando :e; para abrir o arquivo em uma aba, o comando é :tabe.

Ao contrário de splits, criar uma nova aba sem passar um arquivo não cria uma nova aba com o buffer atual; :tabe sem um nome de arquivo irá criar uma nova aba com um buffer em branco. E sim, você pode abrir o mesmo arquivo em mais de uma aba e as alterações feitas em uma irão refletir na outra.

Para pular entre abas, você poder usar o comando gt em modo normal ou :tabn em modo de comando. Se você usar um número de repetições (p.ex. 3gt ou :tabn 3) o VIM irá pular diretamente para aquela aba (no caso, para a terceira), não importando a aba atual. gT em modo normal ou :tabp move o cursor para a aba anterior.

Se quiser mover abas de posição, você deve usar :tabm. :tabm irá mover a aba atual para ficar depois da aba indicada (p.ex., :tabm 3 irá mover a aba atual para depois da terceira aba). :tabm também aceita parâmetros considerando a aba atual: :tabm +2 irá mover a aba atual duas abas pra frente (para a direita) e :tabm -2 irá mover a aba duas abas pra trás (para a esquerda).

Atalhos padrão para mover para a próxima aba do sistema operacional também são aceitos por padrão. [Ctrl][PageDn] e [Ctrl][PageUp] no Linux e [Command][Shift]] e [Command][Shift][ no OS X, por exemplo. Como não existe nenhum padrão para consoles, não há nenhum atalho padrão e devem ser usados os comandos de seleção de abas que vimos antes.

Mais pra frente, quando estivermos falando do arquivo de configuração, eu vou explicar um “truque” para pular diretamente para a aba desejada, assim como funciona no Firefox e no Chrome.

Uma Lição de VIM #10: Splits

(Essa é a parte em que você vai passar uma hora dividindo a tela em pedacinhos cada vez mais pequenos.)

Até agora, enquanto falávamos de editar textos no VIM, vimos apenas como editar um arquivo por vez. Existem formas de editar mais de um arquivo (usando :e e :e#{número}) mas estas estão longe de serem fáceis de serem utilizadas.

Existem duas formas de manter dois (ou mais) arquivos abertos ao mesmo tempo. Uma delas são “splits”. Basicamente, splits permitem que você “reparta” a tela em pedaços, podendo mostrar outros arquivos (ou até mesmo outra vez o mesmo arquivo).

Para criar splits, existem dois comandos que devem ser usados em modo de comando: :sp e :vsp. Ambos comandos aceitam o nome do arquivo a ser aberto no novo split; se não for passado o nome de um arquivo, o arquivo que já está aberto será carregado.

A diferença entre eles é que :sp irá criar um split horizontal...

horizontal-split

... enquanto que :vsp irá criar um split vertical.

vertical-split

Dentro de cada split, comandos executados irão afetar apenas o buffer atual: :w irá salvar apenas o arquivo apresentar no split atual, :e irá abrir um arquivo no split atual e assim por diante.

Note que eu falei “buffer atual”. Como falei antes, “buffer” é o nome dado para a representação do arquivo em memória e que tanto :sp quanto :vsp sem parâmetros irão abrir um split com o arquivo atual — que, na verdade, é o buffer atual. Se você fizer isso e começar a editar o texto em um dos splits, o conteúdo do outro também irá mudar, já que ambos estão apresentando o mesmo buffer.

Para fechar um split, basta fechar o arquivo, tanto com :q quanto :wq ou qualquer outro comando que feche um arquivo. O split será removido e o cursor irá para o próximo split. Se não houverem mais splits, o VIM irá fechar, como já vinhamos vendo desde o começo.

E sim, você pode fazer quantos splits e de formas diversas quantas vezes quiser (até que não sobre mais espaço na tela, quer dizer).

all

Para “manusear” splits, você irá utilizar comandos que começam com, em modo normal, [Ctrl]w. [Ctrl]w, por si só, não faz nada (a não ser que você repita o comando, mas isso é outra coisa) e requer uma ação a ser executada no split (assim como alguns comandos requerem uma movimentação).

[Ctrl]wj ou [Ctrl]w[direcional para baixo]
Move o cursor para o split abaixo do atual. Se não houverem outros splits abaixo do atual, permanece no mesmo. Aceita um número de repetiçoes, ou seja, 3[Ctrl]wj irá imediatamente pular para o 3o. split abaixo do atual.
[Ctrl]wh ou [Ctrl]w[direcional para a esquerda] e [Ctrl]wk ou [Ctrl]w[direcional para cima] e [Ctrl]wl ou [Ctrl]w[direcional para a direita]
O mesmo que [Ctrl]wj, mas indo para o split da esquerda, acima ou direita, respectivamente.
[Ctrl]w+ e [Cltr]w-
Aumenta ou diminui o tamanho do split em uma linha. Se for passado um número antes do comando — por exemplo 3[Ctrl]w+ — o número de linhas afetas será o número indicado.
[Ctrl]w> e [Ctrl]w<
O mesmo que [Ctrl]w+ e [Ctrl]w-, mas altera o número de colunas ao invés do número de linhas.
[Ctrl]w_ e [Ctrl]w|
Deixa o split com o maior altura possível (ou seja, coloca o máximo de linhas possíveis para o split) ou com a maior largura possível (ou seja, coloca o máximo de colunas possíveis para o split).
[Ctrl]w=
Altera o tamanho dos splits para que estes fiquem o mais equilibrados possíveis.
[Ctrl]wH, [Ctrl]wJ, [Ctrl]wK,/tt> e [Ctrl]wL
Move o split atual para o canto mais a esquerda, abaixo, acima ou direita, respectivamente (note que a letra de movimentação está em maiúsculas).
[Ctrl]ww
Move o cursor para o split anterior. Se você está em um split qualquer e fizer 3[Ctrl]wj para ir para o 3o. split abaixo do atual, [Ctrl]ww irá mover o cursor de volta para o split original (e [Ctrl]ww irá mover o cursor de volta para o 3o. split abaixo do atual).
[Ctrl]wf
Abre o arquivo com o nome sob o cursor em um novo split.

Quando falei do grep, eu comentei que existe o comando :cope para abrir a janela do Quickfix. Bom, se você quiser ficar pulando entre a janela do Quickfix e o texto, os comandos [Ctrl]w acima irão ajudar.

Existem ainda alguns outros comandos para splits, mas veremos estes mais a frente.

Uma Lição de VIM #9: Localizar e Substituir

(Essa é a parte em que você vai precisar aprender expressões regulares — mais uma vez.)

Uma coisa relativamente comum quando se está programando é substituir todas as ocorrências de uma palavra por outra[1]

Para fazer “localizar e substituir” (“search and replace”) existe o comando :substitute em modo de comando (ou simplesmente :s).

Até aí sem problemas, mas existe uma pequena pegadinha (na verdade, duas, mas uma de cada vez): :s é, na verdade, :{range}s, onde {range} é a parte do texto que o comando :s deve ser executado — e sim, eu sei que não falei sobre este tipo de comando antes, mas essa era a melhor oportunidade.

Então, {range}. {range} é opcional e, se não for passado, o comando será executado da linha atual. Isto, obviamente, não é muito útil. {range} é formado por um par[2], separado por vírgulas, indicando o início e o fim da execução do comando.

O uso básico de {range} é “linha inicial,linha final“. Por exemplo, :1,5s irá executar o comando :s entre as linhas 1 (a primeira, não existe linha 0 no VIM) e 5.

E, mais uma vez, existem indicadores especiais, inclusive para {range}.

Um número indica o número da linha, como já comentei. $ é a última linha do arquivo (assim, :1,$s irá executar :s em todo o arquivo); % é um alias para 1,$ (ou seja, todo o arquivo); '{marcador} irá, obviamente, utilizar os marcadores (ou seja, :'a,'bs irá executar :s entre o marcador a e o marcador b — E marcadores entre arquivos [em maiúsculas] não são permitidos).

(E existe outros dois marcadores especiais que eu não comentei antes por achar que não há uso fora do :s que são '< e '> que indicam, respectivamente, o início e o fim da região visual — mas o VIM vai adicionar estes dois marcadores automaticamente se você tiver uma região visual selecionada e pressionar : e por isso ficaram pra trás. Então não se assuste se o VIM começar a colocar coisas na linha de comando sem que você tenha digitado.)

Daqui pra frente, eu vou colocar o comando como :%s, já que esta é a execução mais comum do comando. Mas lembre-se que % = 1,$ = do começo ao fim.

:%s funciona, assim como a pesquisa, com expressões regulares, só que ao invés de termos uma expressão, teremos duas: a de pesquisa e a de substituição. Em casos mais simples, onde você quer substituir “palavra 1” por “palavra 2”, o comando será :%s/palavra 1/palavra 2. Mais uma vez, conhecer expressões regulares vai ajudar aqui — e fica a dica para olhar sobre “grupos”.

A segunda pegadinha é que :%s executa o comando em cada linha do range e, como padrão, somente a primeira ocorrência é substituída. Assim, se “palavra 1” existir mais de uma vez em uma linha, somente a primeira será alterada.

Para resolver isso, você deve usar o terceiro parâmetro de :%s, {flags}. As flags mais comuns são:

g
Substitui todas as ocorrências da expressão de procura na linha, não apenas a primeira.
i
Ignora maiúsculas e minúsculas (“ignore case”)
c
Pede confirmação em cada alteração.

Concluindo: para substituir “void” por “int*” em todo o arquivo mas apenas no começo da linha, ignorando se está em maiúsculas ou minúsculas (porque o estagiário pensou que estava digitando uma monografia), mas confirmando cada mudança, você faria :%s/^void/int*/ic (como é apenas no começo da linha e nós forçcamos isso na expressão regular — o ^ ali — não precisamos usar a flag g, já que não teria efeito nenhum).

[1] E, mas pra frente, veremos que existem plugins que deixam esta parte mais fácil.

[2] Na verdade, não e um par mas, de novo, fazer substituição em apenas uma linha não é muito útil, principalmente considerando os comandos que o VIM tem para movimentação do cursor.

Uma Lição de VIM #8: Procurar em Vários Arquivos

(Essa é a parte em que mais uma vez você vai ter que pesquisar sobre expressões regulares.)

Já vimos o comando de pesquisa, que tem um modo inteiro só pra si[1].

Mas como fazer para encontrar ocorrências de uma palavra em mais de um arquivo? Para isto, existe o comando :grep.

O grep é uma ferramente comum em Unixes (e Linux) em geral, mas o VIM tem scripts que fazem a mesma coisa em outros sistemas operacionais (por exemplo, Windows). Assim, o mesmo comando vai funcionar da mesma forma não importando qual sistema você esteja utilizando.

Como o :grep usa outras funcionalidades existentes no VIM, iremos ver um pouco mais do que simplesmente “Procurar”, mas isso é necessário.

Como o modo de pesquisa, :grep precisa de uma expressão regular. Ao contrário do modo de pesquisa, o :grep também precisa de uma lista de arquivos a serem pesquisados. Por baixo dos panos, o que o VIM faz é chamar o comando “grep” (do Unix), verifica o resultado e permite pular facilmente entre os elementos encontrados (então todas as opções disponíveis para o grep podem ser passadas diretamente de dentro do VIM).

Por exemplo, para pesquisar por arquivos que contém a palavra “void”, você só precisa executar o comando :grep void * (onde :grep é o comando, void é a expressão a ser pesquisada e * é a lista de arquivos a serem pesquisados). Como o grep (o aplicativo do Unix) somente pesquisa arquivos no diretório especificado (no nosso caso anterior, como não foi passado diretório algum, será considerado o diretório atual), o :grep (o comando do VIM) também não vai entrar em nenhum subdiretório (de novo, porque o VIM simplesmente chama o grep [aplicativo do Unix] e facilita pular entre os elementos encontrados). Para fazer uma procura que encontre a expressão além do diretório atual, basta adicionar a opção -r para o grep (grep void -r *).

Ok, agora que você sabe usar o :grep… Como é que você vê os resultados?

Primeira informação periférica: O VIM tem um tipo de “janela” especial, chamada “Quickfix”. Essa “janela” é, na verdade, um “split” da tela (e mais a frente veremos como trabalhar com “splits” e abas). Para exibir o Quickfix, é usado o comando :copen; para fechar o Quickfix, basta usar :copen de novo. Para passar para o próximo elemento existente no Quickfix, use :cnext (ou simplesmente :cn); para passar para o elemento anterior, use :cprevious (ou simplesmente :cp); para mover o cursor para a posição do elemento atual do Quickfix, use :cc (que é simplesmente :cc mesmo).

A segunda informação periférica: Como eu falei, usar :grep {expressão} * irá procurar {expressão} a partir do diretório atual. Para descobrir qual é o “diretório atual” para o VIM, use :pwd (de “print working directory”, que também é um comando Unix); para mudar para outro diretório, utilize o comando :cd {diretório}, como você faria num shell normal.

(E antes que alguém pergunte: Sim, você pode fazer um grep fora do diretório atual passando o diretório em questão no próprio comando do grep: :grep void /tmp -r irá procurar por “void” em todos os arquivos existentes no diretório /tmp.)

[1] Apenas para lembrar, / entra no modo de pesquisa, onde só é preciso entrar a expressão regular a ser encontrada; para passar para a próxima ocorrência, use n em modo normal; para passar para a ocorrência anterior, use N também em modo normal; para remover o realce das palavras encontradas, use :noh em modo de comando.