2022-04-25 08:33:38 +00:00
|
|
|
import { Hook, Manifest } from "@plugos/plugos/types";
|
|
|
|
import { System } from "@plugos/plugos/system";
|
|
|
|
import { EventEmitter } from "@plugos/plugos/event";
|
2022-06-17 18:17:22 +00:00
|
|
|
import { ShortcutItem } from "../types";
|
2022-03-29 09:21:32 +00:00
|
|
|
|
|
|
|
export type CommandDef = {
|
|
|
|
name: string;
|
|
|
|
|
2022-04-21 09:46:33 +00:00
|
|
|
contexts?: string[];
|
|
|
|
|
2022-03-29 09:21:32 +00:00
|
|
|
// Bind to keyboard shortcut
|
|
|
|
key?: string;
|
|
|
|
mac?: string;
|
2022-05-06 16:55:04 +00:00
|
|
|
|
2022-06-17 18:17:22 +00:00
|
|
|
// Shortcuts in UI
|
|
|
|
shortcut?: ShortcutDef;
|
2022-05-06 16:55:04 +00:00
|
|
|
};
|
|
|
|
|
2022-06-17 18:17:22 +00:00
|
|
|
export type ShortcutDef = {
|
2022-05-06 16:55:04 +00:00
|
|
|
label: string;
|
2022-03-29 09:21:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export type AppCommand = {
|
|
|
|
command: CommandDef;
|
|
|
|
run: () => Promise<void>;
|
|
|
|
};
|
|
|
|
|
|
|
|
export type CommandHookT = {
|
|
|
|
command?: CommandDef;
|
|
|
|
};
|
|
|
|
|
|
|
|
export type CommandHookEvents = {
|
2022-05-06 16:55:04 +00:00
|
|
|
commandsUpdated(
|
|
|
|
commandMap: Map<string, AppCommand>,
|
2022-06-17 18:17:22 +00:00
|
|
|
appButtons: ShortcutItem[]
|
2022-05-06 16:55:04 +00:00
|
|
|
): void;
|
2022-03-29 09:21:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export class CommandHook
|
|
|
|
extends EventEmitter<CommandHookEvents>
|
|
|
|
implements Hook<CommandHookT>
|
|
|
|
{
|
|
|
|
editorCommands = new Map<string, AppCommand>();
|
2022-06-17 18:17:22 +00:00
|
|
|
shortcutItems: ShortcutItem[] = [];
|
2022-03-29 09:21:32 +00:00
|
|
|
|
|
|
|
buildAllCommands(system: System<CommandHookT>) {
|
|
|
|
this.editorCommands.clear();
|
2022-06-17 18:17:22 +00:00
|
|
|
this.shortcutItems = [];
|
2022-03-29 09:21:32 +00:00
|
|
|
for (let plug of system.loadedPlugs.values()) {
|
|
|
|
for (const [name, functionDef] of Object.entries(
|
|
|
|
plug.manifest!.functions
|
|
|
|
)) {
|
|
|
|
if (!functionDef.command) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const cmd = functionDef.command;
|
|
|
|
this.editorCommands.set(cmd.name, {
|
|
|
|
command: cmd,
|
|
|
|
run: () => {
|
|
|
|
return plug.invoke(name, []);
|
|
|
|
},
|
|
|
|
});
|
2022-06-17 18:17:22 +00:00
|
|
|
if (cmd.shortcut) {
|
|
|
|
this.shortcutItems.push({
|
|
|
|
label: cmd.shortcut.label,
|
2022-05-06 16:55:04 +00:00
|
|
|
run: () => {
|
|
|
|
return plug.invoke(name, []);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2022-03-29 09:21:32 +00:00
|
|
|
}
|
|
|
|
}
|
2022-06-17 18:17:22 +00:00
|
|
|
this.emit("commandsUpdated", this.editorCommands, this.shortcutItems);
|
2022-03-29 09:21:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
apply(system: System<CommandHookT>): void {
|
|
|
|
this.buildAllCommands(system);
|
|
|
|
system.on({
|
|
|
|
plugLoaded: () => {
|
|
|
|
this.buildAllCommands(system);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
validateManifest(manifest: Manifest<CommandHookT>): string[] {
|
|
|
|
let errors = [];
|
|
|
|
for (const [name, functionDef] of Object.entries(manifest.functions)) {
|
|
|
|
if (!functionDef.command) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const cmd = functionDef.command;
|
|
|
|
if (!cmd.name) {
|
|
|
|
errors.push(`Function ${name} has a command but no name`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|