Skip to main content

ass_editor/extensions/
manager_loading.rs

1//! Extension loading, initialization, and teardown for the manager.
2//!
3//! Covers registering extensions, running their initialization and shutdown
4//! lifecycle hooks, and unloading them along with their registered commands.
5
6use crate::core::Result;
7
8use super::command::ExtensionState;
9use super::context::ExtensionContext;
10use super::extension::EditorExtension;
11use super::manager::ExtensionManager;
12
13#[cfg(not(feature = "std"))]
14use alloc::{boxed::Box, format, string::ToString};
15
16impl ExtensionManager {
17    /// Load an extension
18    pub fn load_extension(&mut self, extension: Box<dyn EditorExtension>) -> Result<()> {
19        let extension_name = extension.info().name.clone();
20        let dependencies = extension.info().dependencies.clone();
21
22        // Check for dependency conflicts
23        let has_deps = self.with_inner(|inner| {
24            dependencies
25                .iter()
26                .all(|dep| inner.extension_states.contains_key(dep))
27        });
28
29        if !has_deps {
30            return Err(crate::core::EditorError::CommandFailed {
31                message: format!("Extension '{extension_name}' has unmet dependencies"),
32            });
33        }
34
35        self.with_inner_mut(|inner| {
36            if inner.extensions.contains_key(&extension_name) {
37                return Err(crate::core::EditorError::CommandFailed {
38                    message: format!("Extension '{extension_name}' is already loaded"),
39                });
40            }
41
42            inner.extensions.insert(extension_name.clone(), extension);
43            inner
44                .extension_states
45                .insert(extension_name.clone(), ExtensionState::Uninitialized);
46            Ok(())
47        })
48    }
49
50    /// Initialize an extension
51    pub fn initialize_extension(
52        &mut self,
53        extension_name: &str,
54        context: &mut dyn ExtensionContext,
55    ) -> Result<()> {
56        self.with_inner_mut(|inner| {
57            inner
58                .extension_states
59                .insert(extension_name.to_string(), ExtensionState::Initializing);
60
61            if let Some(extension) = inner.extensions.get_mut(extension_name) {
62                match extension.initialize(context) {
63                    Ok(()) => {
64                        inner
65                            .extension_states
66                            .insert(extension_name.to_string(), ExtensionState::Active);
67
68                        // Register commands
69                        for command in extension.commands() {
70                            inner
71                                .commands
72                                .insert(command.id.clone(), (extension_name.to_string(), command));
73                        }
74
75                        Ok(())
76                    }
77                    Err(e) => {
78                        inner
79                            .extension_states
80                            .insert(extension_name.to_string(), ExtensionState::Error);
81                        Err(e)
82                    }
83                }
84            } else {
85                Err(crate::core::EditorError::CommandFailed {
86                    message: format!("Extension '{extension_name}' not found"),
87                })
88            }
89        })
90    }
91
92    /// Unload an extension
93    pub fn unload_extension(
94        &mut self,
95        extension_name: &str,
96        context: &mut dyn ExtensionContext,
97    ) -> Result<()> {
98        // Shutdown the extension first
99        self.shutdown_extension(extension_name, context)?;
100
101        self.with_inner_mut(|inner| {
102            // Remove the extension
103            inner.extensions.remove(extension_name);
104            inner.extension_states.remove(extension_name);
105
106            // Remove commands
107            inner
108                .commands
109                .retain(|_, (ext_name, _)| ext_name != extension_name);
110
111            // Remove extension data
112            inner.extension_data.remove(extension_name);
113        });
114
115        Ok(())
116    }
117
118    /// Shutdown an extension
119    fn shutdown_extension(
120        &mut self,
121        extension_name: &str,
122        context: &mut dyn ExtensionContext,
123    ) -> Result<()> {
124        self.with_inner_mut(|inner| {
125            inner
126                .extension_states
127                .insert(extension_name.to_string(), ExtensionState::ShuttingDown);
128
129            if let Some(extension) = inner.extensions.get_mut(extension_name) {
130                extension.shutdown(context)?;
131                inner
132                    .extension_states
133                    .insert(extension_name.to_string(), ExtensionState::Shutdown);
134            }
135            Ok(())
136        })
137    }
138}