Reinicie o emacs de dentro do emacs

44

Eu reinicio muito o meu emacs. Tudo o que eu quero fazer é criar uma função que elimine o emacs atual, apenas para gerar um novo em seu lugar. Idealmente, isso também funcionaria em um TTY.

PythonNut
fonte
8
Por curiosidade, por que você mata e imediatamente recomeça com tanta frequência?
Dan
2
Desenvolvo ativamente o meu .emacs.d, o que significa que eu reinicio o emacs para remover qualquer lixo que tenha sido jogado no meu ambiente. Existem alguns outros casos de uso em que faço isso, mas esse é o maior.
PythonNut
1
@ PythonNut, acho que você precisa reformular sua pergunta um pouco. Você pode dizer bashpara reiniciar depois de terminar? Ou vi? Ou qualquer outro processo, como regra? Não, porque isso está fora do escopo de suas preocupações e é tratado adequadamente externamente. De qualquer forma, o que você realmente deseja é uma maneira de reinicializar o emacs, limpando sua VM e executando novamente seu código de inicialização ( sem interromper o processo). Isso seria útil e adequado ao emacs. Eu não sei se existe, embora :)
Harpo
4
@harpo sim, posso começar basha reiniciar exec bash. Não faço ideia do vim.
PythonNut
11
FWIW, estou mais inclinado a iniciar uma nova instância do Emacs para testar alterações na configuração, em vez de sair e reiniciar. Por quê? Como se meu código apresentar um erro, o Emacs poderá não ser capaz de carregar minha configuração quando eu o reiniciar e, nesse momento, não consigo obter uma instância em execução com minhas configurações normais, então tenho que usar uma edição menos familiar ambiente para corrigir o erro. Isso não vai acontecer com frequência, mas é irritante quando acontece. É emacs -qclaro que posso executar e corrigir o problema, mas prefiro manter uma instância 'boa' em execução o tempo todo ao invadir minha configuração, apenas por segurança.
phils

Respostas:

25

Nota: Embrulhei o seguinte em um pacote restart-emacsdisponível aqui .


Aqui está uma maneira alternativa de alcançar o que você deseja usando o elisp puro (não exatamente porque você depende de um shell). O truque é iniciar outro processo do emacs pouco antes do emacs atual ser eliminado.

(defun launch-separate-emacs-in-terminal ()
  (suspend-emacs "fg ; emacs -nw"))

(defun launch-separate-emacs-under-x ()
  (call-process "sh" nil nil nil "-c" "emacs &"))

(defun restart-emacs ()
  (interactive)
  ;; We need the new emacs to be spawned after all kill-emacs-hooks
  ;; have been processed and there is nothing interesting left
  (let ((kill-emacs-hook (append kill-emacs-hook (list (if (display-graphic-p)
                                                           #'launch-separate-emacs-under-x
                                                         #'launch-separate-emacs-in-terminal)))))
    (save-buffers-kill-emacs)))

O código para iniciar uma versão GUI do emacs é simples. O código para iniciar o emacs em um terminal é um pouco complicado. Ele usa o fato de que você pode passar uma string para a suspend-emacsqual seria passada como entrada terminal para o processo pai (o shell). A partir da documentação

(suspend-emacs e STUFFSTRING opcional)

Pare o Emacs e retorne ao processo superior. Você pode retomar mais tarde. Se o `não puder suspender 'for nulo, ou se o sistema não suportar o controle de tarefas, execute um subshell.

Se arg STUFFSTRING opcional for nulo, seus caracteres serão preenchidos para serem lidos como entrada terminal pelo pai do Emacs, após a suspensão.

Então, basicamente suspendemos o emacs imediatamente antes de ser morto, informamos ao shell pai para retomar o emacs atualmente suspenso (que sairá em breve) e depois iniciaremos outro processo do emacs. Observe que isso não funciona em plataformas nas quais o emacs de terminal pode / não realmente suspende, mas inicia um subshell, por exemplo, no Windows.

Iqbal Ansari
fonte
Isso não funciona para mim: quando corro sh -c "emacs &"do shell, ele pára com " emacs: standard input is not a tty". (Quando eu faço M-x restart-emacsque eu nem sequer ver essa mensagem de erro, Emacs apenas termina.)
Constantine
Funciona para mim no X. Não funciona em um terminal porque redireciona stdin e stdout para / dev / null; passar o pai tty para o subprocesso é provavelmente factível, mas mais complicado.
Beni Cherniavsky-Paskin
1
Isso funciona perfeitamente e realmente me assusta um pouco. Por que diabos o Emacs tem permissão para passar comandos para sua concha?
Radon Rosborough
qual combinação de teclas você usa para isso?
slk500 30/09
32

Até onde eu sei, você não pode dizer ao Emacs para reiniciar após o término, mas você pode definir o código de saída para que o processo que iniciou o Emacs em primeiro lugar possa detectar que você deseja reiniciar.

Por exemplo, esse script de shell reinicia o Emacs se ele tiver saído com o código 123.

#!/bin/sh
while emacs -nw "$@"; [ $? = 123 ]; do :; done

Em seguida, definimos kill-emacs-and-restartque faz com que o Emacs termine com o código de saída igual ao número mágico reconhecido pelo script:

(defun kill-emacs-and-restart ()
  (interactive)
  (kill-emacs 123))

Agora, se você executar o Emacs através deste script, poderá reiniciar M-x kill-emacs-and-restart(ou vinculá-lo a uma sequência de teclas).

Constantine
fonte
Ótima maneira de contornar o problema! Eu aceito isso se você puder me dizer o porquê you cannot tell Emacs to re-start after terminating. Isso é uma limitação técnica?
PythonNut
3
@ PythonNut: Até onde eu sei, a única maneira de reiniciar um processo é usando uma das funções da exec...família (nos sistemas POSIX, pelo menos). As funções de controle de processo do Emacs Lisp não expõem chamadas de baixo nível. Porém, eu não sou especialista, então espero que alguém com mais conhecimento entre em contato.
Constantine
2

Roubado descaradamente de https://unix.stackexchange.com/questions/114238/is-it-possibe-to-change-parent-shells-working-directory-programmatically

Supondo que eu tenho a sintaxe correta para incorporar "em uma string, isso deve ser feito.

(defun restart-emacs ()
  (call-process "sh" nil nil nil "-c" "gdb -p $(ps h -o ppid -p $$) -ex 'call execl(\"/bin/sh\", \"/bin/sh\", \"-c\", \"exec emacs\")'"))
Joshua
fonte
11
Por favor não. Isso ignora toda a limpeza interna do Emacs e descarta todo o estado atual (por exemplo, buffers modificados) sem confirmação .
lunaryorn
o aviso de lunaryorn está correto.
Joshua