Skip to content

Commit 06b2856

Browse files
author
Akos Kitta
committed
feat: use new debug -I -P CLI output
- Can pick a programmer if missing, - Can auto-select a programmer on app start, - Can edit the `launch.json`, Signed-off-by: Akos Kitta <[email protected]>
1 parent 503533d commit 06b2856

17 files changed

+544
-115
lines changed

Diff for: .eslintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module.exports = {
1818
'electron-app/src-gen/*',
1919
'electron-app/gen-webpack*.js',
2020
'!electron-app/webpack.config.js',
21-
'plugins/*',
21+
'electron-app/plugins/*',
2222
'arduino-ide-extension/src/node/cli-protocol',
2323
'**/lib/*',
2424
],

Diff for: arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+4
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ import { TerminalFrontendContribution as TheiaTerminalFrontendContribution } fro
361361
import { SelectionService } from '@theia/core/lib/common/selection-service';
362362
import { CommandService } from '@theia/core/lib/common/command';
363363
import { CorePreferences } from '@theia/core/lib/browser/core-preferences';
364+
import { SelectProgrammer } from './contributions/select-programmer';
365+
import { AutoSelectProgrammer } from './contributions/auto-select-programmer';
364366

365367
// Hack to fix copy/cut/paste issue after electron version update in Theia.
366368
// https://github.com/eclipse-theia/theia/issues/12487
@@ -753,6 +755,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
753755
Contribution.configure(bind, CreateCloudCopy);
754756
Contribution.configure(bind, UpdateArduinoState);
755757
Contribution.configure(bind, BoardsDataMenuUpdater);
758+
Contribution.configure(bind, SelectProgrammer);
759+
Contribution.configure(bind, AutoSelectProgrammer);
756760

757761
bindContributionProvider(bind, StartupTaskProvider);
758762
bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window

Diff for: arduino-ide-extension/src/browser/boards/boards-data-store.ts

