use std::any::Any;
use bitflags::bitflags;
use crate::hooks::{CommandHook, KeyboardHook, LifecycleHook, PaneHook, ThemeHook};
use crate::theme::ThemeDefinition;
use crate::types::{
CustomChartConfig, CustomTableConfig, GaugePaneConfig, PluginContext, StatPaneConfig, Theme,
};
pub type PluginResult<T> = Result<T, PluginError>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PluginError {
InitializationFailed(String),
IncompatibleVersion { required: String, actual: String },
MissingCapability(String),
InvalidConfiguration(String),
MissingDependency(String),
AlreadyRegistered(String),
NotFound(String),
OperationFailed(String),
}
impl std::fmt::Display for PluginError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::InitializationFailed(msg) => write!(f, "Plugin initialization failed: {msg}"),
Self::IncompatibleVersion { required, actual } => {
write!(f, "Incompatible version: requires {required}, got {actual}")
}
Self::MissingCapability(cap) => write!(f, "Missing capability: {cap}"),
Self::InvalidConfiguration(msg) => write!(f, "Invalid configuration: {msg}"),
Self::MissingDependency(dep) => write!(f, "Missing dependency: {dep}"),
Self::AlreadyRegistered(name) => write!(f, "Plugin already registered: {name}"),
Self::NotFound(name) => write!(f, "Plugin not found: {name}"),
Self::OperationFailed(msg) => write!(f, "Operation failed: {msg}"),
}
}
}
impl std::error::Error for PluginError {}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PluginCapabilities: u32 {
const COMMANDS = 1 << 0;
const PANES = 1 << 1;
const KEYBOARD = 1 << 2;
const THEMING = 1 << 3;
const VISUALIZATIONS = 1 << 4;
const DATA_SOURCES = 1 << 5;
const AGENT_COMMANDS = 1 << 6;
const STATUS_LINE = 1 << 7;
const FINDER_SOURCES = 1 << 8;
const CUSTOM_THEMES = 1 << 9;
}
}
#[derive(Debug, Clone)]
pub struct CommandConfig {
pub name: String,
pub aliases: Vec<String>,
pub description: String,
pub accepts_args: bool,
}
#[derive(Debug, Clone)]
pub struct PaneConfig {
pub name: String,
pub label: String,
pub description: String,
pub icon: Option<String>,
}
#[derive(Debug, Clone)]
pub struct KeybindingConfig {
pub keys: String,
pub command: String,
pub description: String,
pub modes: Vec<String>,
}
pub trait Plugin: Any + Send + Sync {
fn name(&self) -> &'static str;
fn version(&self) -> &'static str;
fn description(&self) -> &'static str {
""
}
fn capabilities(&self) -> PluginCapabilities;
fn min_editor_version(&self) -> Option<&'static str> {
None
}
fn dependencies(&self) -> &[&'static str] {
&[]
}
fn init(&mut self, ctx: &PluginContext) -> PluginResult<()>;
fn activate(&mut self, _ctx: &PluginContext) -> PluginResult<()> {
Ok(())
}
fn deactivate(&mut self, _ctx: &PluginContext) -> PluginResult<()> {
Ok(())
}
fn commands(&self) -> Vec<CommandConfig> {
vec![]
}
fn pane_types(&self) -> Vec<PaneConfig> {
vec![]
}
fn keybindings(&self) -> Vec<KeybindingConfig> {
vec![]
}
fn themes(&self) -> Vec<ThemeDefinition> {
vec![]
}
fn custom_table_panes(&self) -> Vec<CustomTableConfig> {
vec![]
}
fn custom_chart_panes(&self) -> Vec<CustomChartConfig> {
vec![]
}
fn custom_stat_panes(&self) -> Vec<StatPaneConfig> {
vec![]
}
fn custom_gauge_panes(&self) -> Vec<GaugePaneConfig> {
vec![]
}
fn lifecycle_hooks(&self) -> Option<Box<dyn LifecycleHook>> {
None
}
fn command_hooks(&self) -> Option<Box<dyn CommandHook>> {
None
}
fn keyboard_hooks(&self) -> Option<Box<dyn KeyboardHook>> {
None
}
fn theme_hooks(&self) -> Option<Box<dyn ThemeHook>> {
None
}
fn pane_hooks(&self) -> Option<Box<dyn PaneHook>> {
None
}
fn execute_command(&mut self, _command: &str, _args: &str, _ctx: &PluginContext) -> bool {
false
}
fn on_theme_changed(&mut self, _theme: Theme) {}
fn refreshable_pane_types(&self) -> Vec<(&str, u32)> {
vec![]
}
fn trigger_pane_refresh(&mut self, _pane_type: &str, _ctx: &PluginContext) -> bool {
false
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}