Skip to content

ATL-1206, 1195, 1193, 1207, 1215, 786: Various fixes and improvements for ATL Sprint 20 #303

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 10 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@
"--log-level=debug",
"--hostname=localhost",
"--no-cluster",
"--app-project-path=${workspaceRoot}/electron-app",
"--remote-debugging-port=9222",
"--no-app-auto-install",
"--plugins=local-dir:plugins"
"--plugins=local-dir:../plugins"
],
"env": {
"NODE_ENV": "development"
Expand Down
2 changes: 1 addition & 1 deletion arduino-ide-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
],
"arduino": {
"cli": {
"version": "20210329"
"version": "0.18.1"
}
}
}
67 changes: 47 additions & 20 deletions arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Mutex } from 'async-mutex';
import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry, SelectionService, ILogger } from '@theia/core';
import { MAIN_MENU_BAR, MenuContribution, MenuModelRegistry, SelectionService, ILogger, DisposableCollection } from '@theia/core';
import {
ContextMenuRenderer,
FrontendApplication, FrontendApplicationContribution,
Expand All @@ -12,7 +12,7 @@ import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/li
import { CommandContribution, CommandRegistry } from '@theia/core/lib/common/command';
import { MessageService } from '@theia/core/lib/common/message-service';
import URI from '@theia/core/lib/common/uri';
import { EditorMainMenu, EditorManager } from '@theia/editor/lib/browser';
import { EditorMainMenu, EditorManager, EditorOpenerOptions } from '@theia/editor/lib/browser';
import { FileDialogService } from '@theia/filesystem/lib/browser/file-dialog';
import { ProblemContribution } from '@theia/markers/lib/browser/problem/problem-contribution';
import { MonacoMenus } from '@theia/monaco/lib/browser/monaco-menu';
Expand All @@ -26,7 +26,7 @@ import { inject, injectable, postConstruct } from 'inversify';
import * as React from 'react';
import { remote } from 'electron';
import { MainMenuManager } from '../common/main-menu-manager';
import { BoardsService, CoreService, Port, SketchesService, ExecutableService } from '../common/protocol';
import { BoardsService, CoreService, Port, SketchesService, ExecutableService, Sketch } from '../common/protocol';
import { ArduinoDaemon } from '../common/protocol/arduino-daemon';
import { ConfigService } from '../common/protocol/config-service';
import { FileSystemExt } from '../common/protocol/filesystem-ext';
Expand All @@ -44,10 +44,12 @@ import { WorkspaceService } from './theia/workspace/workspace-service';
import { ArduinoToolbar } from './toolbar/arduino-toolbar';
import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { OutputService } from '../common/protocol/output-service';
import { ResponseService } from '../common/protocol/response-service';
import { ArduinoPreferences } from './arduino-preferences';
import { SketchesServiceClientImpl } from '../common/protocol/sketches-service-client-impl';
import { SaveAsSketch } from './contributions/save-as-sketch';
import { FileChangeType } from '@theia/filesystem/lib/browser';
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';

@injectable()
export class ArduinoFrontendContribution implements FrontendApplicationContribution,
Expand Down Expand Up @@ -81,7 +83,7 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
protected readonly fileDialogService: FileDialogService;

@inject(FileService)
protected readonly fileSystem: FileService;
protected readonly fileService: FileService;

@inject(SketchesService)
protected readonly sketchService: SketchesService;
Expand Down Expand Up @@ -149,16 +151,20 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
@inject(ExecutableService)
protected executableService: ExecutableService;

@inject(OutputService)
protected readonly outputService: OutputService;
@inject(ResponseService)
protected readonly responseService: ResponseService;

@inject(ArduinoPreferences)
protected readonly arduinoPreferences: ArduinoPreferences;

@inject(SketchesServiceClientImpl)
protected readonly sketchServiceClient: SketchesServiceClientImpl;

@inject(FrontendApplicationStateService)
protected readonly appStateService: FrontendApplicationStateService;

protected invalidConfigPopup: Promise<void | 'No' | 'Yes' | undefined> | undefined;
protected toDisposeOnStop = new DisposableCollection();

@postConstruct()
protected async init(): Promise<void> {
Expand All @@ -182,6 +188,23 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
}
this.boardsServiceClientImpl.onBoardsConfigChanged(updateStatusBar);
updateStatusBar(this.boardsServiceClientImpl.boardsConfig);
this.appStateService.reachedState('ready').then(async () => {
const sketch = await this.sketchServiceClient.currentSketch();
if (sketch && (!await this.sketchService.isTemp(sketch))) {
this.toDisposeOnStop.push(this.fileService.watch(new URI(sketch.uri)));
this.toDisposeOnStop.push(this.fileService.onDidFilesChange(async event => {
for (const { type, resource } of event.changes) {
if (type === FileChangeType.ADDED && resource.parent.toString() === sketch.uri) {
const reloadedSketch = await this.sketchService.loadSketch(sketch.uri)
if (Sketch.isInSketch(resource, reloadedSketch)) {
this.ensureOpened(resource.toString(), true, { mode: 'open' });
}
}
}
}));
}
});

}

