Commit Graph
7 Commits
Author SHA1 Message Date
Sebastian 60eb7b086e 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.
2026-10-15 22:39:09 +02:00
Karim Jerbi 9cf9ff2c5c style: apply cargo fmt across workspace 2026-10-11 03:14:29 +01:00
Hakan Seven 7b4cef41f7 Complete parametric ribbon and constraint tools 2026-09-14 01:05:39 +03:00
Hakan SevenandClaude Opus 4.8 77c0c5a9d0 feat(plugin): surface loaded plugin commands in command-line autocomplete
Autocomplete suggestions came only from all_registered_command_names() —
the compile-time inventory registry returning &'static str — so
runtime-loaded plugin commands could never appear. Typing a plugin's
command prefix (e.g. `LS_`) showed nothing even with the plugin loaded
and its ribbon tab active; dispatch worked, only discovery was blind.

Collect each enabled plugin's ribbon ToolDef command ids plus its
manifest command_prefixes into a dynamic candidate pool
(OwnedRibbonGroup::command_ids → PluginManager::command_names →
plugin_command_names), refreshed in rebuild_ribbon_modules on startup
load, settings reload, and every enable/disable toggle. ranked_matches
now merges this pool with the static registry and returns owned strings.

A plugin.toml `commands = [...]` list for sub-verbs with no ribbon button
(e.g. LS_AUTOLABEL) stays a follow-up — it's a plugin-API surface change.

Closes #272

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 23:01:53 +03:00
Karim Jerbi 73b05e1dec perf(core): cache ribbon_groups() with OnceLock, avoid per-frame tree allocations
Change CadModule::ribbon_groups() from -> Vec<RibbonGroup> to -> &[RibbonGroup],
backed by a per-module OnceLock cache. The ribbon group tree is static data
(&'static str, Copy enums) that was being fully reconstructed — Vecs, String
clones, enum discriminants — on every call, including all three per-frame
call sites (view(), dropdown_overlay(), style_combo_overlay()).

- 7 built-in modules + 2 plugin templates cache via function-local OnceLock.
  Safe because each is a unit struct with exactly one instance per process
  (plugins run in isolated child processes; see PluginProcess::spawn()).
- SharedCadModule avoids the static pattern entirely, storing groups in an
  instance field (owned.rs).
- IPC runner converts &RibbonGroup -> OwnedRibbonGroup directly via new
  From<&T> impls, avoiding an intermediate clone.
- render_small/render_large and the two make_tool_row closures now borrow
  (&RibbonItem, &[ToolDef]) instead of taking ownership, so the view loop
  doesn't need to clone items to satisfy the old by-value signatures.
- Various match-ergonomics deref fixes (*id, *default, *icon, etc.) from
  the &RibbonItem pattern change.
2026-07-02 21:00:57 +01:00
Sebastian 2b898d6f22 Fix 4: shared-memory 2026-06-25 00:01:36 +03:00
Sebastian dcfaed0182 Initial commit 2026-06-25 00:01:36 +03:00