So legen Sie den Exit-Status für Emacsclient fest

1133
milkypostman

Ich habe festgestellt, dass ich meine Haupt-Emacs-Sitzung (CocoaEmacs in OSX) verwende, um meine Bash-Befehlszeile zu bearbeiten. Dafür habe ich meinen EDITOR auf gesetzt emacsclient. Dann bearbeite ich die Zeile in Emacs und speichere und beende den Puffer - normalerweise mit dem "C-x #"welcher ausgeführt wird (server-edit).

Das Problem ist, dass ich mich manchmal mitten im Editieren einer Zeile befinde und mir klar wird, dass ich die Zeile nicht wirklich ausführen möchte (Bedauerungssätze). Das Problem ist, dass bash anhand des Rückgabestatus bestimmt, ob die Zeile ausgeführt werden soll oder nicht.

Was ich möchte, ist, dass es zwei Möglichkeiten für mich gibt.

  1. Wenn ich auf "C-x #"den Puffer speichere und den Exit-Code zurückschicke 0(dh ich habe meine Bearbeitung abgeschlossen und bin bereit für die Bash, um damit fertig zu werden).

  2. Wenn ich den Puffer abschalte, dann speichere den Puffer nicht ab, brich ihn ab und gib einen Exit-Code ungleich Null zurück. Ich hätte nichts dagegen, wenn ich eine alternative Bindung treffen müsste.

Eine Teillösung besteht nur darin, die Zeile zu kommentieren. Ich sehe das nicht als Option für mich, da ich normalerweise eine Befehlszeile in Emacs editiere, weil ich an einer mehrzeiligen Sache arbeite.

4
Würde der Puffer leeren, speichern und beenden für Sie arbeiten? Sollte leicht sein, das an etwas zu binden. user314253 vor 13 Jahren 0
Wahrscheinlich nicht, weil ich nicht möchte, dass die Geschichte gelöscht wird, und ich denke, dass ein Problem damit besteht. obwohl ich die bash-geschichte etwas besser beherrschen muss. milkypostman vor 13 Jahren 0

2 Antworten auf die Frage

4
pnkfelix

In relativ aktuellen Versionen von Emacs (z. B. in meiner Kopie von Emacs 24.2, nicht jedoch in der Verteilung von OS X von Emacs 22.1 von OS X) können Sie Elisp-Code schreiben, der einen Befehl an den Emacsclient sendet und ihn mit einem Exit-Status zum Beenden auffordert.

Das ist einfacher als es sich anhört.

Es gibt eine lokale Puffervariable server-buffer-clientsmit den Clients, die an den Puffer angehängt sind. Mit der Funktion server-send-stringkönnen Befehle nach dem server-process-filterProtokoll übertragen werden.

Zum Beispiel:

(server-send-string (car server-buffer-clients) "-error die") 

bewirkt, dass (einer der mit dem Puffer verknüpften) Emacsclient den Text sofort ausgibt

*ERROR*: die 

und dann mit Exitcode 1 beenden.


Es ist also ziemlich einfach, eine interaktive Funktion zu definieren, die Sie von emacs selbst aufrufen können, um die emacsclients auszuschalten:

(defun tell-emacsclients-for-buffer-to-die () "Sends error exit command to every client for the current buffer." (interactive) (dolist (proc server-buffer-clients) (server-send-string proc "-error die"))) 

Mit dem oben genannten in Ihrer .emacsDatei (und einer ausreichend aktuellen Version von Emacs) können Sie aufrufen M-x tell-emacsclients-for-buffer-to-die, um die Emacsclients mit Fehlerstatus zu beenden. (Natürlich können Sie diese Funktion auch an eine geeignete alternative Tastenfolge binden.)


Fußnote

Idealerweise würde man dann die obige Funktion mit einem Haken an der server-kill-bufferFunktion koppeln, um die Zielnummer (2.) in der ursprünglichen Frage zu erreichen. (Das heißt, C-x #wenn Sie den Puffer töten, ohne ihn zu speichern, wird derselbe Fehler ausgegeben, der von emacsclient ausgeführt wird.)

Meine Versuche, dies zu dem zu addieren, kill-buffer-hooksind jedoch fehlgeschlagen, da die server-kill-bufferFunktion kill-buffer-hooknach dem server-visit-hookAusführen der Hooks an die Spitze der Liste gesetzt wird und die Standardfunktion daher server-kill-bufferzuerst ausgeführt wird. (Man könnte das kill-buffer-hookspäter reparieren, aber ich bin mir noch nicht sicher, wo der Code dafür in den Elisp-Kontrollfluss eingefügt werden soll.)

Update: Okay, hier ist eine wirklich hackige Methode, um das Obige zu erreichen:

(defun kill-buffer-with-special-emacsclient-handling () (interactive) (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t) (kill-buffer))  (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling) 

Update 2: Etwas robustere Variante:

(defun kill-buffer-with-special-emacsclient-handling () "Wrapper around kill-buffer that ensures tell-emacsclients-for-buffer-to-die is on the hooks" (interactive) (add-hook 'kill-buffer-hook 'tell-emacsclients-for-buffer-to-die nil t) (kill-buffer))  ;; (global-set-key (kbd "C-x k") 'kill-buffer)  (defun install-emacsclient-wrapped-kill-buffer () "Installs wrapped kill-buffer with special emacsclient handling. Best not to install it unconditionally because the server is not necessarily running." (interactive) (global-set-key (kbd "C-x k") 'kill-buffer-with-special-emacsclient-handling))  (add-hook 'server-switch-hook 'install-emacsclient-wrapped-kill-buffer) 
OK, lassen Sie mich das ausprobieren und sehen, wie gut es funktioniert. Das war es, wonach ich gesucht hatte. milkypostman vor 11 Jahren 0
milkypostman: hat es für dich funktioniert? pnkfelix vor 10 Jahren 0
Ich kann mich jetzt nicht erinnern. Ich habe aber ähnliche Probleme und werde es erneut versuchen. milkypostman vor 10 Jahren 0
1
Gilles

Drücken Ctrl+CSie einfach das Terminal, in dem Sie bash laufen. Dadurch wird die Ausgabe abgebrochen und die ursprüngliche Zeile in die Historie verschoben. Wenn Sie dies nicht direkt tun können, weil Emacs im selben Terminal ausgeführt wird, beenden Sie den emacsclientVorgang mit den Mitteln Ihrer Wahl.

das ist gut. Gibt es eine einfache Möglichkeit, den Client-Prozess von emacs aus zu beenden? das wäre noch besser, findest du nicht? sieht durch `server.el` schwierig aus milkypostman vor 13 Jahren 0