8

I am trying to bind a key in minibuffer-local-map to a command which uses abort-recursive-edit or exit-minibuffer and then proceeds executing more elisp code. So I want to exit the minibuffer and then continue from the context before. The only solution I have found so far is to use run-with-timer like in this contrived example:

(defun example ()
  (interactive)
  ;; This is my current workaround
  ;; (run-with-timer 0.1 nil 'split-window-vertically)
  (abort-recursive-edit) 
  ;; This code won't be executed
  (split-window-vertically))

Is there a cleaner/better way to do something like this? I could try to setup everything with with-current-window and stuff like that and exit the minibuffer in the last instruction but maybe there is a better alternative?

clemera
  • 3,401
  • 13
  • 40

2 Answers2

8

I wrote about this once.

The code:

(defmacro ivy-quit-and-run (&rest body)
  "Quit the minibuffer and run BODY afterwards."
  `(progn
     (put 'quit 'error-message "")
     (run-at-time nil nil
                  (lambda ()
                    (put 'quit 'error-message "Quit")
                    ,@body))
     (minibuffer-keyboard-quit)))
abo-abo
  • 13,943
  • 1
  • 29
  • 43
5

I don't know of a way to do what you request.

As you say in your question, and as @abo-abo shows, a workaround is to use a timer to execute the code you want run after the minibuffer is exited.

The more typical approach is to execute the code from the minibuffer (i.e., before exiting). To do that, you need to set up and use the proper context, which in your case means select the window that you want to split. But your question was how to avoid doing this.

The reason you cannot (as far as I know) exit the minibuffer and then invoke the remaining code in your command is that exiting the minibuffer performs a non-local exit, by throwing to a catch tag outside the command's invocation stack (typically tag exit, but you can also exit to the top-level).

Drew
  • 75,699
  • 9
  • 109
  • 225