Criando suas próprias funções de autocomplear no Bash
Um dos melhores amigo de quem usa a linha de comando é o TAB. Além de ajudar a economizar um bocado de digitação, ele te lembra das opções dos comandos e dos diretórios ou arquivos que está tentando acessar.
Mas e quando o comando não tem um autocompletar? Ou quando você gostaria de seus próprios scripts tivessem um autocompletar?
Neste post vou mostrar como você pode criar suas próprias funções de auto completar! =)
Para essa tarefa, o Bash nos fornece os comandos complete
e compgen
, além de
algumas variáveis:
- COMP_LINE: a linha de comando no momento
- COMP_WORDS: lista de argumentos passados para o comando no momento
- COMP_CWORD: o índice do argumento onde o cursor está no momento
- COMP_WORDBREAKS: lista de caracteres separadores de palavras
- COMPREPLY: um array contendo as possíveis “completadas”
Capturar o argumento atual
Utilizando as variáveis fornecidas pelo Bash, podemos fazer o seguinte:
1
|
|
Assim, se estivermos digitando “nome mari” e apartarmos [TAB][TAB], o valor de
current
será “mari”.
Lista de possíveis “completadas”
Para isso vamos utilizar o comando compgen
com a opção -W
. Ele vai receber
uma lista de palavras, comparar com a palavra desejada e retornar uma lista de
possíveis “completadas”, por exemplo:
1 2 3 4 |
|
Sendo assim, podemos utilizar o resultado do compgen
para popular a variável
COMPREPLY que será utilizada pelo comando complete
.
Criando nossa primeira função
As funções de autocompletar podem ficar em um arquivo na a pasta /etc/bash_completion.d (que inclusive é um ótimo lugar para ver exemplos de código) ou ficar direto no seu arquivo ~/.bashrc. Para simplificar, vou usar o ~/.bashrc e adicionar o código:
1 2 3 4 5 |
|
Estamos dizendo ao comando complete
que utilize a função _nome
para
modificar a variável COMPREPLY
com as possíveis “completadas” para o comando
nome
. Recarregue o seu ~/.bashrc e teste:
1 2 3 4 5 6 7 8 9 |
|
Agora que já entendemos como funciona, vamos para um exemplo real.
Oh my gems!
Um exemplo bem simples é o autocompletar que criei para o
Oh my gems! (um
substituto para os gemsets do rvm, geralmente usado em
conjunto com o rbenv). Além da opção reset, o comando
ohmygems
pode receber como parâmetro o nome de um novo “gemset” ou dos
“gemsets” existentes, que são nada mais que os os subdiretórios de
~/.gem/repos:
1 2 3 4 5 6 |
|
Agora vamos para um exemplo um pouco mais complexo.
Rake
Acredito que todo programador ruby utiliza o Rake (Ruby Make). Contudo, diferente do Make, o Rake não cria automaticamente um autocompletar com as tasks que você define no Rakefile. Mas nós podemos criar criar um! =)
Para ver todas as tasks disponíveis, podemos utilizar a opção -P
ou
--prereqs
do rake
, que mostra as tasks e suas dependências:
1 2 3 4 5 6 7 8 9 |
|
Beleza. Agora, para pegar apenas as tasks vamos usar o grep
e o cut
:
1 2 3 4 5 6 |
|
Já temos nossa lista de possíveis “completadas”, então vamos criar nossa função:
1 2 3 4 5 6 |
|
Geralmente, as tasks do rake
são separadas por contextos e esses contextos são
separados por “:”. Por exemplo rake db:drop:all
. A variável COMP_WORDBREAKS,
que guarda os caracteres separadores de palavras para o autocompletar, tem como
valor original a lista "'><;|&(:
. Repare que o : está entre esses caracteres,
mas não queremos que ele seja um separador de palavras. Para removê-lo, vamos
adicionar o seguinte antes da nossa função no ~/.bashrc:
1
|
|
Com isso você já tem um autocompletar para o rake
. No entanto, se estiver em
um projeto Rails, o rake
carrega a aplicação antes de executar as tasks.
Assim, a cada vez que você faz rake [TAB][TAB]
vai levar alguns segundos para
te mostrar as possíveis tasks, o que torna o auto complete inútil. Para resolver
esse problema, podemos criar um arquivo que será nosso cache de tasks do rake
e apenas atualizá-lo se algum dos arquivos de tasks for alterado depois da
criação do cache. Podemos verificar também se existem o arquivo Rakefile antes
de executar qualquer coisa. Nossa função de autocompletar final para o rake
fica assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
No manual de referência do bash do site do projeto GNU você encontra a documentação completa para a criação de funções para autocompletar. Você pode criar funções bem mais complexas, que completam de acordo com a opção anterior e etc. Só depende da sua criatividade e habilidade com shell script =)