We are gearing up for our collaborative effort for ICFP and so I figured it might be nice to write out a little "how to make it work" guide for Rudel, the collaborative editing framework for Emacs. To get this out of the way first, Rudel doesn't work out of the box. In order to use it, we had to hack a bit on the source to correct what we can only guess are legitimate errors. That said, I certainly don't have the expertise on the system in order to dictate the correct way to solve these problem.
As a note, throughout this contest our setup will be:
- Rudel v0.3
- Obby backend
- TCP transport
- Port 6522
- not using the built in Rudel/Obby encryption
- all connections must be tunneled over SSH (for encryption/access control)
- No global or user passwords
The first step for using Rudel is to, naturally, install Rudel. If you have
Emacs v24, you may use the package manager via M-x package-list-packages
.
This will make sure that it also gets any dependencies, however I don't think
there are any that aren't already part of Emacs. If you are not using Emacs
v24, you will need to install package.el
(and this will actually be useful as
I believe it will have to track down some dependencies). This can be done like
this:
cd .emacs.d
wget http://repo.or.cz/w/emacs.git/blob_plain/1a0a666f941c99882093d7bd08ced15033bc3f0c:/lisp/emacs-lisp/package.el
Then from Emacs, M-x load-file
that package.el
file. Then you can use
continue as if you were using v24 (except where noted).
Rudel is available via the the Marmalade repository. In order to enable the
Marmalade repository, you should add something like this early in your .emacs
file:
;; (load "~/.emacs.d/package.el") ;; If not v24 ;; Load up the new package manager (require 'package) ;; Add the Marmalade repo (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/") t) (package-initialize)
The install/compile should seemingly complete without any issues. (If you are
not on v24, then there might be an issue with package displaying the info page
of certain packages, Rudel amongst them. Instead of using M-x
package-list-packages
, use M-x package-install
and specify "rudel" when it
asks).
Now the trouble fun begins.
1.1 We broke your Emacs
Try closing and restarting Emacs. On your next start, Emacs will fail to read
your .emacs
file with an error like:
Symbol's function definition is void: eieio-defclass-autoload
This is because there are some bugs in Rudel that make it not load properly. My solution is to not use the standard method of loading Rudel. The first order of business is stopping it from loading the correct but broken way via the package manager. Go into the shell and move the rudel directory somewhere where it cannot be found by the package manager:
cd .emacs.d
mv elpa/rudel-0.3 ./
Now Emacs should read your .emacs
without issue (because it no longer is
trying to load Rudel).
The next order of business, we want to be able to load and use Rudel. In order
to do this, we will run Rudel's compile script. Do a M-x load-file
on
.emacs.d/rudel-0.3/rudel-compile.el
. This will compile and generate some
files, most importantly for our purposes, it will generate rudel-loaddefs.el
.
Perform a M-x load-file
on .emacs.d/rudel-0.3/rudel-loaddefs.el
and Rudel
should be operational. Try it out. Use M-x rudel-host-session
to start a
session (protocol obby, transport tcp, port 6522). Then join that session via
M-x rudel-join-session
. Try publishing a buffer with M-x
rudel-publish-buffer
. This should all work.
We want to make this permanent, so we should add something like:
(load-file "~/.emacs.d/rudel-0.3/rudel-loaddefs.el")
…to our .emacs
file after the (package-initialize)
statement.
Look, I know this is extremely hackish, but I think it will work for everybody. It is the only way I have consistently been able to get things working.
1.2 Joining and leaving sessions
So, as best I can see, this is the status of this functionality in Rudel: you can join sessions and you can leave, but as far as the server cares, you can never leave. This doesn't seem like too much of a problem at first, but here is how problems start to manifest.
- A username must be unique: This means that each time you log in, you have to pick a unique name, not the one you used last time. This manifests as a lot of "smithzv", "smithzv2", "smithzv3", etc. Luckily, you shouldn't be disconnected often.
- A color must be unique at login time. This one isn't as bad as you can
change colors once you are in the session using
rudel-change-color
. This means that a good practice is to log in and pick a garish and otherwise infrequently used color and then immediately change it to something more appropriate. No need to worry about conflicts after you have logged in.
1.3 Undo and Rudel
So, one of the biggest problems that I have with collaborative editing in Rudel is that undo are treated very literally. I you undo, you implicitly expect it to apply to your code. However, with Rudel, where someone could be editing somewhere else in the file, undo is happy to go about undoing their work as they type rather than the edits you just made.
The end result is that in a collaborative editing environment, undo is a very dangerous thing; doubly so when undo means what it does in Emacs land (i.e. you can redo by undoing an undo). Basically, if you are using Rudel, you probably should not be using undo, at all. This is a pretty tall order if you have deeply internalized undo into your editing commands (as I have).
In strikes me that a helpful heuristic would be to undo only within a region that contains only your edits (or even using something like multiple-regions to allow for undo of anything that you have edited but not things that others have). This means that if you are the only person editing a buffer, undo works exactly as expected, but if there are others editing the buffer, it will only undo your edits. Note that this isn't always what you want.
However, I'm not sure that such a heuristic is possible (or more likely, it is possible but is hard to do). I'll take a look. It seems that for safe, useful undoing, you need to tell everybody that is working on that buffer that they need to stop what they are doing so you may perform your undos.
I realize that other undo systems can be used with Emacs. For instance, there is Undo-Tree. I am not sure how well these work (or really how they work). Perhaps someone who is better versed in these tools can enlighten us.
1.4 When things go wrong
There are times when, try as it might, Rudel screws up and the files become out of sync. This happens fairly infrequently, thank goodness, but when it does, Rudel does not handle this gracefully. There is no "resync" function that I can see. This means that if you find that your buffer says one thing, but someone elses says something else (this usually manifests a what looks like a typo, but if you fix it, another person goes back and changes it back to its typo state), you will have do something pretty drastic in order to get Rudel to work correctly again. There are a couple of things that must work, but they both are pretty annoying:
- Ditch this buffer, have everybody unsubscribe, rename the buffer so it will share under a different name, then republish. This way everything has started fresh with this buffer.
- Restart the entire Rudel session.
Of course, the first method is preferred to the second.
1.5 Dealing with Annoying Colors
If you start using Rudel, sometimes a collaborator will
pick a color that doesn't work with your theme or general aesthetic. Luckily,
there is something you can do about it even if they refuse to change their color (or are perhaps away from keyboard), you can turn off all coloring by author.
Simply specialize the variable rudel-overlay-author-display
(set it to nil
)
and no more colors. This is pretty necessary right now because Rudel is ignorant of the difference between light and dark themes. Thus two locally appropriate choices might be completely inappropriate for the remote party.