Question

Scenario:

  • I start to type M-x to type a command
  • I switch to another emacs window/buffer because I realise I'm executing the command in the wrong window
  • I start to type M-x again to execute the command in the correct window

Result: I get the dreaded "Command attempted to use minibuffer while in minibuffer"

This happens to me multiple times a day while using emacs, and not just in this scenario. This behaviour is highly user-hostile (ref. Modes and Pseudo-modes in The Humane Interface by Jef Raskin)

Is there a way to customize emacs behaviour so that instead of giving this error, it just cancels the first minibuffer and replaces it with a new one?

Was it helpful?

Solution

Indeed this emacs "feature" is aggressive and annoying. I found this to be the right answer to the problem .Most likely you lost focus of the minibuffer because you switched windows with the mouse and NOT a minibuffer command. So whenever you lose focus using the mouse, the minibuffer will be cleared. Check this post. It works for me and it's way better than recursive minibuffers which will cause a headache

http://trey-jackson.blogspot.com/2010/04/emacs-tip-36-abort-minibuffer-when.html

OTHER TIPS

You can set the variable enable-recursive-minibuffers, which will prevent that error message from coming up. But it just enables multiple calls to the minibuffer - it doesn't redirect the current minibuffer's command to the new buffer. You can give this a try, but I think it'll be more confusing because the original action is still pending...

M-x is bound to 'execute-extended-command, and re-hosting (changing the original buffer) for that command is kind of like programming with continuation. i.e. you call a subroutine from location X, but instead of returning to X when done, you return to Y. I personally think it'd open up more confusion than it'd solve. But I understand the frustration (and know others who have the same frustration).

I'm not sure if there is such a customization, but the way I avoid this is hitting ctrl-g to cancel the command I was in the middle of writing in the minibuffer.

Since my first answer doesn't directly give you what you want, I thought I'd come up with a real solution. This is what I have:

(defvar my-execute-extended-command-source-buffer nil
  "var holding the buffer to which the extended-execute-command should apply")
(defvar in-my-execute-extended-command nil
  "internal use - indicates whether we're in a 'recursive edit' of sorts")
(defun my-execute-extended-command (command)
  "home-grown version of execute-extended-command that supports re-hosting the buffer"
  (interactive (list (if in-my-execute-extended-command
                   nil
                 (let ((in-my-execute-extended-command t))
                   (setq my-execute-extended-command-source-buffer (current-buffer))
                   (completing-read "My-x " obarray 'commandp t nil 'extended-command-history nil nil)))))
  (if in-my-execute-extended-command
      (progn (setq my-execute-extended-command-source-buffer (current-buffer))
             (select-window (minibuffer-window)))
    (switch-to-buffer my-execute-extended-command-source-buffer)
    (call-interactively (symbol-function (intern command)))))

I've tested it this way. I bound it to a key (F10 in my case b/c I didn't want to lose M-x). Then, with two windows open, each showing a different buffer (say A and B):

  1. From window showing buffer A: F10 isearch-for
  2. Switch from minibuffer to window showing A: C-x o
  3. Switch from window showing A to that showing B: C-x o
  4. "re-host" the command from buffer B: F10
  5. Now back in the minibuffer, finish the command ward RET

When I started typing a search term, the search applied to buffer B.

This only replaces the M-x functionality, not the commands invoked from M-x. Also, this version does not support the prefix argument.

Hopefully this is what you want.

Can anyone improve on the following?

I've given up and just want to set \C-w to cancel any previous minibuffer before opening a new one (like doing \C-g\C-w)

So far thanks to Trey I've got:

(defun cancel-completing-read ()
  (if (> (minibuffer-depth) 0) (exit-minibuffer))
   (completing-read "My-x " obarray 'commandp t nil 'extended-command-history nil nil))

(defun cancel-and-execute-command (command)
  (interactive (list (cancel-completing-read)))
  (call-interactively (symbol-function (intern command))))

(global-set-key "\M-x" 'cancel-and-execute-command)

What command should I use in the place of exit-minibuffer above?

I've tried

keyboard-escape-quit
exit-minibuffer
keyboard-quit

Here you go:

;; automatically cancel the minibuffer when you switch to it, to avoid
;; "attempted to use minibuffer" error.
;; cy was here

(provide 'cancel-minibuffer)

(defun cancel-minibuffer-first (sub-read &rest args)
    (let ((active (active-minibuffer-window)))
        (if active
                (progn
                    ;; we have to trampoline, since we're IN the minibuffer right now.
                    (apply 'run-at-time 0 nil sub-read args)
                    (abort-recursive-edit))
            (apply sub-read args))))

(advice-add 'read-from-minibuffer :around #'cancel-minibuffer-first)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top