5

I use emacs in console mode (i.e. no mouse, one frame) with a fixed four window configuration:

+------+------+
| win  | win  |
|  1   |   3  |
+------+------+
| win  | win  |
|  2   |   4  |
+------+------+

Window 3 is my main editing window, I spend most of the time in that one. Windows 1 and 2 hold the same two buffers all the time, I rarely change into these windows because the buffers auto-update themselves and they contain read-only information. Windows 4 is my satellite window, and it's nice that most emacs commands that open a new buffer (e.g. grep, compilation commands, etc) show that new buffer always in Window 4. That makes life very easy because I bound F12 to jump directly between Window 3 and Window 4 and back.

The bad bloke is psvn.el. The svn-status buffer is always opened in Window 3, as desired.
But all other buffers (*svn-diff*, *svn-log*, ...) open randomly in Window 1, 2 or 3, and I can never predict in which one they'll open. Sometimes, the same buffer is even shown on two of those windows at the same time, and that's driving me mad!

How do I tell emacs/psvn to stop doing that? I tried all the usual measures (tweaking same-window-buffer-names, split-height-threshold, split-width-threshold, ...), but nothing's worked so far :-(

Please no solutions involving ecb.

ACz
  • 388
  • 3
  • 9
  • 1
    To take complete control over how certain buffers are displayed, you can go into the source code of the `psvn.el` and modify it (or create new functions) using the `display-buffer` family of functions. Here are links to two recent threads where I and other thread participants have given examples of how to display a particular buffer in a given window (or create a new window if it doesn't exist): http://stackoverflow.com/a/21544307/2112489   and  http://stackoverflow.com/a/21591259/2112489   There are other alternatives, but nipping the bud at the source is my preferred way to handle things. – lawlist Feb 13 '14 at 18:10
  • 1
    For example, the author of the source code at issue seems to have a personal preference for `pop-to-buffer` -- you could replace those with your own display buffer function. You may need to adjust other portions of the code, but that is the general idea. – lawlist Feb 13 '14 at 18:26

2 Answers2

6

Building on what @lawlist said, here is an example of how to override the display-buffer functionality by writing your own display-buffer function and adding an element to display-buffer-alist.

Here we have an interactive function that will mark the currently selected window as the "satellite" window:

(defun mark-this-window-as-satellite ()
  "Mark the current window as the satellite window."
  (interactive)
  (mapc (lambda (win) (set-window-parameter win 'satellite nil))
    (window-list))
  (set-window-parameter nil 'satellite t)
  (message "Window: %s is now the satellite window." (selected-window)))

This is a helper which will allow us to scan and find the satellite window:

(defun get-satellite-window ()
  "Find and return the satellite window or nil if non exists."
  (find-if (lambda (win) (window-parameter win 'satellite)) (window-list)))

We then write a function that will override display-buffer's behavior. This function will look for a satellite window and display the buffer there:

(defun display-buffer-in-satellite (buffer ignore)
  "Display the buffer in the satellite window, or the first window \
    it finds if there is no satellite."
  (let ((satellite-window (or (get-satellite-window)
                              (first (window-list)))))
    (select-window satellite-window)
    (display-buffer-same-window buffer nil)
    (display-buffer-record-window 'reuse satellite-window buffer)
    satellite-window))

Lastly, you nee to add a regexp/function pair to display-buffer-alist that will make all your SVN buffers use the new satellite function:

(push '("\\*svn-" display-buffer-in-satellite) display-buffer-alist)

You can add similar elements for other bothersome modes as well.

itsjeyd
  • 5,070
  • 2
  • 30
  • 49
Jordon Biondo
  • 3,974
  • 1
  • 27
  • 37
  • Although the `display-buffer-function` is presently available in a recent version of Emacs Trunk, it is slated to be deprecated at some point in the future by the Emacs team and replaced by the `display-buffer-alist`. With that being said, I see no reason not to use it while it remains an available option. Excerpt from `window.el`: `(make-obsolete-variable 'display-buffer-function 'display-buffer-alist "24.3")` – lawlist Feb 13 '14 at 20:18
  • 1
    IIUC you should be able to get the same result with `(push '("\\*svn-" display-buffer-in-satellite) display-buffer-alist)`. – Stefan Feb 14 '14 at 00:56
  • I wasn't aware, that seems to be a much better option, I've changed the answer. – Jordon Biondo Feb 14 '14 at 08:21
  • 1
    Another note: it looks like you are just using one frame, but in case you are not. You can map `window-list' across `frame-list' to get all windows in all frames. – Jordon Biondo Feb 17 '14 at 13:11
2

Maybe you could mark windows 1 and 2 to be dedicated. This will prevent anything to change the buffer they display (you will even need to undedicate them in the - supposedly rare - event that you want to manually switch buffers in them using C-xb).

If you have dedicated-mode installed, just run M-xdedicated-mode in the relevant windows.

If not, you can just define your own small function to mark windows as dedicated:

(defun my-dedicated-window-toggle ()
  "Toggle `window-dedicated-p' in the current window"
  (interactive)
  (set-window-dedicated-p
    (selected-window)
    (not (window-dedicated-p))))
François Févotte
  • 19,520
  • 4
  • 51
  • 74