Nível: Introdutório Damian Conway, Dr., CEO and Chief Trainer, Thoughtstream
06/Mai/2009 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.
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
|
Prefixo
|
Significado
| |
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
|
Prefixo
|
Significado
| |
&
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ção
|
Sintaxe 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ário |
bool
?
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 é:
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 em seu .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.
Sobre o autor  | 
|  | Damian 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. |
Avalie esta página
|