7

We all use multi-windows in Emacs, and for some projects, I developed a habit of using four windows, one each for a different buffer.

I wonder if I can define a function and when I start to work in a project, it will take the project name as input and set up the working environment like this (using an R project as an example):

  • Window 1 will always shows the main.R file in the project folder;
  • Window 2 will always shows the *R-main* process buffer;
  • Window 3 will shows the project_log.org file in the project folder;
  • Window 4 is a reference window, shows the dired buffer in the project folder.

Each window has equal size.

Greenonline
  • 161
  • 1
  • 3
  • 11
yi.tang.uni
  • 1,017
  • 8
  • 20
  • I'm an elisp beginner myself, but I'm sure this could be done relatively easily. Here's a relevant tutorial: http://ergoemacs.org/emacs/emacs_winner_mode.html. And this page lists some other functions that might be useful: http://www.chemie.fu-berlin.de/chemnet/use/info/elisp/elisp_26.html – Brian Z Mar 13 '15 at 12:42
  • See suggestions in http://www.reddit.com/r/emacs/comments/1m73gs/how_do_you_manage_multiple_workspaces/ – Swaroop C H Mar 13 '15 at 14:41
  • Good suggestions so far. You can use this package to set windows to "always" show specific buffers: emacs-purpose – nanny Mar 13 '15 at 14:44
  • @yi.tang.uni I'm not familiar with R, but I think I can write a function that uses emacs-purpose to do what you want. Only, I'm not sure what you mean by "always". If you open another R file (e.g. "lib.R"), where should it open? – bmag Mar 17 '15 at 16:33
  • @bmag I tried to use emacs-purpose but it seems really complex to me, I read the wiki pages but still don't have a clue. I don't think it is a good idea to lock the windows, but would like to give it go, so please lock the window 2 to R-main all the time if you can do. – yi.tang.uni Mar 18 '15 at 18:00

3 Answers3

3

In addition to the other answers, consider bookmarks. If you use library Bookmark+ then you can bookmark any of these thingies to return to a particular configuration you like:

  • a desktop
  • a window configuration
  • a frame configuration

"Jumping" to such a bookmark restores the setup that was recorded. This means that you can easily and quickly switch among different desktops etc. You can of course jump to a bookmark programmatically (e.g. from your init file), as well as interactively.

The most general of these is a desktop bookmark. Starting with Emacs 24, it includes restoring frames, windows, and buffers as they were snapshot (as much as possible).

Drew
  • 77,472
  • 10
  • 114
  • 243
1

An easy way to do this is by storing a window configuration as a directory local variable.

First, arrange the window the way you like them, open files etc.

Add the window configuration as directory local variable:

(add-dir-local-variable nil 'my-window-conf (window-state-get nil t))

Restore the window configuration with

(defun my-window-conf-restore ()
  "Restore project window configuration."
  (interactive)
  (when (boundp 'my-window-conf)
    (delete-other-windows)
    (window-state-put my-window-conf)))
olaf b
  • 566
  • 2
  • 7
1

Using Purpose, you can try the following. Note that I don't really know R, so you need to fill in the code for creating the *R-main* buffer.

Also, if you open more than 2 files with the same name, then Emacs will start playing with their buffer names. To fix this, use a proper regexp in bmag-R-purpose-conf (exact regexp depends the value of uniquify-buffer-name-style).

;; define purposes suitable for R projects
(defvar bmag-R-purpose-conf (purpose-conf
                 "R-project"
                 ;; R files are considered "code" buffers
                 :regexp-purposes '(("\\.R$" . code))
                 ;; the *R-main* buffer is considered a "repl"
                 ;; buffer.
                 ;; the project_log.org buffer is considered a
                 ;; "log" buffer
                 :name-purposes '(("*R-main*" . repl)
                          ("project_log.org" . log))))

;; mysterious incantation - generated with `purpose-save-window-layout'
(defvar bmag-R-layout
  '(t
    (0 0 92 36)
    (nil
     (0 0 92 18)
     ;; top-left window is dedicated to "code" buffers (R files)
     (:purpose code :purpose-dedicated t :width 0.5 :height 0.5 :edges
           (0.0 0.0 0.5 0.5))
     ;; top-right window is dedicated to "repl" buffers (*R-main*)
     (:purpose repl :purpose-dedicated t :width 0.5 :height 0.5 :edges
           (0.5 0.0 1.0 0.5)))
    (nil
     (0 18 92 36)
     ;; bottom-left window is not dedicated, but will initialy show a "log"
     ;; buffer (project_log.org)
     (:purpose log :purpose-dedicated nil :width 0.5 :height 0.5 :edges
           (0.0 0.5 0.5 1.0))
     ;; bottom-right window is not dedicated, but will initialy show a dired
     ;; buffer
     (:purpose dired :purpose-dedicated nil :width 0.5 :height 0.5 :edges
           (0.5 0.5 1.0 1.0)))))

(defun bmag-project-root ()
  "Get project's root directory."
  (expand-file-name (read-directory-name "Project root directory: " nil nil t)))

(defun bmag-file-in-project (root name)
  (file-truename (concat root name)))

(defun bmag-open-R-project ()
  (interactive)
  (let ((root (bmag-project-root)))
    (purpose-mode)
    ;; activate Purpose configuration for current project
    (purpose-set-extension-configuration :project bmag-R-purpose-conf)
    ;; make current frame display windows as specified in `bmag-R-layout'
    (purpose-set-window-layout bmag-R-layout)
    ;; open relevant buffers. Purpose takes care of displaying them in the correct windows
    (dired root)
    (find-file (bmag-file-in-project root "/project_log.org"))
    (find-file (bmag-file-in-project root "/main.R"))
    ;; --- insert code for creating *R-main* here ---
    ))

You can adapt this solution to other languages. For example, Python:

(defvar bmag-python-purpose-conf
  (purpose-conf "python-project"
        :mode-purposes '((python-mode . code)
                 (inferior-python-mode . repl))
        :name-purposes '(("project_log.org" . log))))

;; note: `bmag-python-layout' is identical to `bmag-R-layout'
(defvar bmag-python-layout
  '(t
    (0 0 92 36)
    (nil
     (0 0 92 18)
     (:purpose code :purpose-dedicated t :width 0.5 :height 0.5 :edges
           (0.0 0.0 0.5 0.5))
     (:purpose repl :purpose-dedicated t :width 0.5 :height 0.5 :edges
           (0.5 0.0 1.0 0.5)))
    (nil
     (0 18 92 36)
     (:purpose log :purpose-dedicated nil :width 0.5 :height 0.5 :edges
           (0.0 0.5 0.5 1.0))
     (:purpose dired :purpose-dedicated nil :width 0.5 :height 0.5 :edges
           (0.5 0.5 1.0 1.0)))))

(defun bmag-open-python-project ()
  (interactive)
  (let ((root (bmag-project-root)))
    (purpose-mode)
    (purpose-set-extension-configuration :project bmag-python-purpose-conf)
    (purpose-set-window-layout bmag-python-layout)
    (dired root)
    (find-file (bmag-file-in-project root "/project_log.org"))
    (find-file (bmag-file-in-project root "/main.py"))
    (python-shell-switch-to-shell)))

If you use Projectile (or an equivalent package), you could use it to get the project's root directory automatically.

bmag
  • 1,713
  • 10
  • 12