I'm not familiar with Spacemacs, so hopefully you can apply this answer and let me know what modifications are necessary, and I can edit this answer so that it's applicable to both Spacemacs and other Emacs users.
The easiest way to achieve this in Emacs is to load the package other-frame-window (it's available using list-packages
or package-install
, which from reading docs seem to be readily available in Spacemacs).
In traditional Emacs, the C-x 4
and C-x 5
prefixes have been used to operate on windows and frames, respectively, but they're not easily extensible and they operate in a slightly unintuitive way, so other-frame-window
attempts to address this by creating two new prefixes at C-x 7
and C-x 9
, both of which have the same following map, but the C-x 7
commands operate on an (Emacs) window, and C-x 9
on frames.
While it supports some built-in commands (which you can read about in the library's docs) for deleting windows/frames, moving them about, etc., the default thing it does when presented with an interactive command is to create a new window or frame and run the command in that new context. So, doing what you want is as simple as applying the following Elisp in your init file:
(other-frame-window-mode)
(define-key ofw-transient-map (kbd "z") #'magit-status)
Here, we first enable the OFW minor mode. (Since other-frame-window
operates as a minor mode, you'll need to enable it — to start, simply executing other-frame-window-mode
in the buffer you want to use will let you try it. You can run the command again to disable it.)
Then, we add z
to the keyboard map to invoke magit-status
. Once you do this, C-x 9 z
will open Magit in another frame.
(C-x 7 z
, will, obviously, open Magit in a new window, but that's relatively useless since that's the default behavior. This default behavior, by the way, is controlled by magit-display-buffer-function
as was mentioned in Michael's comment to your question, but all the standard choices work on windows, not frames, and rigging up your own with this variable as suggested is rather difficult, and exactly the plumbing that other-frame-window
takes care of for you.)
You could, of course, define a macro to do this directly without needing three keystrokes, or if you dip into the source code in other-frame-window.el
, you can roll your own interactive function to do it directly.
Note that Magit will not dismiss upon pressing q
in the case when it's the only buffer in the frame. That's because it's well-behaved and does a bury-buffer rather than kill-buffer, so that if the current frame happens to be the only frame, you won't accidentally kill Emacs. You could override this, but I'd advise against it. You can just kill the frame as usual, or use a prefix argument to q
(in regular Emacs, that's C-u q
) to force it to kill the buffer, frame and all.
One final remark: note that, in general, it's not a great idea to hand-write functions that unilaterally open new frames because there are many reasons why Emacs may be unable to do so — most notably, because you're operating in a non-GUI environment like a terminal emulator, SSH or Mosh session. Correctly-written frame-handling commands deal with this appropriately, so deferring this logic to other-frame-window
seems like a good way to get the functionality you want without reinventing the wheel.
display-buffer-alist
and a custom function like in the linked example. stackoverflow.com/questions/18346785/…magit-display-buffer-function
might be the way to go? magit.vc/manual/magit/Switching-Buffers.html#Switching-Buffers