Criando Scripts do Editor Vim, Parte 1: Variáveis, Valores e Expressões

Comece com os Elementos Básicos do Vimscript

Vimscript é um mecanismo para reformar e estender o editor Vim. Criar scripts permite criar novas ferramentas, simplificar tarefas comuns e até projetar novamente e substituir recursos do editor existentes. Este artigo (o primeiro de uma série) introduz os componentes fundamentais da linguagem de programação Vimscript: valores, variáveis, expressões, instruções, funções e comandos. Esses recursos são demonstrados e explicados através de uma série de exemplos simples.

Damian Conway, Dr., CEO and Chief Trainer, Thoughtstream

author photo - damian conwayDamian Conway é um Professor Associado Adjunto de Ciência da Computação na Monash University, Austrália, e CEO da Thoughtstream, uma empresa de treinamento de TI internacional. Ele é um usuário diário do vi há mais de vinte e cinco anos e quase não tem esperanças de acabar com essa compulsão.



06/Mai/2009

Um Grande Editor de Texto

Existe um trocadilho antigo que diz que o Emacs seria um grande sistema operacional se ao menos tivesse um editor de texto decente, enquanto o vi seria um grande editor de texto se ao menos tivesse um sistema operacional decente. Essa brincadeira reflete a grande e única vantagem estratégica que o Emacs sempre teve sobre o vi: uma linguagem de programação de extensão integrada. Na verdade, o fato de os usuários do Emacs estarem dispostos a aturar o RSI-inducing control chords e gravar suas extensões em Lisp mostra como uma linguagem de extensão integrada pode ser uma grande vantagem .

Mas os programadores de vi não precisam mais ter inveja da linguagem de script parentética do Emacs. Nosso editor favorito também pode ser submetido a scripts—e de forma muito mais humana do que o Emacs.

Nesta série de artigos, veremos as variantes modernas mais populares do vi, o editor Vim, e a linguagem de script simples, mas extremamente poderosa, fornecida pelo Vim. Este primeiro artigo explora os blocos de construção básicos da criação de scripts Vim: variáveis, valores, expressões, controle de fluxo simples e algumas das inúmeras funções de utilitários do Vim.

Suponho que você já tenha acesso ao Vim e esteja familiarizado com seus recursos interativos. Se esse não for o caso, alguns bons pontos de partida são o próprio Web site do Vim e vários manuais impressos e recursos on-line; ou você pode simplesmente digitar :help no Vim. Consulte a seção Recursos para obter os links.

A menos que seja indicado de outra forma, todos os exemplos nesta série de artigos supõem que você esteja utilizando o Vim versão 7.2 ou superior. Você pode verificar qual versão do Vim está utilizando invocando o editor da seguinte forma:

vim --version

ou digitando :version no Vim. Se estiver utilizando uma versão mais antiga do Vim, é altamente recomendado atualizá-la para o release mais recente, pois as versões anteriores não suportam muitos dos recursos do Vimscript que iremos explorar. A seção Recursos possui um link para você fazer o download e o upgrade do Vim.


Vimscript

A linguagem de script do Vim, conhecida como Vimscript, é uma linguagem imperativa dinâmica típica que oferece a maioria dos recursos de linguagem comuns: variáveis, expressões, estruturas de controle, funções integradas, funções definidas pelo usuário, cadeias de primeira classe, estruturas de dados de alto nível (listas e dicionários), E/S de terminal e arquivo, correspondência de padrão regex, exceções e um depurador integrado.

Você pode ler a documentação do Vim sobre Vimscript através do sistema de ajuda integrado digitando:

:help vim-script-intro

em qualquer sessão do Vim. Ou apenas continuar lendo.

Executando Scripts Vim

Existem inúmeras maneiras de se executar comandos de scripts Vim. A abordagem mais simples é colocá-lo em um arquivo (normalmente com uma extensão .vim) e executar o arquivo através de :source a partir de uma sessão do Vim:

:source /full/path/to/the/scriptfile.vim

Alternativamente, você pode digitar comandos de script diretamente na linha de comandos do Vim depois de dois pontos. Por exemplo:

:call MyBackupFunc(expand('%'), { 'all':1, 'save':'recent'})