onStart(app: FrontendApplication): void {
Expand Down Expand Up @@ -225,6 +248,10 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
app.shell.leftPanelHandler.removeMenu('settings-menu');
}

onStop(): void {
this.toDisposeOnStop.dispose();
}

protected languageServerFqbn?: string;
protected languageServerStartMutex = new Mutex();
protected async startLanguageServer(fqbn: string, name: string | undefined): Promise<void> {
Expand Down Expand Up @@ -257,14 +284,14 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
if (log) {
const currentSketch = await this.sketchServiceClient.currentSketch();
if (currentSketch) {
currentSketchPath = await this.fileSystem.fsPath(new URI(currentSketch.uri));
currentSketchPath = await this.fileService.fsPath(new URI(currentSketch.uri));
}
}
const { clangdUri, cliUri, lsUri } = await this.executableService.list();
const [clangdPath, cliPath, lsPath] = await Promise.all([
this.fileSystem.fsPath(new URI(clangdUri)),
this.fileSystem.fsPath(new URI(cliUri)),
this.fileSystem.fsPath(new URI(lsUri)),
this.fileService.fsPath(new URI(clangdUri)),
this.fileService.fsPath(new URI(cliUri)),
this.fileService.fsPath(new URI(lsUri)),
]);
this.languageServerFqbn = await Promise.race([
new Promise<undefined>((_, reject) => setTimeout(() => reject(new Error(`Timeout after ${20_000} ms.`)), 20_000)),
Expand Down Expand Up @@ -367,10 +394,10 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
}
}

protected async ensureOpened(uri: string, forceOpen: boolean = false): Promise<any> {
protected async ensureOpened(uri: string, forceOpen: boolean = false, options?: EditorOpenerOptions | undefined): Promise<any> {
const widget = this.editorManager.all.find(widget => widget.editor.uri.toString() === uri);
if (!widget || forceOpen) {
return this.editorManager.open(new URI(uri));
return this.editorManager.open(new URI(uri), options);
}
}

Expand Down Expand Up @@ -420,13 +447,13 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
description: 'Background color of the toolbar items when hovering over them. Such as Upload, Verify, etc.'
},
{
id: 'arduino.toolbar.toggleBackground',
defaults: {
dark: 'editor.selectionBackground',
light: 'editor.selectionBackground',
hc: 'textPreformat.foreground'
},
description: 'Toggle color of the toolbar items when they are currently toggled (the command is in progress)'
id: 'arduino.toolbar.toggleBackground',
defaults: {
dark: 'editor.selectionBackground',
light: 'editor.selectionBackground',
hc: 'textPreformat.foreground'
},
description: 'Toggle color of the toolbar items when they are currently toggled (the command is in progress)'
},
{
id: 'arduino.output.foreground',
Expand Down
25 changes: 19 additions & 6 deletions arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ import { OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl, Ou
import { ExecutableService, ExecutableServicePath } from '../common/protocol';
import { MonacoTextModelService as TheiaMonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
import { MonacoTextModelService } from './theia/monaco/monaco-text-model-service';
import { OutputServiceImpl } from './output-service-impl';
import { OutputServicePath, OutputService } from '../common/protocol/output-service';
import { ResponseServiceImpl } from './response-service-impl';
import { ResponseServicePath, ResponseService } from '../common/protocol/response-service';
import { NotificationCenter } from './notification-center';
import { NotificationServicePath, NotificationServiceServer } from '../common/protocol';
import { About } from './contributions/about';
Expand Down Expand Up @@ -158,6 +158,11 @@ import { MonacoEditorProvider } from './theia/monaco/monaco-editor-provider';
import { MonacoEditorProvider as TheiaMonacoEditorProvider } from '@theia/monaco/lib/browser/monaco-editor-provider';
import { DebugEditorModel } from './theia/debug/debug-editor-model';
import { DebugEditorModelFactory } from '@theia/debug/lib/browser/editor/debug-editor-model';
import { StorageWrapper } from './storage-wrapper';
import { NotificationManager } from './theia/messages/notifications-manager';
import { NotificationManager as TheiaNotificationManager } from '@theia/messages/lib/browser/notifications-manager';
import { NotificationsRenderer as TheiaNotificationsRenderer } from '@theia/messages/lib/browser/notifications-renderer';
import { NotificationsRenderer } from './theia/messages/notifications-renderer';

const ElementQueries = require('css-element-queries/src/ElementQueries');

Expand Down Expand Up @@ -382,11 +387,11 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
Contribution.configure(bind, ArchiveSketch);
Contribution.configure(bind, AddZipLibrary);

bind(OutputServiceImpl).toSelf().inSingletonScope().onActivation(({ container }, outputService) => {
WebSocketConnectionProvider.createProxy(container, OutputServicePath, outputService);
return outputService;
bind(ResponseServiceImpl).toSelf().inSingletonScope().onActivation(({ container }, responseService) => {
WebSocketConnectionProvider.createProxy(container, ResponseServicePath, responseService);
return responseService;
});
bind(OutputService).toService(OutputServiceImpl);
bind(ResponseService).toService(ResponseServiceImpl);

bind(NotificationCenter).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(NotificationCenter);
Expand Down Expand Up @@ -435,4 +440,12 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(SettingsDialogProps).toConstantValue({
title: 'Preferences'
});

bind(StorageWrapper).toSelf().inSingletonScope();
bind(CommandContribution).toService(StorageWrapper);

bind(NotificationManager).toSelf().inSingletonScope();
rebind(TheiaNotificationManager).toService(NotificationManager);
bind(NotificationsRenderer).toSelf().inSingletonScope();
rebind(TheiaNotificationsRenderer).toService(NotificationsRenderer);
});
36 changes: 25 additions & 11 deletions arduino-ide-extension/src/browser/boards/boards-auto-installer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { injectable, inject } from 'inversify';
import { MessageService } from '@theia/core/lib/common/message-service';
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
import { BoardsService, BoardsPackage } from '../../common/protocol/boards-service';
import { BoardsService, BoardsPackage, Board } from '../../common/protocol/boards-service';
import { BoardsServiceProvider } from './boards-service-provider';
import { BoardsListWidgetFrontendContribution } from './boards-widget-frontend-contribution';
import { InstallationProgressDialog } from '../widgets/progress-dialog';
import { BoardsConfig } from './boards-config';
import { Installable } from '../../common/protocol';
import { ResponseServiceImpl } from '../response-service-impl';

/**
* Listens on `BoardsConfig.Config` changes, if a board is selected which does not
Expand All @@ -23,32 +24,45 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
@inject(BoardsServiceProvider)
protected readonly boardsServiceClient: BoardsServiceProvider;

@inject(ResponseServiceImpl)
protected readonly responseService: ResponseServiceImpl;

@inject(BoardsListWidgetFrontendContribution)
protected readonly boardsManagerFrontendContribution: BoardsListWidgetFrontendContribution;

// Workaround for https://github.com/eclipse-theia/theia/issues/9349
protected notifications: Board[] = [];

onStart(): void {
this.boardsServiceClient.onBoardsConfigChanged(this.ensureCoreExists.bind(this));
this.ensureCoreExists(this.boardsServiceClient.boardsConfig);
}

protected ensureCoreExists(config: BoardsConfig.Config): void {
const { selectedBoard } = config;
if (selectedBoard) {
if (selectedBoard && !this.notifications.find(board => Board.sameAs(board, selectedBoard))) {
this.notifications.push(selectedBoard);
this.boardsService.search({}).then(packages => {
const candidates = packages
.filter(pkg => BoardsPackage.contains(selectedBoard, pkg))
.filter(({ installable, installedVersion }) => installable && !installedVersion);
for (const candidate of candidates) {
const candidate = candidates[0];
if (candidate) {
// tslint:disable-next-line:max-line-length
this.messageService.info(`The \`"${candidate.name}"\` core has to be installed for the currently selected \`"${selectedBoard.name}"\` board. Do you want to install it now?`, 'Install Manually', 'Yes').then(async answer => {
const index = this.notifications.findIndex(board => Board.sameAs(board, selectedBoard));
if (index !== -1) {
this.notifications.splice(index, 1);
}
if (answer === 'Yes') {
const dialog = new InstallationProgressDialog(candidate.name, candidate.availableVersions[0]);
dialog.open();
try {
await this.boardsService.install({ item: candidate });
} finally {
dialog.close();
}
await Installable.installWithProgress({
installable: this.boardsService,
item: candidate,
messageService: this.messageService,
responseService: this.responseService,
version: candidate.availableVersions[0]
});
return
}
if (answer) {
this.boardsManagerFrontendContribution.openView({ reveal: true }).then(widget => widget.refresh(candidate.name.toLocaleLowerCase()));
Expand Down
33 changes: 33 additions & 0 deletions arduino-ide-extension/src/browser/boards/boards-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,39 @@ export namespace BoardsConfig {
return `${name}${port ? ' at ' + Port.toString(port) : ''}`;
}

export function setConfig(config: Config | undefined, urlToAttachTo: URL): URL {
const copy = new URL(urlToAttachTo.toString());
if (!config) {
copy.searchParams.delete('boards-config');
return copy;
}

const selectedBoard = config.selectedBoard ? { name: config.selectedBoard.name, fqbn: config.selectedBoard.fqbn } : undefined;
const selectedPort = config.selectedPort ? { protocol: config.selectedPort.protocol, address: config.selectedPort.address } : undefined;
const jsonConfig = JSON.stringify({ selectedBoard, selectedPort });
copy.searchParams.set('boards-config', encodeURIComponent(jsonConfig));
return copy;
}

export function getConfig(url: URL): Config | undefined {
const encoded = url.searchParams.get('boards-config');
if (!encoded) {
return undefined;
}
try {
const raw = decodeURIComponent(encoded);
const candidate = JSON.parse(raw);
if (typeof candidate === 'object') {
return candidate;
}
console.warn(`Expected candidate to be an object. It was ${typeof candidate}. URL was: ${url}`);
return undefined;
} catch (e) {
console.log(`Could not get board config from URL: ${url}.`, e);
return undefined;
}
}

}

}
10 changes: 10 additions & 0 deletions arduino-ide-extension/src/browser/boards/boards-list-widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,14 @@ export class BoardsListWidget extends ListWidget<BoardsPackage> {
]);
}

protected async install({ item, progressId, version }: { item: BoardsPackage, progressId: string, version: string; }): Promise<void> {
await super.install({ item, progressId, version });
this.messageService.info(`Successfully installed platform ${item.name}:${version}`, { timeout: 3000 });
}

protected async uninstall({ item, progressId }: { item: BoardsPackage, progressId: string }): Promise<void> {
await super.uninstall({ item, progressId });
this.messageService.info(`Successfully uninstalled platform ${item.name}:${item.installedVersion}`, { timeout: 3000 });
}

}
Loading