init: programmers

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
Akos Kitta 2020-07-21 17:39:22 +02:00
parent 07692fe368
commit e77c9721cd
10 changed files with 151 additions and 64 deletions

View File

@ -36,7 +36,7 @@ import { ColorContribution } from '@theia/core/lib/browser/color-application-con
import { ColorRegistry } from '@theia/core/lib/browser/color-registry'; import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
import { ArduinoDaemon } from '../common/protocol/arduino-daemon'; import { ArduinoDaemon } from '../common/protocol/arduino-daemon';
import { ConfigService } from '../common/protocol/config-service'; import { ConfigService } from '../common/protocol/config-service';
import { BoardsConfigStore } from './boards/boards-config-store'; import { BoardsDataStore } from './boards/boards-data-store';
import { MainMenuManager } from '../common/main-menu-manager'; import { MainMenuManager } from '../common/main-menu-manager';
import { FileSystemExt } from '../common/protocol/filesystem-ext'; import { FileSystemExt } from '../common/protocol/filesystem-ext';
import { ArduinoMenus } from './menu/arduino-menus'; import { ArduinoMenus } from './menu/arduino-menus';
@ -130,8 +130,8 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
@inject(ConfigService) @inject(ConfigService)
protected readonly configService: ConfigService; protected readonly configService: ConfigService;
@inject(BoardsConfigStore) @inject(BoardsDataStore)
protected readonly boardsConfigStore: BoardsConfigStore; protected readonly boardsDataStore: BoardsDataStore;
@inject(MainMenuManager) @inject(MainMenuManager)
protected readonly mainMenuManager: MainMenuManager; protected readonly mainMenuManager: MainMenuManager;

View File

