WASM plugins
A WASM plugin is a WebAssembly module that turns text into other
text. It runs sealed off from your system, so it suits heavy work or
code you don't fully trust. Scheme is still the main way to extend imp;
plugins are a prototype, only in an imp built with
--features wasm.
What a plugin can do
A plugin's functions each take a string and give back a string. They
can't touch files, the network or the clock. Their one way out is a log,
which :wasm-log shows.
Each call has a budget of work, and each plugin a memory limit. A plugin that runs away stops with an error instead of hanging the editor.
Using a plugin
Load it in init.scm under a name, then hang its
functions on keys or commands:
(load-wasm-plugin! 'case "~/.config/imp/plugins/case.wasm")
(define-operator! "gs" (wasm-operator 'case "snake"))
(define-wasm-filter! 'snake-buffer 'case "snake")wasm-operator makes a Vim operator. Here
gsiw turns the word under the cursor into snake case, and
gs does the same to a visual selection.
define-wasm-filter! makes a command that runs a function
over the whole buffer, here M-x snake-buffer. The change is
one undo step.
In an imp built without the feature, these still exist, but fail with "imp was built without the wasm feature".
Commands
| Command | What it does |
|---|---|
:wasm |
List the loaded plugins and their functions |
:[range]wasm PLUGIN FUNCTION |
Run a function over the lines in the range, or the whole buffer |
:wasm-log |
Show what plugins have logged |
Writing a plugin
imp's source has an example in examples/wasm-plugin: a
Rust plugin whose functions snake, camel and
kebab change the case of identifiers. Build it with:
cargo build --release --target wasm32-unknown-unknownA plugin is a plain WebAssembly module, not a component, and without
WASI. It exports its memory and a function
imp_alloc(len), which imp calls to get room for the input.
Each function takes the address and length of a UTF-8 string, and
returns its result's address shifted left 32 bits, joined with its
length. The one thing it can import is imp.log.