Skip to content

#53 Refresh menus when opening example/recent fails. #1333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 4, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 71 additions & 19 deletions arduino-ide-extension/src/browser/contributions/examples.ts
Original file line number Diff line number Diff line change
@@ -21,23 +21,33 @@ import {
MenuModelRegistry,
} from './contribution';
import { NotificationCenter } from '../notification-center';
import { Board, SketchRef, SketchContainer } from '../../common/protocol';
import {
Board,
SketchRef,
SketchContainer,
SketchesError,
Sketch,
CoreService,
} from '../../common/protocol';
import { nls } from '@theia/core/lib/common';

@injectable()
export abstract class Examples extends SketchContribution {
@inject(CommandRegistry)
protected readonly commandRegistry: CommandRegistry;
private readonly commandRegistry: CommandRegistry;

@inject(MenuModelRegistry)
protected readonly menuRegistry: MenuModelRegistry;
private readonly menuRegistry: MenuModelRegistry;

@inject(MainMenuManager)
protected readonly menuManager: MainMenuManager;

@inject(ExamplesService)
protected readonly examplesService: ExamplesService;

@inject(CoreService)
protected readonly coreService: CoreService;

@inject(BoardsServiceProvider)
protected readonly boardsServiceClient: BoardsServiceProvider;

@@ -50,10 +60,16 @@ export abstract class Examples extends SketchContribution {
);
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars
protected handleBoardChanged(board: Board | undefined): void {
// NOOP
}

protected abstract update(options?: {
board?: Board | undefined;
forceRefresh?: boolean;
}): void;

override registerMenus(registry: MenuModelRegistry): void {
try {
// This is a hack the ensures the desired menu ordering! We cannot use https://github.com/eclipse-theia/theia/pull/8377 due to ATL-222.
@@ -149,23 +165,54 @@ export abstract class Examples extends SketchContribution {
protected createHandler(uri: string): CommandHandler {
return {
execute: async () => {
const sketch = await this.sketchService.cloneExample(uri);
return this.commandService.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
);
const sketch = await this.clone(uri);
if (sketch) {
try {
return this.commandService.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
);
} catch (err) {
if (SketchesError.NotFound.is(err)) {
// Do not toast the error message. It's handled by the `Open Sketch` command.
this.update({
board: this.boardsServiceClient.boardsConfig.selectedBoard,
forceRefresh: true,
});
} else {
throw err;
}
}
}
},
};
}

private async clone(uri: string): Promise<Sketch | undefined> {
try {
const sketch = await this.sketchService.cloneExample(uri);
return sketch;
} catch (err) {
if (SketchesError.NotFound.is(err)) {
this.messageService.error(err.message);
this.update({
board: this.boardsServiceClient.boardsConfig.selectedBoard,
forceRefresh: true,
});
} else {
throw err;
}
}
}
}

@injectable()
export class BuiltInExamples extends Examples {
override async onReady(): Promise<void> {
this.register(); // no `await`
this.update(); // no `await`
}

protected async register(): Promise<void> {
protected override async update(): Promise<void> {
let sketchContainers: SketchContainer[] | undefined;
try {
sketchContainers = await this.examplesService.builtIns();
@@ -197,29 +244,34 @@ export class BuiltInExamples extends Examples {
@injectable()
export class LibraryExamples extends Examples {
@inject(NotificationCenter)
protected readonly notificationCenter: NotificationCenter;
private readonly notificationCenter: NotificationCenter;

protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
private readonly queue = new PQueue({ autoStart: true, concurrency: 1 });

override onStart(): void {
this.notificationCenter.onLibraryDidInstall(() => this.register());
this.notificationCenter.onLibraryDidUninstall(() => this.register());
this.notificationCenter.onLibraryDidInstall(() => this.update());
this.notificationCenter.onLibraryDidUninstall(() => this.update());
}

override async onReady(): Promise<void> {
this.register(); // no `await`
this.update(); // no `await`
}

protected override handleBoardChanged(board: Board | undefined): void {
this.register(board);
this.update({ board });
}

protected async register(
board: Board | undefined = this.boardsServiceClient.boardsConfig
.selectedBoard
protected override async update(
options: { board?: Board; forceRefresh?: boolean } = {
board: this.boardsServiceClient.boardsConfig.selectedBoard,
}
): Promise<void> {
const { board, forceRefresh } = options;
return this.queue.add(async () => {
this.toDispose.dispose();
if (forceRefresh) {
await this.coreService.refresh();
}
const fqbn = board?.fqbn;
const name = board?.name;
// Shows all examples when no board is selected, or the platform of the currently selected board is not installed.
9 changes: 0 additions & 9 deletions arduino-ide-extension/src/browser/contributions/new-sketch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { nls } from '@theia/core/lib/common';
import { injectable } from '@theia/core/shared/inversify';
import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
import {
SketchContribution,
URI,
@@ -17,11 +16,6 @@ export class NewSketch extends SketchContribution {
registry.registerCommand(NewSketch.Commands.NEW_SKETCH, {
execute: () => this.newSketch(),
});
registry.registerCommand(NewSketch.Commands.NEW_SKETCH__TOOLBAR, {
isVisible: (widget) =>
ArduinoToolbar.is(widget) && widget.side === 'left',
execute: () => registry.executeCommand(NewSketch.Commands.NEW_SKETCH.id),
});
}

override registerMenus(registry: MenuModelRegistry): void {
@@ -54,8 +48,5 @@ export namespace NewSketch {
export const NEW_SKETCH: Command = {
id: 'arduino-new-sketch',
};
export const NEW_SKETCH__TOOLBAR: Command = {
id: 'arduino-new-sketch--toolbar',
};
}
}
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ import { MainMenuManager } from '../../common/main-menu-manager';
import { OpenSketch } from './open-sketch';
import { NotificationCenter } from '../notification-center';
import { nls } from '@theia/core/lib/common';
import { SketchesError } from '../../common/protocol';

@injectable()
export class OpenRecentSketch extends SketchContribution {
@@ -33,7 +34,7 @@ export class OpenRecentSketch extends SketchContribution {
@inject(NotificationCenter)
protected readonly notificationCenter: NotificationCenter;

protected toDisposeBeforeRegister = new Map<string, DisposableCollection>();
protected toDispose = new DisposableCollection();

override onStart(): void {
this.notificationCenter.onRecentSketchesDidChange(({ sketches }) =>
@@ -42,8 +43,12 @@ export class OpenRecentSketch extends SketchContribution {
}

override async onReady(): Promise<void> {
this.update();
}

private update(forceUpdate?: boolean): void {
this.sketchService
.recentlyOpenedSketches()
.recentlyOpenedSketches(forceUpdate)
.then((sketches) => this.refreshMenu(sketches));
}

@@ -62,19 +67,25 @@ export class OpenRecentSketch extends SketchContribution {

protected register(sketches: Sketch[]): void {
const order = 0;
this.toDispose.dispose();
for (const sketch of sketches) {
const { uri } = sketch;
const toDispose = this.toDisposeBeforeRegister.get(uri);
if (toDispose) {
toDispose.dispose();
}
const command = { id: `arduino-open-recent--${uri}` };
const handler = {
execute: () =>
this.commandRegistry.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
),
execute: async () => {
try {
await this.commandRegistry.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
);
} catch (err) {
if (SketchesError.NotFound.is(err)) {
this.update(true);
} else {
throw err;
}
}
},
};
this.commandRegistry.registerCommand(command, handler);
this.menuRegistry.registerMenuAction(
@@ -85,17 +96,16 @@ export class OpenRecentSketch extends SketchContribution {
order: String(order),
}
);
this.toDisposeBeforeRegister.set(
sketch.uri,
this.toDispose.pushAll([
new DisposableCollection(
Disposable.create(() =>
this.commandRegistry.unregisterCommand(command)
),
Disposable.create(() =>
this.menuRegistry.unregisterMenuAction(command)
)
)
);
),
]);
}
}
}
151 changes: 42 additions & 109 deletions arduino-ide-extension/src/browser/contributions/open-sketch.ts
Original file line number Diff line number Diff line change
@@ -1,115 +1,44 @@
import { inject, injectable } from '@theia/core/shared/inversify';
import * as remote from '@theia/core/electron-shared/@electron/remote';
import { MaybePromise } from '@theia/core/lib/common/types';
import { Widget, ContextMenuRenderer } from '@theia/core/lib/browser';
import {
Disposable,
DisposableCollection,
} from '@theia/core/lib/common/disposable';
import { nls } from '@theia/core/lib/common/nls';
import { injectable } from '@theia/core/shared/inversify';
import { SketchesError, SketchRef } from '../../common/protocol';
import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
import {
SketchContribution,
Sketch,
URI,
Command,
CommandRegistry,
MenuModelRegistry,
KeybindingRegistry,
MenuModelRegistry,
Sketch,
SketchContribution,
URI,
} from './contribution';
import { ExamplesService } from '../../common/protocol/examples-service';
import { BuiltInExamples } from './examples';
import { Sketchbook } from './sketchbook';
import { SketchContainer } from '../../common/protocol';
import { nls } from '@theia/core/lib/common';

export type SketchLocation = string | URI | SketchRef;
export namespace SketchLocation {
export function toUri(location: SketchLocation): URI {
if (typeof location === 'string') {
return new URI(location);
} else if (SketchRef.is(location)) {
return toUri(location.uri);
} else {
return location;
}
}
export function is(arg: unknown): arg is SketchLocation {
return typeof arg === 'string' || arg instanceof URI || SketchRef.is(arg);
}
}

@injectable()
export class OpenSketch extends SketchContribution {
@inject(MenuModelRegistry)
private readonly menuRegistry: MenuModelRegistry;

@inject(ContextMenuRenderer)
private readonly contextMenuRenderer: ContextMenuRenderer;

@inject(BuiltInExamples)
private readonly builtInExamples: BuiltInExamples;

@inject(ExamplesService)
private readonly examplesService: ExamplesService;

@inject(Sketchbook)
private readonly sketchbook: Sketchbook;

private readonly toDispose = new DisposableCollection();

override registerCommands(registry: CommandRegistry): void {
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH, {
execute: (arg) =>
Sketch.is(arg) ? this.openSketch(arg) : this.openSketch(),
});
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH__TOOLBAR, {
isVisible: (widget) =>
ArduinoToolbar.is(widget) && widget.side === 'left',
execute: async (_: Widget, target: EventTarget) => {
const container = await this.sketchService.getSketches({
exclude: ['**/hardware/**'],
});
if (SketchContainer.isEmpty(container)) {
this.openSketch();
} else {
this.toDispose.dispose();
if (!(target instanceof HTMLElement)) {
return;
}
const { parentElement } = target;
if (!parentElement) {
return;
}

this.menuRegistry.registerMenuAction(
ArduinoMenus.OPEN_SKETCH__CONTEXT__OPEN_GROUP,
{
commandId: OpenSketch.Commands.OPEN_SKETCH.id,
label: nls.localize(
'vscode/workspaceActions/openFileFolder',
'Open...'
),
}
);
this.toDispose.push(
Disposable.create(() =>
this.menuRegistry.unregisterMenuAction(
OpenSketch.Commands.OPEN_SKETCH
)
)
);
this.sketchbook.registerRecursively(
[...container.children, ...container.sketches],
ArduinoMenus.OPEN_SKETCH__CONTEXT__RECENT_GROUP,
this.toDispose
);
try {
const containers = await this.examplesService.builtIns();
for (const container of containers) {
this.builtInExamples.registerRecursively(
container,
ArduinoMenus.OPEN_SKETCH__CONTEXT__EXAMPLES_GROUP,
this.toDispose
);
}
} catch (e) {
console.error('Error when collecting built-in examples.', e);
}
const options = {
menuPath: ArduinoMenus.OPEN_SKETCH__CONTEXT,
anchor: {
x: parentElement.getBoundingClientRect().left,
y:
parentElement.getBoundingClientRect().top +
parentElement.offsetHeight,
},
};
this.contextMenuRenderer.render(options);
execute: async (arg) => {
const toOpen = !SketchLocation.is(arg)
? await this.selectSketch()
: arg;
if (toOpen) {
return this.openSketch(toOpen);
}
},
});
@@ -130,13 +59,20 @@ export class OpenSketch extends SketchContribution {
});
}

private async openSketch(
toOpen: MaybePromise<Sketch | undefined> = this.selectSketch()
): Promise<void> {
const sketch = await toOpen;
if (sketch) {
this.workspaceService.open(new URI(sketch.uri));
private async openSketch(toOpen: SketchLocation | undefined): Promise<void> {
if (!toOpen) {
return;
}
const uri = SketchLocation.toUri(toOpen);
try {
await this.sketchService.loadSketch(uri.toString());
} catch (err) {
if (SketchesError.NotFound.is(err)) {
this.messageService.error(err.message);
}
throw err;
}
this.workspaceService.open(uri);
}

private async selectSketch(): Promise<Sketch | undefined> {
@@ -220,8 +156,5 @@ export namespace OpenSketch {
export const OPEN_SKETCH: Command = {
id: 'arduino-open-sketch',
};
export const OPEN_SKETCH__TOOLBAR: Command = {
id: 'arduino-open-sketch--toolbar',
};
}
}
10 changes: 0 additions & 10 deletions arduino-ide-extension/src/browser/contributions/save-sketch.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { injectable } from '@theia/core/shared/inversify';
import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
import { SaveAsSketch } from './save-as-sketch';
import {
SketchContribution,
@@ -19,12 +18,6 @@ export class SaveSketch extends SketchContribution {
registry.registerCommand(SaveSketch.Commands.SAVE_SKETCH, {
execute: () => this.saveSketch(),
});
registry.registerCommand(SaveSketch.Commands.SAVE_SKETCH__TOOLBAR, {
isVisible: (widget) =>
ArduinoToolbar.is(widget) && widget.side === 'left',
execute: () =>
registry.executeCommand(SaveSketch.Commands.SAVE_SKETCH.id),
});
}

override registerMenus(registry: MenuModelRegistry): void {
@@ -68,8 +61,5 @@ export namespace SaveSketch {
export const SAVE_SKETCH: Command = {
id: 'arduino-save-sketch',
};
export const SAVE_SKETCH__TOOLBAR: Command = {
id: 'arduino-save-sketch--toolbar',
};
}
}
51 changes: 14 additions & 37 deletions arduino-ide-extension/src/browser/contributions/sketchbook.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,14 @@
import { inject, injectable } from '@theia/core/shared/inversify';
import { injectable } from '@theia/core/shared/inversify';
import { CommandHandler } from '@theia/core/lib/common/command';
import { CommandRegistry, MenuModelRegistry } from './contribution';
import { MenuModelRegistry } from './contribution';
import { ArduinoMenus } from '../menu/arduino-menus';
import { MainMenuManager } from '../../common/main-menu-manager';
import { NotificationCenter } from '../notification-center';
import { Examples } from './examples';
import {
SketchContainer,
SketchesError,
SketchRef,
} from '../../common/protocol';
import { SketchContainer, SketchesError } from '../../common/protocol';
import { OpenSketch } from './open-sketch';
import { nls } from '@theia/core/lib/common';
import { nls } from '@theia/core/lib/common/nls';

@injectable()
export class Sketchbook extends Examples {
@inject(CommandRegistry)
protected override readonly commandRegistry: CommandRegistry;

@inject(MenuModelRegistry)
protected override readonly menuRegistry: MenuModelRegistry;

@inject(MainMenuManager)
protected readonly mainMenuManager: MainMenuManager;

@inject(NotificationCenter)
protected readonly notificationCenter: NotificationCenter;

override onStart(): void {
this.sketchServiceClient.onSketchbookDidChange(() => this.update());
}
@@ -35,10 +17,10 @@ export class Sketchbook extends Examples {
this.update();
}

private update() {
protected override update(): void {
this.sketchService.getSketches({}).then((container) => {
this.register(container);
this.mainMenuManager.update();
this.menuManager.update();
});
}

@@ -50,7 +32,7 @@ export class Sketchbook extends Examples {
);
}

protected register(container: SketchContainer): void {
private register(container: SketchContainer): void {
this.toDispose.dispose();
this.registerRecursively(
[...container.children, ...container.sketches],
@@ -62,24 +44,19 @@ export class Sketchbook extends Examples {
protected override createHandler(uri: string): CommandHandler {
return {
execute: async () => {
let sketch: SketchRef | undefined = undefined;
try {
sketch = await this.sketchService.loadSketch(uri);
await this.commandService.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
uri
);
} catch (err) {
if (SketchesError.NotFound.is(err)) {
// To handle the following:
// Open IDE2, delete a sketch from sketchbook, click on File > Sketchbook > the deleted sketch.
// Filesystem watcher misses out delete events on macOS; hence IDE2 has no chance to update the menu items.
this.messageService.error(err.message);
// Force update the menu items to remove the absent sketch.
this.update();
} else {
throw err;
}
}
if (sketch) {
await this.commandService.executeCommand(
OpenSketch.Commands.OPEN_SKETCH.id,
sketch
);
}
},
};
}
2 changes: 0 additions & 2 deletions arduino-ide-extension/src/browser/theia/core/about-dialog.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { AboutDialog as TheiaAboutDialog } from '@theia/core/lib/browser/about-dialog';
import { duration } from '../../../common/decorators';

export class AboutDialog extends TheiaAboutDialog {
@duration({ name: 'theia-about#init' })
protected override async init(): Promise<void> {
// NOOP
// IDE2 has a custom about dialog, so it does not make sense to collect Theia extensions at startup time.
4 changes: 4 additions & 0 deletions arduino-ide-extension/src/common/protocol/core-service.ts
Original file line number Diff line number Diff line change
@@ -108,6 +108,10 @@ export interface CoreService {
compile(options: CoreService.Options.Compile): Promise<void>;
upload(options: CoreService.Options.Upload): Promise<void>;
burnBootloader(options: CoreService.Options.Bootloader): Promise<void>;
/**
* Refreshes the underling core gRPC client for the Arduino CLI.
*/
refresh(): Promise<void>;
}

export namespace CoreService {
57 changes: 38 additions & 19 deletions arduino-ide-extension/src/common/protocol/sketches-service.ts
Original file line number Diff line number Diff line change
@@ -21,16 +21,9 @@ export const SketchesService = Symbol('SketchesService');
export interface SketchesService {
/**
* Resolves to a sketch container representing the hierarchical structure of the sketches.
* If `uri` is not given, `directories.user` will be user instead. Specify `exclude` global patterns to filter folders from the sketch container.
* If `exclude` is not set `['**\/libraries\/**', '**\/hardware\/**']` will be used instead.
* If `uri` is not given, `directories.user` will be user instead.
*/
getSketches({
uri,
exclude,
}: {
uri?: string;
exclude?: string[];
}): Promise<SketchContainer>;
getSketches({ uri }: { uri?: string }): Promise<SketchContainer>;

/**
* This is the TS implementation of `SketchLoad` from the CLI and should be replaced with a gRPC call eventually.
@@ -71,7 +64,7 @@ export interface SketchesService {
copy(sketch: Sketch, options: { destinationUri: string }): Promise<string>;

/**
* Returns with the container sketch for the input `uri`. If the `uri` is not in a sketch folder, resolved `undefined`.
* Returns with the container sketch for the input `uri`. If the `uri` is not in a sketch folder, the promise resolves to `undefined`.
*/
getSketchFolder(uri: string): Promise<Sketch | undefined>;

@@ -82,8 +75,10 @@ export interface SketchesService {

/**
* Resolves to an array of sketches in inverse chronological order. The newest is the first.
* If `forceUpdate` is `true`, the array of recently opened sketches will be recalculated.
* Invalid and missing sketches will be removed from the list. It's `false` by default.
*/
recentlyOpenedSketches(): Promise<Sketch[]>;
recentlyOpenedSketches(forceUpdate?: boolean): Promise<Sketch[]>;

/**
* Archives the sketch, resolves to the archive URI.
@@ -114,6 +109,19 @@ export namespace SketchRef {
uri: typeof uriLike === 'string' ? uriLike : uriLike.toString(),
};
}
export function is(arg: unknown): arg is SketchRef {
if (typeof arg === 'object') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const object = arg as any;
return (
'name' in object &&
typeof object['name'] === 'string' &&
'uri' in object &&
typeof object['name'] === 'string'
);
}
return false;
}
}
export interface Sketch extends SketchRef {
readonly mainFileUri: string; // `MainFile`
@@ -122,14 +130,25 @@ export interface Sketch extends SketchRef {
readonly rootFolderFileUris: string[]; // `RootFolderFiles` (does not include the main sketch file)
}
export namespace Sketch {
export function is(arg: any): arg is Sketch {
return (
!!arg &&
'name' in arg &&
'uri' in arg &&
typeof arg.name === 'string' &&
typeof arg.uri === 'string'
);
export function is(arg: unknown): arg is Sketch {
if (!SketchRef.is(arg)) {
return false;
}
if (typeof arg === 'object') {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const object = arg as any;
return (
'mainFileUri' in object &&
typeof object['mainFileUri'] === 'string' &&
'otherSketchFileUris' in object &&
Array.isArray(object['otherSketchFileUris']) &&
'additionalFileUris' in object &&
Array.isArray(object['additionalFileUris']) &&
'rootFolderFileUris' in object &&
Array.isArray(object['rootFolderFileUris'])
);
}
return false;
}
export namespace Extensions {
export const MAIN = ['.ino', '.pde'];
Original file line number Diff line number Diff line change
@@ -332,6 +332,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
'fwuploader', // Arduino Firmware uploader
'discovery-log', // Boards discovery
'config', // Logger for the CLI config reading and manipulation
'sketches-service', // For creating, loading, and cloning sketches
MonitorManagerName, // Logger for the monitor manager and its services
MonitorServiceName,
].forEach((name) => bindChildLogger(bind, name));
2 changes: 0 additions & 2 deletions arduino-ide-extension/src/node/config-service-impl.ts
Original file line number Diff line number Diff line change
@@ -26,7 +26,6 @@ import { DefaultCliConfig, CLI_CONFIG } from './cli-config';
import { Deferred } from '@theia/core/lib/common/promise-util';
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
import { deepClone } from '@theia/core';
import { duration } from '../common/decorators';

const deepmerge = require('deepmerge');

@@ -129,7 +128,6 @@ export class ConfigServiceImpl
return this.daemon.getVersion();
}

@duration()
protected async loadCliConfig(
initializeIfAbsent = true
): Promise<DefaultCliConfig | undefined> {
9 changes: 9 additions & 0 deletions arduino-ide-extension/src/node/core-client-provider.ts
Original file line number Diff line number Diff line change
@@ -94,6 +94,11 @@ export class CoreClientProvider {
return this.onClientDidRefreshEmitter.event;
}

async refresh(): Promise<void> {
const client = await this.client;
await this.initInstance(client);
}

/**
* Encapsulates both the gRPC core client creation (`CreateRequest`) and initialization (`InitRequest`).
*/
@@ -415,6 +420,10 @@ export abstract class CoreClientAware {
protected get onClientDidRefresh(): Event<CoreClientProvider.Client> {
return this.coreClientProvider.onClientDidRefresh;
}

refresh(): Promise<void> {
return this.coreClientProvider.refresh();
}
}

class IndexUpdateRequiredBeforeInitError extends Error {
13 changes: 4 additions & 9 deletions arduino-ide-extension/src/node/examples-service-impl.ts
Original file line number Diff line number Diff line change
@@ -11,14 +11,10 @@ import {
SketchContainer,
} from '../common/protocol/sketches-service';
import { ExamplesService } from '../common/protocol/examples-service';
import {
LibraryLocation,
LibraryPackage,
LibraryService,
} from '../common/protocol';
import { duration } from '../common/decorators';
import { LibraryLocation, LibraryPackage } from '../common/protocol';
import { URI } from '@theia/core/lib/common/uri';
import { Path } from '@theia/core/lib/common/path';
import { LibraryServiceImpl } from './library-service-impl';

interface BuiltInSketchRef {
readonly name: string;
@@ -84,8 +80,8 @@ export class BuiltInExamplesServiceImpl {

@injectable()
export class ExamplesServiceImpl implements ExamplesService {
@inject(LibraryService)
private readonly libraryService: LibraryService;
@inject(LibraryServiceImpl)
private readonly libraryService: LibraryServiceImpl;

@inject(BuiltInExamplesServiceImpl)
private readonly builtInExamplesService: BuiltInExamplesServiceImpl;
@@ -94,7 +90,6 @@ export class ExamplesServiceImpl implements ExamplesService {
return this.builtInExamplesService.builtIns();
}

@duration()
async installed({ fqbn }: { fqbn?: string }): Promise<{
user: SketchContainer[];
current: SketchContainer[];
332 changes: 182 additions & 150 deletions arduino-ide-extension/src/node/sketches-service-impl.ts

Large diffs are not rendered by default.