@ -82,8 +82,8 @@ import {
} from '@theia/core/lib/browser/connection-status-service'; } from '@theia/core/lib/browser/connection-status-service';
import { ConfigServiceClientImpl } from './config-service-client-impl'; import { ConfigServiceClientImpl } from './config-service-client-impl';
import { CoreServiceClientImpl } from './core-service-client-impl'; import { CoreServiceClientImpl } from './core-service-client-impl';
import { BoardsDetailsMenuUpdater } from './boards/boards-details-menu-updater'; import { BoardsDataMenuUpdater } from './boards/boards-details-menu-updater';
import { BoardsConfigStore } from './boards/boards-config-store'; import { BoardsDataStore } from './boards/boards-data-store';
import { ILogger } from '@theia/core'; import { ILogger } from '@theia/core';
import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext'; import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext';
import { WorkspaceFrontendContribution as TheiaWorkspaceFrontendContribution, FileMenuContribution as TheiaFileMenuContribution } from '@theia/workspace/lib/browser'; import { WorkspaceFrontendContribution as TheiaWorkspaceFrontendContribution, FileMenuContribution as TheiaFileMenuContribution } from '@theia/workspace/lib/browser';
@ -183,9 +183,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
}).inSingletonScope(); }).inSingletonScope();
// To be able to track, and update the menu based on the core settings (aka. board details) of the currently selected board. // To be able to track, and update the menu based on the core settings (aka. board details) of the currently selected board.
bind(FrontendApplicationContribution).to(BoardsDetailsMenuUpdater).inSingletonScope(); bind(FrontendApplicationContribution).to(BoardsDataMenuUpdater).inSingletonScope();
bind(BoardsConfigStore).toSelf().inSingletonScope(); bind(BoardsDataStore).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(BoardsConfigStore); bind(FrontendApplicationContribution).toService(BoardsDataStore);
// Logger for the Arduino daemon // Logger for the Arduino daemon
bind(ILogger).toDynamicValue(ctx => { bind(ILogger).toDynamicValue(ctx => {
const parentLogger = ctx.container.get<ILogger>(ILogger); const parentLogger = ctx.container.get<ILogger>(ILogger);

View File

@ -1,14 +1,15 @@
import { injectable, inject, named } from 'inversify'; import { injectable, inject, named } from 'inversify';
import { ILogger } from '@theia/core/lib/common/logger'; import { ILogger } from '@theia/core/lib/common/logger';
import { deepClone } from '@theia/core/lib/common/objects';
import { MaybePromise } from '@theia/core/lib/common/types'; import { MaybePromise } from '@theia/core/lib/common/types';
import { Event, Emitter } from '@theia/core/lib/common/event'; import { Event, Emitter } from '@theia/core/lib/common/event';
import { deepClone, notEmpty } from '@theia/core/lib/common/objects';
import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser'; import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser';
import { BoardsService, ConfigOption, Installable, BoardDetails } from '../../common/protocol'; import { notEmpty } from '../../common/utils';
import { BoardsServiceClientImpl } from './boards-service-client-impl'; import { BoardsServiceClientImpl } from './boards-service-client-impl';
import { BoardsService, ConfigOption, Installable, BoardDetails, Programmer } from '../../common/protocol';
@injectable() @injectable()
export class BoardsConfigStore implements FrontendApplicationContribution { export class BoardsDataStore implements FrontendApplicationContribution {
@inject(ILogger) @inject(ILogger)
@named('store') @named('store')
@ -60,39 +61,59 @@ export class BoardsConfigStore implements FrontendApplicationContribution {
fqbn: string, fqbn: string,
boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<string> { boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<string> {
const configOptions = await this.getConfig(fqbn, boardsPackageVersion); const { configOptions } = await this.getData(fqbn, boardsPackageVersion);
return ConfigOption.decorate(fqbn, configOptions); return ConfigOption.decorate(fqbn, configOptions);
} }
async getConfig( async getData(
fqbn: string, fqbn: string,
boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<ConfigOption[]> { boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<BoardsDataStore.Data> {
const version = await boardsPackageVersion; const version = await boardsPackageVersion;
if (!version) { if (!version) {
return []; return BoardsDataStore.Data.EMPTY;
} }
const key = this.getStorageKey(fqbn, version); const key = this.getStorageKey(fqbn, version);
let configOptions = await this.storageService.getData<ConfigOption[] | undefined>(key, undefined); let data = await this.storageService.getData<BoardsDataStore.Data | undefined>(key, undefined);
if (configOptions) { if (data) {
return configOptions; if (data.programmers !== undefined) { // to be backward compatible. We did not save the `programmers` into the `localStorage`.
return data;
}
} }
const details = await this.getBoardDetailsSafe(fqbn); const boardDetails = await this.getBoardDetailsSafe(fqbn);
if (!details) { if (!boardDetails) {
return []; return BoardsDataStore.Data.EMPTY;
} }
configOptions = details.configOptions; data = { configOptions: boardDetails.configOptions, programmers: boardDetails.programmers };
await this.storageService.setData(key, configOptions); await this.storageService.setData(key, data);
return configOptions; return data;
} }
async setSelected( async selectProgrammer(
{ fqbn, programmer }: { fqbn: string, programmer: Programmer },
boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<boolean> {
const { configOptions, programmers } = deepClone(await this.getData(fqbn, boardsPackageVersion));
if (!programmers.find(p => Programmer.equals(programmer, p))) {
return false;
}
const version = await boardsPackageVersion;
if (!version) {
return false;
}
await this.setData({ fqbn, data: { configOptions, programmers }, version });
this.fireChanged();
return true;
}
async selectConfigOption(
{ fqbn, option, selectedValue }: { fqbn: string, option: string, selectedValue: string }, { fqbn, option, selectedValue }: { fqbn: string, option: string, selectedValue: string },
boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<boolean> { boardsPackageVersion: MaybePromise<Installable.Version | undefined> = this.getBoardsPackageVersion(fqbn)): Promise<boolean> {
const configOptions = deepClone(await this.getConfig(fqbn, boardsPackageVersion)); const { configOptions, programmers } = deepClone(await this.getData(fqbn, boardsPackageVersion));
const configOption = configOptions.find(c => c.option === option); const configOption = configOptions.find(c => c.option === option);
if (!configOption) { if (!configOption) {
return false; return false;
@ -113,16 +134,16 @@ export class BoardsConfigStore implements FrontendApplicationContribution {
if (!version) { if (!version) {
return false; return false;
} }
await this.setConfig({ fqbn, configOptions, version }); await this.setData({ fqbn, data: { configOptions, programmers }, version });
this.fireChanged(); this.fireChanged();
return true; return true;
} }
protected async setConfig( protected async setData(
{ fqbn, configOptions, version }: { fqbn: string, configOptions: ConfigOption[], version: Installable.Version }): Promise<void> { { fqbn, data, version }: { fqbn: string, data: BoardsDataStore.Data, version: Installable.Version }): Promise<void> {
const key = this.getStorageKey(fqbn, version); const key = this.getStorageKey(fqbn, version);
return this.storageService.setData(key, configOptions); return this.storageService.setData(key, data);
} }
protected getStorageKey(fqbn: string, version: Installable.Version): string { protected getStorageKey(fqbn: string, version: Installable.Version): string {
@ -159,3 +180,16 @@ export class BoardsConfigStore implements FrontendApplicationContribution {
} }
} }
export namespace BoardsDataStore {
export interface Data {
readonly configOptions: ConfigOption[];
readonly programmers: Programmer[];
}
export namespace Data {
export const EMPTY: Data = {
configOptions: [],
programmers: []
};
}
}

View File

@ -5,12 +5,12 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
import { BoardsServiceClientImpl } from './boards-service-client-impl'; import { BoardsServiceClientImpl } from './boards-service-client-impl';
import { Board, ConfigOption } from '../../common/protocol'; import { Board, ConfigOption } from '../../common/protocol';
import { FrontendApplicationContribution } from '@theia/core/lib/browser'; import { FrontendApplicationContribution } from '@theia/core/lib/browser';
import { BoardsConfigStore } from './boards-config-store'; import { BoardsDataStore } from './boards-data-store';
import { MainMenuManager } from '../../common/main-menu-manager'; import { MainMenuManager } from '../../common/main-menu-manager';
import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoMenus } from '../menu/arduino-menus';
@injectable() @injectable()
export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution { export class BoardsDataMenuUpdater implements FrontendApplicationContribution {
@inject(CommandRegistry) @inject(CommandRegistry)
protected readonly commandRegistry: CommandRegistry; protected readonly commandRegistry: CommandRegistry;
@ -21,8 +21,8 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
@inject(MainMenuManager) @inject(MainMenuManager)
protected readonly mainMenuManager: MainMenuManager; protected readonly mainMenuManager: MainMenuManager;
@inject(BoardsConfigStore) @inject(BoardsDataStore)
protected readonly boardsConfigStore: BoardsConfigStore; protected readonly boardsDataStore: BoardsDataStore;
@inject(BoardsServiceClientImpl) @inject(BoardsServiceClientImpl)
protected readonly boardsServiceClient: BoardsServiceClientImpl; protected readonly boardsServiceClient: BoardsServiceClientImpl;
@ -30,7 +30,7 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
protected readonly toDisposeOnBoardChange = new DisposableCollection(); protected readonly toDisposeOnBoardChange = new DisposableCollection();
onStart(): void { onStart(): void {
this.boardsConfigStore.onChanged(() => this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard)); this.boardsDataStore.onChanged(() => this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard));
this.boardsServiceClient.onBoardsConfigChanged(({ selectedBoard }) => this.updateMenuActions(selectedBoard)); this.boardsServiceClient.onBoardsConfigChanged(({ selectedBoard }) => this.updateMenuActions(selectedBoard));
this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard); this.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard);
} }
@ -41,8 +41,8 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
this.mainMenuManager.update(); this.mainMenuManager.update();
const { fqbn } = selectedBoard; const { fqbn } = selectedBoard;
if (fqbn) { if (fqbn) {
const configOptions = await this.boardsConfigStore.getConfig(fqbn); const { configOptions, programmers } = await this.boardsDataStore.getData(fqbn);
const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z_boardsConfig']; // `z_` is for ordering. const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z01_boardsConfig']; // `z_` is for ordering.
for (const { label, option, values } of configOptions.sort(ConfigOption.LABEL_COMPARATOR)) { for (const { label, option, values } of configOptions.sort(ConfigOption.LABEL_COMPARATOR)) {
const menuPath = [...boardsConfigMenuPath, `${option}`]; const menuPath = [...boardsConfigMenuPath, `${option}`];
const commands = new Map<string, Disposable & { label: string }>() const commands = new Map<string, Disposable & { label: string }>()
@ -51,7 +51,7 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
const command = { id }; const command = { id };
const selectedValue = value.value; const selectedValue = value.value;
const handler = { const handler = {
execute: () => this.boardsConfigStore.setSelected({ fqbn, option, selectedValue }), execute: () => this.boardsDataStore.selectConfigOption({ fqbn, option, selectedValue }),
isToggled: () => value.selected isToggled: () => value.selected
}; };
commands.set(id, Object.assign(this.commandRegistry.registerCommand(command, handler), { label: value.label })); commands.set(id, Object.assign(this.commandRegistry.registerCommand(command, handler), { label: value.label }));
@ -67,6 +67,18 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
}) })
]); ]);
} }
const programmersMenuPath = [...ArduinoMenus.TOOLS, 'z02_programmers'];
for (const programmer of programmers) {
const { id, name } = programmer;
const menuPath = [...programmersMenuPath, `${name}`];
const command = { id: `${fqbn}-programmer--${id}` };
const handler = { execute: () => this.boardsDataStore.selectProgrammer({ fqbn, programmer }) };
this.menuRegistry.registerMenuAction(menuPath, { commandId: command.id, label: name });
this.toDisposeOnBoardChange.pushAll([
this.commandRegistry.registerCommand(command, handler),
Disposable.create(() => this.menuRegistry.unregisterMenuAction(command, menuPath))
]);
}
this.mainMenuManager.update(); this.mainMenuManager.update();
} }
} }

