Passing the prefix argument around


Last year I blogged about a solution to a common problem I had with windows in Emacs. I wanted to be able to exit particular fullframed buffers and restore the windows as they were before opening those buffers.

The core of my solution is the following function:

(defun mu-save-wins-then-call (func &optional args)
  "Save current window configuration, then call FUNC optionally with ARGS."
  (interactive)
  (push (current-window-configuration) mu-saved-window-configuration)
  (cond
   ;; We have arguments for the function
   ((bound-and-true-p args) (funcall func args))
   ;; The function requires exactly one argument, and we want it to be nil
   ((equal args "nil") (funcall func nil))
   ;; The function does not expect arguments
   (t (funcall func))))

This function works fine for most of my cases, but it doesn’t take the prefix argument into account. Since I rely heavily on shell-mode, at times I need to open more than one shell buffer, and the documentation of the shell command specifies that the prefix argument can be used to open new buffers on demand:

Run an inferior shell, with I/O through BUFFER (which defaults to `shell'). Interactively, a prefix arg means to prompt for BUFFER.

Hence, I need to mimic C-u M-x shell in mu-save-wins-then-call:

(defun mu-save-wins-then-call (func &optional args)
  "Save current window configuration, then call FUNC optionally with ARGS."
  (interactive "P")
  (push (current-window-configuration) mu--saved-window-configuration)
  (cond
   ;; We have the prefix argument
   ((= (prefix-numeric-value args) 4)
    (let ((current-prefix-arg 4))
      (call-interactively func)))
   ;; We have arguments for the function
   ((bound-and-true-p args) (funcall func args))
   ;; The function expects exactly one argument, and we want it to be nil
   ((equal args "nil") (funcall func nil))
   ;; The function does not expect arguments
   (t (funcall func))))

Now I can open as many fullframed shell buffers as I want with C-u F1:

(defun mu-shell-open (&optional new-buffer)
  "Save window configuration and call `shell'.
With NEW-BUFFER open a new buffer."
  (interactive "P")
  (mu-save-wins-then-call #'shell new-buffer))

(with-eval-after-load 'shell
  (fullframe shell mu-pop-window-configuration))

(bind-key "<f1>" mu-shell-open)

Note that mu-pop-window-configuration is detailed here.