Why ductus
dk is a terminal modal editor inspired by Helix and Vim (ADR 0001). I wrote it because I wanted to own the code of the editor that I use every day (ADR 0001, plan 0005).
Modal editing
In a modal editor, what a key does depends on the Mode. dk has four, Normal, Insert, Select and Block, each with its own table of keys (Glossary, Keys). In Normal mode the letter keys are commands that move, select or change text.
In dk you select first and then you act (Editing).
w selects the text up to the start of the next word and d deletes the text of every Range, so w d deletes up to the next word.
x selects the line, and a second x adds the line below.
% selects the whole text, so %d empties it in one undo step.
Each Range draws in the selection style of the theme, so you see what d will delete before you press it (Display).
A Selection can contain many Ranges, and the motions, d and c act on each of them (Editing).
s opens the prompt select:, and each match of the regex inside the Selection becomes a Range of its own.
So % s, a regex, Enter and d delete every match in the file.
What dk adds
Plugins are WebAssembly components
A Plugin is a WebAssembly component built against one versioned WIT package, ductus:editor (ADR 0004).
You can write one in any language that targets the component model, and for Go that means TinyGo.
I started with embedded Lua and dropped it, because a Lua plugin runs with all the privileges of the user, so it could read any open Document and send it anywhere (ADR 0004). A WebAssembly Plugin gets the editor API and nothing else, and filesystem, process and network access need a Capability (ADR 0004). The host stops a call after 100 ms, and a Plugin cannot grow past 64 MiB of memory (Plugins). A user plugin that traps is unloaded with one warning, and the others keep going.
The defaults are Plugins too
The keymap, the motions and the picker UI ship as Default plugins (ADR 0005).
They use only the public WIT API, like a Plugin that you write, which is the proof that the API is complete enough to build an editor on.
It also means you can replace them: plugins/keymap.wasm, plugins/picker.wasm or plugins/vcs.wasm in the config directory replaces the shipped one (Keys, Plugins).
The price is speed, since one keystroke can cross the WebAssembly boundary many times (ADR 0005).
When the keymap Default plugin is missing, fails to load or traps, dk enters Emergency mode.
Emergency mode has a native keymap that types, moves with the arrows and h, j, k, l, and saves and quits with :w and :q, so unsaved text is never lost (ADR 0005).
Capability grants
A Plugin gets a Capability, such as the right to run a program, only from a grant in your user config (ADR 0007):
[plugins.vcs]
exec = ["jj"]
The one grant that needs no config is the exec = ["jj"] of the shipped vcs plugin, and exec = [] takes it away.
A .ductus directory in a repo cannot grant a Capability, even when you trust the workspace.
A granted Plugin uses its Capability only in a Trusted workspace, and :trust is how you say yes (ADR 0007, Workspaces).
A Plugin that you copy into plugins/ gets no grant until you write one, with the SHA-256 of the file (Plugins).
An exec grant is full trust: jj util exec and git aliases run any program, and dk does not check the arguments (ADR 0007).
That is a pretty big grant, so give one only to a Plugin that you would run as a program.
Features that work with no setup
ADR 0001 names this as an idea of dk, next to modal editing.
- dk ships the config of
goplsandgolangci-lint-lspfor Go, so a Go file starts them when they are onPATH(Language servers). A server reads config from the workspace, such asgo.mod, so it starts only after:trust, once for each workspace (A9). - The keymap binds its default keys with no config, and docs/manual.md lists them (Keys).
- The nix package contains each grammar of the shipped
languages.tomlthat builds under nix, so a Go, Python or Rust file shows its syntax with nogrammarsline (Install). - The vcs Default plugin for jj has its grant with no config, and runs jj once you trust the workspace (Plugins, Workspaces).