Перезапустите Emacs из Emacs

44

Я перезагружаю свои emacs много. Все, что я хочу сделать, - это создать функцию, которая убивает текущий emacs, только чтобы породить новый вместо него. В идеале это также будет работать в TTY.

PythonNut
источник
8
Из любопытства, почему вы убиваете и немедленно перезапускаете так часто?
Дан
2
Я очень активно развиваю свой .emacs.d, что означает, что я перезагружаю emacs, чтобы удалить весь мусор, который я врезался в мою среду Есть несколько других вариантов использования, где я делаю это, но это самый большой.
PythonNut
1
@PythonNut, я думаю, тебе нужно немного переформулировать свой вопрос. Можете ли вы сказать, bashчтобы перезагрузить после завершения? Или vi? Или любой другой процесс, как правило? Нет, потому что это выходит за рамки их интересов и должным образом обрабатывается извне. В любом случае, то, что вам действительно нужно, - это способ реинициализации emacs путем очистки его виртуальной машины и повторного запуска кода инициализации ( без прерывания его процесса). Это было бы полезно и правильно для Emacs. Я не знаю, существует ли он, хотя :)
harpo
4
@ Харпо да, я могу bashначать с exec bash. Я понятия не имею о vim.
PythonNut
11
FWIW, я больше склонен запускать новый экземпляр Emacs для тестирования изменений конфигурации, а не выходить и перезапускать. Зачем? Потому что, если в моем коде есть ошибка, тогда Emacs не сможет загрузить мой конфиг, когда я перезапущу его, и в этот момент я не могу получить работающий экземпляр с моими обычными настройками, поэтому я должен использовать менее знакомое редактирование. среда для исправления ошибки. Это случается не часто, но раздражает, когда это происходит. emacs -qКонечно, я могу запустить и исправить проблему, но я предпочитаю постоянно поддерживать «хороший» экземпляр при взломе моей конфигурации, просто чтобы быть в безопасности.
Филс

Ответы:

25

Примечание: я завернул следующее в пакет, restart-emacsдоступный здесь .


Вот альтернативный способ достичь того, что вы хотите, используя чистый elisp (не совсем, так как вы полагаетесь на оболочку). Хитрость заключается в том, чтобы порождать другой процесс emacs непосредственно перед тем, как текущий emacs будет убит.

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

Код для запуска версии emacs с графическим интерфейсом прост. Код для запуска emacs в терминале немного сложен. Он использует тот факт, что вы можете передать строку, suspend-emacsкоторая будет передана в качестве терминального ввода в родительский процесс (оболочку). Из документации

(suspend-emacs и необязательный STUFFSTRING)

Остановите Emacs и вернитесь к превосходному процессу. Вы можете возобновить позже. Если значение `can-suspend 'не равно nil, или если система не поддерживает управление заданиями, вместо этого запустите subshell.

Если необязательный аргумент arg STUFFSTRING не равен nil, его символы заполняются для чтения в качестве терминального ввода родителем Emacs после приостановки.

Таким образом, мы в основном приостанавливаем emacs как раз перед тем, как он будет убит, сообщаем родительской оболочке возобновить приостановленный в данный момент emacs (который скоро выйдет) и затем запускаем другой процесс emacs. Обратите внимание, что это не работает на платформах, на которых терминал emacs может / не приостанавливает работу, но запускает подоболочку, например, в Windows.

Икбал Ансари
источник
Это не работает для меня: когда я запускаю sh -c "emacs &"из оболочки, он останавливается с " emacs: standard input is not a tty". (Когда M-x restart-emacsя не вижу этого сообщения об ошибке, Emacs просто завершает работу.)
Константин
У меня работает под X. Не будет работать в терминале, потому что он перенаправляет stdin и stdout в / dev / null; передача родительского tty в подпроцесс, вероятно, выполнима, но сложнее.
Бени Чернявский-Паскин
1
Это работает отлично, и это на самом деле меня немного пугает. С какой стати Emacs может передавать команды в содержащую его оболочку?
Радон Росборо
какое связывание клавиш вы используете для этого?
slk500
32

Насколько я знаю, вы не можете сказать Emacs перезапустить после завершения, но вы можете установить код выхода так, чтобы процесс, который первым запустил Emacs, мог определить, что вы хотите перезапустить.

Например, этот сценарий оболочки перезапускает Emacs, если он вышел с кодом 123.

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

Далее мы определим, kill-emacs-and-restartчто заставляет Emacs завершать работу с кодом выхода, равным магическому числу, распознаваемому сценарием:

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

Теперь, если вы запустите Emacs через этот скрипт, вы можете перезапустить его M-x kill-emacs-and-restart(или связать его с последовательностью клавиш).

Константин
источник
Хороший способ обойти проблему! Я приму это, если вы можете сказать мне, почему you cannot tell Emacs to re-start after terminating. Это техническое ограничение?
PythonNut
3
@PythonNut: Насколько мне известно, единственный способ перезапустить процесс - использовать одну из функций exec...семейства (в любом случае, в системах POSIX). Функции управления процессом Emacs Lisp не предоставляют такие низкоуровневые вызовы. Хотя я не эксперт, поэтому, надеюсь, кто-то более знающий примет участие.
Константин
2

Откровенно похищен с https://unix.stackexchange.com/questions/114238/is-it-possibe-to-change-parent-shells-working-directory-programmatics

Предполагая, что у меня есть правильный синтаксис для встраивания "в строку, это должно сделать это.

(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\")'"))
Джошуа
источник
11
Пожалуйста, не надо. Это обходит всю внутреннюю очистку Emacs и сбрасывает все текущее состояние (например, измененные буферы) без подтверждения .
lunaryorn
предупреждение Лунаорна верно.
Джошуа