A command like “find file” asks a question and waits for the answer. The editor must keep running meanwhile: other keys, drawing, workers. The core does this with continuations: Chez can capture “the rest of this command” as a value, put it aside, and resume it later with the answer. So a command is written straight through, and the waiting is invisible.
(suspend procedure) → the value it is resumed withcore
Who uses it. Plugins that offer prompts (the minibuffer). Ordinary authors call the prompt procedures instead.
Does. Pauses the current command. procedure is called at once with a resume procedure; the command then waits. Whoever later calls (resume value) (the minibuffer, when you press RET) makes suspend return value, and the command goes on.
Underneath. The command’s continuation is saved with call/cc and the command loop goes on. The saved data that changed is written at the pause, so a crash during the prompt keeps what the command did before it. Each paused command keeps its own dynamic values, such as its current buffer. If the plugin the command is paused inside changes (reloads, turns off), the command is resumed with a quit, as if you pressed C-g.
Errors.suspend: only a task can wait; suspend: a plugin's start cannot wait (a start does no waiting; it starts a worker); suspend: a plugin's end cannot wait.
;; Emacs waits in a recursive edit: a nested command loop.(defun read-from-minibuffer (prompt &rest _)(recursive-edit))
Where Tuna differs. In Emacs, a command waiting at a prompt holds a nested command loop; a second command that also prompts nests inside it, and the first cannot finish until the second does. Tuna’s paused commands are independent: each resumes when its own prompt is answered.
Does. Ask the user and return the answer; the command waits meanwhile. They belong to the minibuffer and completion plugins, built on suspend. kind is a symbol ('file) that groups history and completion.
Errors. If you press C-g, or the plugin changes, the call raises a quit; let it pass unless you must clean up.
Tuna · files/plugin.ss (part)
(commands:define(find-file)"Visit a file."(layout:show!(open-file! (minibuffer:read-string"Find file: "'file))))
Where Tuna differs. Emacs asks for arguments in the interactive form, with letter codes or a list. A Tuna command reads straight through its prompts, in its body.
Does.request-quit!, callable from any thread, asks the editor thread to stop what it is doing; the keys plugin calls it for C-g. Running code stops at its next check or pause with a quit condition. If it does not stop by itself, the editor thread’s own timer raises the quit inside it after a short grace period. quit-condition? recognises the condition; raise-quit raises one.
Underneath. The core owns the editor thread’s timer and its break, exception, reset and exit handlers; plugins must not replace them.
Where Tuna differs. Emacs’s C-g sets quit-flag, which Lisp code checks at safe points; a tight loop in C may not see it. Tuna also forces the quit after the grace period.
(spawn-task! name thunk)core
Does. Runs thunk soon, as its own task on the editor thread, owned by the run where it is written. It may pause like a command. The keys plugin runs each key’s command this way.
Underneath. A task that ends or pauses is followed by a save point.