Most MUXes are built off very similar codebases and design patters, but within those similar roots are an infinite and varied number of worlds.
In order to cope with the almost maddening variety in MUXing, programmatically, you have to develop some kind of programming language. For instance, TinyFugue's trigger's are a simple programming language.
So, to allow for the largest amount of flexibility in Moxie, Moxie includes a full programming language. While inventing one specifically for Moxie would certainly be the norm, it is not something that should be valued highly. In fact, by using a standard language, you get a lot of benefits of useably free code-base.
So, Moxie includes an embedded lisp interpreter. This gives you the full power of the Lisp language from within your plugin code. What kind of things you write, and how you want to interact with Moxie and your MUX are limited only by your imagination.
This does mean you'll have to learn Lisp - at least a little - in order to write any plugins for Moxie, although I will endeavour to keep things as simple as possible throughout this document.
The simplest plugins are keyword expansions: when you type "/foobar baz" into Moxie, it will try to trigger keyword expansion for the keyword "foobar".
To register a keyword expander, you first have to write the code for the expander, then register it with the keyword expansion hook. all the functions referenced here are exported from the MOXIE package.
First, we'll create a package for our test plugin, and use the moxie package, as well as the bjc-utils package.
(defpackage test-plugin (:use :cl :cl-user :moxie :bjc-utils)) (in-package :test-plugin)
Then we define our expander function. We just want to take a name off of the argument line, and page them with "hello!". For the sake of debugging, we also want to print out what we got as the argument to the lisp REPL:
(defun foobar-handler (string) (format t "foobar-handler got: ~A~%" string) (map-variables "page $1$ = hello!" (split string #\Space)))
The function we've defined returns the string from the map-variables command. This return value is what's sent to the MUX. If we don't want to send anything to the MUX you can return an empty string ("") or nil.
Now that we have the function defined, we want to register it with the keyword expansion hook:
(add-keyword 'foobar-handler "foobar")
To test this, first bring up the REPL window so we can see what's being printed out by the function as it runs. To do this, select "Lisp REPL" from the "Window" menu.
Now, in Moxie, type "/foobar me", and, assuming you're connected to a MUX, you should get a page from yourself saying, "hello!". In the REPL window, however, you'll see:
foobar-handler got: me
Which means the handler received the string "me" as the argument string.
If you're curious how the functions map-variables and split work, in the REPL, type "(documentation 'map-variables 'function)" to view their documentation.
There are other pre-defined triggers that work in a similar fashion. There is a list of them in the moxie.lisp file in the resources directory.
Moxie uses a set of pre-defined symbols to communicate with the lisp sub-system. Below is a table of symbols, what type they are, and what they do.
Name | Type | Description |
moxie::*moxie-result-stream* | stream | The stream for communicating with Moxie. |
moxie::*world* | object | The currently active world-id. This may be 0, if a world hasn't called into the plugin system. |
moxie::eval-hook | function | Used by Moxie to send data from the REPL window to the lisp plugin system. |
moxie::input-to-server-hook | function | Used by Moxie to send data to the lisp plugins after receiving something from the input line. |
moxie::output-from-server-hook | function | Used by Moxie when data is received from the MUX for display on the screen. |
moxie::keystroke-hook | function | Used by Moxie when a registered keystroke is pressed to call into its function |
moxie::world-opened-hook | function | Used by Moxie to tell the plugin system a new world has opened. |
moxie::world-closed-hook | function | Used by Moxie to tell the plugin system a world has closed. |
moxie::start-logging-hook | function | Used by Moxie to tell the plugin system it wishes to log transcripts. |
moxie::stop-logging-hook | function | Used by Moxie to tell the plugin system it no longer wishes to log. |
You can find definitions for all the built in functions in the Application
bundle: Contents/Resources/*.lisp
. The file startlisp
parses the file init-template.lisp
and starts the lisp with the parsed
file, loading the rest of the plug in system with it.
There are certain hooks in tpl.lisp
which the application calls. You
can have a look at them, and even change them if you want, but don't
rename them or Moxie won't work anymore.
Also included in the Application Plug-Ins directory are a few pre-supplied plug ins which you can use as an example. This includes the default logger, numpad movement macros, and ANSI color support.