mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-16 05:39:28 +00:00
@@ -1,14 +1,15 @@
|
||||
import { injectable, inject, named } from 'inversify';
|
||||
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 { 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 { BoardsService, ConfigOption, Installable, BoardDetails } from '../../common/protocol';
|
||||
import { notEmpty } from '../../common/utils';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsService, ConfigOption, Installable, BoardDetails, Programmer } from '../../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class BoardsConfigStore implements FrontendApplicationContribution {
|
||||
export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
|
||||
@inject(ILogger)
|
||||
@named('store')
|
||||
@@ -60,39 +61,59 @@ export class BoardsConfigStore implements FrontendApplicationContribution {
|
||||
fqbn: 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);
|
||||
}
|
||||
|
||||
async getConfig(
|
||||
async getData(
|
||||
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;
|
||||
if (!version) {
|
||||
return [];
|
||||
return BoardsDataStore.Data.EMPTY;
|
||||
}
|
||||
const key = this.getStorageKey(fqbn, version);
|
||||
let configOptions = await this.storageService.getData<ConfigOption[] | undefined>(key, undefined);
|
||||
if (configOptions) {
|
||||
return configOptions;
|
||||
let data = await this.storageService.getData<BoardsDataStore.Data | undefined>(key, undefined);
|
||||
if (data) {
|
||||
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);
|
||||
if (!details) {
|
||||
return [];
|
||||
const boardDetails = await this.getBoardDetailsSafe(fqbn);
|
||||
if (!boardDetails) {
|
||||
return BoardsDataStore.Data.EMPTY;
|
||||
}
|
||||
|
||||
configOptions = details.configOptions;
|
||||
await this.storageService.setData(key, configOptions);
|
||||
return configOptions;
|
||||
data = { configOptions: boardDetails.configOptions, programmers: boardDetails.programmers };
|
||||
await this.storageService.setData(key, data);
|
||||
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 },
|
||||
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);
|
||||
if (!configOption) {
|
||||
return false;
|
||||
@@ -113,16 +134,16 @@ export class BoardsConfigStore implements FrontendApplicationContribution {
|
||||
if (!version) {
|
||||
return false;
|
||||
}
|
||||
await this.setConfig({ fqbn, configOptions, version });
|
||||
await this.setData({ fqbn, data: { configOptions, programmers }, version });
|
||||
this.fireChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected async setConfig(
|
||||
{ fqbn, configOptions, version }: { fqbn: string, configOptions: ConfigOption[], version: Installable.Version }): Promise<void> {
|
||||
protected async setData(
|
||||
{ fqbn, data, version }: { fqbn: string, data: BoardsDataStore.Data, version: Installable.Version }): Promise<void> {
|
||||
|
||||
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 {
|
||||
@@ -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: []
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,12 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { Board, ConfigOption } from '../../common/protocol';
|
||||
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 { ArduinoMenus } from '../menu/arduino-menus';
|
||||
|
||||
@injectable()
|
||||
export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution {
|
||||
export class BoardsDataMenuUpdater implements FrontendApplicationContribution {
|
||||
|
||||
@inject(CommandRegistry)
|
||||
protected readonly commandRegistry: CommandRegistry;
|
||||
@@ -21,8 +21,8 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
|
||||
@inject(MainMenuManager)
|
||||
protected readonly mainMenuManager: MainMenuManager;
|
||||
|
||||
@inject(BoardsConfigStore)
|
||||
protected readonly boardsConfigStore: BoardsConfigStore;
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@@ -30,7 +30,7 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
|
||||
protected readonly toDisposeOnBoardChange = new DisposableCollection();
|
||||
|
||||
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.updateMenuActions(this.boardsServiceClient.boardsConfig.selectedBoard);
|
||||
}
|
||||
@@ -41,8 +41,8 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
|
||||
this.mainMenuManager.update();
|
||||
const { fqbn } = selectedBoard;
|
||||
if (fqbn) {
|
||||
const configOptions = await this.boardsConfigStore.getConfig(fqbn);
|
||||
const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z_boardsConfig']; // `z_` is for ordering.
|
||||
const { configOptions, programmers } = await this.boardsDataStore.getData(fqbn);
|
||||
const boardsConfigMenuPath = [...ArduinoMenus.TOOLS, 'z01_boardsConfig']; // `z_` is for ordering.
|
||||
for (const { label, option, values } of configOptions.sort(ConfigOption.LABEL_COMPARATOR)) {
|
||||
const menuPath = [...boardsConfigMenuPath, `${option}`];
|
||||
const commands = new Map<string, Disposable & { label: string }>()
|
||||
@@ -51,7 +51,7 @@ export class BoardsDetailsMenuUpdater implements FrontendApplicationContribution
|
||||
const command = { id };
|
||||
const selectedValue = value.value;
|
||||
const handler = {
|
||||
execute: () => this.boardsConfigStore.setSelected({ fqbn, option, selectedValue }),
|
||||
execute: () => this.boardsDataStore.selectConfigOption({ fqbn, option, selectedValue }),
|
||||
isToggled: () => value.selected
|
||||
};
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
import { naturalCompare } from '../../../common/utils';
|
||||
import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol';
|
||||
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';
|
||||
|
||||
@injectable()
|
||||
@@ -41,8 +41,8 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
|
||||
@inject(BoardsConfigStore)
|
||||
protected readonly configStore: BoardsConfigStore;
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected coreServiceClient: CoreServiceClientImpl;
|
||||
@@ -52,7 +52,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
// Attached boards plus the user's config.
|
||||
protected availableBoards: AvailableBoard[] = [];
|
||||
// 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 selectedBoard?: (AvailableBoard & { port: Port });
|
||||
|
||||
@@ -86,7 +86,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
placeholder += 'No board selected.';
|
||||
}
|
||||
placeholder += 'Type to filter boards';
|
||||
if (this.boardConfigs.length) {
|
||||
if (this.data.configOptions.length) {
|
||||
placeholder += ' or use the ↓↑ keys to adjust the board settings...';
|
||||
} else {
|
||||
placeholder += '...';
|
||||
@@ -129,7 +129,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
|
||||
// Show the config only if the `input` is empty.
|
||||
if (!lookFor.trim().length) {
|
||||
toAccept.push(...this.boardConfigs.map((config, i) => {
|
||||
toAccept.push(...this.data.configOptions.map((config, i) => {
|
||||
let group: QuickOpenGroupItemOptions | undefined = undefined;
|
||||
if (i === 0) {
|
||||
group = { groupLabel: 'Board Settings', showBorder: true };
|
||||
@@ -157,14 +157,14 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
protected async update(availableBoards: AvailableBoard[]): Promise<void> {
|
||||
// `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 [configs, boards] = await Promise.all([
|
||||
selectedBoard && selectedBoard.fqbn ? this.configStore.getConfig(selectedBoard.fqbn) : Promise.resolve([]),
|
||||
const [data, boards] = await Promise.all([
|
||||
selectedBoard && selectedBoard.fqbn ? this.boardsDataStore.getData(selectedBoard.fqbn) : Promise.resolve(BoardsDataStore.Data.EMPTY),
|
||||
this.boardsService.allBoards({})
|
||||
]);
|
||||
this.allBoards = Board.decorateBoards(selectedBoard, boards)
|
||||
.filter(board => !availableBoards.some(availableBoard => Board.sameAs(availableBoard, board)));
|
||||
this.availableBoards = availableBoards;
|
||||
this.boardConfigs = configs;
|
||||
this.data = data;
|
||||
this.selectedBoard = selectedBoard;
|
||||
|
||||
if (this.isOpen) {
|
||||
@@ -280,7 +280,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
return;
|
||||
}
|
||||
const { fqbn } = this.selectedBoard;
|
||||
this.configStore.setSelected({
|
||||
this.boardsDataStore.selectConfigOption({
|
||||
fqbn,
|
||||
option: config.option,
|
||||
selectedValue: value.value
|
||||
|
||||
Reference in New Issue
Block a user