7

(This is a followup and different from Emacs Fixed Layout )

High Level

My typical Emacs Working environment is:

+------------+--------------------------+--------------------------+
| NeoTree    |  Main                    |  Rhs                     |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
|            |                          |                          |
+------------+--------------------------+--------------------------+

where Main = some *.clj *.cljs file I'm editing, and RHS = cide-repl or cljs repl or eshell

Problem

Sometimes, some emacs functions screw up this layout. Examples: looking up documentation, running cider-debug, showing exceptions, etc ...

What I want:

I would a way to bind some keys, say C-x 1, C-x 2, C-x 3 (yes, I know this is terrible choice, but not focus of question) wherE:

C-x 1 = hide all existing windows, fire up 3-pane setup, with Neotree + last edited clj/cljs file, and RHS = cider-repl C-x 2 = same as C-x 1, but cljs-repl in RHS C-x 3 = same as C-x 1, but eshell in RHS

Question:

The main feature I need in this is a function to say:

  1. hide all existing windows

  2. create this three pane setup

    How do I do that?

Thanks!

Edit: How is this different from original question:

Original question: how can I force emacs to use this 3 pane setup.

This question: emacs is going to screw up my 3 pane setup. How do I have a three-key recovery shortcut?

eav db
  • 201
  • 1
  • 3
  • The example-fn in the following link demonstrates how to programmatically create a 3-way window setup -- you can adjust it as needed (e.g., split left, right, up, or down): http://emacs.stackexchange.com/a/26970/2287 The function to hide all existing windows, except the selected window, is delete-other-windows. I don't use cider/repl etc., so I cannot help you there. Keyboard shortcuts are a different question, and there are plenty of examples available by Googling. And as stated in your previous thread, set-window-dedicated-p is your friend. – lawlist Nov 17 '16 at 17:42
  • It may behoove you to look into Saving Window Configurations in Registers: https://www.gnu.org/software/emacs/manual/html_node/emacs/Configuration-Registers.html There are many libraries dedicated to this concept. A popular library that saves window layouts is elscreen, which provides for a tabbed visual aid to switch between them. – lawlist Nov 17 '16 at 17:45
  • @lawlist: Just wanted to say thanks for all 3 of your detailed responses! (on both questions) – eav db Nov 17 '16 at 20:59
  • winner-mode might be of interest too - https://www.gnu.org/software/emacs/manual/html_node/emacs/Window-Convenience.html – npostavs Nov 18 '16 at 15:54

1 Answers1

4

One possible solution entails creating a few core functions that generate or locate the desired buffers (e.g., *NeoTree*, *eshell*, *cider-repl*), but not display them -- i.e., they are all setup and ready to go, but remain in the background waiting to be used. In this example, I have created two new functions called eshell-get-buffer-create and neotree-get-buffer-create. The latter may need some more work (please let me know), but the former is pretty straight forward and should not need any modifications. I am unfamiliar with cider-repl, so am only using a *scratch* buffer for the center "Main" window. The original poster may wish to create a special function that generates or locates the cider-repl buffer without displaying it, and then replace (get-buffer-create "*scratch*") with the said new function (which should return the buffer at the tail end of the function). I am not using any window registers in this example -- instead, I merely delete all other windows and set-up a new 3-way view each time example-fn is called. A keyboard shortcut of f5 is used in this example, but the original poster is free to change it to something else.

(require 'cl)
(require 'eshell)

(defun eshell-get-buffer-create (&optional arg)
"Create an interactive Eshell buffer.  Return the Eshell buffer,
creating it if needed.  The buffer used for Eshell sessions is
determined by the value of `eshell-buffer-name'.  A numeric prefix
arg (as in `C-u 42 M-x eshell RET') switches to the session with
that number, creating it if necessary.  A nonnumeric prefix arg
means to createa new session.  Returns the buffer selected (or created)."
  (interactive "P")
  (cl-assert eshell-buffer-name)
  (let ((buf (cond ((numberp arg)
        (get-buffer-create (format "%s<%d>"
                 eshell-buffer-name
                 arg)))
       (arg
        (generate-new-buffer eshell-buffer-name))
       (t
        (get-buffer-create eshell-buffer-name)))))
    (cl-assert (and buf (buffer-live-p buf)))
    (with-current-buffer buf
      (unless (derived-mode-p 'eshell-mode)
        (eshell-mode)))
    buf))

(require 'neotree)

(defun neotree-get-buffer-create (&optional dir)
"Return the neotree buffer -- creating it if needed.
The root directory may be set/reset using the optional
argument of DIR; else if buffer exists already use it
as-is; else use `neo-path--get-working-dir'."
  (let ((valid-start-node-p nil)
        (buffer (neo-global--get-buffer t)))
    (neo-global--with-buffer
      (setf valid-start-node-p (neo-buffer--valid-start-node-p))
      (when (or dir (not valid-start-node-p))
        (let ((path (or dir (neo-path--get-working-dir)))
              start-path)
          (unless (and (file-exists-p path)
                       (file-directory-p path))
            (throw 'error "The path is not a valid directory."))
          (setq start-path (expand-file-name (substitute-in-file-name path)))
          (setq neo-buffer--start-node start-path)
          (cd start-path)
          (neo-buffer--save-cursor-pos path nil)
          (let ((start-node neo-buffer--start-node))
            (unless start-node
              (setq start-node default-directory))
            (neo-buffer--with-editing-buffer
             ;; starting refresh
             (erase-buffer)
             (neo-buffer--node-list-clear)
             (neo-buffer--insert-banner)
             (setq neo-buffer--start-line neo-header-height)
             (neo-buffer--insert-tree start-node 1)
             (goto-char (point-min)))))))
    buffer))

(defun example-fn ()
"To try this example, type:  M-x example-fn"
(interactive)
  (let ((a (neotree-get-buffer-create))
        (b (get-buffer-create "*scratch*"))
        (c (eshell-get-buffer-create)))
    (delete-other-windows)
    (switch-to-buffer b) ;; Main -- center window.
    ;; See the doc-strings for `split-window' and `window--display-buffer'.
    (window--display-buffer a (split-window (selected-window) nil 'left)
      'window `((window-width . ,neo-window-width)) display-buffer-mark-dedicated)
    (window--display-buffer c (split-window (selected-window) nil 'right)
      'window nil display-buffer-mark-dedicated)))

(global-set-key [f5] 'example-fn)
lawlist
  • 19,106
  • 5
  • 38
  • 120
  • 1
    Thanks for all your hardwork! Though new to elisp, I'm familiar with both Clojure and SICP -- so I'll make this work. Thanks for providing (1) the basic skeleton, (2) the functions I need to use, with examples of how they're called, and (3) the overall structure! – eav db Nov 18 '16 at 05:09
  • 1
    You are very welcome. I enjoyed creating the noselect buffer generating/locating functions for neotree and eshell, and have added them to my own arsenal for future use. I personally keep display-buffer-mark-dedicated at the default value of nil, but you may wish to look up the doc-string for that variable and see if you want to set either one of those to t within the example-fn. I don't use neotree daily, but like to play around with tree-view libraries occasionally -- so that is why I said in the answer above that it may need some revisions (i.e., I'm not very familiar with it). – lawlist Nov 18 '16 at 05:15