use crate::input::command_registry::CommandRegistry;
use std::path::Path;
use std::sync::{Arc, RwLock};
#[cfg(feature = "plugins")]
use super::thread::PluginThreadHandle;
pub struct PluginManager {
#[cfg(feature = "plugins")]
inner: Option<PluginThreadHandle>,
#[cfg(not(feature = "plugins"))]
_phantom: std::marker::PhantomData<()>,
}
impl PluginManager {
pub fn new(enable: bool, command_registry: Arc<RwLock<CommandRegistry>>) -> Self {
#[cfg(feature = "plugins")]
{
if enable {
match PluginThreadHandle::spawn(command_registry) {
Ok(handle) => {
return Self {
inner: Some(handle),
}
}
Err(e) => {
tracing::error!("Failed to spawn TypeScript plugin thread: {}", e);
#[cfg(debug_assertions)]
panic!("TypeScript plugin thread creation failed: {}", e);
}
}
} else {
tracing::info!("Plugins disabled via --no-plugins flag");
}
Self { inner: None }
}
#[cfg(not(feature = "plugins"))]
{
let _ = command_registry; if enable {
tracing::warn!("Plugins requested but compiled without plugin support");
}
Self {
_phantom: std::marker::PhantomData,
}
}
}
pub fn is_active(&self) -> bool {
#[cfg(feature = "plugins")]
{
self.inner.is_some()
}
#[cfg(not(feature = "plugins"))]
{
false
}
}
pub fn load_plugins_from_dir(&self, dir: &Path) -> Vec<String> {
#[cfg(feature = "plugins")]
{
if let Some(ref manager) = self.inner {
return manager.load_plugins_from_dir(dir);
}
Vec::new()
}
#[cfg(not(feature = "plugins"))]
{
let _ = dir;
Vec::new()
}
}
pub fn run_hook(&self, hook_name: &str, args: super::hooks::HookArgs) {
#[cfg(feature = "plugins")]
{
if let Some(ref manager) = self.inner {
manager.run_hook(hook_name, args);
}
}
#[cfg(not(feature = "plugins"))]
{
let _ = (hook_name, args);
}
}
pub fn deliver_response(&self, response: super::api::PluginResponse) {
#[cfg(feature = "plugins")]
{
if let Some(ref manager) = self.inner {
manager.deliver_response(response);
}
}
#[cfg(not(feature = "plugins"))]
{
let _ = response;
}
}
pub fn process_commands(&mut self) -> Vec<super::api::PluginCommand> {
#[cfg(feature = "plugins")]
{
if let Some(ref mut manager) = self.inner {
return manager.process_commands();
}
Vec::new()
}
#[cfg(not(feature = "plugins"))]
{
Vec::new()
}
}
#[cfg(feature = "plugins")]
pub fn state_snapshot_handle(&self) -> Option<Arc<RwLock<super::api::EditorStateSnapshot>>> {
self.inner.as_ref().map(|m| m.state_snapshot_handle())
}
#[cfg(feature = "plugins")]
pub fn execute_action_async(
&self,
action_name: &str,
) -> Option<anyhow::Result<super::thread::oneshot::Receiver<anyhow::Result<()>>>> {
self.inner
.as_ref()
.map(|m| m.execute_action_async(action_name))
}
#[cfg(feature = "plugins")]
pub fn list_plugins(&self) -> Vec<super::runtime::TsPluginInfo> {
self.inner
.as_ref()
.map(|m| m.list_plugins())
.unwrap_or_default()
}
#[cfg(feature = "plugins")]
pub fn reload_plugin(&self, name: &str) -> anyhow::Result<()> {
self.inner
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Plugin system not active"))?
.reload_plugin(name)
}
pub fn has_hook_handlers(&self, hook_name: &str) -> bool {
#[cfg(feature = "plugins")]
{
self.inner
.as_ref()
.map(|m| m.has_hook_handlers(hook_name))
.unwrap_or(false)
}
#[cfg(not(feature = "plugins"))]
{
let _ = hook_name;
false
}
}
}