Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have found myself using my main Emacs session (CocoaEmacs in OSX) to edit my bash command line. To do so I have my EDITOR set to emacsclient. Then I edit the line in Emacs and save and quit that buffer -- normally using "C-x #" which executes (server-edit).

The problem is that sometimes i'm in the midst of editing a line and I realize I don't want to actually execute the line (regret sets in). The problem is that bash determines whether to execute the line or not based on the return status.

What I would like is for there to be two options for me.

  1. If I hit "C-x #" save the buffer and return exit code 0 (i.e., i've done my editing and i'm ready for bash to get down with it).

  2. If I kill the buffer then don't save the buffer, kill it, and return a non-zero exit code. I wouldn't even mind if I had to hit an alternate binding.

One partial solution is just to comment the line. I don't see this as an option for me as normally reason I am editing a commandline in Emacs is that I'm working on a multi-line thing.

share|improve this question
    
Would blanking the buffer, saving and exiting work for you? Should be easy to bind that to something. –  user314253 Jun 9 '11 at 22:04
    
probably not because i don't want the history to be wiped and i think there is a problem with that. although i need to master the bash history stuff a bit better. –  milkypostman Jun 10 '11 at 2:28

2 Answers 2

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)
share|improve this answer
    
OK, let me try this out and see how well it works. This is what I was looking for. –  milkypostman Jan 28 '13 at 22:35
    
milkypostman: did it work for you? –  pnkfelix Dec 14 '13 at 1:32
    
tbh I don't remember now. but I am having similar problems so I will try again. –  milkypostman Feb 18 at 19:55

Just press Ctrl+C in the terminal where you're running bash. This cancels the edition, and pushes the original line to the history. If you can't do this directly because Emacs is running in the same terminal, kill the emacsclient process by the means of your choice.

share|improve this answer
    
this is good. is there an easy way to kill the client process from inside emacs? that would be even better don't you think? looks tricky through server.el –  milkypostman Jun 11 '11 at 4:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.