Zrestartuj emacsa z poziomu emacsa

44

Często restartuję emacsa. Wszystko, co chcę zrobić, to stworzyć funkcję, która zabije obecnego emacsa, tylko po to, aby zamiast niego utworzyć nową. Idealnie byłoby to również działać w TTY.

PythonNut
źródło
8
Z ciekawości dlaczego zabijasz i od razu tak często restartujesz?
Dan
2
Bardzo aktywnie rozwijam swoje .emacs.d, co oznacza, że ​​ponownie uruchamiam emacsa, aby usunąć śmieci, które wysadziłem w moim środowisku. Jest kilka innych przypadków użycia, w których to robię, ale to jest największe.
PythonNut
1
@PythonNut, myślę, że musisz nieco zmienić swoje pytanie. Czy możesz powiedzieć, bashaby uruchomić ponownie po zakończeniu? Czy vi? Lub jakikolwiek inny proces z reguły? Nie, ponieważ wykracza to poza ich zakres obaw i jest odpowiednio traktowane zewnętrznie. W każdym razie to, czego naprawdę chcesz, to sposób na ponowne zainicjowanie emacsa poprzez wyczyszczenie jego maszyny wirtualnej i ponowne uruchomienie kodu init ( bez zabijania jego procesu). Byłoby to przydatne i właściwe dla emacsa. Nie wiem jednak, czy istnieje :)
harpo
4
@harpo tak, mogę zacząć bashod nowa exec bash. Nie mam pojęcia o Vimie.
PythonNut,
11
FWIW, jestem bardziej skłonny do uruchomienia nowej instancji Emacsa w celu przetestowania zmian konfiguracji, a nie wychodzenia i restartowania. Dlaczego? Ponieważ jeśli mój kod zawiera błąd, Emacs może nie być w stanie załadować mojej konfiguracji po jej ponownym uruchomieniu, i w tym momencie nie mogę uzyskać działającej instancji z moimi normalnymi ustawieniami, więc muszę użyć mniej znanej edycji środowisko, aby naprawić błąd. Nie zdarza się to często, ale jest denerwujące. Mogę emacs -qoczywiście uruchomić i naprawić problem, ale wolę zachować dobrą instancję przez cały czas podczas hakowania mojej konfiguracji, dla zachowania bezpieczeństwa.
phils

Odpowiedzi:

25

Uwaga: zapakowałem następujące elementy w paczkę restart-emacsdostępną tutaj .


Oto alternatywny sposób na osiągnięcie tego, co chcesz, używając czystego elisp (nie tak naprawdę, ponieważ polegasz na powłoce). Sztuką jest odrodzenie innego procesu emacsa tuż przed zabiciem obecnego emacsa.

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

Kod do uruchomienia wersji emacsa z GUI jest prosty. Kod uruchamiający emacsa w terminalu jest nieco trudny. Wykorzystuje fakt, że można przekazać ciąg znaków, suspend-emacsktóry zostanie przekazany jako dane wejściowe terminala do procesu nadrzędnego (powłoki). Z dokumentacji

(suspend-emacs i opcjonalnie STUFFSTRING)

Zatrzymaj Emacsa i wróć do doskonałego procesu. Możesz wznowić później. Jeśli opcja „nie można zawiesić” jest inna niż zero lub system nie obsługuje kontroli zadań, uruchom zamiast tego podpowłokę.

Jeśli opcjonalny argument STUFFSTRING jest inny niż zero, jego znaki są wypychane do odczytu jako dane wejściowe terminala przez rodzica Emacsa, po zawieszeniu.

Tak więc zasadniczo zawieszamy emacsa tuż przed jego zabiciem, powiedzmy powłoce rodzicielskiej, aby wznowiła aktualnie zawieszony emacs (który wkrótce się zakończy), a następnie uruchomi kolejny proces emacs. Zauważ, że to nie działa na platformach, na których emacs terminala może / nie zawiesza się, ale uruchamia podpowłokę, na przykład w systemie Windows.

Iqbal Ansari
źródło
To nie działa dla mnie: kiedy uruchamiam sh -c "emacs &"z powłoki, kończy się na „ emacs: standard input is not a tty”. (Kiedy to M-x restart-emacsrobię, nawet nie widzę tego komunikatu o błędzie, Emacs po prostu kończy działanie.)
Constantine
Działa dla mnie pod X. Nie działa w terminalu, ponieważ przekierowuje stdin i stdout do / dev / null; przekazanie tty rodzica do podprocesu jest prawdopodobnie wykonalne, ale trudniejsze.
Beni Cherniavsky-Paskin
1
Działa to doskonale i trochę mnie przeraża. Dlaczego, u licha, Emacs może przekazywać polecenia do swojej powłoki?
Radon Rosborough,
jakich klawiszy używasz do tego?
slk500
32

O ile wiem, nie możesz powiedzieć Emacsowi, aby uruchomił się ponownie po zakończeniu, ale możesz ustawić kod wyjścia, aby proces, który uruchomił Emacsa, mógł wykryć, że chcesz go ponownie uruchomić.

Na przykład ten skrypt powłoki ponownie uruchamia Emacsa, jeśli zakończył działanie z kodem 123.

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

Następnie określamy kill-emacs-and-restart, że Emacs kończy działanie kodem wyjścia równym magicznej liczbie rozpoznawanej przez skrypt:

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

Teraz, jeśli uruchamiasz Emacsa za pomocą tego skryptu, możesz zacząć od nowa M-x kill-emacs-and-restart(lub powiązać go z sekwencją klawiszy).

Konstantyn
źródło
Fajny sposób ominięcia problemu! Zaakceptuję to, jeśli możesz mi powiedzieć dlaczego you cannot tell Emacs to re-start after terminating. Czy to ograniczenie techniczne?
PythonNut
3
@PythonNut: O ile wiem, jedynym sposobem na ponowne uruchomienie procesu jest użycie jednej z funkcji z exec...rodziny (w każdym razie w systemach POSIX). Funkcje kontroli procesu Emacsa Lispa nie ujawniają takich wywołań niskiego poziomu. Nie jestem jednak ekspertem, więc mam nadzieję, że włączy się ktoś bardziej kompetentny.
Constantine
2

Rażąco skradzione z https://unix.stackexchange.com/questions/114238/is-it-possibe-to-change-parent-shells-working-directory-programmatically

Zakładając, że mam odpowiednią składnię do osadzania „w ciągu, powinno to wystarczyć.

(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\")'"))
Jozuego
źródło
11
Proszę nie. Pomija to wszystkie wewnętrzne czyszczenie Emacsa i odrzuca cały bieżący stan (np. Zmodyfikowane bufory) bez potwierdzenia .
lunaryorn
ostrzeżenie Lunaryorn jest prawidłowe.
Jozuego