The WACky WorkSPACE manager for emACS.
Wacspace is available on Marmalade and
Melpa, so you can install easily with
M-x package-install
. You can also just put wacspace.el
on your
load path and (require 'wacspace)
. Wacspace requires cl-lib
(included in Emacs >= 24.3) and
dash.el (available on Marmalade
and Melpa).
The easiest way to set up wacspace is to just put (wacs-set-up-keys)
into your Emacs configuration somewhere. This will set up C-z
as a
prefix key with the various wacspace commands in convenient bindings.
If for some reason you don't want to use C-z
as a prefix, you can
put something like the following in your configuration:
(wacs-set-up-prefix)
(global-set-key (kbd "C-c C-w") 'wacs-prefix-map)
(In this example, C-c C-w
would be the wacspace prefix.) If you
don't want to use the prefix map, you can also use your own custom
keybindings. The only commands you need to bind are wacspace
,
wacspace-save
, and wacspace-switch-project
.
Once you have a good configuration (see below), using wacspace is very
easy: just press C-z C-w
(or M-x wacspace
) when you're in a
buffer, and your workspace (windows, buffers, and frame) will be
automatically set up according to your current mode. C-z C-w
will
use the default configuration for the mode, but you can also use
alternate workspaces (wacspace supports up to 10, including the
default). To use workspace number 3, for example, press C-z C-3
(or
C-3 M-x wacspace
).
The first time you use wacspace
on a buffer, your workspace will be
set up based on your configuration (see below). Once your workspace is
set up, wacspace will automatically save your window configuration. If
you use wacspace
on any of the buffers that were set up this way, it
will jump to the window setup without re-running your configuration.
You can also save your configuration at any time using C-z C-s
(or
M-x wacspace-save
). wacspace-save
can also use a numeric prefix,
in which case using wacspace
with that numeric prefix will access
that saved workspace. When you kill a buffer in the configuration and
use wacspace
, it will again set up the workspace according to your
configuration. Thus, wacspace
should "just work" most of the time—if
you want concrete behavior examples, check out
features/wacs-save.feature.
If you want to force reconfiguration of a workspace, use C-u C-z C-w
, which will clear the saved workspaces associated with the
current buffer.
If the variable wacs-save-frame
is set to t
(which it is by
default unless you're running Emacs in a terminal), wacspace
will
save and restore frame configuration as well as window configuration.
Managing project workspaces is easy with wacspace. When you use
wacspace
, wacspace will associate your workspace with a project name
(by default, the name of the enclosing folder that contains a .git
,
but this is configurable). You can then easily switch between projects
using C-z C-p
(or M-x wacspace-switch-project
), which will prompt
for a project name (for best results, use ido-mode
, which you should
be using anyway). Wacspace will even remember which prefix key you
used last in that particular project, so you can resume right where
you left off. Wacspace also comes with a number of functions that help
you set up project-specific helper windows (see later).
Configuring wacspace is not much harder—you usually only need to use
one macro, defwacspace
. Here's an example configuraton to get you
started:
(defwacspace (ruby-mode (:var rinari-minor-mode))
(:before rinari-console)
(:after-switch rbenv-use-corresponding)
(:default
(:winconf 3winv)
(:aux1 "*rails console*")
(:aux2 eshell))
(:1
(:frame full))
(:2
(:winconf 2winh)
(:frame left))
(:3
(:main "*rails console*")
(:aux1 :main)
(:winconf 2winh)
(:frame right)
The basic form is (defwacspace (major-mode &optional aux-cond) &body config)
. The aux-cond
can be either be a variable of the form
(:var VAR)
(such as (:var rinari-minor-mode)
, or any other minor
mode variable for that matter) or a function of the form (:fn FN)
(such as (:fn (lambda () (string-match "spec\\.rb$" (buffer-name))))
.
You can also use an inline lambda instead of a (:fn FN)
pair, or a
variable name instead of a (:var VAR)
pair (in all cases, there is
no need for quoting).
The configuration currently supports the following options:
:before
A function to run before setting up the workspace.:after-switch
A function to run after setting up the workspace and every time you switch to a project with that configuration.:default
The default configuration.:[1-9]
The configuration to use with the corresponding prefix. keys. Note that these inherit from the default configuration.:after
A function to run after setting up the workspace.:base-file
A filename to look for to find the project root (useful for the path helper functions). Defaults to".git"
.:project-name-fn
A function to customize the project name (should return a string).
Within the configurations, the following options are available:
:winconf
The window configuration to use (see later).:frame
The frame alignment to use (see later).:main
The top-left window.:aux[1-5]
Auxiliary window number 1-5 (in the order ofother-window
).
There are 2 options to set up a window:
:buffer
Switch to buffer name (or:main
, which signifies the buffer from whichwacspace
was invoked). Ifwacs-regexp-buffer-switching
is set tot
(which it is by default), wacspace will try to switch to the most recent buffer with a regexp match; if none is found, it will switch to a new buffer with that name.:cmd
A command to invoke.
You can also specify default wacspaces, which will be run when no wacspace associated with a major mode is found:
(defwacspace (:default)
(:default
(:aux1 wacs-eshell)))
(defwacspace (:default rinari-minor-mode)
(:before rinari-console)
(:aux1 "*rails console*")
The :default
wacspace (without a minor mode condition) is special:
all wacspaces inherit from it. So if you put a useful base
configuration in your :default
, you can save a lot of configuration
in all your other modes!
Another useful option is to specify wacspace aliases:
(defwacsalias (js-mode rinari-minor-mode)
(ruby-mode rinari-minor-mode))
As you might expect, the above example means that when you're in a
buffer in js-mode
and rinari-minor-mode
, wacspace
will run as if
you're in ruby-mode
and rinari-minor-mode
. You can also alias
multiple modes to a single wacspace using the defwacsaliases
macro.
One thing to be aware of is the specific order in which wacspace
will look for configurations:
- Wacspaces with auxiliary conditions
- Aliases with auxiliary conditions
- Wacspaces without auxiliary conditions
- Aliases without auxiliary conditions
:default
wacspace with auxiliary conditions:default
wacspace without auxiliary conditions
Wacspace comes with some nice path functions to help set up auxiliary
windows. When wacspace
is invoked, the variable wacs-main-buffer
is automatically bound to the buffer from which it was invoked, so you
can use it in any functions that set up windows or that test for
auxiliary conditions. The function wacs-project-dir
finds the base
project directory by looking for a file or folder equal to
wacs-project-base-file
. This variable defaults to ".git"
but can
be set globally or on a per-wacspace basis with the option
:base-file
.
Wacspace also provides functions wacs-eshell
and wacs-shell
,
designed to be used within wacspace configurations, that open an
eshell or shell (respectively) in the project directory. If you have
multiple files in the same directory, they will share the same eshell
or shell buffer.
A winconf is basically just a function to set up your windows. You can
define your own using defwinconf
:
(defwinconf my-cool-winconf
(split-window-right)
(split-window-right)
(split-window-below)
(split-window-below)
(other-window 3)
(split-window-left))
(This is a terrible example of a usable window configuration). You can assume that your function will start with just one window and you don't have to worry about having the primary window active in the end. Wacspace comes with some nice winconfs built in:
+----------------------+
| |
| |
| |
| :main |
| |
| |
| |
+----------------------+
+----------+-----------+
| | |
| | :aux1 |
| | |
| :main +-----------+
| | |
| | :aux2 |
| | |
+----------+-----------+
+----------+-----------+
| | |
| | |
| | |
| :main | :aux1 |
| | |
| | |
| | |
+----------+-----------+
+----------+
| |
| :main |
| |
+----------+
| |
| :aux1 |
| |
+----------+
+----------+-----------+
| | |
| :main | :aux2 |
| | |
+----------+-----------+
| | |
| :aux1 | :aux3 |
| | |
+----------+-----------+
Due to the wide variety of GUI/terminal experiences for Emacs and
screen resolutions, I haven't attempted to include frame-setting
functions with wacspace. Instead, you can use your own functions and
set them using wacs-set-frame-fn
:
(wacs-set-frame-function full my-fill-screen-fn)
In the future, I might add helper functions to set up your own frame functions.
Wacspace is in early alpha phase, and I plan to add more features and fix behavior. Any comments/suggestions/pull requests are much appreciated. Eventually, I would also like to include a variety of default configurations for various modes.