Search code examples
emacsorg-mode

How to change the behaviour of org-agenda-goto to open org-file in a new frame?


When pressing TAB (org-agenda-goto) in org-agenda I want to open the related org-file in a new frame instead of splitting the existing frame.

I could create a modified function of org-agenda-goto replacing switch-to-buffer-other-window with switch-to-buffer-other-frame and rebinding the TAB-key but I assume there is a more elegant way to do so?

The quick solution would be as below modifying line 8:

(defun sk/org-agenda-goto (&optional highlight)
  "Go to the entry at point in the corresponding Org file."
  (interactive)
  (let* ((marker (or (org-get-at-bol 'org-marker)
             (org-agenda-error)))
     (buffer (marker-buffer marker))
     (pos (marker-position marker)))
    (switch-to-buffer-other-frame buffer)
    (widen)
    (push-mark)
    (goto-char pos)
    (when (derived-mode-p 'org-mode)
      (org-show-context 'agenda)
      (recenter (/ (window-height) 2))
      (org-back-to-heading t)
      (let ((case-fold-search nil))
    (when (re-search-forward org-complex-heading-regexp nil t)
      (goto-char (match-beginning 4)))))
    (run-hooks 'org-agenda-after-show-hook)
    (and highlight (org-highlight (point-at-bol) (point-at-eol)))))

I assume it may be done more elegantly with advice but I'm not so experienced in emacs-lisp and would not know how exactly this could be achived or if using advice would be the right approach.

I found out in override prefered method are hints for using advice-add like this in order to replace the original function with my own:

(advice-add 'org-agenda-goto :override #'sk/org-agenda-goto)

Solution

  • You can use advice to temporarily redefine switch-to-buffer-other-window using cl-letf. Assuming your on at least emacs 25.1 you can use define-advice, eg.

    (define-advice org-agenda-goto (:around (orig-fn &rest args) "new-frame")
      (cl-letf (((symbol-function 'switch-to-buffer-other-window)
                 (symbol-function 'switch-to-buffer-other-frame)))
        (apply orig-fn args)))
    

    In the advice orig-fn is a placeholder to org-agenda-goto. Alternatively, you could temporarily override display-buffer's function (there are a number of options you could use here -- see help for display-buffer), eg.

    (define-advice org-agenda-goto (:around (orig-fn &rest args) "new-frame")
      (let ((display-buffer-overriding-action '(display-buffer-pop-up-frame)))
        (apply orig-fn args)))