Как установить статус выхода для emacsclient

1058
milkypostman

Я обнаружил, что использую мой основной сеанс Emacs (CocoaEmacs в OSX) для редактирования командной строки bash. Для этого у меня установлен РЕДАКТОР на emacsclient. Затем я редактирую строку в Emacs, сохраняю и покидаю этот буфер - обычно с помощью "C-x #"которого выполняется (server-edit).

Проблема в том, что иногда я нахожусь в процессе редактирования строки, и я понимаю, что не хочу на самом деле выполнить строку (сожаление наступает). Проблема в том, что bash определяет, выполнять ли строку или нет, основываясь на состоянии возврата.

Я хотел бы, чтобы у меня было два варианта.

  1. Если я нажму, "C-x #"сохраните буфер и верните код выхода 0(т. Е. Я выполнил редактирование и готов к bash, чтобы покончить с этим).

  2. Если я уничтожу буфер, не сохраняйте буфер, не уничтожайте его и не возвращайте ненулевой код завершения. Я бы даже не возражал, если бы мне пришлось нажимать на альтернативное связывание.

Одно частичное решение - просто прокомментировать строку. Я не рассматриваю это как вариант для меня, потому что обычно я редактирую командную строку в Emacs, потому что я работаю над многострочным программированием.

4
Будет ли очистка буфера, сохранение и выход из работы для вас? Должно быть легко связать это с чем-то. user314253 12 лет назад 0
вероятно, не потому, что я не хочу, чтобы история была стёрта, и я думаю, что есть проблема с этим. хотя мне нужно немного лучше освоить историю bash. milkypostman 12 лет назад 0

2 ответа на вопрос

4
pnkfelix

In relatively current versions of Emacs (e.g. in my copy of Emacs 24.2, but not the OS X's distribution of emacs 22.1), you can write Elisp code that will send a command to the emacsclient telling it to exit with an error exit status.

This is easier than it sounds.

There is a buffer-local variable, server-buffer-clients, with the clients that are attached to the buffer. And the function server-send-string can be used to communicate commands following the server-process-filter protocol.

For example:

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

causes (one of the) emacsclient(s) associated with the buffer to immediate issue the text

*ERROR*: die 

and then exit with exit code 1.


So, it is pretty easy to define an interactive function that you could call from emacs itself to kill off the emacsclients:

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

With the above in your .emacs file (and a sufficiently current version of Emacs), you can invoke M-x tell-emacsclients-for-buffer-to-die to make the emacsclients exit with error status. (And of course you could bind this function to an appropriate alternate key sequence.)


Footnote

Ideally, one would then couple the function above with a hook on the server-kill-buffer function to accomplish the goal number (2.) in the original question. (That is, killing the buffer without saving it via C-x # should fire off the same error exits from emacsclient.)

However, my attempts to add this to the kill-buffer-hook have failed, because the server-kill-buffer function is put on the front of the kill-buffer-hook list after the server-visit-hook hooks have been run, and so the default server-kill-buffer function will run first. (One could fix up the kill-buffer-hook afterward, but I am not yet sure where to put the code to do that into the Elisp control flow.)

Update: Okay, here's a really hacky way to accomplish the above:

(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: Slightly more robust variant:

(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) 
Хорошо, позвольте мне попробовать это и посмотреть, насколько хорошо это работает. Это то, что я искал. milkypostman 11 лет назад 0
milkypostman: это сработало для вас? pnkfelix 10 лет назад 0
Я не помню сейчас. но у меня похожие проблемы, поэтому я попробую еще раз. milkypostman 10 лет назад 0
1
Gilles

Просто нажмите Ctrl+Cв терминале, где вы запускаете Bash. Это отменяет издание и подталкивает оригинальную линию к истории. Если вы не можете сделать это напрямую, потому что Emacs работает в том же терминале, завершите emacsclientпроцесс любым способом по вашему выбору.

это хорошо. Есть ли простой способ убить клиентский процесс из Emacs? это было бы еще лучше, не так ли? выглядит хитро через `server.el` milkypostman 12 лет назад 0