Como posso usar meu cliente Emacs local como o $ EDITOR para máquinas remotas que eu acesso através do TRAMP?

44

Costumo usar o TRAMP para gerenciar vários servidores remotos, tanto para editar arquivos quanto para executar shells remotos shell-mode. No entanto, isso não funciona quando um comando usa a EDITORvariável para editar um arquivo, crontab -eespecialmente porque shell-modeé um terminal "burro" que não suporta a execução de outro editor dentro dele.

Localmente, faço isso com uma chamada apropriada, emacsclientque abre um novo buffer e facilita a vida. Infelizmente, isso não funciona na máquina remota.

Eu acho que eu poderia usar ed. (Hah!)

Como posso configurar um controle remoto EDITORque permita editar arquivos com minha instância local do Emacs?

Tikhon Jelvis
fonte

Respostas:

23

[NOTA] esta resposta foi fortemente editada para acompanhar as atualizações dos with-editordesenvolvimentos. A maioria dos comentários provavelmente não fará mais sentido. Existem alguns novos comentários que fazem sentido.


O Magit contém uma biblioteca chamada with-editordisponível em https://github.com/magit/with-editor, que permite usar o Emacs local como um $ EDITOR em máquinas remotas através do TRAMP.

Outra alternativa é https://github.com/habnabit/remote-emacsclient , mas parece mais complicado e menos genérico.

A maneira mais simples de instalar with-editoré através do MELPA:

M-x package-install with-editor

Caso contrário, basta pegar https://github.com/magit/with-editor/blob/master/with-editor.el em algum lugar do seu caminho de carregamento e require(também depende do traço).

Em seguida, basta começar shell, eshellou ansi-terme faça o seguinte:

M-x with-editor-export-editor

Ele perguntará em qual $ EDITOR você está interessado, basta pressionar Enter para a EDITORvariável padrão . Depois, dentro do shell, você pode digitar crontab -ee editar seu crontab no emacs. Pressione C-c C-cpara salvar o crontab ou C-c C-kpara cancelar a edição.

Se você deseja uma configuração mais permanente:

(add-hook 'shell-mode-hook  'with-editor-export-editor)
(add-hook 'term-mode-hook   'with-editor-export-editor)
(add-hook 'eshell-mode-hook 'with-editor-export-editor)

Como alternativa, você pode usar M-x with-editor-async-shell-command crontab -e RETpara comandos rápidos.

Silex
fonte
Você poderia elaborar como essa with-editorbiblioteca se relaciona com a pergunta? Soa útil
Malabarba
@Silex: Eu precisaria definir a $EDITORvariável como algo na máquina remota para que isso funcione? Isso apenas se encaixa emacsclient?
Tikhon Jelvis
Mas sim, isso parece exatamente o que eu quero. Vou tentar de alguma forma - presumo que ele possa ser instalado sozinho, sem o restante da ramificação?
Tikhon Jelvis
1
@TikhonJelvi: certamente será instalável por si só, mas por enquanto é apenas parte disso git-modes. Estou acompanhando essa biblioteca de perto e é apenas que seu autor (@tarsius) está ocupado com o lançamento do magit, mas eventualmente ele seria um pacote próprio. Sobre o $ EDITOR, você não precisa configurá-lo para nada, é feito quando necessário quando você executa qualquer comando que o utilize. O Magit usa essa biblioteca com $ GIT_EDITOR.
Silex 9/10
1
Observe que isso irá parar de funcionar após o sshing para um controle remoto a partir de um shell-mode/ term-modebuffer existente . Isso pode ser solucionado com algumas configurações adicionais, consulte emacs.stackexchange.com/questions/5589/… . Se você conseguir fazê-lo funcionar, relate suas descobertas em github.com/magit/magit/issues/1638 .
tarsius
1

Disclaimer: Eu não tentei isso.

Você pode obter parte do caminho com uma saída de comando de observação de função para um comando para abrir o arquivo usando TRAMP. Falha de segurança? Sim. Funcional? Provavelmente.

Use um shell-modegancho para adicionar um gancho para after-change-hooknos shell-mode. Este gancho observa uma sequência específica. Exemplo:

;; RemoteTRAMP token: <authentication token maybe?>
;; RemoteTRAMP edit: /path/to/my/file

Em seguida, ele usa tramp-find-filepara abrir o arquivo. Isso é relativamente seguro porque a ÚNICA COISA que o controle remoto pode fazer é acionar a tramp-find-file. Uma confirmação primeiro seria boa, mas opcional.

Quando a edição termina, outro gancho pode acionar a saída do programa fictício (por exemplo, enviando C-c).

O pior caso (por segurança) é que eles encontram uma maneira de executar código arbitrário. Se você tiver variáveis ​​de buffer definidas para sempre avaliar, um invasor mal-intencionado poderá substituir configurações importantes sem o seu conhecimento. Eles também podem iniciar um ataque de negação de serviço fazendo com que muitos buffers sejam abertos. As confirmações provavelmente podem impedir todas as opções acima.