View File

@ -17,7 +17,7 @@ import {
import { naturalCompare } from '../../../common/utils'; import { naturalCompare } from '../../../common/utils';
import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol'; import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol';
import { CoreServiceClientImpl } from '../../core-service-client-impl'; import { CoreServiceClientImpl } from '../../core-service-client-impl';
import { BoardsConfigStore } from '../boards-config-store'; import { BoardsDataStore } from '../boards-data-store';
import { BoardsServiceClientImpl, AvailableBoard } from '../boards-service-client-impl'; import { BoardsServiceClientImpl, AvailableBoard } from '../boards-service-client-impl';
@injectable() @injectable()
@ -41,8 +41,8 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
@inject(BoardsServiceClientImpl) @inject(BoardsServiceClientImpl)
protected readonly boardsServiceClient: BoardsServiceClientImpl; protected readonly boardsServiceClient: BoardsServiceClientImpl;
@inject(BoardsConfigStore) @inject(BoardsDataStore)
protected readonly configStore: BoardsConfigStore; protected readonly boardsDataStore: BoardsDataStore;
@inject(CoreServiceClientImpl) @inject(CoreServiceClientImpl)
protected coreServiceClient: CoreServiceClientImpl; protected coreServiceClient: CoreServiceClientImpl;
@ -52,7 +52,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
// Attached boards plus the user's config. // Attached boards plus the user's config.
protected availableBoards: AvailableBoard[] = []; protected availableBoards: AvailableBoard[] = [];
// Only for the `selected` one from the `availableBoards`. Note: the `port` of the `selected` is optional. // Only for the `selected` one from the `availableBoards`. Note: the `port` of the `selected` is optional.
protected boardConfigs: ConfigOption[] = []; protected data: BoardsDataStore.Data = BoardsDataStore.Data.EMPTY;
protected allBoards: Board.Detailed[] = [] protected allBoards: Board.Detailed[] = []
protected selectedBoard?: (AvailableBoard & { port: Port }); protected selectedBoard?: (AvailableBoard & { port: Port });
@ -86,7 +86,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
placeholder += 'No board selected.'; placeholder += 'No board selected.';
} }
placeholder += 'Type to filter boards'; placeholder += 'Type to filter boards';
if (this.boardConfigs.length) { if (this.data.configOptions.length) {
placeholder += ' or use the ↓↑ keys to adjust the board settings...'; placeholder += ' or use the ↓↑ keys to adjust the board settings...';
} else { } else {
placeholder += '...'; placeholder += '...';
@ -129,7 +129,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
// Show the config only if the `input` is empty. // Show the config only if the `input` is empty.
if (!lookFor.trim().length) { if (!lookFor.trim().length) {
toAccept.push(...this.boardConfigs.map((config, i) => { toAccept.push(...this.data.configOptions.map((config, i) => {
let group: QuickOpenGroupItemOptions | undefined = undefined; let group: QuickOpenGroupItemOptions | undefined = undefined;
if (i === 0) { if (i === 0) {
group = { groupLabel: 'Board Settings', showBorder: true }; group = { groupLabel: 'Board Settings', showBorder: true };
@ -157,14 +157,14 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
protected async update(availableBoards: AvailableBoard[]): Promise<void> { protected async update(availableBoards: AvailableBoard[]): Promise<void> {
// `selectedBoard` is not an attached board, we need to show the board settings for it (TODO: clarify!) // `selectedBoard` is not an attached board, we need to show the board settings for it (TODO: clarify!)
const selectedBoard = availableBoards.filter(AvailableBoard.hasPort).find(({ selected }) => selected); const selectedBoard = availableBoards.filter(AvailableBoard.hasPort).find(({ selected }) => selected);
const [configs, boards] = await Promise.all([ const [data, boards] = await Promise.all([
selectedBoard && selectedBoard.fqbn ? this.configStore.getConfig(selectedBoard.fqbn) : Promise.resolve([]), selectedBoard && selectedBoard.fqbn ? this.boardsDataStore.getData(selectedBoard.fqbn) : Promise.resolve(BoardsDataStore.Data.EMPTY),
this.boardsService.allBoards({}) this.boardsService.allBoards({})
]); ]);
this.allBoards = Board.decorateBoards(selectedBoard, boards) this.allBoards = Board.decorateBoards(selectedBoard, boards)
.filter(board => !availableBoards.some(availableBoard => Board.sameAs(availableBoard, board))); .filter(board => !availableBoards.some(availableBoard => Board.sameAs(availableBoard, board)));
this.availableBoards = availableBoards; this.availableBoards = availableBoards;
this.boardConfigs = configs; this.data = data;
this.selectedBoard = selectedBoard; this.selectedBoard = selectedBoard;
if (this.isOpen) { if (this.isOpen) {
@ -280,7 +280,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
return; return;
} }
const { fqbn } = this.selectedBoard; const { fqbn } = this.selectedBoard;
this.configStore.setSelected({ this.boardsDataStore.selectConfigOption({
fqbn, fqbn,
option: config.option, option: config.option,
selectedValue: value.value selectedValue: value.value

View File

@ -1,7 +1,7 @@
import { inject, injectable } from 'inversify'; import { inject, injectable } from 'inversify';
import { CoreService } from '../../common/protocol'; import { CoreService } from '../../common/protocol';
import { MonitorConnection } from '../monitor/monitor-connection'; import { MonitorConnection } from '../monitor/monitor-connection';
import { BoardsConfigStore } from '../boards/boards-config-store'; import { BoardsDataStore } from '../boards/boards-data-store';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl'; import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
@ -16,8 +16,8 @@ export class UploadSketch extends SketchContribution {
@inject(MonitorConnection) @inject(MonitorConnection)
protected readonly monitorConnection: MonitorConnection; protected readonly monitorConnection: MonitorConnection;
@inject(BoardsConfigStore) @inject(BoardsDataStore)
protected readonly boardsConfigStore: BoardsConfigStore; protected readonly boardsDataStore: BoardsDataStore;
@inject(BoardsServiceClientImpl) @inject(BoardsServiceClientImpl)
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl; protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
@ -77,7 +77,7 @@ export class UploadSketch extends SketchContribution {
if (!boardsConfig.selectedBoard.fqbn) { if (!boardsConfig.selectedBoard.fqbn) {
throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`); throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`);
} }
const fqbn = await this.boardsConfigStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); const fqbn = await this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn);
await this.coreService.upload({ await this.coreService.upload({
sketchUri: sketch.uri, sketchUri: sketch.uri,
fqbn, fqbn,

View File

@ -1,7 +1,7 @@
import { inject, injectable } from 'inversify'; import { inject, injectable } from 'inversify';
import { ArduinoMenus } from '../menu/arduino-menus'; import { ArduinoMenus } from '../menu/arduino-menus';
import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
import { BoardsConfigStore } from '../boards/boards-config-store'; import { BoardsDataStore } from '../boards/boards-data-store';
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl'; import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution'; import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
import { CoreService } from '../../common/protocol'; import { CoreService } from '../../common/protocol';
@ -12,8 +12,8 @@ export class VerifySketch extends SketchContribution {
@inject(CoreService) @inject(CoreService)
protected readonly coreService: CoreService; protected readonly coreService: CoreService;
@inject(BoardsConfigStore) @inject(BoardsDataStore)
protected readonly boardsConfigStore: BoardsConfigStore; protected readonly boardsDataStore: BoardsDataStore;
@inject(BoardsServiceClientImpl) @inject(BoardsServiceClientImpl)
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl; protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
@ -65,7 +65,7 @@ export class VerifySketch extends SketchContribution {
if (!boardsConfig.selectedBoard.fqbn) { if (!boardsConfig.selectedBoard.fqbn) {
throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`); throw new Error(`No core is installed for the '${boardsConfig.selectedBoard.name}' board. Please install the core.`);
} }
const fqbn = await this.boardsConfigStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn); const fqbn = await this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard.fqbn);
await this.coreService.compile({ await this.coreService.compile({
sketchUri: sketch.uri, sketchUri: sketch.uri,
fqbn, fqbn,

View File

@ -205,6 +205,7 @@ export interface BoardDetails {
readonly fqbn: string; readonly fqbn: string;
readonly requiredTools: Tool[]; readonly requiredTools: Tool[];
readonly configOptions: ConfigOption[]; readonly configOptions: ConfigOption[];
readonly programmers: Programmer[];
} }
export interface Tool { export interface Tool {
@ -269,6 +270,23 @@ export interface ConfigValue {
readonly selected: boolean; readonly selected: boolean;
} }
export interface Programmer {
readonly name: string;
readonly platform: string;
readonly id: string;
}
export namespace Programmer {
export function equals(left: Programmer | undefined, right: Programmer | undefined): boolean {
if (!left) {
return !right;
}
if (!right) {
return !left;
}
return left.id === right.id && left.name === right.name && left.platform === right.platform;
}
}
export namespace Board { export namespace Board {
export function is(board: any): board is Board { export function is(board: any): board is Board {

View File

@ -1 +1,5 @@
export const naturalCompare: (left: string, right: string) => number = require('string-natural-compare').caseInsensitive; export const naturalCompare: (left: string, right: string) => number = require('string-natural-compare').caseInsensitive;
export function notEmpty(arg: string | undefined | null): arg is string {
return !!arg;
}

View File

@ -1,7 +1,7 @@
import { injectable, inject, postConstruct, named } from 'inversify'; import { injectable, inject, postConstruct, named } from 'inversify';
import { ILogger } from '@theia/core/lib/common/logger'; import { ILogger } from '@theia/core/lib/common/logger';
import { Deferred } from '@theia/core/lib/common/promise-util'; import { Deferred } from '@theia/core/lib/common/promise-util';
import { BoardsService, BoardsPackage, Board, BoardsServiceClient, Port, BoardDetails, Tool, ConfigOption, ConfigValue } from '../common/protocol'; import { BoardsService, BoardsPackage, Board, BoardsServiceClient, Port, BoardDetails, Tool, ConfigOption, ConfigValue, Programmer } from '../common/protocol';
import { import {
PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq, PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq,
PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq
@ -10,6 +10,7 @@ import { CoreClientProvider } from './core-client-provider';
import { BoardListReq, BoardListResp, BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb'; import { BoardListReq, BoardListResp, BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb';
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
import { Installable } from '../common/protocol/installable'; import { Installable } from '../common/protocol/installable';
import { ListProgrammersAvailableForUploadReq, ListProgrammersAvailableForUploadResp } from './cli-protocol/commands/upload_pb';
@injectable() @injectable()
export class BoardsServiceImpl implements BoardsService { export class BoardsServiceImpl implements BoardsService {
@ -209,10 +210,10 @@ export class BoardsServiceImpl implements BoardsService {
const { client, instance } = coreClient; const { client, instance } = coreClient;
const { fqbn } = options; const { fqbn } = options;
const req = new BoardDetailsReq(); const detailsReq = new BoardDetailsReq();
req.setInstance(instance); detailsReq.setInstance(instance);
req.setFqbn(fqbn); detailsReq.setFqbn(fqbn);
const resp = await new Promise<BoardDetailsResp>((resolve, reject) => client.boardDetails(req, (err, resp) => { const detailsResp = await new Promise<BoardDetailsResp>((resolve, reject) => client.boardDetails(detailsReq, (err, resp) => {
if (err) { if (err) {
reject(err); reject(err);
return; return;
@ -220,13 +221,13 @@ export class BoardsServiceImpl implements BoardsService {
resolve(resp); resolve(resp);
})); }));
const requiredTools = resp.getToolsdependenciesList().map(t => <Tool>{ const requiredTools = detailsResp.getToolsdependenciesList().map(t => <Tool>{
name: t.getName(), name: t.getName(),
packager: t.getPackager(), packager: t.getPackager(),
version: t.getVersion() version: t.getVersion()
}); });
const configOptions = resp.getConfigOptionsList().map(c => <ConfigOption>{ const configOptions = detailsResp.getConfigOptionsList().map(c => <ConfigOption>{
label: c.getOptionLabel(), label: c.getOptionLabel(),
option: c.getOption(), option: c.getOption(),
values: c.getValuesList().map(v => <ConfigValue>{ values: c.getValuesList().map(v => <ConfigValue>{
@ -236,10 +237,28 @@ export class BoardsServiceImpl implements BoardsService {
}) })
}); });
const listReq = new ListProgrammersAvailableForUploadReq();
listReq.setInstance(instance);
listReq.setFqbn(fqbn);
const listResp = await new Promise<ListProgrammersAvailableForUploadResp>((resolve, reject) => client.listProgrammersAvailableForUpload(listReq, (err, resp) => {
if (err) {
reject(err);
return;
}
resolve(resp);
}));
const programmers = listResp.getProgrammersList().map(p => <Programmer>{
id: p.getId(),
name: p.getName(),
platform: p.getPlatform()
});
return { return {
fqbn, fqbn,
requiredTools, requiredTools,
configOptions configOptions,
programmers
}; };
} }