Mas poucas pessoas fazem isso. Afinal, o grande objetivo da criação de scripts é reduzir a quantidade de caracteres que você deve digitar. Portanto, a maneira mais comum de se invocar scripts Vim é criando novos mapeamentos de teclado, como a seguir:

:nmap ;s :source /full/path/to/the/scriptfile.vim<CR>

:nmap \b :call MyBackupFunc(expand('%'), { 'all': 1 })<CR>

Comandos como esses normalmente são colocados no arquivo de inicialização .vimrc em seu diretório inicial. Consequentemente, quando você estiver no modo Normal (em outras palavras, sem inserir texto), a sequência de chaves ;s executará o arquivo de script especificado, e uma sequência \b chamará a função MyBackupFunc() (que, presumivelmente, você definiu em algum lugar no .vimrc).

Todos os exemplos de Vimscript neste artigo utilizam mapeamentos de chaves de vários tipos como acionadores. Em futuros artigos, vamos explorar duas outras técnicas de chamada comuns: executando scripts como comandos com vírgulas a partir da linha de comandos do Vim e utilizando eventos do editor para acionar scripts automaticamente.


Um Exemplo Sintático

Vim possui recursos de realce da sintaxe extremamente sofisticados, que você pode ativar com o comando :syntax enable integrado e desativar novamente com :syntax off.

É cansativo ter que digitar dez ou mais caracteres cada vez que você quer alternar o realce da sintaxe. Em vez disso, é possível colocar as seguintes linhas de Vimscript em seu arquivo .vimrc:

Listagem 1. Alternando o Realce da Sintaxe
function! ToggleSyntax()
   if exists("g:syntax_on")
      syntax off
   else
      syntax enable
   endif
endfunction

nmap <silent>  ;s  :call ToggleSyntax()<CR>

Isso faz com que a sequência ;s ative ou desative o realce da sintaxe cada vez que ele for digitado quanto você estiver no modo Normal. Vamos dar uma olhada em cada componente desse script.

O primeiro bloco de código é, obviamente, uma declaração de função, definindo uma função denominada ToggleSyntax(), que não possui nenhum argumento. Essa função definida pelo usuário primeiro chama uma função do Vim integrada chamada exists(), passando para ela uma cadeia. A função exists() determina se uma variável com o nome especificado pela cadeia (nesse caso, a variável global g:syntax_on) foi definida.

Se sim, a instrução if executa syntax off; caso contrário, executa syntax enable. Como syntax enable define a variável g:syntax_on, e syntax off remove a definição, chamar a função ToggleSyntax() repetidamente faz uma alternância entre a ativação e a desativação do realce da sintaxe.

Tudo que resta é configurar uma sequência de chaves (;s neste exemplo) para chamar a função ToggleSyntax():

nmap <silent> ;s :call ToggleSyntax()<CR>

nmap significa "normal-mode key mapping." A opção <silent> depois de nmap faz com que o mapeamento não ecoe nenhum comando que ele está executando, garantindo que o novo comando ;s faça seu trabalho de forma discreta. Esse trabalho significa executar o comando:

:call ToggleSyntax()<CR>

que é como você chama uma função no Vimscript quando pretende ignorar o valor de retorno.

Observe que os índices <CR> no final é a sequência literal de caracteres <,C,R,>. O Vimscript reconhece isso como sendo equivalente a um retorno de linha literal. De fato, o Vimscript entende muitas outras representações semelhantes de caracteres que não podem ser impressos. Por exemplo, é possível criar um mapeamento do teclado para deixar sua barra de espaço agir como a tecla page-down (como na maioria dos navegadores da Web), como a seguir:

:nmap <Space> <PageDown>

Você pode ver a lista completa desses símbolos especiais digitando :help keycodes no Vim.

Observe também que ToggleSyntax() pôde chamar o comando integrado syntax diretamente. Isso porque cada comando com dois pontos integrados no Vim também é automaticamente uma instrução no Vimscript. Por exemplo, para facilitar a criação de títulos centralizados para documentos gravados no Vim, é possível criar uma função que converta para maiúscula cada palavra na linha atual, centralize a linha inteira e vá para a próxima linha, como a seguir:

