Wednesday, April 28, 2010

Emacs Tip #36: Abort the minibuffer when using the mouse

A friend of mine loves using Emacs, but is always complaining about something. This time it's Emacs' behavior to keep the minibuffer active when you use the mouse to select another window. For example, you start doing a C-x C-f, click elsewhere, and do the C-x C-f again. Emacs will beep and tell you Command attempted to use minibuffer while in minibuffer.

After swallowing my, "well don't use the mouse" response I set about trying to fix it. I'm sure this has been solved before, I just didn't have enough google-fu to find the solution.


(defun stop-using-minibuffer ()
"kill the minibuffer"
(when (and (>= (recursion-depth) 1) (active-minibuffer-window))
(abort-recursive-edit)))

(add-hook 'mouse-leave-buffer-hook 'stop-using-minibuffer)


Edited to add:
A commenter suggested using recursive minibuffers. I think that the resulting behavior is more confusing than helpful.

Yes, it avoids the error, but then you get this ever-increasing stack of minibuffers building up. If/when the user notices the minibuffer hanging around it'll be annoying (I've had people ask, "Why is it trying to find a file?" (because the minibuffer still shows Find file: /path/to/somewhere)). And heaven forbid they click in the minibuffer, type C-g and get back to the window configuration they were looking at when they started that command, which was ... 15 minutes ago.

15 comments:

jz said...

Have you considered using C-g?

BFW said...

@jz C-g only works when the focus is inside the minibuffer. When the focus is in another buffer, C-g does nothing to the minibuffer.

cyd said...

Consider using recursive minibuffers:

(setq enable-recursive-minibuffers t)

BFW said...

@cyd Right, I should have mentioned recursive-minibuffers in my post ... I've found that it's more confusing to the (beginning) users. Will update post with my thoughts on recursive minibuffers.

YHVH said...

Is there a key binding to focus the minibuffer? There is a discussion on superuser
http://superuser.com/questions/132225/how-to-get-back-to-an-active-minibuffer-prompt-in-emacs-without-the-mouse

BFW said...

@YHVH There's no built-in way to return focus to the minibuffer, but there is a solution (already posted). Check it out.

Georg said...

IMO checking for an active recursive edit is too lax -- that function will also e.g. quit the Elisp Debugger when changing windows with the mouse.

Maybe (and (>= (recursion-depth) 1) (active-minibuffer-window)) would be acceptable?

BFW said...

@Georg I'll add that.

Michael Mrozek said...

"And heaven forbid they click in the minibuffer, type C-g and get back to the window configuration they were looking at when they started that command, which was ... 15 minutes ago"

YES. I've made that exact mistake before, it drives me crazy

Anonymous said...

there is one command C-x o i.e. CTRL+x followed by o
This will change you through minibuffer to buffer to frame to everything that is on screen sequentially. It is like TAB.

BFW said...

@Anonymous Sure you can use C-x o, but the point was that the person didn't want to...

Anonymous said...

Provided the user understands the concept of recursive minibuffers, you can eliminate any associated confusion if you enable minibuffer-depth-indicate-mode as well.

BFW said...

@Anonymous The chances of the user understanding (or even really wanting) recursive minibuffers is IMO slight to none. But that is certainly a possibility.

fssadasd said...

Now for the million-dollar question: how do you answer the minibuffer (or dialog) question on your desktop when you're sitting at your laptop and have done "ssh desktop emacsclient"?

(When I do this, emacsclient just hangs until I walk over to my desktop and answer the question.)

http://bobkerns.typepad.com said...

"he chances of the user understanding (or even really wanting) recursive minibuffers is IMO slight to none."

Yes. I've been using Emacs and predecessors since before it was called Emacs, and was implemented in ITS TECO.

I googled "emacs minibuffer annoying" to get here. In my case, it was because enable-recursive-minibuffers was set. Disabling it the solution to my main problem.

I don't use the mouse a lot, but I'll adopt your solution for that aspect as well. But I think I also may want to make c-X c-O abort as well.

Thanks for the hint!