Reiniciar emacs desde dentro de emacs

44

Reinicio mucho mis emacs. Todo lo que quiero hacer es crear una función que mate a los emacs actuales, solo para generar uno nuevo en su lugar. Idealmente, esto también funcionaría en un TTY.

PythonNut
fuente
8
Por curiosidad, ¿por qué matas e inmediatamente reinicias tan seguido?
Dan
2
Desarrollo muy activamente mi .emacs.d, lo que significa que reinicio emacs para eliminar cualquier basura que haya lanzado a mi entorno. Hay algunos otros casos de uso donde hago esto, pero ese es el más grande.
PythonNut
1
@PythonNut, creo que necesitas replantear un poco tu pregunta. ¿Puedes decir bashque reinicies después de terminar? O vi? ¿O cualquier otro proceso, como regla? No, porque eso está fuera de su alcance de preocupaciones y se maneja adecuadamente externamente. En cualquier caso, lo que realmente desea es una forma de reinicializar emacs, limpiando su VM y volviendo a ejecutar su código de inicio ( sin matar su proceso). Eso sería útil y apropiado para emacs. Sin embargo, no sé si existe :)
harpo
44
@harpo sí, puedo bashreiniciar con exec bash. No tengo idea sobre vim.
PythonNut
11
FWIW, estoy más inclinado a comenzar una nueva instancia de Emacs para probar los cambios de configuración, en lugar de salir y reiniciar. ¿Por qué? Porque si mi código tiene un error, es posible que Emacs no pueda cargar mi configuración cuando lo reinicio, y en ese momento no puedo obtener una instancia en ejecución con mi configuración normal, por lo que tengo que usar una edición menos familiar entorno para corregir el error. No sucederá con frecuencia, pero es molesto cuando sucede. Puedo ejecutar emacs -qy solucionar el problema, por supuesto, pero prefiero mantener una "buena" instancia ejecutándose en todo momento al piratear mi configuración, solo para estar seguro.
phils

Respuestas:

25

Nota: He incluido lo siguiente en un paquete restart-emacsdisponible aquí .


Aquí hay una forma alternativa de lograr lo que desea usando elisp puro (no realmente porque confía en un shell). El truco es generar otro proceso de emacs justo antes de que se elimine el emacs actual.

(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)))

El código para iniciar una versión GUI de emacs es sencillo. El código para iniciar emacs en una terminal es un poco complicado. Utiliza el hecho de que puede pasar una cadena a la suspend-emacsque se pasaría como entrada de terminal al proceso primario (el shell). De la documentación

(suspender-emacs y STUFFSTRING opcional)

Detenga Emacs y regrese al proceso superior. Puedes reanudar más tarde. Si 'no se puede suspender' no es nulo, o si el sistema no admite el control de trabajos, ejecute una subshell.

Si el argumento opcional STUFFSTRING no es nulo, sus caracteres se rellenan para que el padre de Emacs los lea como entrada de terminal, después de la suspensión.

Así que básicamente suspendemos emacs justo antes de que se elimine, dígale al shell principal que reanude los emacs actualmente suspendidos (que saldrá pronto) y luego inicie otro proceso de emacs. Tenga en cuenta que esto no funciona en plataformas en las que el terminal emacs puede / no suspende realmente, sino que inicia una subshell, por ejemplo, en Windows.

Iqbal Ansari
fuente
Esto no funciona para mí: cuando ejecuto sh -c "emacs &"desde el shell, se detiene con " emacs: standard input is not a tty". (Cuando lo hago M-x restart-emacs, ni siquiera veo ese mensaje de error, Emacs simplemente termina.)
Constantine
Funciona para mí bajo X. No funcionará en una terminal porque redirige stdin y stdout a / dev / null; pasar el tty padre al subproceso es probablemente factible pero más complicado.
Beni Cherniavsky-Paskin
1
Esto funciona perfectamente, y en realidad me da un poco de miedo. ¿Por qué demonios se le permite a Emacs pasar comandos a su caparazón contenedor?
Radon Rosborough
¿Qué combinación de teclas utilizas para eso?
slk500
32

Hasta donde sé, no puede decirle a Emacs que se reinicie después de finalizar, pero puede configurar el código de salida para que el proceso que inició Emacs en primer lugar pueda detectar que desea reiniciar.

Por ejemplo, este script de shell reinicia Emacs si salió con el código 123.

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

A continuación, definimos kill-emacs-and-restartque hace que Emacs termine con el código de salida igual al número mágico reconocido por el script:

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

Ahora, si ejecuta Emacs a través de este script, puede reiniciar M-x kill-emacs-and-restart(o vincularlo a una secuencia de teclas).

Constantina
fuente
¡Buena forma de esquivar el problema! Aceptaré esto si puedes decirme por qué you cannot tell Emacs to re-start after terminating. ¿Es esto una limitación técnica?
PythonNut
3
@PythonNut: Hasta donde yo sé, la única forma de reiniciar un proceso es mediante el uso de una de las funciones de la exec...familia (de todos modos, en los sistemas POSIX). Las funciones de control de procesos de Emacs Lisp no exponen tales llamadas de bajo nivel. Sin embargo, no soy un experto, así que espero que alguien más informado intervenga.
Constantine
2

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

Suponiendo que tengo la sintaxis correcta para incrustar "en una cadena, esto debería hacerlo.

(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
fuente
11
Por favor no lo hagas. Esto omite toda la limpieza interna de Emacs y descarta todo el estado actual (por ejemplo, buffers modificados) sin confirmación .
lunaryorn
La advertencia de Lunaryorn es correcta.
Joshua