Listagem 2. Criando Títulos Centralizados
function! CapitalizeCenterAndMoveDown()
   s/\<./\u&/g   "Built-in substitution capitalizes each word
   center        "Built-in center command centers entire line
   +1            "Built-in relative motion (+1 line down)
endfunction

nmap <silent>  \C  :call CapitalizeCenterAndMoveDown()<CR>

Instruções Vimscript

Como os exemplos anteriores ilustraram, todas as instruções no Vimscript são finalizadas por uma nova linha (como em shell scripts ou Python). Se você precisar executar uma instrução através de várias linhas, o marcador de continuação será uma única barra invertida. Raramente a barra invertida não vai no final da linha a ser continuada, mas sim no começo da linha de continuação:

Listagem 3. Continuando Linhas Utilizando Barra Invertida
call SetName(
\             first_name,
\             middle_initial,
\             family_name
\           )

Também é possível colocar duas ou mais instruções em uma única linha separando-as com uma barra vertical:

echo "Starting..." | call Phase(1) | call Phase(2) | echo "Done"

Ou seja, a barra vertical no Vimscript é equivalente a um ponto e vírgula na maioria das outras linguagens de programação. Infelizmente, o Vim não poderia utilizar o ponto e vírgula, já que o caractere já significa alguma coisa no início de um comando (especificamente, ele significa "da linha atual para..." como parte do intervalo da linha do comando).

Comentários

Um uso importante da barra vertical como um separador de instrução é nos comentários. Os comentários do Vimscript começam com aspas duplas e continuam até o final da linha, como a seguir:

Listagem 4. Comentários no Vimscript
if exists("g:syntax_on")
   syntax off      "Not 'syntax clear' (which does something else)
else
   syntax enable   "Not 'syntax on' (which overrides colorscheme)
endif

Infelizmente, as cadeias do Vimscript também podem começar com aspas duplas e sempre têm precedência sobre os comentários. Isso significa que você não pode colocar um comentário em qualquer lugar onde se espera uma cadeia, pois ele sempre será interpretado como uma cadeia:

echo "> " "Print generic prompt

O comando echo espera uma ou mais cadeias, portanto, essa linha produz um erro ao reclamar sobre a aspa de fechamento ausente na (que o Vim acredita ser) a segunda cadeia.

Comentários podem, entretanto, sempre aparecer no início de uma instrução, portanto, você pode corrigir o problema acima utilizando uma barra vertical para iniciar explicitamente uma nova instrução antes de iniciar o comentário, como a seguir:

echo "> " |"Print generic prompt

Valores e Variáveis

A designação de variável no Vimscript requer uma palavra-chave especial, let:

Listagem 5. Utilizando a Palavra-chave let
let name = "Damian"

let height = 165

let interests = [ 'Cinema', 'Literature', 'World Domination', 101 ]

let phone     = { 'cell':5551017346, 'home':5558038728, 'work':'?' }

Observe que as cadeias podem ser especificadas com aspas duplas ou aspas simples como delimitadores. As cadeias com aspas duplas respeitam "sequências de escape" especiais tais como "\n" (para nova linha), "\t" (para tabular), "\u263A" (para Unicode smiley face) ou "\<ESC>" (para o caractere de escape). Em contraste, as cadeias de aspas simples tratam tudo que está dentro de seus delimitadores como caracteres literais—exceto aspas simples consecutivas, que são tratadas como aspas simples literais.

Normalmente, os valores em Vimscript são um dos três tipos a seguir:

  • escalar: um valor único, como uma cadeia ou número. Por exemplo: "Damian" ou 165
  • lista: uma sequência ordenada de valores delimitados por colchetes, com índices de números inteiros implícitos começando com zero. Por exemplo: ['Cinema', 'Literature', 'World Domination', 101]
  • dicionário: um conjunto não ordenado de valores delimitados por chaves, com chaves de cadeias explícitas. Por exemplo: {'cell':5551017346, 'home':5558038728, 'work':'?'}

Observe que os valores em uma lista ou em um dicionário não têm que ser todos do mesmo tipo; você pode misturar cadeias, números e até listas e dicionários aninhados se quiser.

