forked from 1b-agent/opencadstudio-upstream
- plugin-architecture.md: new "Entity class display labels (API v10)" section documenting the split (stable identity keys in XDATA, display labels in the plugin declaration), the live-loaded-plugin gating (missing, disabled, cap-excluded, failed, removed, or dead → bare native type), the "<Label> (<Native>)" display rule, that raw schema fields (`type`, `dxf_name`, `record_type`) and LIST are unchanged, and that the label is display-only. `plugin.toml` deliberately does not carry the table: it is the pre-load discovery file and labels must activate on live manifests. - Template v2 demonstrates the whole convention: declares `SURVEY-CLASS:POINT -> "Survey Point"` and stamps the identity key in MARK_FIRST_SURVEY_POINT, so marked points show as "Survey Point (Point)" while the plugin is loaded. plugin.toml's api_version is bumped to 10 (keep in sync with ApiVersion::CURRENT) with a NOTE on where the class table lives. DESIGN.md documents the flow. - Template v2's stale `acadrust` pin (8a28c21, predating the host's codec bump to 278c49a) is realigned with the host's pin: without it the template no longer compiles on main — its `acadrust::EntityType` and the host re-exports are distinct types when the revisions disagree (verified the same four type errors occur before and after this feature's template edit). - changelogs/unreleased.md entry (Plugins section).
99 lines
3.8 KiB
Markdown
99 lines
3.8 KiB
Markdown
# `plugin-template-v2` — Shared-memory `DocumentReader` example
|
|
|
|
This crate is a runnable plugin template that demonstrates the V2 host/plugin
|
|
contract:
|
|
|
|
- **Zero-copy reads** through [`ocs_plugin_api::host::DocumentReader`].
|
|
- **Validated writes** through the existing `HostApi` RPCs (`add_entity`,
|
|
`write_record`).
|
|
- **Read→write round-trips**: read an entity handle from the shared document
|
|
view and attach XDATA to it.
|
|
|
|
It lives under `docs/` (not `crates/`) because it is documentation/example code
|
|
rather than a runtime dependency of the host.
|
|
|
|
---
|
|
|
|
## Commands
|
|
|
|
| Command | Purpose |
|
|
|---|---|
|
|
| `COUNT_SURVEY_POINTS` | Count point entities on the `SURVEY` layer via `document_reader()`. |
|
|
| `ADD_SURVEY_POINT` | Add a new point entity on the `SURVEY` layer via `host.add_entity()`. |
|
|
| `MARK_FIRST_SURVEY_POINT` | Read the first `SURVEY` point and mark it with an XDATA record (including the `SURVEY-CLASS:POINT` identity key). |
|
|
| `COUNT_MARKED_SURVEY_POINTS` | Count `SURVEY` points that carry the `SURVEYMARK` XDATA record. |
|
|
|
|
---
|
|
|
|
## Design notes
|
|
|
|
### Reads are zero-copy; writes are RPCs
|
|
|
|
`document_reader()` returns a read-only view backed by host-owned shared memory
|
|
(for out-of-process plugins) or by `&CadDocument` (for in-process plugins). The
|
|
plugin iterates entities without copying the model.
|
|
|
|
All mutations still cross the validated RPC boundary. This preserves the
|
|
host's crash-safety boundary: a buggy plugin cannot corrupt the host document
|
|
because it never holds a mutable reference to host memory.
|
|
|
|
### Entity handles bridge reads and writes
|
|
|
|
Each [`ReaderEntity`](ocs_plugin_api::host::ReaderEntity) exposes the entity
|
|
`handle`. A plugin can therefore:
|
|
|
|
1. Find an entity of interest with `document_reader().for_each_entity(...)`.
|
|
2. Use that handle with `host.write_record(handle, record)` to attach XDATA.
|
|
3. Read the record back later with `host.read_record(handle, app_name)`.
|
|
|
|
This is the primary read→write round-trip pattern the template demonstrates.
|
|
|
|
### Entity class display labels
|
|
|
|
The template also demonstrates the entity-class label convention (API v10):
|
|
|
|
- the plugin declares `ENTITY_CLASSES` and exposes it through
|
|
`BuiltinPlugin::entity_classes()`: app `SURVEYMARK`, prefix
|
|
`SURVEY-CLASS:`, and key → label mappings;
|
|
- `MARK_FIRST_SURVEY_POINT` stamps a `SURVEY-CLASS:POINT` string value into
|
|
the point's XDATA alongside the existing marker value.
|
|
|
|
While the plugin is loaded, the host shows marked points as
|
|
"Survey Point (Point)" in the Properties panel title and in the
|
|
`display_type` field of the records/automation APIs; without the plugin they
|
|
are plain "Point" again. Only the stable key round-trips the drawing — the
|
|
label text lives in the plugin and can be reworded or localized without
|
|
touching saved files. The label is display-only: it never governs snapping,
|
|
selection, or any other behavior.
|
|
|
|
### Ribbon integration
|
|
|
|
The plugin registers one ribbon module (`SurveyTools`) with one group
|
|
(`Survey`). Each tool emits a `ModuleEvent::Command(...)` carrying the command
|
|
name. The host routes the command to `BuiltinPlugin::dispatch`.
|
|
|
|
---
|
|
|
|
## Building and running
|
|
|
|
From the workspace root:
|
|
|
|
```bash
|
|
cargo build -p plugin-template-v2
|
|
```
|
|
|
|
The resulting cdylib plus `plugin.toml` (checked in alongside this file) can
|
|
be installed into the host's plugins folder (see `docs/plugin-architecture.md`).
|
|
Replace `plugin.toml`'s `rustc_version` and `acadrust_source` placeholders in
|
|
your packaging step. The release workflow in `docs/plugin-template` shows how.
|
|
|
|
---
|
|
|
|
## Compatibility
|
|
|
|
The template is built against the current `ocs_plugin_api` and declares
|
|
`ApiVersion::CURRENT`. Older plugins compiled against API v2 continue to load
|
|
on an API v3 host because new `HostApi` methods are appended at the end of the
|
|
trait and the host accepts plugin majors from `API_VERSION_MIN_SUPPORTED` up to
|
|
`API_VERSION`.
|