9

I have two windows open and split vertically (single frame):

A) contains my work
B) contains either dired or ibuffer.

I would like to be able to navigate to a file/buffer in pane B and hit "o" have it open in pane A. Is this possible? Right now emacs is creating a new pane in the lower portion of pane A to open the file.

edit: according to user lawlist the above described behavior will happen when the frame is large. This appears to be the case for me because now that I am at home (not on an external monitor, smaller frame) emacs is behaving as I desire. The question now becomes: can I prevent emacs from opening a new window when the current frame is large?

2
  • 1
    Welcome to the Emacs beta forum. As part of the Emacs lingo/jargon, we use the word window to refer to a buffer quadrant within the same frame. A frame is considered to be the whole kitten-kaboodle, which can have many windows within it. Emacs can generate multiple frames, with each frame containing multiple windows.
    – lawlist
    Aug 27, 2015 at 22:28
  • thanks for the clarification! I've been a long time emacs user but have never fully understood the terminology.
    – Robert
    Aug 27, 2015 at 22:50

3 Answers 3

8

Here are four (4) sample custom display-buffer family of functions that can be custom tailored to suit a user's particular needs -- above; below; left; right -- and here are four (4) interactive functions to display the file or directory of the current line of a dired-mode buffer. There are only three conditions: (a) if there is already a window displaying the target buffer, then choose it; (b) if there is a window in the direction desired that is available, then use it; (c) the catch-all is to create a new window in the desired direction if the other conditions are not met.

Usage:

M-x dired-display-above

M-x dired-display-below

M-x dired-display-left

M-x dired-display-right

There so many key-bindings already built-in to dired-mode and dired+, that I dare not attempt to make up my own. The user is free choose his/her own keyboard shortcuts, which is beyond the scope of this limited example.

The user is free to add additional conditions to the sample display-buffer family of functions to handle more situations -- e.g., more windows than just a couple.

