std/extensions
Extensions of an application. Each is a folder with a manifest,
extension.toml, and a Cuarzo program, made with
std/extension, that runs in a process of its own and
talks to the application over JSON messages; an extension that fails, or
never answers, does not take the application down. An editor built on it
runs language servers for other languages as extensions, as their
manifests say.
import "std/extensions"
ExtensionHost host = extension_host("1.2") // the application's API
host.load_folder(config_dir() + "/app/extensions")?
host.activate("onStartup")
for c in host.commands() do
print(c.id, c.title)
end
print(host.run_command("todo.count", args)?)[extension]
id = "acme.todo"
name = "TODO"
version = "1.0.0"
api = "1.0" # the API it was written for
main = "todo.cz" # built by the host, or: program = "build/todo"
activation = ["onCommand:todo.count", "onLanguage:todo"]
[[commands]]
id = "todo.count"
title = "Count TODOs"
[[menus]]
location = "editor/context"
command = "todo.count"
when = "textFocus"
[[keybindings]]
key = "ctrl+alt+t"
command = "todo.count"
when = "textFocus"
[[settings]]
key = "todo.pattern"
type = "string"
default = "TODO"
[[languages]]
id = "todo"
extensions = [".todo"]
[[grammars]]
language = "todo"
path = "todo.tmLanguage.json"
[[themes]]
label = "Todo Dark"
path = "dark.json"
kind = "dark"
[[views]]
id = "todo.list"
title = "TODOs"
location = "sidebar"
[[language_servers]]
language = "todo"
command = ["./server", "--stdio"]An extension runs on the application when it was written for the same
major version of the API and a minor version up to the application's
(api_compatible(wanted, has)); one that is not, or whose manifest is
wrong, is loaded as failed, with its problem.
Method of ExtensionHost |
|
|---|---|
load_folder(folder), load(folder), find(id) |
the extensions; each an Extension with its manifest, state ("inactive", "active", or "failed"), problem, and crashes |
commands(), menus(), keybindings(), settings_schema(), languages(), grammars(), themes(), views(), language_server(language) |
what the usable extensions add, without running them: key bindings for std/keybindings, settings as a JSON Schema for std/settings |
activate(event) |
starts the extensions that wait for event, as "onStartup", "onLanguage:todo", or "onView:todo.list"; "*" starts all |
run_command(command, args) |
runs a command, starting its extension first ("onCommand:<id>"); its result, or an ERROR of kind "extension" when the extension answers with one, stops, or takes longer than timeout_ms (10 seconds) |
send_event(name, data) |
an event to every running extension, as "settingsChanged" |
pump(wait_ms) |
handles what the extensions sent, while the application waits |
stop() |
asks each extension to shut down, and ends those that do not |
host.answer answers what extensions ask (an ExtensionRequest with the
extension's id, the method, and the params): SOME with a result or
an error, or NONE, which tells the extension the application does not
know the request. What extensions log is in host.log. An extension that
stops, or does not answer in time, is ended and started again for the
next command, up to max_crashes (3) times. A host builds an extension's
main file with host.compiler (cuarzo).
std/extension
An extension's side. run_extension(activate) serves the application
until it shuts the extension down: it calls activate once, with an
ExtensionContext, then runs the commands registered and calls the
listeners of events. A command that panics answers with an error, and the
extension goes on.
import "std/extension"
exit(run_extension(func(ExtensionContext ctx) do
ctx.register_command("todo.count", func(Json args) Result[Json] do
return Result.OK(Json.NUMBER(f64(count_todos(json_text(json_get(args, "text"))))))
end)
end))Method of ExtensionContext |
|
|---|---|
register_command(id, handler) |
a command: handler gets its arguments and gives its result |
on_event(name, handler) |
listens to an event |
request(method, params) |
asks the application and waits for its answer |
notify(method, params), log(text) |
tells it something |
It also has the application's api, the event that activated it, and
the settings the application last sent. The messages are JSON with a
Content-Length header, as the Language Server Protocol has them:
activate, command, event, and shutdown from the application; any
request and log from the extension.