[Area de transferência remota]

Dica, o comando pbcopy do Mac é o mesmo que xclip -selection clipboard no Linux e o comando pbpaste é o mesmo que xclip -selection clipboard -o. O comando xclip não serve porque ele requer o X Window instalado.

Copiar e Colar

Edito muito código em servidores remotos via ssh, sem modo gráfico, normalmente uso o neovim. Seria ótimo poder copiar e colar da máquina remota para a máquina e vice-versa. Colar da máquina local para a remota é a parte simples, o próprio terminal já se encarrega disso, mas copiar da máquina remota para a local requer um pouco de código.

Usando netcat

Inicialmente pensei em usar o netcat para subir um pequeno servidor direcionando a saída do netcat para o pbcopy, então bastaria enviar para o servidor.

Para subir 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 não é muito prática e além disso o texto passa raw pela rede. Uma maneira preferível seria usar ssh diretamente. Mas isso requer que a maquina local rode um servidor ssh, também seria possível fazer um túnel ssh, mas mesmo essa solução ainda não é perfeita.

Usando SSH

echo "texto para ser enviado"|ssh maquina-local 'pbcopy'

Usando ssh também seria possível pegar o texto da área de transferência da máquina com o seguinte comando.

ssh maquina-local 'pbpaste'

Com ssh ainda não é a melhor maneira, mas como não precisa iniciar um serviço para ficar escutando uma porta da para colocar o comando no evento TextYankPost do newvim e sempre que um texto for copiado o neovim vai enviar o texto via ssh.

augroup remote_clipboard
  au!
  au TextYankPost * call system("ssh maquina-local 'pbcopy'", @")
augroup END

Udando OSC52

Mas existe uma maneira muito melhor de ter a mesma funcionalidade e sem precisar subir um servidor ssh local nem trafegar o texto sem criptografia pela rede. Para isso usamos o OSC (Operating System Command), um subconjunto dos códigos escape do padrão ANSI. Emuladores de terminal modernos como o iTerm2 podem executar uma variedade de sequências OSC como exibir links, mudar o título da janela e no nosso caso copiar texto para a área de transferência usando o código 52. Como no exemplo.

echo -ne "\033]52;c;$(echo -n "texto para ser enviado" | base64)\a"

É necessário converter o texto para base64 antes de enviar, o que acaba introduzindo outro problema, o utilitário base64 que do Linux e do Mac por padrão quebram a linha se o texto for muito grande e isso atrapalha a decodificação, o resultado é que o texto vai ser truncado se for muito grande.

Para resolver esse problema tem um parâmetro para não truncar a saída em base64, mas esse parâmetro difere no Linux e no Mac, então precisamos acomodar essa diferença no nosso script.

Esta é uma versão do script que pode ser executada tanto no Mac (Darwin) como 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 ultima versão funciona bem, mas tem o problema de fazer sempre duas chamadas para o sistema operacional, uma para descobrir qual sistema está sendo executado e outra para conversão para base64, para meu uso isso não é um problema, não senti diferença de desempenho, mas no fim, achei melhor colocar a detecção da plataforma em um script, junto com a conversão e então apenas chamar esse script pela função Copy do fragmento de código anterior.

Aqui está o 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

Eu nomeei o script de b64, ele vai ser útil em outras ocasiões em que vou precisar converter para base64 sem truncar a linha.

E aqui está a versão final do script que permite que sempre que eu copiar um texto no neovim o texto copiado também esteja disponível na área de transferência da máquina local.

" It Sends yanked text to the client 
" machine's clipboard. Requires terminal 
" emulator with OSC52 support
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 particularmente bem, principalmente pelo fato que não preciso lembrar de nada, nenhuma nova tecla de atalho, nenhum novo serviço, ela simplesmente funciona. Claro, com alguns pontos importantes para se ter em mente, por exemplo, o emulador de terminal precisa ser compatível com OSC52, mas o que eu uso já é compatível, então para mim não muda nada.

Essa solução também tem a vantagem de usar a mesma conexão ssh do terminal, ou seja, não preciso me preocupar com a criptografia.

Cesar Gimenes