Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Plugins

ccalc’s built-in list is extended via a lightweight plugin system. A plugin is a separate Rust crate that implements the Plugin trait and registers itself at startup. The engine checks the plugin registry before its own built-in table, so plugins can shadow existing built-ins when needed.

Writing a plugin

Add ccalc-engine as a dependency and implement the Plugin trait:

# my-plugin/Cargo.toml
[dependencies]
ccalc-engine = { path = "../ccalc-engine" }
#![allow(unused)]
fn main() {
use ccalc_engine::env::{Env, Value};
use ccalc_engine::plugin::Plugin;

pub struct MyPlugin;

impl Plugin for MyPlugin {
    fn name(&self) -> &str { "myfunc" }

    fn call(&self, _name: &str, args: &[Value], _env: &Env) -> Result<Value, String> {
        if args.is_empty() {
            return Err("myfunc: at least one argument required".into());
        }
        Ok(args[0].clone())
    }
}
}

Exporting multiple names

A single plugin registration can expose several function names. Override exported_names with a const-backed slice:

#![allow(unused)]
fn main() {
const NAMES: &[&str] = &["myfunc", "myother", "mythird"];

impl Plugin for MyPlugin {
    fn name(&self) -> &str { "myfunc" }

    fn exported_names(&self) -> &[&str] { NAMES }

    fn call(&self, name: &str, args: &[Value], _env: &Env) -> Result<Value, String> {
        // dispatch internally based on which name was called
        match name {
            "myfunc"  => Ok(Value::Void),
            "myother" => Ok(Value::Void),
            _         => Err(format!("{name}: not implemented")),
        }
    }
}
}

All exported names appear in tab completion automatically.

Registering a plugin

In your fork of crates/ccalc/src/main.rs, call register_plugin after exec::init():

#![allow(unused)]
fn main() {
fn run() {
    ccalc_engine::exec::init();
    ccalc_engine::plugin::register_plugin(Box::new(MyPlugin));
    // …
}
}

Add your crate to the workspace and as a dependency of ccalc:

# Cargo.toml (workspace root)
[workspace]
members = ["crates/ccalc", "crates/ccalc-engine", "crates/my-plugin"]

# crates/ccalc/Cargo.toml
[dependencies]
my-plugin = { path = "../my-plugin" }

Built-in plugins

ccalc-plot is the reference plugin shipped with ccalc. It registers the plot, scatter, bar, stem, xlabel, ylabel, and title names. See Phase 29 — Plot engine for rendering details.