Akos Kitta fa4626bf14 feat: support updates in lib/boards widget
- can show badge with updates count,
 - better hover for libraries and platforms,
 - save/restore widget state (Closes #1398),
 - fixed `sentence` and `paragraph` order (Ref #1611)

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
2023-03-16 10:03:30 +01:00

152 lines
4.0 KiB
TypeScript

import {
CommandHandler,
CommandRegistry,
} from '@theia/core/lib/common/command';
import {
Disposable,
DisposableCollection,
} from '@theia/core/lib/common/disposable';
import {
MenuModelRegistry,
MenuPath,
SubMenuOptions,
} from '@theia/core/lib/common/menu';
import { unregisterSubmenu } from './arduino-menus';
export interface MenuTemplate {
readonly menuLabel: string;
}
export function isMenuTemplate(arg: unknown): arg is MenuTemplate {
return (
typeof arg === 'object' &&
(arg as MenuTemplate).menuLabel !== undefined &&
typeof (arg as MenuTemplate).menuLabel === 'string'
);
}
export interface MenuActionTemplate extends MenuTemplate {
readonly menuPath: MenuPath;
readonly handler: CommandHandler;
/**
* If not defined the insertion oder will be the order string.
*/
readonly order?: string;
}
export function isMenuActionTemplate(
arg: MenuTemplate
): arg is MenuActionTemplate {
return (
isMenuTemplate(arg) &&
(arg as MenuActionTemplate).handler !== undefined &&
typeof (arg as MenuActionTemplate).handler === 'object' &&
(arg as MenuActionTemplate).menuPath !== undefined &&
Array.isArray((arg as MenuActionTemplate).menuPath)
);
}
export function menuActionWithCommandDelegate(
template: Omit<MenuActionTemplate, 'handler' | 'menuLabel'> & {
command: string;
},
commandRegistry: CommandRegistry
): MenuActionTemplate {
const id = template.command;
const command = commandRegistry.getCommand(id);
if (!command) {
throw new Error(`Could not find the registered command with ID: ${id}`);
}
return {
...template,
menuLabel: command.label ?? id,
handler: {
execute: (args) => commandRegistry.executeCommand(id, args),
isEnabled: (args) => commandRegistry.isEnabled(id, args),
isVisible: (args) => commandRegistry.isVisible(id, args),
isToggled: (args) => commandRegistry.isToggled(id, args),
},
};
}
export interface SubmenuTemplate extends MenuTemplate {
readonly menuLabel: string;
readonly submenuPath: MenuPath;
readonly options?: SubMenuOptions;
}
interface Services {
readonly commandRegistry: CommandRegistry;
readonly menuRegistry: MenuModelRegistry;
}
class MenuIndexCounter {
private _counter: number;
constructor(counter = 0) {
this._counter = counter;
}
getAndIncrement(): number {
const counter = this._counter;
this._counter++;
return counter;
}
}
export function registerMenus(
options: {
contextId: string;
templates: Array<MenuActionTemplate | SubmenuTemplate>;
} & Services
): Disposable {
const { templates } = options;
const menuIndexCounter = new MenuIndexCounter();
return new DisposableCollection(
...templates.map((template) =>
registerMenu({ template, menuIndexCounter, ...options })
)
);
}
function registerMenu(
options: {
contextId: string;
menuIndexCounter: MenuIndexCounter;
template: MenuActionTemplate | SubmenuTemplate;
} & Services
): Disposable {
const {
template,
commandRegistry,
menuRegistry,
contextId,
menuIndexCounter,
} = options;
if (isMenuActionTemplate(template)) {
const { menuLabel, menuPath, handler, order } = template;
const id = generateCommandId(contextId, menuLabel, menuPath);
const index = menuIndexCounter.getAndIncrement();
return new DisposableCollection(
commandRegistry.registerCommand({ id }, handler),
menuRegistry.registerMenuAction(menuPath, {
commandId: id,
label: menuLabel,
order: typeof order === 'string' ? order : String(index).padStart(4),
})
);
} else {
const { menuLabel, submenuPath, options } = template;
return new DisposableCollection(
menuRegistry.registerSubmenu(submenuPath, menuLabel, options),
Disposable.create(() => unregisterSubmenu(submenuPath, menuRegistry))
);
}
function generateCommandId(
contextId: string,
menuLabel: string,
menuPath: MenuPath
): string {
return `arduino-${contextId}-context-${menuPath.join('-')}-${menuLabel}`;
}
}