Plugins in practice
Table of Contents
This chapter is the short way in: how to add a plugin from the editor, how to change one that exists and use your own copy, and how to write a plugin for a file type Kalem does not open yet. The chapters after it say how everything works; this one says what to do.
A plugin is a small program Kalem runs in a sandbox: it sees the file it was given and nothing else, has its own memory and time, and a plugin that fails is closed without taking Kalem down. The viewers of pictures, PDF files and workbooks are plugins too, none built into Kalem: the first file of a kind that needs one names it, to install; language plugins (a syntax and a language server for a programming language) need no code at all.
1. Adding a plugin from the editor
In the Kalem menu (and the command palette):
- Browse Plugins lists the plugins of the official index,
getkalem/plugins, with what is installed. Choosing one shows what it is, where it comes from and what it may do, and installs it. - Install Plugin from GitHub… asks for a link: a repository that is a plugin, a folder in one, or a release's page. That is how a plugin of your own, or anyone's that is not in the index, gets in.
- Installed Plugins lists yours, offers an update when there is one, and removes.
On the command line: kalem plugin browse, kalem plugin install
NAME (a name from the index, a link, or a folder on disk), kalem
plugin list, kalem plugin remove ID. Language plugins has the details,
and how to add an index of your own as a source.
2. What you need to build one
- Rust, with rustup.
- The target plugins are built for, once:
rustup target add wasm32-unknown-unknown. - The tool that wraps a build as a component, once:
cargo install --locked wasm-tools. - Kalem itself:
kalem plugin buildandkalem plugin devdo the rest.
3. Changing a plugin that exists
Every plugin lives in getkalem/plugins, one folder each under
plugins/. To change the workbook viewer, say:
git clone https://github.com/getkalem/plugins cd plugins # edit plugins/xlsx/src/… cargo test -p kalem-plugin-xlsx # the plugin's own tests, natively kalem plugin dev plugins/xlsx # built, installed, built again at each change
kalem plugin dev builds the plugin, installs it, and builds and
installs it again whenever its sources change, until you stop it. A
Kalem that is running opens the next file with your build; one started
later finds it installed. A panic in your code reaches Kalem's log with
the names of your functions.
One thing to know: your build replaces the copy you installed from
the index, whatever its version; kalem plugin list says which copy is
in use. To go back to the released one, kalem plugin install xlsx
again; kalem plugin remove org.kalem.xlsx takes your copy out and
leaves no workbook viewer until one is installed.
To give your change to others:
- the best way is a pull request to
getkalem/plugins; - or push your fork, raise
versioninplugins/xlsx/plugin.json(to0.0.11, say) and tag itxlsx-v0.0.11(the tag must name the manifest's version): the repository's release workflow builds the component and publishes it (GitHub turns workflows off on a fork until you enable them, once, in its Actions tab). Then anyone installs it with Install Plugin from GitHub… and the link of your fork's folder,https://github.com/YOU/plugins/tree/main/plugins/xlsx. (A fork'sindex.jsonpoints atgetkalem/plugins, astools/build-index.pywrites it, so adding it as a plugin source does not give your version.)
4. A plugin for a file type of your own
kalem plugin new NAME starts one. Inside a checkout of
getkalem/plugins it makes plugins/NAME; anywhere else, a crate of
its own in NAME/:
kalem plugin new dots cd dots cargo test # the tests that come with it, natively kalem plugin build # dist/dots.wasm, the component kalem plugin dev # installed, and built again as you work
What you get is a working viewer of a small format. A viewer's format
is one that is not text: Kalem opens every text file in a mode, as text
to edit, even one a viewer could show (an SVG drawing is XML), and hands
a file to a viewer only when it is not text, as a NUL byte among its
first bytes shows. So the template's format is a picture whose first
bytes are DOTS and a NUL, then its rows, # a dark cell and . a
light one, a line a row. With the plugin installed (by
kalem plugin dev, say), make one and open it:
printf 'DOTS\0.##.\n#..#\n.##.\n' > a.dots kalem view a.dots # its rows and its information, printed kalem a.dots # the picture, in the window or the terminal
A .dots file of # and . alone is text: it opens as text to edit,
and kalem view says that no installed plugin opens it. A format that
is text is a language plugin's or an extension plugin's (see
Beyond viewers), not a viewer's. The plugin's two files:
plugin.json: the plugin's id, name, version, what it opens (its extension,"opens": [".dots"], and its first bytes,"applies": {"magic": ["44 4F 54 53 00"]}, so that a file of the format opens whatever its name) and its permissions (a viewer needs none); its limits are Kalem's defaults unless it addslimits.src/lib.rs: the viewer, and the document it opens. Which files are its own is the manifest's to say (opens, andappliesfor first bytes, whole names or markers: see the chapter on plugins), not itsdetect, which Kalem does not ask. The viewer reads one (open; the file comes through a handle,read_allor a piece at a time, since the plugin has no file system). The document says what the file holds (structure: one picture, pages, frames or sheets), how large a unit is (size), draws it when asked (render: pixels, at the scale asked, in the theme's colors) and gives its text (text, for search, copying and the terminal) and its information panel (info). Each part is marked in the file; replace the picture with your format, and its first bytes (MAGIC) with your format's, in the file and inplugin.jsonalike: a test checks that the manifest declares them.
Tests run natively with cargo test, as for any crate; the same code is
the component Kalem runs. The contract has more than the skeleton uses,
each with a default: links in a unit, an outline, search, editing and
saving (save), a file that needs a password, and, with the grid
feature of kalem-plugin, sheets of cells as the workbook viewer has
them. Plugins lists them, and kalem-viewer's documentation says what each
does.
To publish it: put the crate in a GitHub repository of its own, run
kalem plugin build, and attach dist/dots.wasm to a release there;
anyone installs it with Install Plugin from GitHub… and the
repository's link (Kalem takes the component from the release). To be
in the official index, open a pull request that adds plugins/dots to
getkalem/plugins.
5. Beyond viewers
A plugin may add commands, keys and panels to the editor rather than open files (an extension plugin), and a language plugin is a manifest with a syntax and a language server, no code: Plugins and Language plugins say how.