Skip to content

Commit 1af67a5

Browse files
committed
feat: implement plugin loading callbacks and tracking for installed plugins
Signed-off-by: 7HR4IZ3 <90985774+7HR4IZ3@users.noreply.github.com>
1 parent 64f1d9d commit 1af67a5

2 files changed

Lines changed: 55 additions & 18 deletions

File tree

src/lib/acode.js

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import helpers from "utils/helpers";
4444
import KeyboardEvent from "utils/keyboardEvent";
4545
import Url from "utils/Url";
4646
import constants from "./constants";
47+
import { onPluginLoadCallback, onPluginsLoadCompleteCallback, LOADED_PLUGINS } from "lib/loadPlugins";
4748

4849
export default class Acode {
4950
#modules = {};
@@ -62,6 +63,7 @@ export default class Acode {
6263
},
6364
},
6465
];
66+
#pluginWatchers = {}
6567

6668
constructor() {
6769
const encodingsModule = {
@@ -78,7 +80,7 @@ export default class Acode {
7880
list: themes.list,
7981
update: themes.update,
8082
// Deprecated, not supported anymore
81-
apply: () => {},
83+
apply: () => { },
8284
};
8385

8486
const sidebarAppsModule = {
@@ -285,21 +287,21 @@ export default class Acode {
285287
*/
286288
installPlugin(pluginId, installerPluginName) {
287289
return new Promise((resolve, reject) => {
288-
confirm(
289-
strings.install,
290-
`Do you want to install plugin '${pluginId}'${installerPluginName ? ` requested by ${installerPluginName}` : ""}?`,
291-
)
292-
.then((confirmation) => {
293-
if (!confirmation) {
294-
reject(new Error("User cancelled installation"));
290+
fsOperation(Url.join(PLUGIN_DIR, pluginId))
291+
.exists()
292+
.then((isPluginExists) => {
293+
if (isPluginExists) {
294+
reject(new Error("Plugin already installed"));
295295
return;
296296
}
297297

298-
fsOperation(Url.join(PLUGIN_DIR, pluginId))
299-
.exists()
300-
.then((isPluginExists) => {
301-
if (isPluginExists) {
302-
reject(new Error("Plugin already installed"));
298+
confirm(
299+
strings.install,
300+
`Do you want to install plugin '${pluginId}'${installerPluginName ? ` requested by ${installerPluginName}` : ""}?`,
301+
)
302+
.then((confirmation) => {
303+
if (!confirmation) {
304+
reject(new Error("User cancelled installation"));
303305
return;
304306
}
305307

@@ -398,6 +400,31 @@ export default class Acode {
398400
});
399401
}
400402

403+
[onPluginLoadCallback](pluginId) {
404+
if (this.#pluginWatchers[pluginId]) {
405+
this.#pluginWatchers[pluginId].resolve();
406+
delete this.#pluginWatchers[pluginId];
407+
}
408+
}
409+
410+
[onPluginsLoadCompleteCallback]() {
411+
for (const key in this.#pluginWatchers) {
412+
this.#pluginWatchers[key].reject();
413+
}
414+
}
415+
416+
waitForPlugin(pluginId) {
417+
return new Promise((resolve, reject) => {
418+
if (LOADED_PLUGINS.has(pluginId)) {
419+
return resolve(true);
420+
}
421+
422+
this.#pluginWatchers[pluginId] = {
423+
resolve, reject
424+
}
425+
});
426+
}
427+
401428
get exitAppMessage() {
402429
const numFiles = editorManager.hasUnsavedFiles();
403430
if (numFiles) {

src/lib/loadPlugins.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@ const THEME_IDENTIFIERS = new Set([
2424
"acode.plugin.extra_syntax_highlights",
2525
]);
2626

27+
export const onPluginLoadCallback = Symbol("onPluginLoadCallback");
28+
export const onPluginsLoadCompleteCallback = Symbol("onPluginsLoadCompleteCallback");
29+
30+
export const LOADED_PLUGINS = new Set();
31+
2732
export default async function loadPlugins(loadOnlyTheme = false) {
2833
const plugins = await fsOperation(PLUGIN_DIR).lsDir();
2934
const results = [];
3035
const failedPlugins = [];
31-
const loadedPlugins = new Set();
3236

3337
if (plugins.length > 0) {
3438
toast(strings["loading plugins"]);
@@ -42,15 +46,15 @@ export default async function loadPlugins(loadOnlyTheme = false) {
4246
// Only load theme plugins matching current theme
4347
pluginsToLoad = plugins.filter((pluginDir) => {
4448
const pluginId = Url.basename(pluginDir.url);
45-
return isThemePlugin(pluginId) && !loadedPlugins.has(pluginId);
49+
return isThemePlugin(pluginId) && !LOADED_PLUGINS.has(pluginId);
4650
});
4751
} else {
4852
// Load non-theme plugins that aren't loaded yet and are enabled
4953
pluginsToLoad = plugins.filter((pluginDir) => {
5054
const pluginId = Url.basename(pluginDir.url);
5155
return (
5256
!isThemePlugin(pluginId) &&
53-
!loadedPlugins.has(pluginId) &&
57+
!LOADED_PLUGINS.has(pluginId) &&
5458
enabledMap[pluginId] !== true
5559
);
5660
});
@@ -74,17 +78,22 @@ export default async function loadPlugins(loadOnlyTheme = false) {
7478

7579
try {
7680
await loadPlugin(pluginId);
77-
loadedPlugins.add(pluginId);
81+
LOADED_PLUGINS.add(pluginId);
82+
83+
acode[onPluginLoadCallback](pluginId);
84+
7885
results.push(true);
7986
} catch (error) {
8087
console.error(`Error loading plugin ${pluginId}:`, error);
8188
failedPlugins.push(pluginId);
8289
results.push(false);
8390
}
8491
});
85-
92+
8693
await Promise.allSettled(loadPromises);
8794

95+
acode[onPluginsLoadCompleteCallback](pluginId);
96+
8897
if (failedPlugins.length > 0) {
8998
setTimeout(() => {
9099
cleanupFailedPlugins(failedPlugins).catch((error) => {
@@ -95,6 +104,7 @@ export default async function loadPlugins(loadOnlyTheme = false) {
95104
return results.filter(Boolean).length;
96105
}
97106

107+
98108
function isThemePlugin(pluginId) {
99109
// Convert to lowercase for case-insensitive matching
100110
const id = pluginId.toLowerCase();

0 commit comments

Comments
 (0)