2

When I use tuareg I like to have the toplevel in a separate frame, but as soon as I evaluate some code in the original frame the toplevel window reopen in that frame and that's not what I wan't.

More generally, I'd like to always popup new windows into frames as I'm using emacs daemon and a tiling window manager, I would like to replace all the window part of emacs by the frame.

There's a function to pop a window into a frame but I'd like to change the default behaviour.

"Pop" a window into a frame

How tuareg works :

I can open ocaml interpreter with C-c C-s, if the interpreter isn't running it runs it in a new buffer called *ocaml toplevel* in a new window splitted horizontally. If it's already opened but the window at the bottom isn't, it open the window with the already opened *ocaml toplevel* in it. It is binded to the function :

(defun tuareg-run-ocaml ()
  "Run an OCaml toplevel process.  I/O via buffer `*ocaml-toplevel*'."
  (interactive)
  (tuareg-run-process-if-needed)
  (display-buffer tuareg-interactive-buffer-name))

I guess that it's display-buffer whih I wan't to hack...

There's also evaluate region and evaluate buffer that evaluate some code in the tuareg buffer by the opened interpreter, and if it's not opened it opens it in a new window at the bottom like previously. In fact, it is quite similar to elisp evaluation but the result is in the *\ocaml toplevel* buffer and the window is always reopened when needed to show the result.

I don't show these functions because they call other tuareg functions so there would be a lot of functions in the post and I don't want to bother you with all that code. Jus tell me if you want more.

Thanks

12
  • I use a custom solution -- see this related thread entitled How to intercept a file before it opens and decide which frame: stackoverflow.com/questions/18346785/… Most people, however, look for something more simple with a little regexp and customizing the display-buffer-alist -- that will not cover all the situations, but it will as to many.
    – lawlist
    Dec 21, 2015 at 17:51
  • There are quite a few examples already out there -- Google a bit for: "display-buffer-alist" emacs -- if you still need some help, provide an example of a specific set of circumstances with the buffer you are trying to display in the target frame -- e.g., major-mode, function being called (e.g., a compile command or something), exact buffer name, whether you need a specific frame, or just any old frame, a new frame, or an existing frame, etc.
    – lawlist
    Dec 21, 2015 at 18:49
  • I'll give it a try but I think emacs daemon does part of the job of that function... I think what I need in first time is to replace split-window-preferred-function which I guess is what is called to popup things like tuareg toplevel or other sort of menus... I have tried to replace it with the same value as pop-up-frame-function i.e. (lambda nil (make-frame pop-up-frame-alist)) but that one doesn't work as I expected, it open the buffer in the current frame. Dec 21, 2015 at 18:51
  • For example, I have tuareg top level in a frame and source code in another frame, when I ask tuareg to evaluate some source code in the source frame it split the window to show tuareg toplevel. I don't wan't him to split the window for the toplevel since there is a frame currently showing it. And if I run the toplevel for the first time, it would be cool to open it in another buffer. Dec 21, 2015 at 18:55
  • To properly assist you, we need to see the source-code of the function responsible for "it split the window to show tuareg toplevel". If you can track down that function, then the solution can be specifically tailored to suit your needs. I don't use that library and haven't the slightest idea where to even start the search. Start with the name of the function that you call which begins the process and work your way forwards. The most common approach is to use M-x describe-key & M-x find-find-function. There may of course be a reader of this thread intimately familiar with tuareg.
    – lawlist
    Dec 21, 2015 at 21:39

1 Answer 1

1

The following example relies upon two functions from the frame-fns.el library written by Drew Adams -- http://www.emacswiki.org/emacs/frame-fns.el -- which has been consolidated into just one function for the purposes of this example. The original poster has indicated that the function tuareg-run-ocaml is the most likely suspect that causes behavior described by the original poster as: "it split the window to show tuareg toplevel". This example modifies tuareg-run-ocaml by adding an optional second argument of display-buffer for ACTION -- e.g., what do we want to do with the buffer. We use Drew Adams' function to test for whether there is an existing frame named TUAREG: If there is, then we use that. If there is not, then we create a new frame with that name. If the buffer is already being displayed in that frame, then use the same window -- if not, then the buffer is displayed in the largest visible window in said frame.

