refactor(plugin): drop built-in plugins, external-only

OpenCADStudio no longer bundles plugins — every add-on is an external
cdylib loaded from the plugins folder or installed via the marketplace.

- Remove the demo plugin and the in-tree ocs_example_plugin crate.
- Remove the inventory-based built-in registration path (PluginRegistration,
  all_plugins, installed_manifests); registry now serves core ribbon tabs
  plus loaded external plugins, and try_dispatch routes only to externals.
- Plugin Manager drops the 'compiled into this build' section; the
  enable/disable toggle moves onto loaded external cards.
- Prune the now-dead HostSession/DocumentTab helpers and re-exports.

Part of the #100 extensibility epic (phase 2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-17 15:50:52 +03:00
commit eb53e445ab
22 changed files with 65 additions and 585 deletions

View file

@ -1,16 +0,0 @@
[package]
name = "ocs_example_plugin"
version = "0.1.0"
edition = "2021"
description = "Reference external add-on for Open CAD Studio — builds a cdylib the host loads at runtime."
license = "GPL-3.0-only"
# A dynamically-loaded plugin is a C-ABI dynamic library. `cargo build -p
# ocs_example_plugin` produces target/<profile>/libocs_example_plugin.so (or
# .dll/.dylib); drop it beside a plugin.toml in the plugins folder.
[lib]
crate-type = ["cdylib"]
[dependencies]
# The stable contract, with the runtime `host` surface (HostApi/BuiltinPlugin).
ocs_plugin_api = { path = "../ocs_plugin_api", features = ["host"] }

View file

@ -1,37 +0,0 @@
# ocs_example_plugin
Reference **dynamically-loaded** add-on for Open CAD Studio. It depends only on
`ocs_plugin_api` (with the `host` feature) — never on the `OpenCADStudio`
binary — so it shows the full surface an out-of-tree plugin targets: a
`PluginManifest`, a `CadModule` ribbon tab, a `BuiltinPlugin` entry point, and
the `export_plugin!` C-ABI export.
## Build & install
```sh
cargo build -p ocs_example_plugin # → target/debug/libocs_example_plugin.so
```
Copy the library and `plugin.toml` into a folder named after the plugin id under
the user plugins directory:
```
<config>/OpenCADStudio/plugins/opencad.example/
plugin.toml
libocs_example_plugin.so # .dll on Windows, .dylib on macOS
```
`<config>` is `%APPDATA%` (Windows), `~/Library/Application Support` (macOS), or
`$XDG_CONFIG_HOME` / `~/.config` (Linux).
Restart Open CAD Studio. The host loads the cdylib at startup (after checking
`ocs_plugin_api_version`), adds the **Example** ribbon tab, and routes `EX_`
commands to it. `PLUGINS` lists it under *External* as **Loaded**; run `EX_HELLO`
to see it respond.
## Contract
- `ocs_plugin_api::export_plugin!(MyPlugin)` emits `ocs_plugin_api_version()` and
`ocs_plugin_register()`.
- The package must be built with the **same toolchain and `ocs_plugin_api`
version** as the host (approach B — the version symbol enforces the latter).

View file

@ -1,13 +0,0 @@
[plugin]
id = "opencad.example"
name = "Example Plugin"
version = "0.1.0"
description = "Reference dynamically-loaded add-on"
author = "Open CAD Studio contributors"
license = "GPL-3.0-only"
[opencad]
api_version = 1
ribbon_order = 50
command_prefixes = ["EX_"]
xdata_apps = []

View file

@ -1,68 +0,0 @@
//! Reference external add-on, built as a `cdylib` the host loads at runtime.
//!
//! It depends only on `ocs_plugin_api` (with the `host` feature) — never on the
//! `OpenCADStudio` binary — so it demonstrates the stable contract an
//! out-of-tree plugin targets: a `PluginManifest`, a `CadModule` ribbon tab, a
//! `BuiltinPlugin` entry point, and the `export_plugin!` C-ABI export.
use ocs_plugin_api::host::{BuiltinPlugin, HostApi};
use ocs_plugin_api::manifest::{ApiVersion, PluginManifest};
use ocs_plugin_api::ribbon::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem, ToolDef};
static MANIFEST: PluginManifest = PluginManifest {
id: "opencad.example",
name: "Example Plugin",
version: "0.1.0",
description: "Reference dynamically-loaded add-on",
api_version: ApiVersion::CURRENT,
ribbon_order: 50,
xdata_apps: &[],
command_prefixes: &["EX_"],
};
/// Ribbon tab for the example plugin.
struct ExampleModule;
impl CadModule for ExampleModule {
fn id(&self) -> &'static str {
"example"
}
fn title(&self) -> &'static str {
"Example"
}
fn ribbon_groups(&self) -> Vec<RibbonGroup> {
vec![RibbonGroup {
title: "Demo",
tools: vec![RibbonItem::LargeTool(ToolDef {
id: "EX_HELLO",
label: "Hello",
icon: IconKind::Glyph(""),
event: ModuleEvent::Command("EX_HELLO".to_string()),
})],
}]
}
}
/// The plugin entry point handed to the host.
struct ExamplePlugin;
impl BuiltinPlugin for ExamplePlugin {
fn manifest(&self) -> &'static PluginManifest {
&MANIFEST
}
fn ribbon(&self) -> Box<dyn CadModule> {
Box::new(ExampleModule)
}
fn dispatch(&self, host: &mut dyn HostApi, cmd: &str) -> bool {
match cmd {
"EX_HELLO" => {
host.push_info("Hello from the external example plugin (cdylib loaded).");
true
}
_ => false,
}
}
}
// Emit the C-ABI symbols the host loader looks for.
ocs_plugin_api::export_plugin!(ExamplePlugin);