O programa no controle remoto pode ser implementado trivialmente em C (ou em qualquer outro idioma).

J David Smith
fonte
1

https://stackoverflow.com/questions/2231902/originate-edit-of-remote-file-using-emacs-tramp-from-ssh-session tem uma resposta aceita bastante simples que equivale a

(setq server-use-tcp t)
(setq server-host "name_of_local_machine")
(server-start)
;; Maybe also muck with `server-auth-dir`

e depois use

emacsclient -f ~/.emacs.d/server/server /`hostname`:/path/to/local/file

Também há https://stackoverflow.com/questions/12546722/using-emacs-server-and-emacsclient-on-other-machines-as-other-users que é mais complexo, mas onde as respostas também (aproximadamente) são similares bases.

triplo
fonte
1

Eu tenho um pequeno script no meu caminho no host remoto em ~/bin/ec, abreviação de emacsclient.

#!/bin/bash

params=()
for p in "$@"; do
  if [ "$p" == "-n" ]; then
    params+=( "$p" )
  elif [ "${p:0:1}" == "+" ]; then
    params+=( "$p" )
  else
    params+=( "/ssh:z:"$(readlink -f $p) )
  fi
done
emacsclient --server-file=$HOME/.emacs.d/server/server "${params[@]}"

Este script passa -ne +args inalterados para o emacsclient, caso contrário, os args são tratados como arquivos para o seu Emacs local abrir. Cada arquivo é prefixado com o protocolo TRAMP e o host para que o Emacs saiba como abri-lo. Você pode mudar ssh:para um protocolo TRAMP diferente, se preferir.

Você deve substituir zpelo nome do host da sua máquina remota. Isso é usado pelo Emacs local para se conectar via TRAMP. (Você pode usar hostnameaqui por generalidade. Prefiro usar pequenas entradas como zno meu local ssh_configpor questões de brevidade, e o controle remoto não faz ideia de que estou fazendo isso. Experimente!)

Uso:

  • ec file no shell remoto abre o arquivo no Emacs local e aguarda
  • ec -n file no shell remoto abre o arquivo no Emacs local e retorna
  • export EDITOR=~/bin/ecno controle remoto .bashrcfaz a mágica acontecer

Para garantir que meu serverarquivo seja bom, eu tenho isso no meu local .emacs, novamente usando o pequeno nome de host z:

(setq server-use-tcp t
      server-port    9999)
(defun server-start-and-copy ()
  "Start server and copy server file to remote box."
  (interactive)
  (server-start)
  (copy-file "~/.emacs.d/server/server" "/z:.emacs.d/server/server" t)
  (chmod "/z:.emacs.d/server/server" (string-to-number "644" 8))
  )
(add-hook 'emacs-startup-hook 'server-start-and-copy)

A porta 9999 é um RemoteForward. Coloquei isso no meu local ~/.ssh/ssh_configpara automatizar o encaminhamento, além do material do ControlMaster para obter velocidade.

Host z
HostName dev.example.com
User dev
ControlMaster auto
ControlPath ~/.ssh/z.sock
RemoteForward 9999 localhost:9999

Por fim, verifique se o TRAMP conhece o seu ssh_configse você o usar:

(require 'tramp)
(tramp-set-completion-function "ssh"
  '((tramp-parse-sconfig "~/.ssh/config")))
Andy
fonte
0

Pode exigir alguns ajustes, mas aqui está a idéia:

EDITOR="ssh artagnon@luneth \"emacsclient -n /`hostname`:$1\""
artagnon
fonte
1
Você quer dizer voltar ao servidor remoto para o cliente em que o Emacs está executando? Isso geralmente não é possível.
Gilles 'SO- stop be evil'
Bem, se você não pode alcançar o cliente onde o Emacs está executando, é impossível fazer qualquer coisa.
Artagnon # 23/14
2
Você pode perguntar ao ssh, através de ~ / .ssh / config, para sempre encaminhar o ouvinte local do ssh para uma porta na máquina remota. Você provavelmente também desejaria encaminhar seu agente ssh, embora as opiniões variem quanto à segurança. Isso permitirá que você volte ao fazer EDITOR = "ssh $ user @ localhost: 1234 ..."
Ben Hyde
Outra opção talvez estaria escrevendo um pequeno wrapper para chamada edit-server.el
stsquad
0

Realmente surpreso, ninguém mencionou sshfsainda. Isto é o que eu costumo fazer quando for remoto:

1) multi-term; sshfs user@host:/dir/i/want/ /mnt/point/on/my/machine
2) open whatever I want to edit in my local emacs
3) get-term; ssh user@host to launch executables etc

Embora multi-termnão sincronize o diretório de trabalho local com o diretório remoto, ele supera todas as outras soluções que tentei de longe. Embora o rastreamento de diretórios seja um recurso bem-vindo, com certeza.

Benjamin Lindqvist
fonte