How can I make Org-Roam work in a single-window-mode? (Only one window + the backlinks buffer)

I would like to use Org-Roam with only a single-window. Technically two windows if you count the Backlinks Buffer.

Traditionally, when I open a node via the Backlinks Buffer, it will open as a new window below the existing one. So I would have three windows: one with the buffer where I was previously, the one with the new node, and the Backlinks Buffer. I would prefer, instead, if the new link occupied the whole left part of the frame, remove the previous Buffer from view.

I have tried fixing that using advices and functions of my own (I’m not a programmer in the slightest) but nothing seemed to work universally and flawlessly with all the links/nodes/things that open stuff from the Backlinks Buffer.

Is there any official or recommended way to do that?

Thanks!

You say you use Doom in another thread. Doom has its own window management (called popup, or something rather). You’d need to look into how you can tame windows with it from Doom resources or community. I spent countless hours a few years back only to learn this lesson without succeeding to help the other person (on this forum).

By default, org-roam should use pop-to-buffer-same-window…

See lines 437-439 here.

See how your system is configured to respond to this function.

I’ll be brief here and try to come back with more to explain this, but here is what I consider to be one of minimum configuration approaches to achieve “Org-Roam with only a single-window”. No need for advice or custom functions; only with user options made available by Emacs and Org. (Org-roam just leverages these). As I don’t fully understand how Doom does things, your miles will vary for sure…


(add-to-list 'display-buffer-alist
             '("\\*org-roam\\*"
               (display-buffer-in-side-window)
               (window-width . 0.25)
               (side . left) ; << replace left with right as you prefer; top
                             ; and bototom are also acceptable here
               (slot . 0)))

(setopt display-buffer-base-action
        '((display-buffer-use-some-window)))

(setf (alist-get 'file org-link-frame-setup)
                     #'find-file)

Hey @nobiot I was wondering if it was possible to open it in a new frame? I like how org-remark can open the notes buffer in a new frame.
Is it possible to achieve it? It is probably off topic here, but is there any general way? Or can the above settings be modified to achieve it?

Much thanks.

Sure, it should be possible. I won’t test it now myself, but the theory tells me the following ways:

To open org-roam-buffer, this should work.

(add-to-list 'display-buffer-alist
             '("\\*org-roam\\*"
               (display-buffer-pop-up-frame`)) ;<< there are other functions to open a new frame; try them

I can’t be certain how you can open a link target back in the “main” frame from within org-roam-buffer – I only use one frame. The default org-roam-preview-visit uses pop-to-buffer-same-window as shown in the code excerpt below. I don’t know if it woks across frames (it may well do). If not, you may need to override the preview-visit function with using display-buffer-use-some-frame or display-buffer-other-frame.

        (display-buffer-fn (if other-window
                               #'switch-to-buffer-other-window
                             #'pop-to-buffer-same-window)))
1 Like

Thanks, I had some more time to look into this, I was earlier trying to use display-buffer-overriding-action but it turned out to make the situation more complex than I like, I opted for overriding the functions altogether in the end.

This opens the org-roam-buffer in another frame, i think its workable too - but I lose the ability of org-roam-buffer following the currently opened node.

(defun org-roam-buffer--redisplay-h ()
  "Reconstruct the persistent `org-roam-buffer'.
This needs to be quick or infrequent, because this designed to
run at `post-command-hook'."
  (and (get-buffer-window org-roam-buffer 'all-frames)
       (org-roam-buffer-persistent-redisplay)))

However, if we add the 'all-frames argument to get-buffer-window here; it will follow the currently “selected” window, although this is very finicky since even the mouse cursor moving over the frame will cause the org-roam-buffer to change as its part of a post-command-hook.

Ultimately, i settled on changing the display-buffer-fn

(display-buffer-fn (if other-window
                               #'switch-to-buffer-other-window
                             #'org-roam-get-or-create-frame)))

in both org-roam-preview-visit and org-roam-grep-visit with the following function

(defvar org-roam-frame nil
  "Dedicated frame for visiting links from Org-roam buffers.")

(defun org-roam-get-or-create-frame (buffer)
  "Get the existing Org-roam frame or create a new one, and open BUFFER in it."
  (if (frame-live-p org-roam-frame)
      ;; If the frame exists, just select it
      (progn
	(select-frame-set-input-focus org-roam-frame)
	(pop-to-buffer buffer))
    (setq org-roam-frame
          (make-frame '((name . "*Org-roam-visit*"))))
    (select-frame-set-input-focus org-roam-frame)
    (switch-to-buffer buffer)))

This creates a new frame, and uses that to visit links from the org-roam-buffer as opposed to having the org-roam-buffer itself in another frame.

1 Like