Ao contrário dos valores, as variáveis não têm um tipo inerente. Em vez disso, elas assumem o tipo do primeiro valor designado a elas. Portanto, no exemplo precedente, as variáveis name e height agora são escalares (ou seja, elas podem daqui por diante armazenar apenas cadeias ou números), interests agora é uma variável da lista (ou seja, ela pode armazenar apenas listas) e phone agora é uma variável do dicionário (e pode armazenar apenas dicionários). Os tipos de variáveis, após designados, são permanentes e estritamente obrigatórios no tempo de execução:

let interests = 'unknown' " Error: variable type mismatch

Por padrão, uma variável tem escopo definido na função para a qual é designada pela primeira vez, ou é global se sua primeira designação ocorrer fora de qualquer função. Entretanto, variáveis também podem ser declaradas explicitamente como pertencentes a outros escopos, utilizando uma variedade de prefixos, conforme resumido na Tabela 1.

Tabela 1. Definição de Escopo da Variável do Vimscript
PrefixoSignificado
g:varname A variável é global
s:varname A variável é local para o arquivo de script atual
w:varname A variável é local para a janela do editor atual
t:varname A variável é local para a guia do editor atual
b:varname A variável é local para o buffer do editor atual
l:varname A variável é local para a função atual
a:varname A variável é um parâmetro da função atual
v:varname A variável é predefinida pelo Vim

Existem também pseudovariáveis que os scripts podem utilizar para acessar os outros tipos de contêiner de valor fornecidos pelo Vim. Elas são resumidas na Tabela 2.

Tabela 2. Pseudovariáveis do Vimscript
PrefixoSignificado
&varname Uma opção do Vim (opção local se definida, caso contrário, global)
&l:varname Uma opção local do Vim
&g:varname Uma opção global do Vim
@varname Um registro do Vim
$varname Uma variável de ambiente

A "opção" pseudovariáveis pode ser particularmente útil. Por exemplo, é possível configurar dois mapas chaves para aumentar ou diminuir o atual espaçamento da tabulação da seguinte forma:

nmap <silent> ]] :let &tabstop += 1<CR>

