Skip to main content

cvkg_cli/
plugin.rs

1//! Plugin system for extending the CVKG CLI.
2//!
3//! Plugins can register custom commands, build steps, and asset processors.
4//!
5//! # Example
6//!
7//! ```ignore
8//! use cvkg_cli::plugin::{Plugin, PluginContext, CommandResult};
9//!
10//! struct MyPlugin;
11//!
12//! impl Plugin for MyPlugin {
13//!     fn name(&self) -> &str { "my-plugin" }
14//!     fn register(&self, ctx: &mut PluginContext) {
15//!         ctx.register_command("my-cmd", |args| {
16//!             println!("Hello from plugin!");
17//!             CommandResult::Ok
18//!         });
19//!     }
20//! }
21//! ```
22
23/// Result of a plugin command execution.
24pub enum CommandResult {
25    /// Command executed successfully.
26    Ok,
27    /// Command failed with an error message.
28    Error(String),
29}
30
31/// Context passed to plugins during registration.
32pub trait PluginContext {
33    /// Register a custom command.
34    fn register_command(&mut self, name: &str, handler: fn(args: &[String]) -> CommandResult);
35    /// Register a build step that runs after the default build.
36    fn register_build_step(&mut self, name: &str, handler: fn() -> anyhow::Result<()>);
37    /// Register an asset processor for a given file extension.
38    fn register_asset_processor(
39        &mut self,
40        extension: &str,
41        handler: fn(path: &std::path::Path) -> anyhow::Result<()>,
42    );
43}
44
45/// Plugin trait for extending the CVKG CLI.
46///
47/// Implement this trait to add custom commands, build steps, or asset processors.
48pub trait Plugin: Send + Sync {
49    /// Unique name for this plugin.
50    fn name(&self) -> &str;
51    /// Called during CLI initialization to register commands and hooks.
52    fn register(&self, ctx: &mut dyn PluginContext);
53    /// Called before the CLI shuts down.
54    fn shutdown(&self) {}
55}
56
57/// Registry for loaded plugins.
58pub struct PluginRegistry {
59    plugins: Vec<Box<dyn Plugin>>,
60}
61
62impl PluginRegistry {
63    /// Create a new empty plugin registry.
64    pub fn new() -> Self {
65        Self {
66            plugins: Vec::new(),
67        }
68    }
69
70    /// Register a plugin.
71    pub fn register<P: Plugin + 'static>(&mut self, plugin: P) {
72        log::info!("Registering plugin: {}", plugin.name());
73        self.plugins.push(Box::new(plugin));
74    }
75
76    /// Get the number of registered plugins.
77    pub fn len(&self) -> usize {
78        self.plugins.len()
79    }
80
81    /// Check if no plugins are registered.
82    pub fn is_empty(&self) -> bool {
83        self.plugins.is_empty()
84    }
85}
86
87impl Default for PluginRegistry {
88    fn default() -> Self {
89        Self::new()
90    }
91}