Skip to content

Commit d6691be

Browse files
author
Akos Kitta
committed
s
Signed-off-by: Akos Kitta <[email protected]>
1 parent 75e00c2 commit d6691be

File tree

6 files changed

+184
-91
lines changed

6 files changed

+184
-91
lines changed

arduino-ide-extension/src/browser/contributions/examples.ts

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,16 @@ import {
2121
MenuModelRegistry,
2222
} from './contribution';
2323
import { NotificationCenter } from '../notification-center';
24-
import { Board, SketchRef, SketchContainer } from '../../common/protocol';
24+
import {
25+
Board,
26+
SketchRef,
27+
SketchContainer,
28+
SketchesError,
29+
} from '../../common/protocol';
2530
import { nls } from '@theia/core/lib/common';
2631

2732
@injectable()
2833
export abstract class Examples extends SketchContribution {
29-
@inject(CommandRegistry)
30-
protected readonly commandRegistry: CommandRegistry;
31-
32-
@inject(MenuModelRegistry)
33-
protected readonly menuRegistry: MenuModelRegistry;
34-
3534
@inject(MainMenuManager)
3635
protected readonly menuManager: MainMenuManager;
3736

@@ -41,6 +40,12 @@ export abstract class Examples extends SketchContribution {
4140
@inject(BoardsServiceProvider)
4241
protected readonly boardsServiceClient: BoardsServiceProvider;
4342

43+
@inject(CommandRegistry)
44+
private readonly commandRegistry: CommandRegistry;
45+
46+
@inject(MenuModelRegistry)
47+
private readonly menuRegistry: MenuModelRegistry;
48+
4449
protected readonly toDispose = new DisposableCollection();
4550

4651
protected override init(): void {
@@ -50,10 +55,13 @@ export abstract class Examples extends SketchContribution {
5055
);
5156
}
5257

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

63+
protected abstract update(board?: Board | undefined): void;
64+
5765
override registerMenus(registry: MenuModelRegistry): void {
5866
try {
5967
// 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,11 +157,19 @@ export abstract class Examples extends SketchContribution {
149157
protected createHandler(uri: string): CommandHandler {
150158
return {
151159
execute: async () => {
152-
const sketch = await this.sketchService.cloneExample(uri);
153-
return this.commandService.executeCommand(
154-
OpenSketch.Commands.OPEN_SKETCH.id,
155-
sketch
156-
);
160+
try {
161+
const sketch = await this.sketchService.cloneExample(uri);
162+
return this.commandService.executeCommand(
163+
OpenSketch.Commands.OPEN_SKETCH.id,
164+
sketch
165+
);
166+
} catch (err) {
167+
if (SketchesError.NotFound.is(err)) {
168+
this.update();
169+
} else {
170+
throw err;
171+
}
172+
}
157173
},
158174
};
159175
}
@@ -162,10 +178,10 @@ export abstract class Examples extends SketchContribution {
162178
@injectable()
163179
export class BuiltInExamples extends Examples {
164180
override async onReady(): Promise<void> {
165-
this.register(); // no `await`
181+
this.update(); // no `await`
166182
}
167183

168-
protected async register(): Promise<void> {
184+
protected override async update(): Promise<void> {
169185
let sketchContainers: SketchContainer[] | undefined;
170186
try {
171187
sketchContainers = await this.examplesService.builtIns();
@@ -197,24 +213,24 @@ export class BuiltInExamples extends Examples {
197213
@injectable()
198214
export class LibraryExamples extends Examples {
199215
@inject(NotificationCenter)
200-
protected readonly notificationCenter: NotificationCenter;
216+
private readonly notificationCenter: NotificationCenter;
201217

202-
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
218+
private readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
203219

204220
override onStart(): void {
205-
this.notificationCenter.onLibraryDidInstall(() => this.register());
206-
this.notificationCenter.onLibraryDidUninstall(() => this.register());
221+
this.notificationCenter.onLibraryDidInstall(() => this.update());
222+
this.notificationCenter.onLibraryDidUninstall(() => this.update());
207223
}
208224

209225
override async onReady(): Promise<void> {
210-
this.register(); // no `await`
226+
this.update(); // no `await`
211227
}
212228

213229
protected override handleBoardChanged(board: Board | undefined): void {
214-
this.register(board);
230+
this.update(board);
215231
}
216232

217-
protected async register(
233+
protected override async update(
218234
board: Board | undefined = this.boardsServiceClient.boardsConfig
219235
.selectedBoard
220236
): Promise<void> {

arduino-ide-extension/src/browser/contributions/open-recent-sketch.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { MainMenuManager } from '../../common/main-menu-manager';
1515
import { OpenSketch } from './open-sketch';
1616
import { NotificationCenter } from '../notification-center';
1717
import { nls } from '@theia/core/lib/common';
18+
import { SketchesError } from '../../common/protocol';
1819

1920
@injectable()
2021
export class OpenRecentSketch extends SketchContribution {
@@ -42,6 +43,10 @@ export class OpenRecentSketch extends SketchContribution {
4243
}
4344

4445
override async onReady(): Promise<void> {
46+
this.update();
47+
}
48+
49+
private update(): void {
4550
this.sketchService
4651
.recentlyOpenedSketches()
4752
.then((sketches) => this.refreshMenu(sketches));
@@ -70,11 +75,20 @@ export class OpenRecentSketch extends SketchContribution {
7075
}
7176
const command = { id: `arduino-open-recent--${uri}` };
7277
const handler = {
73-
execute: () =>
74-
this.commandRegistry.executeCommand(
75-
OpenSketch.Commands.OPEN_SKETCH.id,
76-
sketch
77-
),
78+
execute: async () => {
79+
try {
80+
await this.commandRegistry.executeCommand(
81+
OpenSketch.Commands.OPEN_SKETCH.id,
82+
sketch
83+
);
84+
} catch (err) {
85+
if (SketchesError.NotFound.is(err)) {
86+
this.update();
87+
} else {
88+
throw err;
89+
}
90+
}
91+
},
7892
};
7993
this.commandRegistry.registerCommand(command, handler);
8094
this.menuRegistry.registerMenuAction(

arduino-ide-extension/src/browser/contributions/open-sketch.ts

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { inject, injectable } from '@theia/core/shared/inversify';
22
import * as remote from '@theia/core/electron-shared/@electron/remote';
3-
import { MaybePromise } from '@theia/core/lib/common/types';
43
import { Widget, ContextMenuRenderer } from '@theia/core/lib/browser';
54
import {
65
Disposable,
@@ -20,32 +19,81 @@ import {
2019
import { ExamplesService } from '../../common/protocol/examples-service';
2120
import { BuiltInExamples } from './examples';
2221
import { Sketchbook } from './sketchbook';
23-
import { SketchContainer } from '../../common/protocol';
24-
import { nls } from '@theia/core/lib/common';
22+
import {
23+
SketchContainer,
24+
SketchesError,
25+
SketchRef,
26+
} from '../../common/protocol';
27+
import { nls } from '@theia/core/lib/common/nls';
28+
29+
export type SketchLocation = string | URI | SketchRef | Sketch;
30+
export namespace SketchLocation {
31+
export function toUri(location: SketchLocation): URI {
32+
if (typeof location === 'string') {
33+
return new URI(location);
34+
} else if (SketchRef.is(location)) {
35+
return toUri(location.uri);
36+
} else if (Sketch.is(location)) {
37+
return toUri(location.uri);
38+
} else {
39+
return location;
40+
}
41+
}
42+
}
43+
export interface OpenSketchParams {
44+
readonly toOpen: SketchLocation;
45+
/**
46+
* If `true`, the open sketch command will try to open the sketch in a new workspace even if the sketch is invalid or missing.
47+
* If an invalid sketch is opened in a Theia workspace, a new temporary sketch will be created on the fly, and the
48+
* workspace will fall back to the new temporary sketch location. It's `false` by default.
49+
*/
50+
readonly forceOpen?: boolean;
51+
}
52+
export namespace OpenSketchParams {
53+
export function is(arg: unknown): arg is OpenSketchParams {
54+
if (typeof arg === 'object') {
55+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
56+
return 'toOpen' in (arg as any);
57+
}
58+
return false;
59+
}
60+
}
2561

2662
@injectable()
2763
export class OpenSketch extends SketchContribution {
2864
@inject(MenuModelRegistry)
29-
protected readonly menuRegistry: MenuModelRegistry;
65+
private readonly menuRegistry: MenuModelRegistry;
3066

3167
@inject(ContextMenuRenderer)
32-
protected readonly contextMenuRenderer: ContextMenuRenderer;
68+
private readonly contextMenuRenderer: ContextMenuRenderer;
3369

3470
@inject(BuiltInExamples)
35-
protected readonly builtInExamples: BuiltInExamples;
71+
private readonly builtInExamples: BuiltInExamples;
3672

3773
@inject(ExamplesService)
38-
protected readonly examplesService: ExamplesService;
74+
private readonly examplesService: ExamplesService;
3975

4076
@inject(Sketchbook)
41-
protected readonly sketchbook: Sketchbook;
77+
private readonly sketchbook: Sketchbook;
4278

43-
protected readonly toDispose = new DisposableCollection();
79+
private readonly toDispose = new DisposableCollection();
4480

4581
override registerCommands(registry: CommandRegistry): void {
4682
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH, {
47-
execute: (arg) =>
48-
Sketch.is(arg) ? this.openSketch(arg) : this.openSketch(),
83+
execute: async (arg) => {
84+
let toOpen: string | URI | SketchRef | Sketch | undefined = undefined;
85+
if (!OpenSketchParams.is(arg)) {
86+
toOpen = await this.selectSketch();
87+
} else {
88+
toOpen = arg.toOpen;
89+
}
90+
if (toOpen) {
91+
return this.openSketch(
92+
toOpen,
93+
OpenSketchParams.is(arg) ? arg.forceOpen : false
94+
);
95+
}
96+
},
4997
});
5098
registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH__TOOLBAR, {
5199
isVisible: (widget) =>
@@ -55,7 +103,7 @@ export class OpenSketch extends SketchContribution {
55103
exclude: ['**/hardware/**'],
56104
});
57105
if (SketchContainer.isEmpty(container)) {
58-
this.openSketch();
106+
this.selectSketch().then((sketch) => this.openSketch(sketch));
59107
} else {
60108
this.toDispose.dispose();
61109
if (!(target instanceof HTMLElement)) {
@@ -130,16 +178,28 @@ export class OpenSketch extends SketchContribution {
130178
});
131179
}
132180

133-
async openSketch(
134-
toOpen: MaybePromise<Sketch | undefined> = this.selectSketch()
181+
private async openSketch(
182+
toOpen: SketchLocation | undefined,
183+
forceOpen?: boolean
135184
): Promise<void> {
136-
const sketch = await toOpen;
137-
if (sketch) {
138-
this.workspaceService.open(new URI(sketch.uri));
185+
if (!toOpen) {
186+
return;
187+
}
188+
const uri = SketchLocation.toUri(toOpen);
189+
if (!forceOpen) {
190+
try {
191+
await this.sketchService.loadSketch(uri.toString());
192+
} catch (err) {
193+
if (SketchesError.NotFound.is(err)) {
194+
this.messageService.error(err.message);
195+
}
196+
throw err;
197+
}
139198
}
199+
this.workspaceService.open(uri);
140200
}
141201

142-
protected async selectSketch(): Promise<Sketch | undefined> {
202+
private async selectSketch(): Promise<Sketch | undefined> {
143203
const config = await this.configService.getConfiguration();
144204
const defaultPath = await this.fileService.fsPath(
145205
new URI(config.sketchDirUri)

arduino-ide-extension/src/browser/contributions/sketchbook.ts

Lines changed: 14 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,14 @@
1-
import { inject, injectable } from '@theia/core/shared/inversify';
1+
import { injectable } from '@theia/core/shared/inversify';
22
import { CommandHandler } from '@theia/core/lib/common/command';
3-
import { CommandRegistry, MenuModelRegistry } from './contribution';
3+
import { MenuModelRegistry } from './contribution';
44
import { ArduinoMenus } from '../menu/arduino-menus';
5-
import { MainMenuManager } from '../../common/main-menu-manager';
6-
import { NotificationCenter } from '../notification-center';
75
import { Examples } from './examples';
8-
import {
9-
SketchContainer,
10-
SketchesError,
11-
SketchRef,
12-
} from '../../common/protocol';
6+
import { SketchContainer, SketchesError } from '../../common/protocol';
137
import { OpenSketch } from './open-sketch';
14-
import { nls } from '@theia/core/lib/common';
8+
import { nls } from '@theia/core/lib/common/nls';
159

1610
@injectable()
1711
export class Sketchbook extends Examples {
18-
@inject(CommandRegistry)
19-
protected override readonly commandRegistry: CommandRegistry;
20-
21-
@inject(MenuModelRegistry)
22-
protected override readonly menuRegistry: MenuModelRegistry;
23-
24-
@inject(MainMenuManager)
25-
protected readonly mainMenuManager: MainMenuManager;
26-
27-
@inject(NotificationCenter)
28-
protected readonly notificationCenter: NotificationCenter;
29-
3012
override onStart(): void {
3113
this.sketchServiceClient.onSketchbookDidChange(() => this.update());
3214
}
@@ -35,10 +17,10 @@ export class Sketchbook extends Examples {
3517
this.update();
3618
}
3719

38-
private update() {
20+
protected override update(): void {
3921
this.sketchService.getSketches({}).then((container) => {
4022
this.register(container);
41-
this.mainMenuManager.update();
23+
this.menuManager.update();
4224
});
4325
}
4426

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

53-
protected register(container: SketchContainer): void {
35+
private register(container: SketchContainer): void {
5436
this.toDispose.dispose();
5537
this.registerRecursively(
5638
[...container.children, ...container.sketches],
@@ -62,24 +44,19 @@ export class Sketchbook extends Examples {
6244
protected override createHandler(uri: string): CommandHandler {
6345
return {
6446
execute: async () => {
65-
let sketch: SketchRef | undefined = undefined;
6647
try {
67-
sketch = await this.sketchService.loadSketch(uri);
48+
await this.commandService.executeCommand(
49+
OpenSketch.Commands.OPEN_SKETCH.id,
50+
uri
51+
);
6852
} catch (err) {
6953
if (SketchesError.NotFound.is(err)) {
70-
// To handle the following:
71-
// Open IDE2, delete a sketch from sketchbook, click on File > Sketchbook > the deleted sketch.
72-
// Filesystem watcher misses out delete events on macOS; hence IDE2 has no chance to update the menu items.
73-
this.messageService.error(err.message);
54+
// Force update the menu items to remove the absent sketch.
7455
this.update();
56+
} else {
57+
throw err;
7558
}
7659
}
77-
if (sketch) {
78-
await this.commandService.executeCommand(
79-
OpenSketch.Commands.OPEN_SKETCH.id,
80-
sketch
81-
);
82-
}
8360
},
8461
};
8562
}

0 commit comments

Comments
 (0)