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)