nmap <silent> [[ :let &tabstop -= &tabstop > 1 ? 1 : 0<CR>

Expressões

Observe que o mapeamento de chaves [[ no exemplo anterior utiliza uma expressão contendo uma "expressão ternária" em forma de C:

&tabstop > 1 ? 1 : 0

Isso impede o mapa de chaves de diminuir o atual espaçamento de tabulações abaixo do mínimo razoável de 1. Assim como sugere esse exemplo, expressões no Vimscript são compostas dos mesmos operadores básicos que são utilizados na maioria das outras linguagens de script modernas e com geralmente a mesma sintaxe. Os operadores disponíveis (agrupados por precedência crescente) são resumidos na Tabela 3.

Tabela 3. Tabela de Precedência do Operador Vimscript
OperaçãoSintaxe do Operador
Designação
Numeric-add-and-assign
Numeric-subtract-and-assign
String-concatenate-and-assign
let var=expr
let var+=expr
let var-=expr
let var.=expr
Operador Ternáriobool?expr-if-true:expr-if-false
OR Lógico bool||bool
AND Lógico bool&&bool
Igualdade numérica ou da cadeia
Desigualdade numérica ou da cadeia
Maior que numérico ou da cadeia
Maior que ou igual a numérico ou da cadeia
Menor que numérico ou da cadeia
Menor que numérico ou da cadeia
expr==expr
expr!=expr
expr>expr
expr>=expr
expr<expr
expr<=expr
Adição numérica
Subtração numérica
Concatenação de cadeia
num+num
num-num
str.str
Multiplicação numérica
Divisão numérica
Módulo numérico
num*num
num/num
num%num
Converter em número
Negação numérica
NOT Lógico
+num
-num
!bool
Precedência parentética (expr)

Caveats Lógicos

Em Vimscript, como em C, apenas o valor numérico zero é false em um contexto booleano; qualquer valor numérico diferente de zero—seja positivo ou negativo—é considerado true. No entanto, todos os operadores de comparação e lógicos retornam consistentemente o valor 1 para true.

Quando uma cadeia é utilizada como um booleano, primeiro ela é convertida em um número inteiro e depois avaliada para truth (diferente de zero) ou falsehood (zero). Isso indica que a grande maioria das cadeias—incluindo a maioria das cadeias não vazias—será avaliada como false. Um erro típico é testar uma cadeia vazia da seguinte forma:

Listagem 6. Teste Falho para Cadeia Vazia
let result_string = GetResult();

if !result_string
   echo "No result"
endif

O problema é que, embora isso não funcione de forma correta quando result_string é designado a uma cadeia vazia, isso também indica que "No result" ifresult_string contém uma cadeia como "I am NOT an empty string", pois essa cadeia é convertida primeiro em um número (zero) e depois em um booleano (false).

A solução correta é testar explicitamente se as cadeias estão vazias utilizando a função integrada apropriada:

Listagem 7. Teste Correto para Cadeia Vazia
ifempty(result_string)
   echo "No result"
endif

Caveats de Comparador

Em Vimscript, comparadores sempre executam uma comparação numérica, a menos que ambos os operandos sejam cadeias. Em particular, se um operando for uma cadeia e o outro um número, a cadeia será convertida em um número e os dois operandos serão comparados automaticamente. Isso pode levar a erros sutis:

let ident = 'Vim'

if ident == 0 "Always true (string 'Vim' converted to number 0)

Uma solução mais robusta nesses casos é:

Clique aqui para ver lista de códigos

if ident == '0'   "Uses string equality if ident contains string"but numeric equality if ident contains number

As comparações de cadeia normalmente respeitam a configuração local da opção ignorecase do Vim, mas qualquer comparador de cadeia também pode ser marcado explicitamente como com distinção entre maiúsculas e minúsculas (anexando-se um #) ou sem distinção entre maiúsculas e minúsculas (anexando-se um ?):

Listagem 8. Definindo Maiúsculas e Minúsculas dos Comparadores de Cadeia
if name ==? 'Batman'         |"Equality always case insensitive
   echo "I'm Batman"
elseif name <# 'ee cummings' |"Less-than always case sensitive
   echo "the sky was can dy lu minous"
endif

O uso de operadores "com definição explícita de maiúsculas e minúsculas" para todas as comparações de cadeias é altamente recomendado, pois eles garantem que os scripts se comportem de forma confiável, independentemente de variações nas configurações de opções do usuário.

Caveats Aritméticos

Durante o uso de expressões aritméticas, também é importante lembrar que até a versão 7.2, o Vim suportava apenas números inteiros aritméticos. Um erro comum em versões anteriores era gravar algo como:

Listagem 9. Problema com Número Inteiro Aritmético
"Step through each file...
for filenum in range(filecount)
   " Show progress...
   echo (filenum / filecount * 100) . '% done'" Make progress...
   call process_file(filenum)
endfor

Como filenum sempre será menor que filecount, a divisão do número inteiro filenum/filecount sempre produzirá zero, portanto, cada iteração do loop ecoará:

Now 0% done

Mesmo na versão 7.2, o Vim só realiza operações aritméticas de ponto flutuante se um dos operandos for explicitamente um ponto flutuante:

let filecount = 234

echo filecount/100   |" echoes 2
echo filecount/100.0 |" echoes 2.34

Outro Exemplo de Comutação

É fácil adaptar o script de comutação de sintaxe mostrado anteriormente para criar outras ferramentas úteis. Por exemplo, se houver um conjunto de palavras que você sempre escreve incorretamente ou aplica de forma errada, é possível incluir um script no .vimrc para ativar o mecanismo de correspondência do Vim e realçar palavras problemáticas quando você estiver fazendo uma revisão de texto.

Por exemplo, é possível criar um mapeamento chaves (por exemplo: ;p) que faz com que um texto semelhante ao parágrafo anterior seja exibido no Vim, como a seguir:

É fácil adaptar o script de comutação de sintaxe mostrado anteriormente para se criar outras ferramentas úteis. Por exemplo, se houver um conjunto de palavras que você sempre escreve incorretamente ou aplica de forma errada, é possível incluir um script emseu .vimrc para ativar o mecanismo de correspondência do Vim e realçar palavras problemáticas quando você estiver fazendo uma revisão de texto.

Esse script pode ser semelhante ao seguinte:

Listagem 10. Realçando Palavras Utilizadas Incorretamente com Mais Frequência
"Create a text highlighting style that always stands out...
highlight STANDOUT term=bold cterm=bold gui=bold

"List of troublesome words...
let s:words = [
             \ "it's",  "its",
             \ "your",  "you're",
             \ "were",  "we're",   "where",
             \ "their", "they're", "there",
             \ "to",    "too",     "two"
             \ ]

"Build a Vim command to match troublesome words...
let s:words_matcher
\ = 'match STANDOUT /\c\<\(' . join(s:words, '\|') . '\)\>/'

"Toggle word checking on or off...
function! WordCheck ()
   "Toggle the flag (or set it if it doesn't yet exist)...
   let w:check_words = exists('w:check_words') ? !w:check_words : 1

   "Turn match mechanism on/off, according to new state of flag...
   if w:check_words
      exec s:words_matcher
   else
      match none
   endif
endfunction

"Use ;p to toggle checking...
nmap <silent> ;p :call WordCheck()<CR>

A variável w:check_words é utilizada como um sinalizador booleano para ativar ou desativar a verificação ortográfica. A primeira linha da função WordCheck() verifica se o sinalizador já existe, em cujo caso, a designação simplesmente comuta o valor booleano da variável:

let w:check_words = exists('w:check_words') ? !w:check_words : 1

Se w:check_words ainda não existir é criada através da designação do valor 1 para ela:

let w:check_words = exists('w:check_words') ? !w:check_words : 1

Observe o uso do prefixo w:, que significa que a variável do sinalizador é sempre local para a janela atual. Isso permite que a verificação ortográfica seja comutada independentemente para cada janela do editor (que é consistente com o comportamento do comando match, cujos efeitos são sempre locais para a janela atual também).

A verificação ortográfica é ativada através da configuração do comando match do Vim. Um match espera uma especificação de realce de texto (STANDOUT neste exemplo), seguida por uma expressão regular que especifique qual texto realçar. Nesse caso, esse regex é construído utilizando OR em todas as palavras especificadas na variável da lista de s:words do script (ou seja: join(s:words, '\|')). Esse conjunto de alternativas é colocado entre colchetes por limites de palavras sem distinção entre maiúsculas e minúsculas (\c\<\(...\)\>) para garantir que apenas palavras inteiras sejam correspondidas, independentemente de letras maiúsculas.

A função WordCheck() então converte a cadeia resultante como um comando Vim e o executa (exec s:words_matcher) para ativar o recurso de correspondência. Quando w:check_words é desativada, a função executa um comando match none para desativar a correspondência especial.


Criando Scripts no Modo de Inserção

Vimscripting não é de maneira nenhuma restrito ao modo Normal. Você também pode utilizar os comandos imap ou iabbrev para configurar mapeamentos de chaves ou abreviações que possam ser utilizados durante a inserção de texto. Por exemplo:

imap <silent> <C-D><C-D> <C-R>=strftime("%e %b %Y")<CR>

imap <silent> <C-T><C-T> <C-R>=strftime("%l:%M %p")<CR>

Com esses mapeamentos no .vimrc, a digitação de CTRL-D duas vezes no modo de Inserção faz o Vim chamar sua função integrada strftime() e inserir a data resultante, enquanto que digitar CTRL-T duas vezes insere o horário atual.

Você pode utilizar o mesmo padrão geral para fazer um mapa de inserção ou uma abreviação executarem qualquer ação passível de scripts. Basta colocar a expressão Vimscript apropriada ou chamada de função entre um <C-R>= inicial (que diz ao Vim para inserir o resultado das avaliações seguintes) e um <CR> final (que diz ao Vim para avaliar de fato a expressão precedente). Lembre-se, porém, que <C-R> (abreviação do Vim para CTRL-R) não é o mesmo que <CR> (abreviação do Vim para um retorno de linha).

Por exemplo, é possível utilizar a função integrada getcwd() para criar uma abreviação para o diretório de trabalho atual, como a seguir:

iabbrev <silent> CWD <C-R>=getcwd()<CR>

Ou poderia integrar uma calculadora simples que possa ser chamada digitando-se CTRL-C durante inserções de texto:

imap <silent> <C-C> <C-R>=string(eval(input("Calculate: ")))<CR>

Aqui, a expressão:

string( eval( input("Calculate: ") ) )

primeiro chama a função integrada input() para solicitar ao usuário que digite seu cálculo, que input() depois retorna como uma cadeia. Essa cadeia de entrada é então passada para a eval() integrada, que a avalia como uma expressão do Vimscript e retorna o resultado. Em seguida, a função integrada string() converte o resultado numérico de volta em uma cadeia, que a sequência <C-R>= do mapeamento de chaves pode inserir.

Um Script no Modo de Inserção Mais Complexo

Os mapeamentos de inserção podem envolver scripts consideravelmente mais sofisticados do que os exemplos anteriores. Nesses casos, geralmente é uma boa ideia refatorar o código em uma função definida pelo usuário, que o mapeamento de chaves pode chamar.

Por exemplo, é possível alterar o comportamento de CTRL-Y durante inserções. Normalmente um CTRL-Y no modo de Inserção faz uma "cópia vertical". Ou seja, ele copia o caractere na mesma coluna a partir da linha imediatamente acima do cursor. Por exemplo, um CTRL-Y na seguinte situação inseriria um "m" no cursor:

Glib jocks quiz nymph to vex dwarf
Glib jocks quiz ny_

No entanto, talvez você prefira que suas cópias verticais ignorem a interferência de quaisquer linhas vazias e copie o caractere da mesma coluna da primeira linha não em branco acima do ponto de inserção. Isso significaria, por exemplo, que um CTRL-Y na seguinte situação também inseriria um "m", mesmo que a linha imediatamente precedente estivesse vazia:

Glib jocks quiz nymph to vex dwarf

Glib jocks quiz ny_

seria possível conseguir esse comportamento aprimorado colocando o seguinte em seu arquivo .vimrc:

Listagem 11. Melhorando Cópias Verticais para Ignorar Linhas em Branco
"Locate and return character "above" current cursor position...
function! LookUpwards()
   "Locate current column and preceding line from which to copy...
   let column_num      = virtcol('.')
   let target_pattern  = '\%' . column_num . 'v.'
   let target_line_num = search(target_pattern . '*\S', 'bnW')

   "If target line found, return vertically copied character...
if !target_line_num return "" else return matchstr(getline(target_line_num), target_pattern) endif endfunction "Reimplement CTRL-Y within insert mode...
imap <silent> <C-Y> <C-R><C-R>=LookUpwards()<CR>

A função LookUpwards() primeiro determina em qual coluna na tela (ou "coluna virtual") o ponto de inserção está atualmente utilizando a função integrada virtcol(). O argumento '.' especifica que você quer o número da coluna da atual posição do cursor:

let column_num = virtcol('.')

LookUpwards() então utiliza a função integrada search() para procurar no arquivo a posição do cursor:

let target_pattern = '\%' . column_num . 'v.'
let target_line_num = search(target_pattern . '*\S', 'bnW')

A procura utiliza um padrão de destino especial (isto é: \%column_numv.*\S) para localizar a linha precedente mais próxima que possui um caractere sem ser um espaço em branco (\S) na ou após (.*) a coluna do cursor (\%column_numv). O segundo argumento para search() é a cadeia de configuração bnW, que diz à função para procurar de trás para frente, mas não mover o cursor e nem quebrar a procura. Se a procura for bem-sucedida, search() retornará o número de linha da linha precedente apropriada; se essa procura falhar, ela retornará zero.

A instrução if então descobre qual caractere—se houver algum—deve ser copiado no ponto de inserção. Se uma linha precedente adequada não foi localizada, target_line_num receberá um zero, portanto, a primeira instrução de retorno será executada e retornará uma cadeia vazia (indicando "inserir nada").

Se, no entanto, uma linha precedente adequada foi identificada, a segunda instrução de retorno será executada. Primeiro ela obtém uma cópia dessa linha precedente do atual buffer do editor:

return matchstr(getline(target_line_num), target_pattern)

Depois ela localiza e retorna a cadeia de um caractere que a chamada anterior para search() correspondeu com sucesso:

return matchstr(getline(target_line_num), target_pattern)

Tendo implementado esse novo comportamento de cópia vertical em LookUpwards(), tudo que resta fazer é substituir o comando CTRL-Y padrão no modo de Inserção utilizando imap:

imap <silent> <C-Y> <C-R><C-R>=LookUpwards()<CR>

Observe que, enquanto exemplos de imap anteriores utilizaram <C-R>= para invocar uma chamada de função do Vimscript, este exemplo utiliza <C-R><C-R>= em seu lugar. A forma CTRL-R única insere o resultado da expressão subsequente como se ele tivesse sido digitado diretamente, o que significa que quaisquer caracteres especiais no resultado mantêm seus significados e comportamentos especiais. A forma CTRL-R dupla, por outro lado, insere o resultado como um texto literalmente sem nenhum processamento adicional.

A inserção literal é mais apropriada neste exemplo, já que o objetivo é copiar exatamente o texto acima do cursor. Se o mapeamento de chaves utilizou <C-R>=, copiar um caractere de escape literal da linha anterior seria equivalente a digitá-lo, o que faria o editor sair instantaneamente do modo de Inserção.

Aprendendo as Funções Integradas do Vim

Como você pode ver em cada um dos exemplos anteriores, muito da força do Vimscript vem de seu conjunto extensivo de mais de 200 funções integradas. Você pode começar a aprender sobre elas digitando:

:help functions

ou, para acessar uma listagem categorizada (mais útil):

:help function-list


Pensando no Futuro

Vimscript é um mecanismo para reformar e estender o editor Vim. Criar scripts permite criar novas ferramentas (como um realçador de palavras problemáticas) e simplificar tarefas comuns (como alterar espaçamento da tabulação, ou inserir informações de data e horário, ou comutar o realce da sintaxe) e até refazer completamente o design de recursos do editor existentes (por exemplo, aprimorar o comportamento "copiar-a-linha-anterior" de CTRL-Y).

Para muitas pessoas, a maneira mais fácil de se aprender uma nova linguagem é através de exemplos. Portanto, você pode encontrar um suprimento infinito de Vimscripts de amostra—sendo que a maioria são ferramentas úteis em sua maneira—no wiki Dicas do Vim. Ou, para obter exemplos mais extensivos da criação de scripts do Vim, você pode pesquisar os 2000 maiores projetos no archive de scripts do Vim. Ambos são listados em Recursos abaixo.

Se você já estiver familiarizado com Perl, ou Python, ou Ruby, ou PHP, ou Lua, ou Awk, ou Tcl, ou qualquer linguagem shell, o Vimscript será frequentemente familiar (em sua abordagem geral e em seus conceitos) e frustrantemente diferente (em sua característica sintática particular). Para superar essa dissonância cognitiva e dominar o Vimscript, você terá que passar algum tempo experimentando, explorando e jogando com linguagens. Portanto, por que não aproveitar seu domínio total sobre a maneira como o Vim funciona atualmente para saber se você pode criar scripts para uma solução melhor?

Este artigo descreveu apenas as variáveis, os valores, as expressões e as funções básicas do Vimscript. A variedade de "melhores soluções" que você terá chances de construir com apenas esses componentes é, com certeza, extremamente limitada. Portanto, nas seções futuras, nós veremos técnicas e ferramentas Vimscript mais avançadas: estruturas de dados, controle de fluxo, comandos definidos pelo usuário, scripts orientados a eventos, construção de módulos Vim e extensão do Vim utilizando outras linguagens de script. Em particular, o próximo artigo nesta série terá seu foco direcionado para os recursos das funções definidas pelo usuário do Vimscript e para as várias maneiras como eles podem melhorar sua experiência com o Vim.

Recursos

Aprender

Obter produtos e tecnologias

Discutir

  • Envolva-se com a Comunidade do My developerWorks; com seu perfil pessoal e sua página inicial customizada, você pode padronizar o developerWorks de acordo com seus interesses e interagir com outros usuários do developerWorks.

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Linux
ArticleID=396934
ArticleTitle=Criando Scripts do Editor Vim, Parte 1: Variáveis, Valores e Expressões
publish-date=05062009