ATL-302: Added built-in examples to the app.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta
2020-08-13 13:34:56 +02:00
committed by Akos Kitta
parent b5d7c3b45d
commit 1c9fcd0cdf
27 changed files with 728 additions and 101 deletions

View File

@@ -2,6 +2,7 @@ import { inject, injectable, interfaces } from 'inversify';
import URI from '@theia/core/lib/common/uri';
import { ILogger } from '@theia/core/lib/common/logger';
import { FileSystem } from '@theia/filesystem/lib/common';
import { MaybePromise } from '@theia/core/lib/common/types';
import { LabelProvider } from '@theia/core/lib/browser/label-provider';
import { MessageService } from '@theia/core/lib/common/message-service';
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
@@ -13,11 +14,12 @@ import { Command, CommandRegistry, CommandContribution, CommandService } from '@
import { EditorMode } from '../editor-mode';
import { SketchesServiceClientImpl } from '../../common/protocol/sketches-service-client-impl';
import { SketchesService, ConfigService, FileSystemExt, Sketch } from '../../common/protocol';
import { FrontendApplicationContribution, FrontendApplication } from '@theia/core/lib/browser';
export { Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry, URI, Sketch, open };
@injectable()
export abstract class Contribution implements CommandContribution, MenuContribution, KeybindingContribution, TabBarToolbarContribution {
export abstract class Contribution implements CommandContribution, MenuContribution, KeybindingContribution, TabBarToolbarContribution, FrontendApplicationContribution {
@inject(ILogger)
protected readonly logger: ILogger;
@@ -37,6 +39,9 @@ export abstract class Contribution implements CommandContribution, MenuContribut
@inject(LabelProvider)
protected readonly labelProvider: LabelProvider;
onStart(app: FrontendApplication): MaybePromise<void> {
}
registerCommands(registry: CommandRegistry): void {
}
@@ -75,11 +80,12 @@ export abstract class SketchContribution extends Contribution {
}
export namespace Contribution {
export function configure<T>(bind: interfaces.Bind, serviceIdentifier: interfaces.ServiceIdentifier<T>): void {
export function configure<T>(bind: interfaces.Bind, serviceIdentifier: typeof Contribution): void {
bind(serviceIdentifier).toSelf().inSingletonScope();
bind(CommandContribution).toService(serviceIdentifier);
bind(MenuContribution).toService(serviceIdentifier);
bind(KeybindingContribution).toService(serviceIdentifier);
bind(TabBarToolbarContribution).toService(serviceIdentifier);
bind(FrontendApplicationContribution).toService(serviceIdentifier);
}
}

View File

@@ -0,0 +1,74 @@
import { inject, injectable } from 'inversify';
import { MenuPath, SubMenuOptions } from '@theia/core/lib/common/menu';
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
import { OpenSketch } from './open-sketch';
import { ArduinoMenus } from '../menu/arduino-menus';
import { MainMenuManager } from '../../common/main-menu-manager';
import { ExamplesService, ExampleContainer } from '../../common/protocol/examples-service';
import { SketchContribution, CommandRegistry, MenuModelRegistry } from './contribution';
@injectable()
export class Examples extends SketchContribution {
@inject(MainMenuManager)
protected readonly menuManager: MainMenuManager;
@inject(ExamplesService)
protected readonly examplesService: ExamplesService;
@inject(CommandRegistry)
protected readonly commandRegistry: CommandRegistry;
@inject(MenuModelRegistry)
protected readonly menuRegistry: MenuModelRegistry;
protected readonly toDisposeBeforeRegister = new DisposableCollection();
onStart(): void {
this.registerExamples(); // no `await`
}
protected async registerExamples() {
let exampleContainer: ExampleContainer | undefined;
try {
exampleContainer = await this.examplesService.all();
} catch (e) {
console.error('Could not initialize built-in examples.', e);
}
if (!exampleContainer) {
this.messageService.error('Could not initialize built-in examples.');
return;
}
this.toDisposeBeforeRegister.dispose();
this.registerRecursively(exampleContainer, ArduinoMenus.FILE__SKETCH_GROUP, this.toDisposeBeforeRegister, { order: '4' });
this.menuManager.update();
}
registerRecursively(
exampleContainer: ExampleContainer,
menuPath: MenuPath,
pushToDispose: DisposableCollection = new DisposableCollection(),
options?: SubMenuOptions): void {
const { label, sketches, children } = exampleContainer;
const submenuPath = [...menuPath, label];
// TODO: unregister submenu? https://github.com/eclipse-theia/theia/issues/7300
this.menuRegistry.registerSubmenu(submenuPath, label, options);
children.forEach(child => this.registerRecursively(child, submenuPath, pushToDispose));
for (const sketch of sketches) {
const { uri } = sketch;
const commandId = `arduino-open-example-${submenuPath.join(':')}--${uri}`;
const command = { id: commandId };
const handler = {
execute: async () => {
const sketch = await this.sketchService.cloneExample(uri);
this.commandService.executeCommand(OpenSketch.Commands.OPEN_SKETCH.id, sketch);
}
};
pushToDispose.push(this.commandRegistry.registerCommand(command, handler));
this.menuRegistry.registerMenuAction(submenuPath, { commandId, label: sketch.name });
pushToDispose.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
}
}
}

View File

@@ -0,0 +1,36 @@
import { /*inject,*/ injectable } from 'inversify';
// import { remote } from 'electron';
// import { ArduinoMenus } from '../menu/arduino-menus';
import { SketchContribution, Command, CommandRegistry } from './contribution';
import { LibraryPackage } from '../../common/protocol';
// import { SaveAsSketch } from './save-as-sketch';
// import { EditorManager } from '@theia/editor/lib/browser';
// import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor';
@injectable()
export class IncludeLibrary extends SketchContribution {
registerCommands(registry: CommandRegistry): void {
registry.registerCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY, {
execute: async arg => {
if (LibraryPackage.is(arg)) {
this.includeLibrary(arg);
}
}
});
}
protected async includeLibrary(library: LibraryPackage): Promise<void> {
// Always include to the main sketch file unless a c, cpp, or h file is the active one.
console.log('INCLUDE', library);
}
}
export namespace IncludeLibrary {
export namespace Commands {
export const INCLUDE_LIBRARY: Command = {
id: 'arduino-include-library'
};
}
}

View File

@@ -6,6 +6,8 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
import { SketchContribution, Sketch, URI, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
import { ExamplesService } from '../../common/protocol/examples-service';
import { Examples } from './examples';
@injectable()
export class OpenSketch extends SketchContribution {
@@ -16,6 +18,12 @@ export class OpenSketch extends SketchContribution {
@inject(ContextMenuRenderer)
protected readonly contextMenuRenderer: ContextMenuRenderer;
@inject(Examples)
protected readonly examples: Examples;
@inject(ExamplesService)
protected readonly examplesService: ExamplesService;
protected readonly toDisposeBeforeCreateNewContextMenu = new DisposableCollection();
registerCommands(registry: CommandRegistry): void {
@@ -53,6 +61,14 @@ export class OpenSketch extends SketchContribution {
});
this.toDisposeBeforeCreateNewContextMenu.push(Disposable.create(() => this.menuRegistry.unregisterMenuAction(command)));
}
try {
const { children } = await this.examplesService.all();
for (const child of children) {
this.examples.registerRecursively(child, ArduinoMenus.OPEN_SKETCH__CONTEXT__EXAMPLES_GROUP, this.toDisposeBeforeCreateNewContextMenu);
}
} catch (e) {
console.error('Error when collecting built-in examples.', e);
}
const options = {
menuPath: ArduinoMenus.OPEN_SKETCH__CONTEXT,
anchor: {