Tuna’s core: what it is and how to use it

This guide explains Tuna’s core to someone who knows Emacs. It shows every form and procedure a plugin author or a user writes, each beside its closest Emacs equivalent, and says plainly where Tuna differs and why. Nothing here is built yet: it describes the approved design.

Before you start

How to read the guide:

Tuna is written in Chez Scheme, version 10.4.1. Its code reads like any Scheme. Two things look unusual at first: names written buffers:insert! (a name insert! from the contract buffers), and keywords written for: or depth: (a word ending in a colon, which names the argument after it).

What the core is

The core is the part of Tuna that every other part runs on. It does seven things:

  1. Runs plugins. It starts, stops, reloads and swaps them, and undoes everything a plugin set up when it stops.
  2. Checks plugins. A plugin can name only what it imports; the build checks every name before anything runs.
  3. Keeps state. It holds the user’s data, the lists plugins add entries to, and settings, each change recorded with its owner.
  4. Runs the command loop. One thread, the editor thread, runs all plugin code: keys, commands, timers.
  5. Runs heavy work on workers, other threads that cannot touch editor state.
  6. Pauses commands at a prompt without stopping the editor, and stops runaway code on C-g.
  7. Lets you change things live: M-:, C-M-x, reload-config, and a record of who changed what.

What the core is not. The core knows nothing about keys, buffers, windows, commands, files, the minibuffer, the screen or the browser. Each of those is a plugin. Even writing saved data to disk is a plugin (journal-store): the core keeps the data and says when it must be written; the storage plugin decides where and how. Without a storage plugin Tuna still runs; it saves nothing. The same is true of the process service that runs your shells.

Where Emacs differs: Emacs’s core is written in C and holds buffers, windows, keymaps, redisplay and the command loop. Tuna’s core holds none of these. The gain is that each of them can be replaced, reloaded or turned off like any plugin; the cost is that a working editor needs about sixteen plugins listed (see defaults.ss, proposed).

The pieces

Everything in Tuna is made of these pieces. Learn them and the rest follows.

PieceOne lineExampleClosest in Emacs
CoreThe plugin runtime and its rules; no editor features.starting and stopping plugins, workersthe C core and subr.el, without the editor parts
PluginA folder with a plugin.ss file (and maybe a contract.ss) that does one job. Its file runs top to bottom when it turns on.buffers, minibuffer, highlight, terminala package, loaded with require
ContractA plugin’s public interface: the names others may use. Others write (import (buffers)) and call buffers:insert!. A contract offers verbs.(buffers), (text-store)a package’s public functions, by naming convention only
Saved dataThe user’s data: one plain value per name, checked, written to disk after every command, kept across reloads, crashes and restarts.buffer text, undo history, prompt historysavehist, desktop, auto-save files
OptionA setting. Each owner (a plugin, an init.ss line, your session) has its own layer; the newest wins. A layer may be scoped to a buffer or a mode.fill-columndefcustom, setq-local
HookA list of procedures others add to; each entry belongs to whoever added it.buffers:after-change-hooka hook variable
TableA list of named entries others add to through verbs; each entry belongs to whoever added it and goes when they go.key bindings, commands, faces on a bufferkeymaps, overlays, auto-mode-alist
WorkerHeavy work on its own thread. It gets plain read-only data, gives back plain data, and can reach nothing else.fuzzy matching, highlighting a big filea subprocess with a filter

A plugin’s ordinary variables (a counter, a cache, written with plain define) are none of these: they are the plugin’s alone, nobody else can reach them, and they start fresh each time the plugin starts.

How the pieces relate. The user's init.ss chooses plugins; plugins keep their data in the core and add entries through other plugins' verbs; a plugin reaches another only through its contract (dashed); heavy work goes to a worker thread; the storage plugin writes the saved data the core hands it.
The core (one per Tuna; small; knows no editor features)init.ssthe user's choicesM-: sessionthe user's live changesPlugin runtimestart, stop, reload, swapCommand loopeditor threadTimers, pausedcommands, quitOptionsdefine-optionSaved datadefine-savedTables and hooksdefine-tableIdsnew-idWorker jobsstart-jobPlugin: journal-storefills (storage)Plugin: buffersplugin.ssPlugin: highlightplugin.ssWorker threadruns highlight's scanContract (buffers)its export listuse-pluginset!define-savedkeys:bind! (a verb)calls buffers:textstart-jobplain datachanged entries

Words used everywhere

These words appear on every page. Each is also in the glossary.