;; Original Author:  Drew Adams -- http://www.emacswiki.org/emacs/frame-fns.el
;; @lawlist combined the functions `get-frame-name` and `get-a-frame`.
(defun db-get-frame--drew-adams (frame)
  "Return a frame, if any, named FRAME (a frame or a string).
  If none, return nil. If FRAME is a frame, it is returned."
  (let ((get-frame-name--drew-adams
          (lambda (&optional frame)
            (unless frame (setq frame (selected-frame)))
            (if (framep frame)
                (cdr (assq 'name (frame-parameters frame)))
              (error "Argument not a frame: `%s'" frame)))))
    (cond ((framep frame) frame)
          ((stringp frame)
           (catch 'get-a-frame-found
             (dolist (fr (frame-list))
               (when (string= frame (funcall get-frame-name--drew-adams fr))
                 (throw 'get-a-frame-found fr)))
             nil))
          (t
           (error "Arg neither a string nor a frame: `%s'" frame)))))

(defun db-display-buffer-fn (buffer _alist)
  (let (frame)
    (if (db-get-frame--drew-adams "TUAREG")
      (setq frame (db-get-frame--drew-adams "TUAREG"))
      (setq frame (make-frame (list '(name . "TUAREG")))))
    (select-frame frame)
    (raise-frame frame)
    (unless (get-buffer-window buffer)
      (set-window-buffer (get-largest-window) buffer))
    (select-window (get-buffer-window buffer))))

;; In order to redefine `tuareg-run-ocaml', need to make sure the library is loaded.
(require 'tuareg)

(defun tuareg-run-ocaml ()
  "Run an OCaml toplevel process.  I/O via buffer `*ocaml-toplevel*'."
  (interactive)
  (tuareg-run-process-if-needed)
  (display-buffer tuareg-interactive-buffer-name '(db-display-buffer-fn)))
6
  • It workes like a charm ! I just had to add '(db-display-buffer-fn) to switch-buffer for function tureg-eval-region and now it works EXACTLY how I want ! Your explanations have been really full of teaching and I am sincerely grateful to you, THANK'S A LOT. I have just a last question: this has been very specific to tuareg but there are also other modes that have a dedicated window, like a compile window or interpreter, can I generalize the process or should I do a hack for each one ? Dec 23, 2015 at 8:26
  • There will undoubtedly be a few or more exceptions to the general rule where where setting the display-buffer-alist will not suffice. I recently found an unrelated situation where a popular built-in minor-mode was merely splitting a window and selecting the new window instead of using display-buffer. So, if you want it to be perfect, use a scalpel instead of a machete. If you want to cover the majority of situations, then setting the display-buffer-alist will suffice for most. I like the scalpel approach, which is custom tailored -- but most people want an easier approach . . . .
    – lawlist
    Dec 23, 2015 at 9:09
  • Its bedtime again (1:14 a.m.) -- I'll check back again tomorrow if you need additional follow-up. If it is resolved, then a check-mark would be appreciated. Either way, I'm pleased to help if you need further assistance.
    – lawlist
    Dec 23, 2015 at 9:15
  • I'll try to do it with all the informations I have now, thank you ! Dec 23, 2015 at 18:57
  • The example in the link to the first comment of the original question uses the display-buffer-alist and tests for certain buffer names to determine what frame should be used. It is possible to use other/additional criteria, such as a major-mode -- e.g., (eq major-mode 'text-mode) -- however, some libraries display the buffer before a major-mode has been set (so the test would fail to the extent it relies on the major mode existing). I usually fix the source code so that the major-mode is set before the buffer is displayed, instead of after the fact.
    – lawlist
    Dec 23, 2015 at 19:12

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.