forked from 1b-agent/opencadstudio-upstream
feat(plugin-api): entity-class display declarations on the manifest (API v10)
Plugins can now declare the entity classes they identify via XDATA, and the
host resolves them to display-only type labels while the declaring plugin is
loaded.
- Append `BuiltinPlugin::entity_classes()` (a guarded trailing vtable slot,
the same additive pattern as `on_load` in v5) returning a &'static
`EntityClasses { app_id, class_prefix, labels }`. The static
`PluginManifest` struct is deliberately untouched: older cdylibs share it
by pointer and its layout is frozen ABI since v1, so adding a field would
read past their allocation.
- `OwnedEntityClasses` travels on the registered manifest as
`OwnedPluginManifest.entity_classes` with `#[serde(default)]`, so manifests
serialized before the field keep decoding (older runners tolerate it
both ways).
- The runner folds the declaration into the GetManifest registration only
when the loaded cdylib's exported `ocs_plugin_api_version` symbol reports
>= 10 — an older binary's vtable predates the slot, so it is never called;
its entities simply keep their native type names.
- `PluginManager::entity_class_declarations` exposes the live set, filtered
to alive, non-disabled plugins in load order. The registered manifests are
the only source and nothing is cached: not installed, disabled,
cap-excluded (`OCS_PLUGIN_MAX_API_VERSION`), failed at load, removed, or a
dead process all contribute nothing.
- Embedded version info `api_version` follows the bump to 10;
`API_VERSION_MIN_SUPPORTED` stays 3.
Tests: runner fold (v10 folds, pre-v10 skipped, `entity_classes()` panic is
contained and reported), manager filtering (disabled / dead / undeclaring
skipped; declarations disappear once the process dies — verified with a real
killed child), bincode registration round-trip, and older-manifest serde
default.
This commit is contained in:
1 parent
859070403c
commit
60eb7b086e
9 files changed
+502
-13
No files matched your search
@@ -27,8 +27,11 @@
|
||||
/// `delete_xrecord` / `list_xrecords`). v9 appends the reference-only entity
|
||||
/// designation (`HostApi::set_reference_only`): display-only geometry a plugin
|
||||
/// still owns and refreshes while the built-in edit paths treat it like a
|
||||
/// locked layer.
|
||||
pub const API_VERSION: u32 = 9;
|
||||
/// locked layer. v10 appends `BuiltinPlugin::entity_classes`: plugin-declared
|
||||
/// XDATA class-identity display labels, folded into the registered manifest.
|
||||
/// Display-only; the host consults the declaration only while the declaring
|
||||
/// plugin is loaded, and entities without one keep their native type names.
|
||||
pub const API_VERSION: u32 = 10;
|
||||
|
||||
/// Oldest plugin API major the current host still loads. This keeps previously
|
||||
/// compiled cdylibs usable as long as their vtable layout is a prefix of the
|
||||
@@ -77,6 +80,35 @@ pub fn host_accepts_plugin_version(plugin_major: u32) -> bool {
|
||||
plugin_major >= API_VERSION_MIN_SUPPORTED && plugin_major <= effective_max_api_version()
|
||||
}
|
||||
|
||||
/// A plugin's declaration of the entity classes it identifies via XDATA,
|
||||
/// surfaced by the host as display-only type labels (the Properties panel
|
||||
/// title and the automation `display_type` field).
|
||||
///
|
||||
/// The split is deliberate: the *identity* is a stable class KEY stamped into
|
||||
/// the entity's XDATA (one string value per entity, e.g. `"MYAPP-CLASS:LINE"`)
|
||||
/// and round-trips with the drawing; the *display labels* live in this
|
||||
/// declaration, so they are plugin-localizable and fixable without rewriting
|
||||
/// drawings. The declaration is consulted only while the declaring plugin is
|
||||
/// loaded — a plugin that is not installed, disabled, failed to load, or whose
|
||||
/// process has died contributes nothing, and its entities display as their
|
||||
/// bare native type.
|
||||
///
|
||||
/// Declared through [`crate::host::BuiltinPlugin::entity_classes`] (API v10);
|
||||
/// see `docs/plugin-architecture.md` for the full convention.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct EntityClasses {
|
||||
/// XDATA application name whose records carry the class-identity keys
|
||||
/// (e.g. `"CVIFC"`). Should be one of the manifest's `xdata_apps` so the
|
||||
/// host knows the plugin writes under this id.
|
||||
pub app_id: &'static str,
|
||||
/// Prefix that marks a string XDATA value as a class-identity key
|
||||
/// (e.g. `"CVIFC-CLASS:"`). The remainder of the value is the class key.
|
||||
pub class_prefix: &'static str,
|
||||
/// Class key → display label (e.g. `"LINE"` → `"Linear Element"`), in
|
||||
/// declaration order. Display text never round-trips the drawing.
|
||||
pub labels: &'static [(&'static str, &'static str)],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::test_lock::ENV_LOCK;
|
||||
|
||||
Reference in new issue
Block a user