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}