Area de transferência remota
Dica: O comando pbcopy
no Mac é equivalente a xclip -selection clipboard
no Linux. O comando pbpaste
no Mac corresponde a xclip -selection clipboard -o
no Linux. O comando xclip
não funciona porque requer o X Window instalado.
Copiar e Colar
Eu edito muito código em servidores remotos via SSH, sem interface gráfica, geralmente uso o Neovim. Seria ótimo poder copiar e colar entre a máquina remota e a local. Colar da máquina local para a remota é simples, pois o terminal já faz isso. Porém, copiar da máquina remota para a local exige um pouco de código.
Usando netcat
Inicialmente, pensei em usar o netcat para criar um pequeno servidor que direciona a saída para o pbcopy
. Assim, bastaria enviar dados para o servidor.
Para iniciar o “serviço de cópia”:
nc -l 9090 | pbcopy
Para enviar o texto para o servidor:
echo "texto para ser enviado" | nc maquina-local 9090
O problema dessa abordagem é que ela não é muito prática e o texto é enviado sem criptografia pela rede. Uma alternativa melhor seria usar SSH diretamente. Porém, isso requer que a máquina local execute um servidor SSH. Também é possível criar um túnel SSH, mas essa solução ainda não é ideal.
Usando SSH
echo "texto para ser enviado" | ssh maquina-local 'pbcopy'
Com SSH, também é possível obter o texto da área de transferência da máquina local usando o seguinte comando:
ssh maquina-local 'pbpaste'
Embora o SSH não seja a melhor solução, ele elimina a necessidade de iniciar um serviço para escutar uma porta. Podemos integrar o comando no evento TextYankPost
do Neovim. Assim, sempre que um texto for copiado, o Neovim enviará o texto via SSH.
augroup remote_clipboard
au!
au TextYankPost * call system("ssh maquina-local 'pbcopy'", @")
augroup END
Usando OSC52
Existe uma maneira mais eficiente de obter a mesma funcionalidade sem precisar iniciar um servidor SSH local ou enviar o texto sem criptografia pela rede. Para isso, usamos o OSC (Operating System Command), um subconjunto dos códigos de escape do padrão ANSI. Emuladores de terminal modernos como o iTerm2 podem executar diversas sequências OSC, como exibir links, alterar o título da janela e, no nosso caso, copiar texto para a área de transferência usando o código 52. Veja o exemplo:
echo -ne "]52;c;$(echo -n "texto para ser enviado" | base64)\a"
É necessário converter o texto para base64 antes de enviá-lo. Isso pode causar um problema: os utilitários base64
do Linux e do Mac, por padrão, quebram a linha se o texto for muito longo, o que atrapalha a decodificação. Como resultado, o texto pode ser truncado se for muito grande.
Para resolver esse problema, existe um parâmetro para evitar a quebra de linha na saída do base64
, mas esse parâmetro difere entre Linux e Mac. Portanto, precisamos ajustar nosso script para acomodar essa diferença.
Esta é uma versão do script que pode ser executada tanto no Mac (Darwin) quanto no Linux.
augroup remote_clipboard
au!
function Copy()
if system('uname -s') == "Darwin\n"
let l:c64 = system("base64 --break=0", @")
else
let l:c64 = system("base64 -w0", @")
endif
let l:s = "\e]52;c;" . l:c64 . "\x07"
call chansend(v:stderr, l:s)
endfunction
autocmd TextYankPost * call Copy()
augroup END
Essa última versão funciona bem, mas faz duas chamadas ao sistema operacional: uma para identificar o sistema em uso e outra para converter para base64. Para melhorar, coloquei a detecção da plataforma e a conversão em um script separado e chamei esse script na função Copy
do código anterior.
Aqui está um exemplo do script que usa o parâmetro adequado dependendo do sistema operacional.
#!/bin/zsh
if [[ "${OSTYPE}" == "darwin"* ]]; then
base64 --break=0 "$@"
elif [[ "${OSTYPE}" == "linux"* ]]; then
base64 -w0 "$@"
fi
Nomeei o script de b64
. Ele será útil em outras situações onde precisar converter para base64 sem truncar a linha.
Aqui está a versão final do script que permite que, sempre que eu copiar um texto no Neovim, o texto também fique disponível na área de transferência da máquina local.
" Envia o texto copiado para a área de transferência do cliente
" Requer um emulador de terminal com suporte a OSC52
augroup remote_clipboard
au!
function Copy()
let l:c64 = system("b64", @")
let l:s = "\e]52;c;" . l:c64 . "\x07"
call chansend(v:stderr, l:s)
endfunction
autocmd TextYankPost * call Copy()
augroup END
Essa solução final funciona muito bem porque não preciso lembrar de nada: nenhuma nova tecla de atalho, nenhum novo serviço. Ela simplesmente funciona. Claro, há pontos importantes a considerar, como a necessidade de um emulador de terminal compatível com OSC52. No meu caso, o que uso já suporta, então não há mudanças para mim.
Além disso, essa solução utiliza a mesma conexão SSH do terminal, garantindo que o texto seja enviado de forma criptografada.