(defun my-display-buffer-below (buffer alist)
"Doc-string."
  (let (
      (window
        (cond
          ((get-buffer-window buffer (selected-frame)))
          ((window-in-direction 'below))
          (t
            (split-window (selected-window) nil 'below)))))
    (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated)
    window))

(defun my-display-buffer-above (buffer alist)
"Doc-string."
  (let (
      (window
        (cond
          ((get-buffer-window buffer (selected-frame)))
          ((window-in-direction 'above))
          (t
            (split-window (selected-window) nil 'above)))))
    (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated)
    window))

(defun my-display-buffer-left (buffer alist)
"Doc-string."
  (let (
      (window
        (cond
          ((get-buffer-window buffer (selected-frame)))
          ((window-in-direction 'left))
          (t
            (split-window (selected-window) nil 'left)))))
    (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated)
    window))

(defun my-display-buffer-right (buffer alist)
"Doc-string."
  (let (
      (window
        (cond
          ((get-buffer-window buffer (selected-frame)))
          ((window-in-direction 'right))
          (t
            (split-window (selected-window) nil 'right)))))
    (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated)
    window))

(defun dired-display-above ()
"Doc-string."
(interactive)
  (let* (
      (file-or-dir (dired-get-file-for-visit))
      (buffer (find-file-noselect file-or-dir)))
    (my-display-buffer-above buffer nil)))

(defun dired-display-below ()
"Doc-string."
(interactive)
  (let* (
      (file-or-dir (dired-get-file-for-visit))
      (buffer (find-file-noselect file-or-dir)))
    (my-display-buffer-below buffer nil)))

(defun dired-display-left ()
"Doc-string."
(interactive)
  (let* (
      (file-or-dir (dired-get-file-for-visit))
      (buffer (find-file-noselect file-or-dir)))
    (my-display-buffer-left buffer nil)))

(defun dired-display-right ()
"Doc-string."
(interactive)
  (let* (
      (file-or-dir (dired-get-file-for-visit))
      (buffer (find-file-noselect file-or-dir)))
    (my-display-buffer-right buffer nil)))

EDIT:  Here is a slightly more sophisticated / fun implementation of the above-concept, which gives the user the ability to use this non-interactively or interactively; e.g., M-x dired-display-buffer -- where the user will be prompted to choose a directory if not hovering over a file in dired-mode, and to choose a display direction (left, right, above, below).

(defun my-display-buffer (buffer-or-name alist direction &optional size pixelwise)
"BUFFER:  The buffer that will be displayed.
ALIST:  See the doc-string of `display-buffer' for more information.
DIRECTION:  Must use one of these symbols:  'left 'right 'below 'above
SIZE:  See the doc-string for `split-window'.
PIXELWISE:  See the doc-string for `split-window'.
There are three possibilities:
-  (1) If a window on the frame already displays the target buffer,
then just reuse the same window.
-  (2) If there is already a window in the specified direction in relation
to the selected window, then display the target buffer in said window.
-  (3) If there is no window in the specified direction, then create one
in that direction and display the target buffer in said window."
  (let* ((buffer
           (if (bufferp buffer-or-name)
             buffer-or-name
             (get-buffer buffer-or-name)))
         (window
           (cond
             ((get-buffer-window buffer (selected-frame)))
             ((window-in-direction direction))
             (t
               (split-window (selected-window) size direction pixelwise)))))
    (window--display-buffer buffer window 'window alist display-buffer-mark-dedicated)
    window))

(defun dired-display-buffer (&optional direction alist)
"Display a dired-mode buffer or a file underneath point in a dired-mode buffer."
(interactive)
  (let* ((file-or-dir (or (and (eq major-mode 'dired-mode) (dired-get-file-for-visit))
                               (read-directory-name "Directory:  ")))
         (buffer (find-file-noselect file-or-dir))
         (direction
           (if direction
             direction
             (let ((char (read-char-exclusive (concat
                      "["
                      (propertize "l" 'face '(:foreground "red"))
                      "]"
                      (propertize "eft" 'face '(:foreground "blue"))
                      " | ["
                      (propertize "r" 'face '(:foreground "red"))
                      "]"
                      (propertize "ight" 'face '(:foreground "blue"))
                      " | ["
                      (propertize "a" 'face '(:foreground "red"))
                      "]"
                      (propertize "bove" 'face '(:foreground "blue"))
                      " | ["
                      (propertize "b" 'face '(:foreground "red"))
                      "]"
                      (propertize "elow" 'face '(:foreground "blue"))))))
                (cond
                  ((eq char ?l)
                    'left)
                  ((eq char ?r)
                    'right)
                  ((eq char ?a)
                    'above)
                  ((eq char ?b)
                    'below)
                  ;;; FIXME:  @lawlist may add a loop similar to `org-capture'
                  ;;; whereby a new `read-char-exclusive' will be initiated if
                  ;;; a user did not initially choose a valid option (l/r/a/b).
                  (t
                    (let ((debug-on-quit nil)
                          (msg (concat "dired-display-buffer:  "
                                       "You did not select l/r/a/b "
                                       "-- exiting.")))
                      (signal 'quit `(,msg)))))))))
    (my-display-buffer buffer alist direction)))
4
  • oh this is perfect. Can someone help me with simple hydra for dired-mode-map, bound to o and then hjkl for display-above/below/left/right?
    – iLemming
    Nov 7, 2016 at 7:15
  • oh I think I got it: (defhydra dired-open (dired-mode-map "O" :exit t) "dired-open" ("j" dired-display-below "below") ("k" dired-display-above "above") ("h" dired-display-left "left") ("l" dired-display-right "left"))
    – iLemming
    Nov 7, 2016 at 7:22
  • Small thing about the approach - it doesn't jump to the newly created window. Can't figure out how to force it.
    – iLemming
    Nov 7, 2016 at 7:55
  • 2
    @Agzam -- The function select-window can be used at the tail end of each my-display-buffer-... function. As you can see, the result/value that is thrown at the end on the very last line is window. If you don't need the result/value to use in conjunction with another function, then just wrap the window on the very last line with this: (select-window window). Do that with all four (4) functions -- i.e., my-display-buffer-below; my-display-buffer-above; my-display-buffer-left; and my-display-buffer-right.
    – lawlist
    Nov 7, 2016 at 15:33
3

Your question is unclear, and so risks being closed. Do you have two frames or a single frame with two Emacs windows? Whatever they are, if there are two, is each of them split vertically? And just what do you mean by "split vertically"? What do you mean by a "pane"? What do you mean by "it", in "have it open in pane A"?

A wild guess is that you have a single Emacs frame that is split into two Emacs windows, A and B, with window A above window B, window B is selected, and window B is showing a Dired buffer.

o is bound by default to dired-find-file-other-window. If the above wild guess is correct then o on a file name in B should open in A. This is what I see when starting Emacs without an init file: emacs -Q. Do you not see that?

If this is not the scenario, please describe clearly what you are doing, step by step, starting with emacs -Q.

4
  • 2
    It depends on the size of the frame -- a large frame will result in the behavior described by the O.P.; whereas, a smaller frame will result in the behavior Drew described.
    – lawlist
    Aug 27, 2015 at 22:43
  • lawlist I think that is exactly what is happening. When attached to my external monitor with a large frame what I described happens, but now that I am home on my smaller laptop display it asks as I desire - is there a way to force it not to open another window?
    – Robert
    Aug 27, 2015 at 22:55
  • Hi Drew sorry I'm not fully up to speed on the emacs lingo in regards to the differences between a frame & window. What I meant in my original question (if I now understand windows and frames correctly) is that I have a single emacs frame and two emacs windows side by side (vertically C-x 3). Everything works as intended when I'm on my laptop and the frame is small, but as lawlist pointed out when the frame is large what I describe happens.
    – Robert
    Aug 27, 2015 at 23:06
  • Yes, it is possible. However, a general setting of the display-buffer family of variables will affect other situations not yet foreseen. You could customize the display-buffer-alist, which is somewhat confusing even for experienced Emacs users. There are variables that control when to split windows and minimum sizes of windows, and the list goes on and on. To contain the outbreak, you could advise dired-find-file-other-window with a let-bound version of the display-buffer-alist, but I'll leave that answer to another forum participant. There are a variety of solutions. :)
    – lawlist
    Aug 27, 2015 at 23:07
2

NOTE:  The following variables are global, which means that they will affect other functions besides dired-find-file-other-window. The user may wish to advice the function at issue so as not to globally affect other functions. [However, this author will leave that option to another forum participant.] Alternatively, there is another answer that this author posted containing custom functions that can be used so as not to affect anything else.


The variable split-width-threshold has a doc-string which states:

Minimum width for splitting windows sensibly.
If this is an integer, ‘split-window-sensibly’ may split a window
horizontally only if it has at least this many columns.  If this
is nil, ‘split-window-sensibly’ is not allowed to split a window
horizontally.

Setting the following in the .emacs file will achieve the desired effect. The user can also set the value to a higher number. The default value is 160

(setq split-width-threshold nil)

Here is a link to the relevant section in the manual:

https://www.gnu.org/software/emacs/manual/html_node/emacs/Window-Choice.html


See also the related variable split-height-threshold, which has a default value of 80

The doc-string states:

Minimum height for splitting windows sensibly.
If this is an integer, `split-window-sensibly' may split a window
vertically only if it has at least this many lines.  If this is
nil, `split-window-sensibly' is not allowed to split a window
vertically.  If, however, a window is the only window on its
frame, `split-window-sensibly' may split it vertically
disregarding the value of this variable.
1
  • This actually worked quite well! Now if anything funny starts happening I at least know where to look. Thanks again!
    – Robert
    Aug 28, 2015 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.