+26-14
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
44
import { Emitter, Event } from '@theia/core/lib/common/event';
55
import { ILogger } from '@theia/core/lib/common/logger';
66
import { deepClone } from '@theia/core/lib/common/objects';
7+
import type { Mutable } from '@theia/core/lib/common/types';
78
import { inject, injectable, named } from '@theia/core/shared/inversify';
89
import {
910
BoardDetails,
1011
BoardsService,
1112
ConfigOption,
13+
ConfigValue,
1214
Programmer,
15+
isProgrammer,
1316
} from '../../common/protocol';
1417
import { notEmpty } from '../../common/utils';
1518
import { NotificationCenter } from '../notification-center';
@@ -43,7 +46,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
4346
const key = this.getStorageKey(fqbn);
4447
let data = await this.storageService.getData<ConfigOption[]>(key);
4548
if (!data || !data.length) {
46-
const details = await this.getBoardDetailsSafe(fqbn);
49+
const details = await this.loadBoardDetails(fqbn);
4750
if (details) {
4851
data = details.configOptions;
4952
if (data.length) {
@@ -91,14 +94,15 @@ export class BoardsDataStore implements FrontendApplicationContribution {
9194
return data;
9295
}
9396

94-
const boardDetails = await this.getBoardDetailsSafe(fqbn);
97+
const boardDetails = await this.loadBoardDetails(fqbn);
9598
if (!boardDetails) {
9699
return BoardsDataStore.Data.EMPTY;
97100
}
98101

99102
data = {
100103
configOptions: boardDetails.configOptions,
101104
programmers: boardDetails.programmers,
105+
selectedProgrammer: boardDetails.programmers.find((p) => p.default),
102106
};
103107
await this.storageService.setData(key, data);
104108
return data;
@@ -142,11 +146,12 @@ export class BoardsDataStore implements FrontendApplicationContribution {
142146
}
143147
let updated = false;
144148
for (const value of configOption.values) {
145-
if (value.value === selectedValue) {
146-
(value as any).selected = true;
149+
const mutable: Mutable<ConfigValue> = value;
150+
if (mutable.value === selectedValue) {
151+
mutable.selected = true;
147152
updated = true;
148153
} else {
149-
(value as any).selected = false;
154+
mutable.selected = false;
150155
}
151156
}
152157
if (!updated) {
@@ -172,9 +177,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
172177
return `.arduinoIDE-configOptions-${fqbn}`;
173178
}
174179

175-
protected async getBoardDetailsSafe(
176-
fqbn: string
177-
): Promise<BoardDetails | undefined> {
180+
async loadBoardDetails(fqbn: string): Promise<BoardDetails | undefined> {
178181
try {
179182
const details = this.boardsService.getBoardDetails({ fqbn });
180183
return details;
@@ -213,14 +216,23 @@ export namespace BoardsDataStore {
213216
configOptions: [],
214217
programmers: [],
215218
};
216-
export function is(arg: any): arg is Data {
219+
export function is(arg: unknown): arg is Data {
217220
return (
218-
!!arg &&
219-
'configOptions' in arg &&
220-
Array.isArray(arg['configOptions']) &&
221-
'programmers' in arg &&
222-
Array.isArray(arg['programmers'])
221+
typeof arg === 'object' &&
222+
arg !== null &&
223+
Array.isArray((<Data>arg).configOptions) &&
224+
Array.isArray((<Data>arg).programmers) &&
225+
((<Data>arg).selectedProgrammer === undefined ||
226+
isProgrammer((<Data>arg).selectedProgrammer))
223227
);
224228
}
225229
}
226230
}
231+
232+
export function isEmptyData(data: BoardsDataStore.Data): boolean {
233+
return (
234+
Boolean(!data.configOptions.length) &&
235+
Boolean(!data.programmers.length) &&
236+
Boolean(!data.selectedProgrammer)
237+
);
238+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { inject, injectable } from '@theia/core/shared/inversify';
2+
import { isBoardIdentifierChangeEvent } from '../../common/protocol';
3+
import { BoardsDataStore, isEmptyData } from '../boards/boards-data-store';
4+
import { BoardsServiceProvider } from '../boards/boards-service-provider';
5+
import { Contribution } from './contribution';
6+
7+
/**
8+
* Before CLI 0.35.0-rc.3, there was no `programmer#default` property in the `board details` response.
9+
* This method does the programmer migration in the data store. If there is a programmer selected, it's a noop.
10+
* If no programmer is selected, it forcefully reloads the details from the CLI and updates it in the local storage.
11+
*/
12+
@injectable()
13+
export class AutoSelectProgrammer extends Contribution {
14+
@inject(BoardsServiceProvider)
15+
private readonly boardsServiceProvider: BoardsServiceProvider;
16+
@inject(BoardsDataStore)
17+
private readonly boardsDataStore: BoardsDataStore;
18+
19+
override onStart(): void {
20+
this.boardsServiceProvider.onBoardsConfigDidChange((event) => {
21+
if (isBoardIdentifierChangeEvent(event)) {
22+
this.ensureProgrammerIsSelected();
23+
}
24+
});
25+
}
26+
27+
override onReady(): void {
28+
this.boardsServiceProvider.ready.then(() =>
29+
this.ensureProgrammerIsSelected()
30+
);
31+
}
32+
33+
private async ensureProgrammerIsSelected(): Promise<void> {
34+
const fqbn = this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn;
35+
if (!fqbn) {
36+
return;
37+
}
38+
console.debug(`Ensuring a programmer is selected for ${fqbn}...`);
39+
const data = await this.boardsDataStore.getData(fqbn);
40+
if (isEmptyData(data)) {
41+
// For example, the platform is not installed.
42+
console.debug(`Skipping. No boards data is available for ${fqbn}.`);
43+
return;
44+
}
45+
if (data.selectedProgrammer) {
46+
console.debug(
47+
`A programmer is already selected for ${fqbn}: '${data.selectedProgrammer.id}'.`
48+
);
49+
return;
50+
}
51+
let programmer = data.programmers.find((p) => p.default);
52+
if (programmer) {
53+
// select the programmer if the default info is available
54+
await this.boardsDataStore.selectProgrammer({
55+
fqbn,
56+
selectedProgrammer: programmer,
57+
});
58+
console.debug(`Selected '${programmer.id}' programmer for ${fqbn}.`);
59+
return;
60+
}
61+
console.debug(`Reloading board details for ${fqbn}...`);
62+
const reloadedData = await this.boardsDataStore.loadBoardDetails(fqbn);
63+
if (!reloadedData) {
64+
console.debug(`Skipping. No board details found for ${fqbn}.`);
65+
return;
66+
}
67+
if (!reloadedData.programmers.length) {
68+
console.debug(`Skipping. ${fqbn} does not have programmers.`);
69+
return;
70+
}
71+
programmer = reloadedData.programmers.find((p) => p.default);
72+
if (!programmer) {
73+
console.debug(
74+
`Skipping. Could not find a default programmer for ${fqbn}. Programmers were: `
75+
);
76+
return;
77+
}
78+
const result = await this.boardsDataStore.selectProgrammer({
79+
fqbn,
80+
selectedProgrammer: programmer,
81+
});
82+
if (result) {
83+
console.debug(`Selected '${programmer.id}' programmer for ${fqbn}.`);
84+
} else {
85+
console.debug(
86+
`Could not select '${programmer.id}' programmer for ${fqbn}.`
87+
);
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)