Mulai ulang emacs dari dalam emacs

44

Saya banyak me-restart emacs saya. Yang ingin saya lakukan adalah membuat fungsi yang membunuh emacs saat ini, hanya untuk menelurkan yang baru sebagai gantinya. Idealnya, ini juga akan bekerja di TTY.

PythonNut
sumber
8
Karena penasaran, mengapa Anda membunuh dan segera memulai kembali begitu sering?
Dan
2
Saya sangat aktif mengembangkan .emacs.d, yang berarti saya memulai kembali emacs untuk menghilangkan sampah apa pun yang telah saya buang ke lingkungan saya. Ada beberapa kasus penggunaan lain di mana saya melakukan ini, tapi itu yang terbesar.
PythonNut
1
@ PhythonNut, saya pikir Anda perlu membingkai ulang pertanyaan Anda sedikit. Bisakah Anda memberi tahu bashuntuk memulai kembali setelah pengakhiran? Atau vi? Atau proses lain, sebagai aturan? Tidak, karena itu di luar ruang lingkup keprihatinan mereka, dan ditangani dengan baik secara eksternal. Bagaimanapun, apa yang Anda benar-benar inginkan adalah cara untuk menginisialisasi ulang emacs, dengan menghapus VM-nya dan menjalankan kembali kode init Anda ( tanpa mematikan prosesnya). Itu akan berguna dan layak untuk emacs. Saya tidak tahu apakah itu ada, :)
harpo
4
@harpo ya, saya bisa bashmemulai kembali dengan exec bash. Saya tidak tahu tentang vim.
PythonNut
11
FWIW, saya lebih cenderung untuk memulai instance baru Emacs untuk menguji perubahan konfigurasi, daripada keluar dan memulai kembali. Mengapa? Karena jika kode saya memiliki kesalahan maka Emacs mungkin tidak dapat memuat konfigurasi saya ketika saya me-restart itu, dan pada saat itu saya tidak bisa benar-benar mendapatkan instance yang berjalan dengan pengaturan normal saya, jadi saya harus menggunakan pengeditan yang kurang familiar lingkungan untuk memperbaiki bug. Itu tidak akan sering terjadi, tetapi itu menjengkelkan ketika itu terjadi. Saya dapat menjalankan emacs -qdan memperbaiki masalah tentu saja, tetapi saya lebih memilih untuk tetap menjalankan contoh 'baik' setiap saat saat meretas konfigurasi saya, hanya agar aman.
phils

Jawaban:

25

Catatan: Saya telah membungkus berikut ini dalam sebuah paket yang restart-emacstersedia di sini .


Berikut adalah cara alternatif untuk mencapai apa yang Anda inginkan menggunakan elisp murni (tidak benar-benar karena Anda mengandalkan shell). Kuncinya adalah memunculkan proses emacs lain sebelum emacs saat ini terbunuh.

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

Kode untuk memulai versi GUI dari emacs sangat mudah. Kode untuk memulai emacs di terminal agak rumit. Ia menggunakan fakta bahwa Anda dapat meneruskan string suspend-emacsyang akan diteruskan sebagai input terminal ke proses induk (shell). Dari dokumentasi

(menangguhkan-emacs & STUFFSTRING opsional)

Hentikan Emacs dan kembali ke proses superior. Anda dapat melanjutkan nanti. Jika `tidak dapat ditangguhkan 'adalah non-nil, atau jika sistem tidak mendukung kontrol pekerjaan, jalankan subkulit sebagai gantinya.

Jika opsional arg STUFFSTRING adalah non-nil, karakternya diisi untuk dibaca sebagai input terminal oleh induk Emacs, setelah suspensi.

Jadi pada dasarnya kita menangguhkan emacs sebelum dibunuh memberitahu shell induk untuk melanjutkan emacs yang saat ini ditangguhkan (yang akan segera keluar) dan kemudian meluncurkan proses emacs lain. Perhatikan bahwa ini tidak berfungsi pada platform di mana terminal emacs dapat / tidak benar-benar menunda tetapi memulai subkulit, misalnya pada windows.

Iqbal Ansari
sumber
Ini tidak berfungsi untuk saya: ketika saya lari sh -c "emacs &"dari shell, ia berhenti dengan " emacs: standard input is not a tty". (Ketika saya melakukannya, M-x restart-emacssaya bahkan tidak melihat pesan kesalahan itu, Emacs baru saja berakhir.)
Constantine
Bekerja untuk saya di bawah X. Tidak akan bekerja di terminal karena itu mengarahkan ulang stdin dan stdout ke / dev / null; meneruskan tty induk ke subproses mungkin bisa dilakukan tetapi lebih rumit.
Beni Cherniavsky-Paskin
1
Ini berfungsi dengan baik, dan itu benar-benar membuatku sedikit takut. Mengapa Emacs diizinkan untuk mengirimkan perintah ke shell yang mengandungnya?
Radon Rosborough
keybinding mana yang Anda gunakan untuk itu?
slk500
32

Sejauh yang saya tahu Anda tidak dapat memberitahu Emacs untuk memulai kembali setelah berakhir, tetapi Anda dapat mengatur kode keluar sehingga proses yang memulai Emacs di tempat pertama dapat mendeteksi bahwa Anda ingin memulai kembali.

Sebagai contoh, skrip shell ini memulai kembali Emacs jika keluar dengan kode 123.

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

Selanjutnya, kami mendefinisikan kill-emacs-and-restartyang membuat Emacs mengakhiri dengan kode keluar sama dengan angka ajaib yang dikenali oleh skrip:

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

Sekarang jika Anda menjalankan Emacs melalui skrip ini, Anda dapat memulai kembali dengan M-x kill-emacs-and-restart(atau mengikatnya ke urutan kunci).

Constantine
sumber
Cara yang bagus untuk menjelajahi masalah! Saya akan menerima ini jika Anda bisa memberi tahu saya alasannya you cannot tell Emacs to re-start after terminating. Apakah ini batasan teknis?
PythonNut
3
@ PhythonNut: Sejauh yang saya tahu satu-satunya cara untuk memulai kembali proses adalah dengan menggunakan salah satu fungsi dari exec...keluarga (pada sistem POSIX, sih). Fungsi kontrol proses Emacs Lisp tidak mengekspos panggilan tingkat rendah seperti itu. Saya bukan ahli, jadi mudah-mudahan seseorang yang lebih berpengetahuan akan berpadu.
Constantine
2

Dicuri secara terang-terangan dari https://unix.stackexchange.com/questions/114238/is-it-possibe-to-change-parent-shells-working-directory-programmatically

Dengan asumsi saya punya sintaks yang tepat untuk menyematkan "dalam sebuah string, ini harus dilakukan.

(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
sumber
11
Tolong jangan. Ini melewati semua pembersihan internal Emacs dan membuang semua status saat ini (mis. Buffer yang dimodifikasi) tanpa konfirmasi .
lunaryorn
peringatan lunaryorn benar.
Yosua